Search code examples
c++simpleitk

Why is PasteImageFilter from SimpleITK so slow? Is there any alternative to it?


I am trying to create an 3D volume (dimenstions are 4000 x 4000 x 1600) from separate images. I have a for loop, where I first create an std::vector and then use ImportImageFilter to create an image with dimensions 4000 x 4000 x 1. After that I use PasteImageFilter to insert the created image to the volume. So every image is like a layer in the big volume.

The code below works but it takes 20-25 seconds to import the image with the PasteImageFilter.

Is there anything i can do to make it run faster?

Important is that i can't have multiple volume copies at the same time, because i would ran out of memory.

sitk::PixelIDValueEnum pixelTypeM1 = sitk::sitkUInt8;
sitk::PixelIDValueEnum pixelTypeM2 = sitk::sitkFloat32;

std::vector<unsigned int> sitkVolumeSize{4000,4000,1600};

sitk::Image sitk_m1_volume( sitkVolumeSize, pixelTypeM1 );
sitk::Image sitk_m2_volume( sitkVolumeSize, pixelTypeM2 );

sitk::PasteImageFilter pasteFilter;
for(int idx = 0; idx < 1600; idx++){

    std::vector<measurement> s1, s2;
    std::tie (s1, s2) = load_data();

    std::vector<float> m1_vec(4000*4000);
    std::vector<uint8_t> m2_vec(4000*4000);
    //some computations here to fill the m1_vec and m2_vec


    std::vector<unsigned int> imageDims{4000, 4000, 1};
    sitk::ImportImageFilter importer;

    importer.SetSize( imageDims );
    importer.SetBufferAsUInt8(m1_vec.data());
    sitk::Image m1_image = importer.Execute();

    importer.SetBufferAsFloat( m2_vec.data() );
    sitk::Image m2_image = importer.Execute();

    pasteFilter.SetDestinationIndex({0,0,idx});
    pasteFilter.SetSourceSize(m2_image.GetSize());
    sitk_m2_volume = pasteFilter.Execute(sitk_m2_volume, m2_image);
    sitk_m1_volume = pasteFilter.Execute(sitk_m1_volume, m1_image);

}

Solution

  • Please ensure that you are compiling in Release mode and not debug this is the most common reason for slow performance using ITK and SimpleITK in C++.

    sitk_m2_volume = pasteFilter.Execute(sitk_m2_volume, m2_image);
    sitk_m1_volume = pasteFilter.Execute(sitk_m1_volume, m1_image);
    

    With the above calls to execute it will create a copy of the sitk_m{2,1}_volumes. This can be expensive with large images. The sitk::PasteImageFilter also supports move symatics with the first argument:

    Image itk::simple::PasteImageFilter::Execute(Image && destinationImage, const Image &   sourceImage 
    )   
    

    If you are not familiar with C++ move semantics and rvalue references please find a good modern C++ reference to learn. This signature can be used like this:

    sitk_m2_volume = pasteFilter.Execute(std::move(sitk_m2_volume), m2_image);
    sitk_m1_volume = pasteFilter.Execute(std::move(sitk_m1_volume), m1_image);
    

    With this call the Image buffer will be moved from the input argument to the output and will not copy the whole buffer thus improving performance.