Is there any way yo directly extract an image from vtkImageData to export it as a tiff/png image?

Hi,

I am testing loading a series of rgb images as a volume using the ImageStacksModule, cropped them with an ROI, and export them as a new series of rgb images in the format of tiff or png.

An example image is here:

So far, I can successfully export a slice of image from a volume by first extracting the numpy array of an image from a vector volume. I then use this numpy array to create a new vector volume node vectorVolume that only contains one image.

After that, I can use vectorVolume.GetImageData() to extract the vtkImageData of the vectorVolume, which now contains only 1 image. This allows me export it using vtkTIFFWriter() or vtkPNGWriter(), which can only take the vtkImageData object.

However, for every image in the original volume, I have to create a new volume with just one image to export it.

Therefore, I’m also thinking about directly output each image from the vtkImageData of the volume acquired from vectorVolumeNode.GetImageData() so that I don’t have to build a new volume for each image.

I could not find a way to do it. For an experiment, I tried to directly pass the numpy array of an image into vtkImageData object following the example here: How to convert 3D numpy array to vtk and save the .vtk file? - #3 by user4

image = imageArray[0, :, :, :] #Get the first image array from slicer.util.arrayFromVolume(vectorVolume)
shape = image.shape
vtype = vtk.util.numpy_support.get_vtk_array_type(image.dtype)

flat_img_array = image.flatten()
vtk_arr = vtk.util.numpy_support.numpy_to_vtk(num_array=flat_img_array, deep=True, array_type=vtype)

imgVTK = vtk.vtkImageData()
imgVTK.GetPointData().SetScalars(vtk_arr)
imgVTK.SetDimensions(shape)

I then exported the imgVTK as PNG:

w_png = vtk.vtkPNGWriter()
w_png.SetInputData(imgVTK)
w_png.GetInput()
w_png.SetFileName('tmp/test.png')
w_png.Write()

However, all I got is an image with pixels re-arranged.

Is there any way I can directly extract each image from vectorVolumeNode.GetImageData() as a single vtkImageData object and export it using vtkTIFFWriter without building a new volume for each image?

Thank you!

I don’t know if it helpful but have you tried using vtkOriemtedImageData?

1 Like

Looks like the data is there, just scrambled. The image you get out is going to be 2D rgb but in your code you set the vtkImageData dimensions as if it were 3D. You need to set the width and height dimensions and the slice dimension to be 1. Then you set the number of components to be 3, Probably best using AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3).

If you want one tiff file per frame, then you can just use the same vtkImageData in a loop that just copies the data and re-runs the writer. It should run pretty fast.

Thanks! I’ll try that, but I could not find information about this method. Can you send me an introduction of vtkOrientedImageData?

Thank you, Steve! What I did successfully is to use slicer.util.arrayFromVolume to get the np array for all rgb images, and then create a single-image volume for each image using slicer.util.updateVolumeFromArray(outputNode, singleImageArray). From each single-image volume, I then get the vtkImage data and export it as tiff/png.

This is still relatively fast, but being able to loop through the original multi-image vtkImageData would be most straightforward and efficient.

However, I could not find a way to directly loop through a multi-image vtkImageData. Can you give me some suggestions about how to do it, or maybe what I did about building a volume for each image is proper?

Here you have code with explamations

Mauro

1 Like

I figured what I did wrong. In addition to the dimensions and AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) as you suggested, I also forgot to set up the component number for the vtk array. of the rgb image using SetNumberOfComponents. I did:

channel_count =3
vtk_arr.SetNumberOfComponents(channel_count) #vtk_arr is the vtkDataArray from the flattened np image array of the single RGB image

Then I successfully output a slice of cropped image! Thanks!

2 Likes

I think that’s veey fantastix

1 Like