Hello everyone,
I was trying to create a 3D web-viewer with the help of the Django framework.
In the backend, I am using python ITK and VTK packages to read a series of DICOM images. And then I am passing the generated actor to the vtk.js on the HTML side for rendering. But I am getting errors related to ‘vtkRenderingOpenGL2Python.vtkOpenGLActor’ and I tried to search in google to find the solution but I couldn’t find any previous document or help related to this topic.
code: Backend side
import os
import vtk
import SimpleITK as sitk
from vtk.util import numpy_support
colors = vtk.vtkNamedColors()
colors.SetColor('SkinColor', [240, 184, 160, 255])
colors.SetColor('BackfaceColor', [255, 229, 200, 255])
colors.SetColor('BkgColor', [51, 77, 102, 255])
# Conversion ITK to VTK
def sitk2vtk(img, debugOn=False):
"""Convert a SimpleITK image to a VTK image, via numpy."""
size = list(img.GetSize())
origin = list(img.GetOrigin())
spacing = list(img.GetSpacing())
ncomp = img.GetNumberOfComponentsPerPixel()
direction = img.GetDirection()
# there doesn't seem to be a way to specify the image orientation in VTK
# convert the SimpleITK image to a numpy array
i2 = sitk.GetArrayFromImage(img)
if debugOn:
i2_string = i2.tostring()
print("data string address inside sitk2vtk", hex(id(i2_string)))
vtk_image = vtk.vtkImageData()
# VTK expects 3-dimensional parameters
if len(size) == 2:
size.append(1)
if len(origin) == 2:
origin.append(0.0)
if len(spacing) == 2:
spacing.append(spacing[0])
if len(direction) == 4:
direction = [direction[0], direction[1], 0.0,
direction[2], direction[3], 0.0,
0.0, 0.0, 1.0]
vtk_image.SetDimensions(size)
vtk_image.SetSpacing(spacing)
vtk_image.SetOrigin(origin)
vtk_image.SetExtent(0, size[0] - 1, 0, size[1] - 1, 0, size[2] - 1)
if vtk.vtkVersion.GetVTKMajorVersion() < 9:
print("Warning: VTK version <9. No direction matrix.")
else:
vtk_image.SetDirectionMatrix(direction)
# depth_array = numpy_support.numpy_to_vtk(i2.ravel(), deep=True,
# array_type = vtktype)
depth_array = numpy_support.numpy_to_vtk(i2.ravel())
depth_array.SetNumberOfComponents(ncomp)
vtk_image.GetPointData().SetScalars(depth_array)
vtk_image.Modified()
#
if debugOn:
print("Volume object inside sitk2vtk")
print(vtk_image)
# print("type = ", vtktype)
print("num components = ", ncomp)
print(size)
print(origin)
print(spacing)
print(vtk_image.GetScalarComponentAsFloat(0, 0, 0, 0))
return vtk_image
# File reader using ITK
# converter image file from ITK to VTK object
def file_reader(directory):
reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(directory)
l = []
for file in os.listdir(directory):
img = directory + file
l.append(img)
filename_sorted = sorted(dicom_names, key=lambda i: int(os.path.splitext(os.path.basename(i))[0]))
reader.SetFileNames(filename_sorted)
image = reader.Execute()
ITK_TO_VTK = sitk2vtk(image)
return ITK_TO_VTK
# Intensity range finder and isovalue creator
def data_range(ITKTOVTK):
# ITKTOVTK = sitk2vtk(image)
intensity_range = ITKTOVTK.GetPointData().GetScalars().GetRange()
isoValue = int((intensity_range[0] + intensity_range[1]) / 3)
return isoValue
# Surface volume rendering algorithm selector
def contour(itk_vtk_obj, isoVal):
contour_algo = vtk.vtkMarchingCubes()
contour_algo.SetInputData(itk_vtk_obj)
contour_algo.SetValue(0, isoVal)
contour_algo.ComputeNormalsOn()
mapper = vtk.vtkPolyDataMapper()
mapper.ScalarVisibilityOff()
mapper.SetInputConnection(contour_algo.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# actor.GetProperty().SetColor(222/256., 184/256., 135/256.)
actor.GetProperty().SetDiffuseColor(colors.GetColor3d('Red')) # red
actor.GetProperty().SetSpecular(0.3)
actor.GetProperty().SetSpecularPower(1)
actor.GetProperty().SetOpacity(0.9)
return actor
And in Django app view.py, I passed the bellow lines of code to render
# Image directory: contains series of dicom files
directory = "/Micro_temp_1/visapp/media/1/Channel_-01-0/"
# Create your views here.
def IndexView(request):
i = file_reader(directory)
iso_Val = data_range(i)
iii = contour(i, iso_Val)
# convert into JSON
iiii = iii.tolist()
reader = json.dumps(iiii)
print(type(iii))
# iiii = volume_render(iii)
context = {"r": reader, "text": "h", "array": [4, 5]}
return render(request, 'visapp/index.html', context)
Inside the Index.HTML page
<script>
const fullScreenRenderer = vtk.Rendering.Misc.vtkFullScreenRenderWindow.newInstance({background: [0, 0, 0],});
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
actor = {{r}}
// console.log(actor)
renderer.addActor(actor);
renderer.getActiveCamera().set({ position: [1, 1, 0], viewUp: [0, 0, -1] });
renderer.resetCamera();
</script>
I am getting a bellow error:
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 3.2.8
Python Version: 3.7.10
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'visapp.apps.VisappConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/home/anaconda3/envs/Micro_temp_1/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/anaconda3/envs/Micro_temp_1/lib/python3.7/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/PycharmProjects/Micro_temp_1/Micro_temp_1/visapp/views.py", line 14, in IndexView
iiii = iii.tolist()
Exception Type: AttributeError at /
Exception Value: 'vtkRenderingOpenGL2Python.vtkOpenGLActor' object has no attribute 'tolist'
Is there any way to send the VTK actor object to the vtk.js side for rendering?