Prism (defined by 6 planes) volume crop from other volume.

Dear All,

reader.GetOutputPort() have a .mhd image
There are 6 planes which is defined by 3 points in which is get the normal of the plane.
I want to remove to a volume, a prism (6 faces) delimited by 6 planes.
volume, renderer, renderWindow, volumeMapper are all defined.
The code below gives the below error.
Can you help?

        plane6 = vtk.vtkPlane()
        plane6.SetOrigin(x1[15],y1[15],z1[15])
        p3p1=np.array([x1[17]-x1[15],y1[17]-y1[15],z1[17]-z1[15]])
        p2p1=np.array([x1[16]-x1[15],y1[16]-y1[15],z1[16]-z1[15]])
        cross1=np.cross(p3p1,p2p1)
        cross1=cross1/np.linalg.norm(cross1)
        dot1=cross1[0]*(sidex[5]-x1[15])+cross1[1]*(sidey[5]-y1[15])+cross1[2]*(sidez[5]-z1[15])
        if (dot1 < 0.0):
            cross1=-cross1
        plane6.SetNormal(cross1[0],cross1[1],cross1[2])
        union = vtk.vtkImplicitBoolean()
        union.AddFunction(plane1)
        union.AddFunction(plane2)
        union.AddFunction(plane3)
        union.AddFunction(plane4)
        union.AddFunction(plane5)
        union.AddFunction(plane6)
        union.SetOperationType(1) #VTK_INTERSECTION 
        extract = vtk.vtkExtractGeometry()
        extract.SetInputConnection(reader.GetOutputPort())
        extract.SetImplicitFunction(union)
        volumeMapper.SetInputConnection(extract.GetOutputPort())
        volume.SetMapper(volumeMapper)
        renderer.AddVolume(volume)
        renderWindow.Render()

2021-03-01 13:18:04.341 ( 31.721s) [ ]vtkDemandDrivenPipeline:760 ERR| vtkCompositeDataPipeline (0000025F7D7C0280): Input for connection index 0 on input port index 0 for algorithm vtkOpenGLGPUVolumeRayCastMapper(0000025F7DA17BD0) is of type vtkUnstructuredGrid, but a vtkImageData is required.

Thanks,

Luís Gonçalves

You are feeding a vtkImageData to a filter that requires vtkUnstructuredGrid inputs.
You can use the filter vtkAdaptiveResampleToImage right before the volume mapper. This filter will resample your unstructured grid into a set of images with adaptive resolutions depending on the input geometry.

Sorry, I do not know how to use it. I tried below: (see how it fits in the last post code)


      image1=vtk.vtkAdaptiveResampleToImage(extract.GetOutputPort())
      volumeMapper.SetInputConnection(image1)

************************************************************************************************++
Traceback (most recent call last):
File “D:\zipback\visual studio 2015\Projects\RegistrationAR\RegistrationAR\teste1.py”, line 214, in thread_function
image1=vtk.vtkAdaptiveResampleToImage(extract.GetOutputPort())
AttributeError: module ‘vtkmodules.all’ has no attribute ‘vtkAdaptiveResampleToImage’

What version of VTK are you using? If I’m not wrong, this filter was introduced in VTK 9.

image

Maybe it didn’t make it to the release then…

You can try using vtkResampleToImage instead. There are 2 methods you might want to use with this filter: SetInputBounds(true) and SetSamplingDimensions(xdim, ydim, zdim).

The goal is to do volume rendering with clipping? If yes, then the usual way to do this is to feed the vtkImageData directly into the vtkVolumeMapper, and use the mapper to clip the data while it is being rendered. The SetClippingPlanes methods are documented here.

In general, using the mapper’s clipping planes is by far the most efficient method, unless the volume is very large and the prism region is very small.

If the prism region is much smaller than the volume, then you can compute the bounding box of the prism, and use this bounding box to crop the volume before feeding it into a mapper that will crop it with the prism.

Converting an image to an unstructured grid and vice-versa is very computationally expensive, so I would avoid that unless you have no other options.


Edit: if you just want to zero all of the image voxels that aren’t inside the prism, this can be efficiently done with vtkImplicitFunctionToImageStencil. See TestStencilWithImplicitFunction.py, unfortunately it’s not a great example because it has few comments. There is a bit more explanation here.

The vtkPlanes class is more efficient to evaluate than vtkImplicitBoolean, so it will provide better performance.


Edit 2: Note that enums that are defined in VTK classes can be accessed like this:

union.SetOperationType(vtk.vtkImplicitBoolean.VTK_INTERSECTION)

The rules for wrapping enums from VTK into Python are as follows:

  1. enum values defined in the global namespace are attributes of the ‘vtk’ namespace
  2. enum values defined in a class namespace are attributes of that class
  3. enum values in an “enum class” are attributes of that “enum class” (similar to the Python “enum” type in Python 3)

In other words, in the Python wrappers, enum constants are used much the same way as in C++.

1 Like