Reference count with Python

python

(Julien Finet) #1

Hi all,

In Python, I have the following code:

  def generateSource():
    reader = itk.ImageReader[ImageType].New()
    ...
    itkToVtkFilter = itk.ImageToVTKImageFilter[ImageType].New()
    itkToVtkFilter.SetInput(reader.GetOutput())
    return itkToVtkFilter.GetImporter()
 
  def main():
    source = generateSource()
    source.Update()

Problem is, reader and itkToVtkFilter are destroyed after generateSource() is called. How can you increase reference count in ITK/Python ? What would be the best approach ?

Thanks,
Julien


(Francois Budin) #2

One approach (I am not sure if it is the best) that I have used in itk.GetArrayFromImage(), is to associate the object that should not be destroyed to the object that is returned, as a “private member” (i.e. a member whose name starts with ‘_’): See https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Bridge/NumPy/wrapping/PyBuffer.i.in#L152


(Francois Budin) #3

Actually @finetjul, there is a way simplier solution than the one I suggested above. Thanks @matt.mccormick for pointing this out. You need to update (call .Update()) your filter before returning the output of your filter.


(Julien Finet) #4

Thanks @fbudin for the 2 solutions. There are problems with both however.

Your first solution (private member) works but the pipeline is never destroyed:
itkToVtkFilter.SetInput(reader.GetOutput())
source = itkToVtkFilter.GetImporter()
source._itkToVtkFilter = itkToVtkFilter
source._dicomReader = dicomReader
return source

For the Update() solution, it does not work. Moreover, I do not want to call .Update() on the filter before returning because it would update the whole extent of the reader (which is actually an ImageSeriesReader with lots of 2D slices). I would prefer if the .Update() is called after specifying the update extent but that happens further down the code (it is the VTK mapper that specifies the update extent).

Thanks,
Julien.


(Francois Budin) #5

I see. Then what you want to look at is this:

You can find some examples on how to use it in the tests, for example here:


(Bradley Lowekamp) #6

The ITK DataObject base class contains a weak pointer to the it’s source filter. So if only a pointer to then end of the pipeline is held the all preceding filters will be deleted. An additional pointer to all root filters in the pipeline needs to be held to keep the whole pipeline around/

I would suggest creating the VTK command object class which holds a pointer the the ITK root filters. Then adding that command class as an observer to the VTK filter to say the “delete” event. This should maintain the reference needed to the root node and automatically be deleted when the VTK filter at the end of the pipeline is deleted. This is an approach that I recall doing in C++, but the translation to python is not clear to me.


(Matt McCormick) #7

The pipeline and autopipeline that @fbudin referenced for generating Python pipelines are quite awesome and worth a look! :eyes:


(Francois Budin) #8

Here is a short example how to use the Python pipeline:

def my_func():

my_pipeline=itk.pipeline()
MedianFilter=itk.MeanImageFilter.IUC2IUC2.New()
my_pipeline.connect(MedianFilter)
my_pipeline.expose("Radius")
thresholdFilter=itk.ThresholdImageFilter.IUC2.New()
my_pipeline.connect(thresholdFilter)
my_pipeline.expose("Lower")
return my_pipeline

my_pipeline = my_func()
my_pipeline.SetInput(im)
my_pipeline.SetRadius(5)
my_pipeline.SetLower(100)
my_pipeline.Update()
arr=itk.GetArrayFromImage(my_pipeline.GetOutput())

You could also derive the itk.pipeline class and create your pipeline inside the constructor __init__ of the new pipeline class like it is done in one ITK test.