Hi,
I have segmented the heart based on a cropped volume and now I want to write this cropped volume back to the original image size. How can I do that in ITK with c++? I really appreciate it if you could help me.
You could fill the original image with zeroes (image->FillBuffer(0);
), then paste the cropped volume back into it.
This pasting of an IO region is only supported by a couple file formats. I know MHA has support and maybe nrrd too. This is done with the ImageFileWriter::SetIORegion method. Here is an example:
Thank you very much. It works.
Hi,
I already cropped a region from an image in 3D slicer and did some processing on it. Now, I wanted to write back this cropped volume on the main image, but I do not know the start index where I was cutting the image in 3D slicer. I was wondering how I can find the start indices of the cropped volume on main image?
What file format did you save the image as? Hopefully you have preserved the physical location related meta data, so the physical location of each pixel remains the same. If you have, it’s just a matter of getting the physical location of the origin on the ROI, then with the original image a call to TransformPhysicalPointToIndex
to get the original index.
My image is in nrrd format. Actually , I did not get what do you mean exactly! Can you explain more?
Here is a good primer on ITK’s image as a special object concept:
https://simpleitk.readthedocs.io/en/master/fundamentalConcepts.html#images
So the physical location of all the voxels should remain the same before and after the crop. By using Image::TransformIndexToPhysicalPoint the point of origin of the cropped image can be determined. Then use TransformPhysicalPointToIndex to converting to the indexing of the original image.
Hi,
I wrote this code to get the indices of the original image however, I have 2 questions:
First, in the code, there is an error in this line : Index1 = image.GetIndex();
Second, I am not sure about what I did for this purpose, does the pixelIndex[0], pixelIndex[1] and pixelIndex[2] of the last image parameter in the code give me the start index for writing back the volume to the original image?
Thanks for your time in advance.
// Software Guide : BeginLatex
//
// The classes responsible for reading and writing images are located at the
// beginning and end of the data processing pipeline. These classes are
// known as data sources (readers) and data sinks (writers).
// Generally speaking they are referred to as filters, although readers have
// no pipeline input and writers have no pipeline output.
//
// The reading of images is managed by the class \doxygen{ImageFileReader}
// while writing is performed by the class \doxygen{ImageFileWriter}. These
// two classes are independent of any particular file format. The actual low
// level task of reading and writing specific file formats is done behind
// the scenes by a family of classes of type \doxygen{ImageIO}.
//
// The first step for performing reading and writing is to include the
// following headers.
//
// \index{itk::ImageFileReader|textbf}
// \index{itk::ImageFileReader!header}
//
// \index{itk::ImageFileWriter|textbf}
// \index{itk::ImageFileWriter!header}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIteratorWithIndex.h"
// Software Guide : EndCodeSnippet
#include "itkImage.h"
int main( int argc, char ** argv )
{
// Verify the number of parameters in the command line
if( argc < 3 )
{
std::cerr << "Usage: " << std::endl;
std::cerr << argv[0] << " inputImageFile outputImageFile " << std::endl;
return EXIT_FAILURE;
}
// Software Guide : BeginLatex
//
// Then, as usual, a decision must be made about the type of pixel used to
// represent the image processed by the pipeline. Note that when reading
// and writing images, the pixel type of the image \textbf{is not
// necessarily} the same as the pixel type stored in the file. Your
// choice of the pixel type (and hence template parameter) should be
// driven mainly by two considerations:
//
// \begin{itemize}
// \item It should be possible to cast the pixel type in the file to
// the pixel type you select. This casting will be performed using the
// standard C-language rules, so you will have to make sure that the
// conversion does not result in information being lost.
// \item The pixel type in memory should be appropriate to the type of
// processing you intend to apply on the images.
// \end{itemize}
//
// A typical selection for medical images is illustrated in
// the following lines.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using PixelType = signed char;
constexpr unsigned int Dimension = 3;
using ImageType = itk::Image< PixelType, Dimension >;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Note that the dimension of the image in memory should match that of
// the image in the file. There are a couple of special cases in which this
// condition may be relaxed, but in general it is better to ensure that both
// dimensions match.
//
// We can now instantiate the types of the reader and writer. These two
// classes are parameterized over the image type.
//
// \index{itk::ImageFileReader!Instantiation}
// \index{itk::ImageFileWriter!Instantiation}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using ReaderType = itk::ImageFileReader< ImageType >;
using WriterType = itk::ImageFileWriter< ImageType >;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Then, we create one object of each type using the New() method and
// assign the result to a \doxygen{SmartPointer}.
//
// \index{itk::ImageFileReader!New()}
// \index{itk::ImageFileWriter!New()}
// \index{itk::ImageFileReader!SmartPointer}
// \index{itk::ImageFileWriter!SmartPointer}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
ReaderType::Pointer reader = ReaderType::New();
WriterType::Pointer writer = WriterType::New();
// Software Guide : EndCodeSnippet
// Here we recover the file names from the command line arguments
//
const char * inputFilename = argv[1];
const char * outputFilename = argv[2];
// Software Guide : BeginLatex
//
// The name of the file to be read or written is passed to the
// SetFileName() method.
//
// \index{itk::ImageFileReader!SetFileName()}
// \index{itk::ImageFileWriter!SetFileName()}
// \index{SetFileName()!itk::ImageFileReader}
// \index{SetFileName()!itk::ImageFileWriter}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
reader->SetFileName(inputFilename);
reader->Update();
ImageType::Pointer image = ImageType::New();
ImageType::Pointer image = reader->GetOutput();
writer->SetFileName( outputFilename );
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
const ImageType::IndexType Index1;
Index1 = image.GetIndex();
ImageType::PointType Point;
image->TransformIndexToPhysicalPoint(Index1, Point);
ImageType::IndexType pixelIndex;
image->TransformPhysicalPointToIndex(Point, pixelIndex);
writer->SetInput( image );
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// At first glance this may look like a quite useless program, but it is
// actually implementing a powerful file format conversion tool! The
// execution of the pipeline is triggered by the invocation of the
// \code{Update()} methods in one of the final objects. In this case, the final
// data pipeline object is the writer. It is a wise practice of defensive
// programming to insert any \code{Update()} call inside a \code{try/catch} block
// in case exceptions are thrown during the execution of the pipeline.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
try
{
writer->Update();
}
catch( itk::ExceptionObject & err )
{
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return EXIT_FAILURE;
}
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Note that exceptions should only be caught by pieces of code that know
// what to do with them. In a typical application this \code{catch} block
// should probably reside in the GUI code. The action on the \code{catch}
// block could inform the user about the failure of the IO operation.
//
// The IO architecture of the toolkit makes it possible to avoid explicit
// specification of the file format used to read or write
// images.\footnote{In this example no file format is specified; this
// program can be used as a general file conversion utility.} The object
// factory mechanism enables the ImageFileReader and ImageFileWriter to
// determine (at run-time) which file format it is working
// with. Typically, file formats are chosen based on the filename
// extension, but the architecture supports arbitrarily complex processes
// to determine whether a file can be read or written. Alternatively, the
// user can specify the data file format by explicit instantiation and
// assignment of the appropriate \doxygen{ImageIO} subclass.
//
// For historical reasons and as a convenience to the user, the
// \doxygen{ImageFileWriter} also has a \code{Write()} method that is
// aliased to the \code{Update()} method. You can in principle use either
// of them but \code{Update()} is recommended since \code{Write()} may be
// deprecated in the future.
//
// Software Guide : EndLatex
return EXIT_SUCCESS;
}
This should be Index1 = image->GetLargestPossibleRegion().GetIndex();
.
But you need two images, the original and cropped. Pseudocode:
indCropped=imageCropped.index;
p=imageOrig.TransformIndexToPhysicalPoint(indCropped);
indOrig=imageOrig.TransformPhysicalPointToIndex(p);
pasteFilter(imageCroppedinto imageOrig, starting at indOrig)
Thanks for your reply, I changed the code and now there is an error in this part :
pixelIndex=image1->TransformPhysicalPointToIndex(Point, image1->GetLargestPossibleRegion().GetIndex());
Moreover, I get confused that for starting index and for copy, which values should I use exactly ?
index[0] = ?? //startX;
index[1] = ?? //startY;
index[2] = ?? //startZ;
Thanks for your help in advance!
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkPasteImageFilter.h"
// Software Guide : EndCodeSnippet
#include "itkImage.h"
int main( int argc, char ** argv )
{
// Verify the number of parameters in the command line
if( argc < 4 )
{
std::cerr << "Usage: " << std::endl;
std::cerr << argv[0] << " cropped volume originalimage outputImageFile " << std::endl;
return EXIT_FAILURE;
}
// Software Guide : BeginLatex
//
// Then, as usual, a decision must be made about the type of pixel used to
// represent the image processed by the pipeline. Note that when reading
// and writing images, the pixel type of the image \textbf{is not
// necessarily} the same as the pixel type stored in the file. Your
// choice of the pixel type (and hence template parameter) should be
// driven mainly by two considerations:
//
// \begin{itemize}
// \item It should be possible to cast the pixel type in the file to
// the pixel type you select. This casting will be performed using the
// standard C-language rules, so you will have to make sure that the
// conversion does not result in information being lost.
// \item The pixel type in memory should be appropriate to the type of
// processing you intend to apply on the images.
// \end{itemize}
//
// A typical selection for medical images is illustrated in
// the following lines.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using PixelType = signed char;
constexpr unsigned int Dimension = 3;
using ImageType = itk::Image< PixelType, Dimension >;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Note that the dimension of the image in memory should match that of
// the image in the file. There are a couple of special cases in which this
// condition may be relaxed, but in general it is better to ensure that both
// dimensions match.
//
// We can now instantiate the types of the reader and writer. These two
// classes are parameterized over the image type.
//
// \index{itk::ImageFileReader!Instantiation}
// \index{itk::ImageFileWriter!Instantiation}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using ReaderType = itk::ImageFileReader< ImageType >;
using WriterType = itk::ImageFileWriter< ImageType >;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Then, we create one object of each type using the New() method and
// assign the result to a \doxygen{SmartPointer}.
//
// \index{itk::ImageFileReader!New()}
// \index{itk::ImageFileWriter!New()}
// \index{itk::ImageFileReader!SmartPointer}
// \index{itk::ImageFileWriter!SmartPointer}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
ReaderType::Pointer reader = ReaderType::New();
ReaderType::Pointer reader1 = ReaderType::New();
WriterType::Pointer writer = WriterType::New();
// Software Guide : EndCodeSnippet
// Here we recover the file names from the command line arguments
//
const char * croppedfilename = argv[1];
const char * originalimagefilename = argv[2];
const char * outputFilename = argv[3];
// Software Guide : BeginLatex
//
// The name of the file to be read or written is passed to the
// SetFileName() method.
//
// \index{itk::ImageFileReader!SetFileName()}
// \index{itk::ImageFileWriter!SetFileName()}
// \index{SetFileName()!itk::ImageFileReader}
// \index{SetFileName()!itk::ImageFileWriter}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
reader->SetFileName(croppedfilename);
reader->Update();
reader1->SetFileName(originalimagefilename);
reader1->Update();
ImageType::Pointer image = ImageType::New();
ImageType::Pointer imag1 = ImageType::New();
ImageType::Pointer image = reader->GetOutput();
ImageType::Pointer image1 = reader1->GetOutput();
writer->SetFileName( outputFilename );
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
const ImageType::IndexType Index1;
//Index1 = image->GetLargestPossibleRegion().GetIndex();
ImageType::PointType Point;
image1->TransformIndexToPhysicalPoint(image->GetLargestPossibleRegion().GetIndex(), Point);
//image1->Update();
ImageType::IndexType pixelIndex;
pixelIndex=image1->TransformPhysicalPointToIndex(Point, image1->GetLargestPossibleRegion().GetIndex());
ImageType::IndexType index;
index[0] = ?? //startX;
index[1] = ?? //startY;
index[2] = ?? //startZ;
using PixelType = signed char;
constexpr unsigned int Dimension = 3;
using ImageType = itk::Image< PixelType, Dimension >;
using FilterType = itk::PasteImageFilter<ImageType, ImageType>;
FilterType::Pointer filter = FilterType::New();
filter->SetSourceImage(image);
filter->SetSourceRegion(image->GetLargestPossibleRegion());
filter->SetDestinationImage(image1);
filter->SetDestinationIndex(index);
writer->SetInput(filter->GetOutput());
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// At first glance this may look like a quite useless program, but it is
// actually implementing a powerful file format conversion tool! The
// execution of the pipeline is triggered by the invocation of the
// \code{Update()} methods in one of the final objects. In this case, the final
// data pipeline object is the writer. It is a wise practice of defensive
// programming to insert any \code{Update()} call inside a \code{try/catch} block
// in case exceptions are thrown during the execution of the pipeline.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
try
{
writer->Update();
}
catch( itk::ExceptionObject & err )
{
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return EXIT_FAILURE;
}
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Note that exceptions should only be caught by pieces of code that know
// what to do with them. In a typical application this \code{catch} block
// should probably reside in the GUI code. The action on the \code{catch}
// block could inform the user about the failure of the IO operation.
//
// The IO architecture of the toolkit makes it possible to avoid explicit
// specification of the file format used to read or write
// images.\footnote{In this example no file format is specified; this
// program can be used as a general file conversion utility.} The object
// factory mechanism enables the ImageFileReader and ImageFileWriter to
// determine (at run-time) which file format it is working
// with. Typically, file formats are chosen based on the filename
// extension, but the architecture supports arbitrarily complex processes
// to determine whether a file can be read or written. Alternatively, the
// user can specify the data file format by explicit instantiation and
// assignment of the appropriate \doxygen{ImageIO} subclass.
//
// For historical reasons and as a convenience to the user, the
// \doxygen{ImageFileWriter} also has a \code{Write()} method that is
// aliased to the \code{Update()} method. You can in principle use either
// of them but \code{Update()} is recommended since \code{Write()} may be
// deprecated in the future.
//
// Software Guide : EndLatex
return EXIT_SUCCESS;
}
Does anyone know the problem of this code? I really appreciate your help in advance!