Search code examples
c++itkcimg

How can I convert a CImg image to an itkImage?


I have a CImg image (with double values) with the following form in c++:

CImg<double> image(512,512);
Tcyl.fill(1);

I would like to use ITK functionality to transform this image. So I need to transform this CImg image into itkImage object. How can I convert?


Solution

  • I have never used ITK before, so this was a learning curve. Anyway, I managed to make a radial gradient of floats in CImg and convert that to an ITK image and then write that as a float TIFF.

    #include <iostream>
    #include <cstdlib>
    #define cimg_display 0
    #include "CImg.h"
    #include "itkImage.h"
    #include "itkImportImageFilter.h"
    #include "itkImageFileWriter.h"
    #include "itkTIFFImageIO.h"
    
    using namespace cimg_library;
    using namespace std;
    
    #define W       512
    #define H       512
    
    int main() {
        // Create and initialise float image with radial gradient
       cimg_library::CImg<float> img(W,H); 
       cimg_forXY(img,x,y) {img(x,y) = hypot((float)(W/2-x),(float)(H/2-y)); }
    
       // Now convert CImg image to ITK image
       const unsigned int Dimension = 2;
       typedef itk::Image<float,Dimension>             InputImageType;
       typedef itk::ImportImageFilter<float,Dimension> ImportFilterType;
       ImportFilterType::Pointer importFilter = ImportFilterType::New();
    
       InputImageType::SizeType imsize;
       imsize[0] = img.width();
       imsize[1] = img.height();
    
       ImportFilterType::IndexType start;
       start.Fill(0);
       ImportFilterType::RegionType region;
       region.SetIndex(start);
       region.SetSize(imsize);
       importFilter->SetRegion(region);
    
       const itk::SpacePrecisionType origin[Dimension] = {0.0,0.0};
       importFilter->SetOrigin(origin);
    
       const itk::SpacePrecisionType spacing[Dimension] = {1.0,1.0};
       importFilter->SetSpacing(spacing);
    
       // Tell ITK importFilter to take pixels directly from CImg's buffer
       importFilter->SetImportPointer(img.data(),imsize[0]*imsize[1],false);
    
       // Write result as a TIFF - so I can check it worked
       typedef itk::ImageFileWriter<InputImageType> WriterType;
       typedef itk::TIFFImageIO                  TIFFIOType;
       TIFFIOType::Pointer tiffIO = TIFFIOType::New();
       tiffIO->SetPixelType(itk::ImageIOBase::SCALAR);
       WriterType::Pointer writer = WriterType::New();
       writer->SetFileName("result.tif");
       writer->SetInput(importFilter->GetOutput());
       writer->SetImageIO(tiffIO);
       writer->Update();
    }
    

    And here's the result (converted to JPEG for SO):

    enter image description here

    It works just the same if you change float for double except you can't write doubles to a TIFF so the last bit won't work.


    I've been messing around some more and managed to load the pixels into a new ITK image ready for further processing, rather than for output:

    #include <iostream>
    #include <cstdlib>
    #define cimg_display 0
    #include "CImg.h"
    #include "itkImage.h"
    #include "itkImageRegionIterator.h"
    
    using namespace cimg_library;
    using namespace std;
    
    #define W 5
    #define H 3
    
    int main() {
        // Create and initialise double image with simple formula
       cimg_library::CImg<double> img(W,H); 
       cimg_forXY(img,x,y) {img(x,y) = (double)x+(10.0*(double)y); }
    
       // Now convert CImg image to ITK image
       const unsigned int Dimension = 2;
       typedef itk::Image<double,2> ImageType;
       ImageType::Pointer image = ImageType::New();
    
       ImageType::SizeType size;
       size[0] = img.width();
       size[1] = img.height();
    
       ImageType::IndexType start;
       start.Fill(0);
    
       ImageType::RegionType region;
       region.SetSize(size);
       region.SetIndex(start);
       image->SetRegions(region);
       image->Allocate();
    
       double origin[2];
       origin[0]=0;
       origin[1]=0;
       image->SetOrigin(origin);
    
       double spacing[2];
       spacing[0]=1;
       spacing[1]=1;
       image->SetSpacing(spacing);
    
       typedef itk::ImageRegionIterator<ImageType> IteratorType;
       IteratorType it(image,region);
       it.GoToBegin();
    
       const double* data = img.data();
       while(!it.IsAtEnd()){
          it.Set(*data);
          ++it;
          ++data;
       }
    
      // Display pixels for checking purposes
      for(unsigned int r = 0; r < H; r++)
      {
          for(unsigned int c = 0; c < W; c++)
          {
              ImageType::IndexType pixelIndex;
              pixelIndex[0] = c;
              pixelIndex[1] = r;
              ImageType::PixelType      pixelValue = image->GetPixel( pixelIndex );
              cout << "Image[" << r << "," << c << "]: " << pixelValue << endl; 
          }
      }
    }
    

    Sample Output

    Image[0,0]: 0
    Image[0,1]: 1
    Image[0,2]: 2
    Image[0,3]: 3
    Image[0,4]: 4
    Image[1,0]: 10
    Image[1,1]: 11
    Image[1,2]: 12
    Image[1,3]: 13
    Image[1,4]: 14
    Image[2,0]: 20
    Image[2,1]: 21
    Image[2,2]: 22
    Image[2,3]: 23
    Image[2,4]: 24