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

Cyril Mory cyril.mory at creatis.insa-lyon.fr
Mon Feb 27 10:24:21 EST 2017


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()->GetLargestPossibleRegion();
   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
>



More information about the Insight-users mailing list