RuntimeError: No suitable template parameter can be found

Hello,

I am trying to replicate the code from this notebook ITK-Watershed to Label Bubbles | Kaggle for 3D watershed segmentation locally. It runs in the notebook, however, locally, itk.GetArrayFromImage(watershedOp) yields RuntimeError: No suitable parameter can be found. I am not sure how to resolve this. Thanks.

Which line produces the error? Which version of ITK are you using?

Thanks for your response:

def apply_watershed(in_vol, 
                    threshold = 0.01, 
                    level = 0.5):
    """
    threshold:  is used to set the absolute minimum height value used during processing. 
        Raising this threshold percentage effectively decreases the number of local minima in the input, 
        resulting in an initial segmentation with fewer regions. 
        The assumption is that the shallow regions that thresholding removes are of of less interest.
    level: parameter controls the depth of metaphorical flooding of the image. 
        That is, it sets the maximum saliency value of interest in the result. 
        Raising and lowering the Level influences the number of segments 
        in the basic segmentation that are merged to produce the final output. 
        A level of 1.0 is analogous to flooding the image up to a 
        depth that is 100 percent of the maximum value in the image. 
        A level of 0.0 produces the basic segmentation, which will typically be very oversegmented. 
        Level values of interest are typically low (i.e. less than about 0.40 or 40% ), 
        since higher values quickly start to undersegment the image.
    """
    #(A rule of thumb is to set the Threshold to be about 1 / 100 of the Level.)
    Dimension = len(np.shape(in_vol))
    # convert to itk array and normalize
    itk_vol_img = itk.GetImageFromArray((in_vol*255.0).clip(0,255).astype(np.uint8))
    InputImageType = itk.Image[itk.ctype('unsigned char'), Dimension]
    OutputImageType = itk.Image[itk.ctype('float'), Dimension]
    dmapOp = itk.SignedMaurerDistanceMapImageFilter[InputImageType, OutputImageType].New(Input = itk_vol_img)
    dmapOp.SetInsideIsPositive(False)
    watershedOp = itk.WatershedImageFilter.New(Input=dmapOp.GetOutput())
    watershedOp.SetThreshold(threshold)
    watershedOp.SetLevel(level)
    watershedOp.Update()
    return itk.GetArrayFromImage(dmapOp), itk.GetArrayFromImage(watershedOp)

The error occurs in the return statement of this function for itk.GetArrayFromImage(watershedOp). I am using ITK version 5.2 with Python 3.8.8 but have also tried ITK version 5.1.2 and Python 3.6.4 like in the notebook. I am using a conda environment.

Try changing the last line into: return itk.GetArrayFromImage(dmapOp.GetOutput()), itk.GetArrayFromImage(watershedOp.GetOutput())

Or for easier debuggability, into a few lines:

distance_image = itk.GetArrayFromImage(dmapOp.GetOutput())
segmentation = itk.GetArrayFromImage(watershedOp.GetOutput())
return distance_image, segmentation

The same RuntimeError still occurs in the segmentation line.

Ah, you might be affected by issue 2551. Does numpy support 64-bit unsigned element type?

Numpy has np.uint64 as a data type if that is what you mean?
watershedOp.GetOutput() produces <itk.itkImagePython.itkImageULL3; proxy of <Swig Object of type 'itkImageULL3
Sorry, I am not sure how to interpret a solution from that issue in this case.

I think that the problem is absence of ULL from this list of types for PyBuffer which does conversion between ITK and Numpy:

If you could create a short, self-contained example I could verify this and create a patch to fix it.

import numpy as np
import itk
from skimage.io import imread, imsave

def apply_watershed(in_vol, threshold=0.01, level=0.5):
    Dimension = len(np.shape(in_vol))
    # convert to itk array and normalize
    itk_vol_img = itk.GetImageFromArray((in_vol*255.0).clip(0,255).astype(np.uint8))
    InputImageType = itk.Image[itk.ctype('unsigned char'), Dimension]
    OutputImageType = itk.Image[itk.ctype('float'), Dimension]
    dmapOp = itk.SignedMaurerDistanceMapImageFilter[InputImageType, OutputImageType].New(Input = itk_vol_img)

    dmapOp.SetInsideIsPositive(False)
    watershedOp = itk.WatershedImageFilter.New(Input=dmapOp.GetOutput())
    watershedOp.SetThreshold(threshold)
    watershedOp.SetLevel(level)
    watershedOp.Update()
    distance_image = itk.GetArrayFromImage(dmapOp.GetOutput())
    segmentation = itk.GetArrayFromImage(watershedOp.GetOutput())
    return distance_image, segmentation

if __name__ == '__main__':
    image = imread('plateau_border.tif')
    dist_img, seg_img = apply_watershed(image)

The attached zip contains the tif file I obtained from ITK-Watershed to Label Bubbles | Kaggle.
plateau_border.zip (1.3 MB)

I hope this is enough for you to work with. Thank you very much for your time and looking into this.

I created PR 2554. If you build ITK yourself, it would be good if you tried the fix now. If not, you will have to wait for the next patch release.

1 Like

Sorry, I’m late to the conversation.

Thanks for reporting issue @nbob, and thanks for addressing the issue @dzenanz :100:.

For the sake of completeness, adding Kevin’s example to the ITKSphinxExamples is still a long stating task that has been lying on my end:

I am sorry; have not found the energy and time to give it a new try. But it will come at some point. Thanks for the patience.

1 Like

Maybe @nbob might be interested in picking up your work? The Python code can be significantly shortened and simplified by using the newer, procedural interface of ITK.

Thank you both for your time. @dzenanz I do not have any experience with ITK or contributing to software. While I am intrigued, I also have no idea what to do to be honest.

Yes, ITK has greatly evolved since then, and this is something that was not complete at the time, so I should have a look at that.

Thanks @nbob. If you feel like you want to give it a try, you can start having a look at more simple examples to see how the framework is designed to pick up the code, show the images, etc.

Other than this specific case, examples demonstrating the many other ITK classes are also more than welcome :100:.

We grant that we should add a CONTRIBUTING file to the documentation.

Kevin’s example is a little bit more complex since it has many parts that I decided to split and put into (hopefully) re-usable files/methods. But last time I gave the example a try, I was not able not reproduce the results on the Kaggle website, and had issues with some Python statements. I should revisit that to see how things are now.

2 Likes