Hello,
with the new wrappers for ITK 5.0 Beta and all the facilities with the new pythonic interface I was wondering how can I especify a filter’s output type on the parameters.
The idea is to change this: rescaler = itk.RescaleIntensityImageFilter[itk.Image.UC2, itk.Image.US2].New()
into something like this: rescaler = itk.rescale_intensity_image_filter(input_image, output_type=itk.Image.US2)
when I want to control the output type of a filter because the one he defaults to doesn’t fit the next one on the pipeline
I am glad you are suggesting this idea because @matt.mccormick and I just talked about this idea. Glad other people share the same idea! I think more generally, the used should be able to pass not only the output_type, but in general the template type. This would allow all template parameters to be set in a pythonic way, and would avoid having to hard code a lot of euristic rules such as:
input type is the first template parameter
output type is the second template parameter
What do we do if we have only one template parameter or if we have more than just for the input and output…
Anybody is more than welcome to give ideas and even start contributing by creating a pull-request
As @fbudin mentioned regarding the implementation, the input type is nearly universally the first template parameter for a filter, but the output type is not necessarily the second or last C++ template parameter, so an output_type argument would be difficult to implement.
Perhaps a type_params argument that provides the types that correspond to the C++ template arguments? What do you think?
and found that inside the itkTemplate.py file, a search is conducted in a dictionary where the keys are pairs (input_tye, output_type) and it takes the first key that matches the input type. That seems easy to change… though I don’t know what consecuences would have for developers to change that bit of code to try and match the complete pair when a type_params argument is provided.
Sorry, I should’ve been more specific there…
The code for the matching process I was referring to, is on the New() method of the itkTemplate class. The
keys = [k for k in keys if k[0] == input_type]
variable ends up holding a list of all matching (input_type, output_type) pairs, and the first match is the one that’s instantiated on return. It goes as follows:
def New(self, *args, **kwargs):
### docstring here
import itk
keys = self.keys()
cur = itk.auto_pipeline.current
### some code here for the ImageFileReader and ImageSeriesReader cases
primary_input_methods = ('Input', 'InputImage', 'Input1')
if len(args) != 0:
# try to find a type suitable for the primary input provided
input_type = output(args[0]).__class__
keys = [k for k in keys if k[0] == input_type]
elif set(primary_input_methods).intersection(kwargs.keys()):
for method in primary_input_methods:
if method in kwargs:
input_type = output(kwargs[method]).__class__
keys = [k for k in keys if k[0] == input_type]
break
elif cur is not None and len(cur) != 0:
# try to find a type suitable for the input provided
input_type = output(cur).__class__
keys = [k for k in keys if k[0] == input_type]
if len(keys) == 0:
raise RuntimeError("No suitable template parameter can be found.")
return self[list(keys)[0]].New(*args, **kwargs)
Correct – for the case of the DanielssonDistanceMapImageFilter, the first template argument is the input image type and the second template argument is the output image type. However, as previously discussed, this is not always true, so we cannot assume that we could use, e.g.
I’ll take a look at the docs on contributing, because I have very (very!) little experience with Git. It would be nice to put my grain of salt though, since I’ve been a user of ITK python wraps one way or another for years now.
As a personal preference, I would rather us not adding some magic guessing (and I would even vote for deprecating the current magic that is used when instantiating the first type that works if multiple types are available). I do really like the idea of having that extra parameter, but I would add a check that it contains all the required templates (i.e. if the class requires two types, than type_params would also have to contain two types).
My thoughts about this was to add it directly inside the functional implementation, and leave the “Object” instantiation with New() untouched, but I don’t have a strong opinion about this and I could easily be convinced that adding it inside New() makes sense.
One thing that needs to be implemented is a test that ensures that no ITK filter actually uses the keyword we actually select as it would cause issues if a filter had a method called SetTemplateParams or whatever keyword we select. This test should be fairly easy to write. I have a work in progress branch in which I am writing similar tests. I will add a reference to those tests in this conversation when I push that branch.
Final thought, I would have used the keyword ttype instead of template_params to stay close to a defacto standard Python developers are used to: NumPy with dtype (assuming dtype stands for “data type”). In our case ttype would stand for “template type”.