(API) Specify image channels

(Hrach) #1

How can I specify image channels.
I have created image object.

        using ImageType = itk::Image< uint8_t, 2 >;
        ImageType::Pointer image = ImageType::New();

        ImageType::SizeType  size;
        size[0] = width;
        size[1] = height;

        ImageType::IndexType start;
        start.Fill( 0 );

        ImageType::RegionType region;
        region.SetSize( size );
        region.SetIndex( start );

        image->SetRegions( region );
        image->Allocate();

I can specify size, start but could not find in documentation how to specify image channels.

(Dženan Zukić) #2

You just have to define vector image type.

using VectorPixelType = itk::Vector<uint8_t, 10>; // 10 channel pixel
using ImageType = itk::Image< VectorPixelType, 2 >; // 2D image

Read more about it in the software guide, section 4.1.6.

(Hrach) #3

Thank you very much for quick response.

In that case I get an error in this line

  rescaler->SetOutputMaximum( 255 );
  rescaler->SetOutputMinimum( 0 );
 error: conversion from ‘int’ to ‘itk::RescaleIntensityImageFilter<itk::Image<itk::Vector<float, 3>, 2>, itk::Image<itk::Vector<unsigned char, 3>, 2> >::OutputPixelType’ {aka ‘itk::Vector<unsigned char, 3>’} is ambiguous
  180 |         rescaler->SetOutputMinimum(   0 );

(Tim Evain) #4

These methods expect arguments of same type as the pixels in your image. Since the pixel in your image is a vector (aka multi-channel image), you should input a vector.

Giving only one value is ambiguous, i.e. in which channel should the value goes ? first? all?
If it’s the latter, you could do something like:

itk::Vector<uint8_t, 3> MaxPixel, MinPixel;
MaxPixel[0] = MaxPixel[1] = MaxPixel[2] = 255;
MinPixel[0] = MinPixel[1] = MinPixel[2] = 0;

rescaler->SetOutputMaximum( MaxPixel );
rescaler->SetOutputMinimum( MinPixel );

HTH,

Tim

1 Like
(Hrach) #5

In that case I get an error in the last line

        using VectorPixelType = itk::Vector<uint8_t, 3>; // 10 channel pixel

        using ImageType = itk::Image< VectorPixelType, 2 >; // 2D image

        using OutputVectorPixelType = itk::Vector<float, 3>; 
        // using OutputPixelType = float;
        using OutputImageType = itk::Image< OutputVectorPixelType, 2 >;

        using FilterType = itk::MinMaxCurvatureFlowImageFilter< ImageType, OutputImageType >;
        FilterType::Pointer filter = FilterType::New();
 invalid static_cast from type ‘itk::Vector<unsigned char, 3>’ to type ‘float’
  185 |       auto b = static_cast< T2 >( a );
(Dženan Zukić) #6

I guess that MinMaxCurvatureFlowImageFilter does not support vector images. You might use SplitComponentsImageFilter or VectorImageToImageAdaptor to split the image into constituent channels, apply some processing on each channel independently, and combine them using ComposeImageFilter.

1 Like
(Bradley Lowekamp) #7

Here is a snippet of code generated in SimpleITK which run certain filters on a “per component basis”:


//
// Dispatched methods to call ExecuteInternal on each component of the VectorImage
//
template <class TImageType> Image BilateralImageFilter::ExecuteInternalVectorImage ( const Image& inImage1 )
{
  typedef TImageType                                                               VectorInputImageType;
  typedef typename VectorInputImageType::InternalPixelType                         ComponentType;
  typedef typename itk::Image<ComponentType, VectorInputImageType::ImageDimension> ComponentImageType;

  // we must define the input and output image types should be the
  // same as the scalar execute internal method
  typedef ComponentImageType  InputImageType;
  // Define output image type
  typedef InputImageType OutputImageType;
  // Get the pointer to the ITK image contained in image1
  typename VectorInputImageType::ConstPointer image1 =
    this->CastImageToITK<VectorInputImageType>( inImage1 );

  typedef itk::VectorIndexSelectionCastImageFilter< VectorInputImageType, ComponentImageType > ComponentExtratorType;
  typename ComponentExtratorType::Pointer extractor = ComponentExtratorType::New();
  extractor->SetInput( image1 );

  typedef itk::ComposeImageFilter<OutputImageType> ToVectorFilterType;
  typename ToVectorFilterType::Pointer toVector = ToVectorFilterType::New();

  unsigned int numComps = image1->GetNumberOfComponentsPerPixel();
  for ( unsigned int i = 0; i < numComps; ++i )
    {
    extractor->SetIndex( i );
    extractor->Update();

    Image tmp = this->ExecuteInternal<InputImageType>( Image( extractor->GetOutput() ) );

    typename OutputImageType::ConstPointer tempITKImage = this->CastImageToITK<OutputImageType>( tmp );

    toVector->SetInput( i, tempITKImage );
    }

  toVector->Update();

  return Image( toVector->GetOutput() );
}
(Hrach) #8

Ok, but in InsightToolkit-5.0.0/Examples/Filtering/MinMaxCurvatureFlowImageFilter.cxx in this example input image has 3 channels and still it does not specify the number of channels.
But still it filters image and writes in the file as a multichanel image

(Hrach) #9

And one more question,
If MaxCurvatureFlowImageFilter does not support vector images how can I filter multi channel images without using vector? Because as I said in example there is no use of vector, but it filters fine

(Dženan Zukić) #10

Instead of itk::Vector<uint8_t, 3>, you might want to try itk::RGBPixel<uint8_t>.

In the example you mentioned, the pixel type is scalar = grayscale (float). If color image is supplied, the IO mechanism in ITK converts it to grayscale and the example deals with that afterwards.

1 Like