vtkImageReslice "Fills Background" with Zeros. How Can I Change this Behavior?

Hello,

I have a DICOM volume that was acquired in a double-oblique orientation on the scanner. After reading the DICOM using vtkDICOMImageReader, I pipe the volume through vtkImageReslice, then use the DICOM image attributes to apply an affine transformation matrix to the reslice filter. This nicely reslices my volume in an axial orientation. All good. BUT! vtkImageReslice seems to “fill the background” of the reformatted volume with zeros. This is not good. I would like the “background” voxels to be transparent.

I found a couple of old @dgobbi posts where he suggests running the DICOM data through a vtkImageMapToColors filter before piping it to the reslicer. But I’m afraid I do not understand how to do this.

Can anyone help?

Thank you,

Michelle K.

You can use vtkImageReslice::SetBackgroundLevel/Color methods to set the background fill level/color. There are also mirror and wrap options.

Thanks, Andras. I tried both SetBackgroundColor and SetBackgroundLevel, but they seem to have no effect on the outcome.
Here are screen grabs of before and after reformatting:
No reformatting:

Reformatted:

Notice that after reformatting, the background is all zeros. The DICOM volume is 256 x 208, and 14 slices deep.

reslice= vtk.vtkImageReslice()
reslice.SetInputConnection(caster.GetOutputPort())
reslice.SetResliceAxes(inverse_affine) # inverse of the DICOM’s affine trans. matrix
# reslice.SetBackgroundColor(0.0, 0.0, 0.0, 1.0) # tried both of these
reslice.SetBackgroundLevel(0) # tried both of these
reslice.AutoCropOutputOn()
reslice.SetOutputDimensionality(2)
reslice.SetInterpolationModeToLinear()
oblique.Update()

Thanks!
Michelle

Hi Michelle,

When both the input and the output of vtkImageReslice are grayscale, setting transparency is impossible because there is no alpha component.

The easiest solution is to use vtkImageResliceToColors with SetOutputFormatToRGBA(), which will produce an RGBA color image as output. The alpha channel of all background pixels will be set to zero, therefore they will be transparent.

When using vtkImageResliceToColors, it is also necessary to call SetLookupTable(). If you already have a lookup table, you can set it here, otherwise you can create one:

lut = vtkScalarsToColors()
lut.SetRange(0.0, 1023.0) # min, max values to map to black and white
lut.SetVectorModeToRGBColors() # in case the input is already color data
reslice = vtkImageResliceToColors()
reslice.SetLookupTable(lut)

Another option for getting transparency is to use vtkImageResliceMapper instead of vtkImageReslice, but that would require a redesign of your pipeline.

1 Like

Thanks, David. The problem with using vtkImageSliceToColors() is that I need to do some arithmetic on the original image scalars each time I reslice. The calculations cannot be performed on RGBA values.

But this gives me an idea. What if I were to reslice the image using vtkImageReslice.SetResliceAxes(), perform my calculations on the resulting slice, update the vtkImageReslice object with the new scalar values, then use vtkImageSliceToColors on the vtkImageReslice object?

i.e., vtkImageData ==> vtkImageReslice ==> scalar arithmetic ==> updated vtkImageReslice ==> vtkImageSliceToColors.

Yes?

  • Michelle

Hi Michelle,

That might not work, because the “scalar arithmetic” will not know which pixels are background pixels. If this doesn’t actually matter, you could try a split pipeline like this:

vtkImageData ---> vtkImageReslice ---> scalar arithmetic
              \--> vtkImageResliceToColors -> render the result

A completely different solution would be to use GenerateStencilOutputOn() with vtkImageReslice. This will cause vtkImageReslice to produce two outputs: the first output will be the resliced image, and the second output will be a vtkImageStencilData object that is a mask for the background pixels.

Several VTK filters have a SetStencilConnection() method that will allow you to use this stencil to mask their actions. For example, vtkImageBlend and even vtkImageReslice itself can use a stencil. A “stencil” in VTK is equivalent to a “selection” in Photoshop.

Now that I’ve better understood your code from the other thread, I have another suggestion about how to properly apply the colors after vtkImageReslice. It’s actually very similar to the pipeline that you suggested, but it incorporates the image stencil.

vtkImageData ---> vtkImageReslice ----->  vtkImageResliceToColors
                          \--> vtkImageStencilData --^

When vtkImageResliceToColors uses a vtkImageStencilData, everything “outside” of the stencil becomes transparent, i.e. RGBA = (0,0,0,0) for all “outside” pixels. So in this case, the first “reslice” is reslicing the data and the second “reslice” is actually just coloring the data. Essentially it’s being used in exactly the same way as vtkImageMapToColors, except that it has a “stencil” input and vtkImageMapToColors does not.

reslice = vtk.vtkImageReslice()
reslice.SetInputConnection(yada_yada)
reslice.SetResliceTransform(...)   # or SetResliceAxes(...)
reslice.GenerateStencilOutputOn() # generate a stencil for use by other filters

toColors = vtk.vtkImageResliceToColors()
# do not set ResliceTransform or ResliceAxes, the other reslice does "reslicing",
# but this one only does color mapping and applies the stencil (the mask)
toColors.SetLookupTable(table)
toColors.SetOutputFormatToRGBA() # need alpha channel for transparency
toColors.SetInputConnection(reslice.GetOutputPort())
toColors.SetStencilConnection(reslice.GetStencilOutputPort())

Thank you for this suggestion, David. However, vtkImageResliceToColors does not have a SetStencilConnection attribute. I am having trouble finding examples and documentation on SetStencilConnection, too. I am using vtk 8.2. What version are you using?

I could have sworn it had a “Connection” method for the stencil, but you’re right, it doesn’t. It only has a SetStencilData() method. I’m using the VTK master branch from git, but the interface to vtkImageReslice hasn’t changed. So the code would have to be changed as follows:

reslice = vtk.vtkImageReslice()
reslice.SetInputConnection(yada_yada)
reslice.SetResliceTransform(...)   # or SetResliceAxes(...)
reslice.GenerateStencilOutputOn() # generate a stencil for use by other filters
reslice.Update() # this is needed before the GetStencilOutput() below

toColors = vtk.vtkImageResliceToColors()
# do not set ResliceTransform or ResliceAxes, the other reslice does "reslicing",
# but this one only does color mapping and applies the stencil (the mask)
toColors.SetLookupTable(table)
toColors.SetOutputFormatToRGBA() # need alpha channel for transparency
toColors.SetInputConnection(reslice.GetOutputPort())
toColors.SetStencilData(reslice.GetStencilOutput())

Some of the VTK tests can be used as examples, but they don’t cover all the use cases:

Filters/Hybrid/Testing/Python/TestImageStencilWithPolydata.py
Imaging/Core/Testing/Cxx/TestStencilWithPolyDataContour.cxx
Imaging/Core/Testing/Cxx/TestStencilWithPolyDataSurface.cxx
Imaging/Core/Testing/Cxx/TestStencilWithLasso.cxx
Imaging/Core/Testing/Cxx/TestImageStencilData.cxx
Imaging/Core/Testing/Python/TestStencilWithFunction.py
Imaging/Core/Testing/Python/TestBlendStencil.py
Imaging/Core/Testing/Python/TestROIStencil.py
Imaging/Core/Testing/Python/TestStencilWithImage.py
Imaging/Core/Testing/Python/TestLassoStencil.py

Hi David,

I am so grateful for your assistance with this zero-filled background issue as well as the opacity issue (Cannot Control Opacity of vtkImageActors) discussed in another thread.

Using the stencil which can optionally be generated by vtkImageReslice was an absolute break-through for me. Finally, the reformatted image overlay makes sense. With your vtkStack, I was able to control the opacity, and with the stencil I was able to remove all of the background zeros.

I am also grateful for all of the help you provide to other vtk users. There is a lot of information in those posts. I have learned so much from you!

Best wishes,
Michelle

Hi Michelle, glad to hear that it’s working. Thanks for posting the image.