How to apply a filter only to a specific region of a 3D volume? [C++]


(Riccardo Ballarini) #1

Hi,
I have a 3D dicom volume, I made a region growing to obtain a binary mask of a specific part of this volume, and now i want to apply a filter and work on the volume only on the part identified by the ones of the binary mask. How can I do that?
I multiply the mask and the volume to set to 0 all the voxel out of the mask, but in this way the filter also work on the voxel at 0, but I want it only on the mask part.
Thanks for the help.


(Pablo Hernandez-Cerdan) #2

You can use SetRequestedRegion(smallerSize). This example shows how to use it: Apply A Filter Only To A Specified Region Of An Image

Finding that smallerSize automatically is another quest. Not sure if there is already a function that extract the smaller bounding box which encloses ALL non-zero voxels.
But it should be easy to get that box just iterating over the image and storing the min/max index with non-zero values on each dimension.
Hope it helps.


(Riccardo Ballarini) #3

Hi and thanks for the answer. I already see that example, but I don’t want to create a bounding box: the mask that I have isn’t regular (e.g. cubic), but has got a different size and shape for each slice of the volume.


(Pablo Hernandez-Cerdan) #4

The filters work with images (i.e. regular/cubic regions). If you want to operate on individual voxels depending on its value, you would need to iterate over the image and apply different logic depending on the value.

What operation do you want to perform in the non-zero voxels?


(Riccardo Ballarini) #5

I start with a CT volume, with region growing I isolate the liver and I create a binary mask (1 liver, 0 all the rest) because I need to work only on the liver. In detail, I have to apply Otsu’s filter (a particular threshold) and then a level-set, in order to segment the vascular network of the liver.
So I should apply otsu and level-set only on the liver (only where the mask is 1), I need the equivalent of something like volume(mask==1) in Matlab, because I can easily do it on Matlab but i don’t know how to do it in ITK.


(Bradley Lowekamp) #6

The OstuThresholdImageFilter does have a SetMaskImage member.

The SimpleITK Python bindings do have overloaded operator so your cold do mask==1 as well.


(Riccardo Ballarini) #7

Blowekamp thanks! I red only the handbook, so I didn’t notice that SetMaskImage input. So I just have to put my binary mask into the otsu filter and it will work only on that regione, right?


(Riccardo Ballarini) #8

I red the documentation about otsu at your link (https://itk.org/Doxygen/html/classitk_1_1OtsuThresholdImageFilter.html) and there isn’t anything about the SetMaskImage member.
Anyway, I tried to use it, but it doesn’t work correctly. I used otsu->SetMaskImage(binarymask) and otsu->SetMaskValue(1), is it right?


(Pablo Hernandez-Cerdan) #9

Post a Minimal Working Example, so other people can reproduce it and see the actual code.

OtsuThresholdImageFilter is derived from HistogramThresholdImageFilter, which contains the SetMaskImage that @blowekamp mentioned. Check the documentation there.


(Ziv Yaniv) #10

Hello @Riccardo_Ballarini,

For future reference, the doxygen page will only show the methods specific to the class. Inherited methods do not appear on the main documentation page. For that, click on “List of all members” top right portion of the page.


(Riccardo Ballarini) #11

@phcerdan the script isn’t “generic”, it works only on my volume, but I can share the otsu block (I think I’m using the SetMaskImage in a wrong way).

typedef itk::OtsuThresholdImageFilter< ImageType, ImageType, ImageType >	OtsuType;
OtsuType::Pointer otsu = OtsuType::New();

otsu->SetOutsideValue( 0 );
otsu->SetInsideValue ( 1 );

otsu->SetInput1( rescaler->GetOutput() );
otsu->SetMaskImage( dilate->GetOutput() );
otsu->SetMaskValue( 1 );

Where ImageType is a generic volume in double, rescaler gives as output the volume in double in the range [0,1] and dilate gives as output the 3D binary mask in double with 0 value for the background and 1 for the foreground.

So should I use also the HistogramThresholdImageFilter?


(Pablo Hernandez-Cerdan) #12

No, you are good using the OtsuThresholdImageFilter. The SetMaskImage function member is defined in the base class: HistogramThesholdImageFilter. That’s why you couldn’t see the documentation for it, but following @zivy suggestion will help you in the future:

Thanks for the extra info. And what is the error you are facing? What are the values on the output image?
Try to set the InsideValue too. Because you are working with double images (this is an overkill in memory for a binary image by the way), the InsideValue is by default set to the std::numeric_limits<double>::max(), which is BIG for the type double, and some viewers might have problems to render.

Check the full list of members here: https://itk.org/Doxygen/html/classitk_1_1OtsuThresholdImageFilter-members.html

Try:

// Set the values of the output image generated by the Otsu filter:
otsu->SetInsideValue ( 1 );
otsu->SetOutsideValue( 0 ); // Zero is the default already. But being explicit is fine.

Also:

It might be equivalent for this case, but prefer to use named Set functions than the SetInputX versions. It makes things clearer. Use SetInput(rescaler->GetOutput() ) and SetMaskImage (as you do) instead of SetInput1 and SetInput2.

Hope it helps


(Riccardo Ballarini) #13

I just made the same steps on Matlab, and I discovered that the ITK script works right. The problem is that Otsu thresholding isn’t the right method for my volume, so the result seemed wrong.
Thanks you all for the help!