[ITK] [ITK-users] Filter working on both itk::Image and itk::VectorImage

Francois Budin francois.budin at kitware.com
Mon Feb 27 13:21:41 EST 2017


Hey Cyril,

This is a good idea. If you want to keep it compatible without requiring
C++11, you might be able to do so using the "EnableIf" functions that are
implemented in ITK, following the same paradigm (SFINAE) than you found.

hth,
Francois

On Mon, Feb 27, 2017 at 10:24 AM, Cyril Mory <
cyril.mory at creatis.insa-lyon.fr> wrote:

> I found some help outside this mailing list, so again, I'm answering my
> own question (I'll try not to make it a habit). There is a solution using
> C++11, and features derived from "Substitution failure is not an error".
> The following code does it. I've added quite a lot of comments, so it
> should be understandable.
>
>
>
> #include <itkImage.h>
> #include <itkVectorImage.h>
> #include <itkImageToImageFilter.h>
> #include <itkImageFileReader.h>
> #include <itkImageRegionConstIterator.h>
> #include <itkImageRegionIterator.h>
>
> #include <type_traits>
> #include <typeinfo>
>
> namespace itk
> {
>
> template <class TInputImage >
> class ITK_EXPORT SFINAETestFilter :
>     public itk::ImageToImageFilter< TInputImage, TInputImage >
> {
> public:
>   /** Standard class typedefs. */
>   typedef SFINAETestFilter Self;
>   typedef itk::ImageToImageFilter<TInputImage, TInputImage> Superclass;
>   typedef itk::SmartPointer<Self> Pointer;
>   typedef itk::SmartPointer<const Self> ConstPointer;
>
>   // Define the types that a slice can take, depending on whether
> TInputImage is an itk::Image or and itk::VectorImage
>   typedef itk::Image<typename TInputImage::InternalPixelType,
> TInputImage::ImageDimension - 1>          ImageSliceType;
>   typedef itk::VectorImage<typename TInputImage::InternalPixelType,
> TInputImage::ImageDimension - 1>    VectorImageSliceType;
>
>   // Define SliceType
>   // std::is_same<T1, T2>::value is true is T1 and T2 are the same type,
> and false otherwise
>   // std::conditional<B, T3, T4>::type is T3 if B is true, T4 otherwise
>   // The code checks if TInputImage::PixelType is an
> itk::VariableLengthVector. If so, it uses VectorImageSliceType as SliceType
>   // Otherwise, it uses ImageSliceType as SliceType
>   typedef typename std::conditional<std::is_same<typename
> TInputImage::PixelType,
> itk::VariableLengthVector<typename TInputImage::InternalPixelType>
> >::value,
>                                     VectorImageSliceType,
>                                     ImageSliceType>::type SliceType;
>
>   /** Method for creation through the object factory */
>   itkNewMacro(Self);
>
>   /** Run-time type information (and related methods). */
>   itkTypeMacro(SFINAETestFilter, ImageToImageFilter);
>
>   /** Superclass typedefs. */
>   typedef typename Superclass::OutputImageRegionType
> OutputImageRegionType;
>   typedef typename Superclass::OutputImagePointer OutputImagePointer;
>
>   /** ImageDimension constants */
>   itkStaticConstMacro(InputImageDimension, unsigned int,
>                       TInputImage::ImageDimension);
>
>   typename SliceType::Pointer GetSlice()
>   {
>   // Create the slice
>   typename SliceType::Pointer firstSlice = SliceType::New();
>
>   // Determine its size
>   typename TInputImage::RegionType largest = this->GetInput()->GetLargestPo
> ssibleRegion();
>   typename SliceType::RegionType region;
>   typename SliceType::SizeType size;
>   typename SliceType::IndexType index;
>   for (unsigned int dim = 0; dim < SliceType::ImageDimension; dim++)
>     {
>     size[dim] = largest.GetSize()[dim];
>     index[dim] = largest.GetIndex()[dim];
>     }
>   region.SetSize(size);
>   region.SetIndex(index);
>
>   // Allocate
>   firstSlice->SetRegions(region);
> firstSlice->SetNumberOfComponentsPerPixel(this->GetInput()->
> GetNumberOfComponentsPerPixel());
>   firstSlice->Allocate();
>
>   // Fill
>   itk::ImageRegionIterator<SliceType> sliceIt(firstSlice, region);
>   itk::ImageRegionConstIterator<TInputImage> inputIt(this->GetInput(),
> largest);
>   while(!sliceIt.IsAtEnd())
>     {
>     sliceIt.Set(inputIt.Get());
>     ++sliceIt;
>     ++inputIt;
>     }
>
>   // Return
>   return firstSlice;
>   }
>
> };
>
> } /* end namespace itk */
>
>
> int main(){
>
> typedef itk::Image<float, 3> ImageType;
> typedef itk::VectorImage<float, 3> VectorImageType;
>
> // With the itk::Image template
> typedef itk::SFINAETestFilter<ImageType> SFINAEWithImageType;
> typename SFINAEWithImageType::Pointer withImageType =
> SFINAEWithImageType::New();
> typedef itk::ImageFileReader<ImageType> ImageReaderType;
> ImageReaderType::Pointer imageReader = ImageReaderType::New();
> imageReader->SetFileName("image.mha");
> imageReader->Update();
> withImageType->SetInput(imageReader->GetOutput());
> withImageType->GetSlice()->Print(std::cout);
>
> itk::Image<float, 2>::IndexType firstPixelIndex;
> firstPixelIndex.Fill(0);
> std::cout << withImageType->GetSlice()->GetPixel(firstPixelIndex) <<
> std::endl;
>
> // With the itk::VectorImage template
> typedef itk::SFINAETestFilter<VectorImageType> SFINAEWithVectorImageType;
> typename SFINAEWithVectorImageType::Pointer withVectorImageType =
> SFINAEWithVectorImageType::New();
> typedef itk::ImageFileReader<VectorImageType> VectorImageReaderType;
> VectorImageReaderType::Pointer vectorImageReader =
> VectorImageReaderType::New();
> vectorImageReader->SetFileName("vectorImage.mha");
> vectorImageReader->Update();
> withVectorImageType->SetInput(vectorImageReader->GetOutput());
> withVectorImageType->GetSlice()->Print(std::cout);
>
> std::cout << withVectorImageType->GetSlice()->GetPixel(firstPixelIndex)
> << std::endl;
>
> return EXIT_SUCCESS;
>
> }
>
>
>
> On 27/02/2017 12:09, Cyril Mory wrote:
>
>> Hi,
>>
>> Still the same topic, but a different issue:
>>
>> I have a filter that is templated over its image input type, usually
>> itk::Image<T, dim>. I want to modify it so that it also works when that
>> type is itk::VectorImage<T, dim>.
>>
>> This filter internally defines SliceType = itk::Image<InputImageType::InternalPixelType,
>> dim - 1>. But when processing an itk::VectorImage, I would like this
>> SliceType to be itk::VectorImage<InputImageType::InternalPixelType, dim
>> - 1>.
>>
>> I don't think there is a way in C++ to recover the itk::Image<> or the
>> itk::VectorImage<> "un-templated", and define a type with whole new
>> template arguments. But is there an ITK mechanism that would solve my
>> problem ?
>>
>> Best regards,
>>
>> Cyril
>>
>> On 22/02/2017 17:39, Matt McCormick wrote:
>>
>>> Hi Cyril,
>>>
>>> Yes, this is a good approach.  Thanks for sharing your investigation.
>>>
>>> Matt
>>>
>>> On Wed, Feb 22, 2017 at 5:52 AM, Cyril Mory
>>> <cyril.mory at creatis.insa-lyon.fr> wrote:
>>>
>>>> Answering my own question:
>>>>
>>>> I found a way to do what I needed using itk::NumericTraits<T> :
>>>>
>>>>    OutputImagePixelType pix;
>>>> itk::NumericTraits<OutputImagePixelType>::SetLength(pix,
>>>> this->GetVectorLength());
>>>>    pix = itk::NumericTraits<OutputImagePixelType>::OneValue(pix) *
>>>> value;
>>>>
>>>> It works for both cases with the same code. However, if there is a
>>>> better
>>>> way (cleaner, safer, more compact, ... whatever the wayin which it is
>>>> better), I'd be happy to learn about it.
>>>>
>>>> Best regards,
>>>> Cyril
>>>>
>>>>
>>>> On 22/02/2017 10:38, Cyril Mory wrote:
>>>>
>>>>> Hi ITK users,
>>>>>
>>>>> I am writing an itk::ImageToImageFilter<T>, and I want the filter to
>>>>> work
>>>>> with T=itk::Image as well as with T=itk::VectorImage.
>>>>>
>>>>> To set/get the vectorLength of an image (which is 1 for an itk::Image,
>>>>> and
>>>>> varies for an itk::VectorImage), I have successfully used the functions
>>>>> Set/GetNumberOfComponentsPerPixel from the itk::ImageBase class,
>>>>> which work
>>>>> for both itk::Image and itk::VectorImage.
>>>>>
>>>>> But I cannot find a way to initialize one of the pixels to a given
>>>>> value,
>>>>> that would work for both cases, i.e. whether that pixel is a scalar or
>>>>> a
>>>>> variableLengthVector. For now, the best I could do is define a function
>>>>> FillPixel in my filter, like this:
>>>>>
>>>>> OutputImagePixelType FillPixel(OutputImageInternalPixelType value)
>>>>> {return
>>>>> value;}
>>>>>
>>>>> and write a template specialization when my filter is instantiated with
>>>>> itk::VectorImage<float, 3>, like this:
>>>>>
>>>>> template <>
>>>>> itk::VariableLengthVector<float>
>>>>> rtk::ConstantImageSource<itk::VectorImage<float, 3> >
>>>>> ::FillPixel(float value)
>>>>> {
>>>>>    itk::VariableLengthVector<float> vect;
>>>>>    vect.SetSize(this->GetVectorLength());
>>>>>    vect.Fill(value);
>>>>>    return (vect);
>>>>> }
>>>>>
>>>>> Did I miss something ? Is there a better way of doing this in ITK ?
>>>>>
>>>>> Looking forward to reading you,
>>>>> Cyril
>>>>>
>>>>> _____________________________________
>>>>> Powered by www.kitware.com
>>>>>
>>>>> Visit other Kitware open-source projects at
>>>>> http://www.kitware.com/opensource/opensource.html
>>>>>
>>>>> Kitware offers ITK Training Courses, for more information visit:
>>>>> http://www.kitware.com/products/protraining.php
>>>>>
>>>>> Please keep messages on-topic and check the ITK FAQ at:
>>>>> http://www.itk.org/Wiki/ITK_FAQ
>>>>>
>>>>> Follow this link to subscribe/unsubscribe:
>>>>> http://public.kitware.com/mailman/listinfo/insight-users
>>>>>
>>>>
>>>> _____________________________________
>>>> Powered by www.kitware.com
>>>>
>>>> Visit other Kitware open-source projects at
>>>> http://www.kitware.com/opensource/opensource.html
>>>>
>>>> Kitware offers ITK Training Courses, for more information visit:
>>>> http://www.kitware.com/products/protraining.php
>>>>
>>>> Please keep messages on-topic and check the ITK FAQ at:
>>>> http://www.itk.org/Wiki/ITK_FAQ
>>>>
>>>> Follow this link to subscribe/unsubscribe:
>>>> http://public.kitware.com/mailman/listinfo/insight-users
>>>>
>>>
>>
> _____________________________________
> Powered by www.kitware.com
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Kitware offers ITK Training Courses, for more information visit:
> http://www.kitware.com/products/protraining.php
>
> Please keep messages on-topic and check the ITK FAQ at:
> http://www.itk.org/Wiki/ITK_FAQ
>
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/insight-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/community/attachments/20170227/abfbde24/attachment.html>
-------------- next part --------------
_____________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users


More information about the Community mailing list