From 7ca5683a7ec5f440ef5ef616e4bd3a1802a6ea64 Mon Sep 17 00:00:00 2001 From: Gregoire Ville Date: Mon, 29 Apr 2024 17:26:34 +0200 Subject: [PATCH 1/2] add of a feature to create a mask from an image.\nWritten by Thoms Durantel --- Anima/math-tools/common_tools/CMakeLists.txt | 1 + .../common_tools/image_to_mask/CMakeLists.txt | 35 ++++++ .../image_to_mask/animaImageToMask.cxx | 108 ++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 Anima/math-tools/common_tools/image_to_mask/CMakeLists.txt create mode 100644 Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx diff --git a/Anima/math-tools/common_tools/CMakeLists.txt b/Anima/math-tools/common_tools/CMakeLists.txt index 4a0a3b040..34de43f19 100644 --- a/Anima/math-tools/common_tools/CMakeLists.txt +++ b/Anima/math-tools/common_tools/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(convert_image) add_subdirectory(convert_shape) add_subdirectory(merge_block_images) add_subdirectory(vectorize_images) +add_subdirectory(image_to_mask) diff --git a/Anima/math-tools/common_tools/image_to_mask/CMakeLists.txt b/Anima/math-tools/common_tools/image_to_mask/CMakeLists.txt new file mode 100644 index 000000000..29d3b7f66 --- /dev/null +++ b/Anima/math-tools/common_tools/image_to_mask/CMakeLists.txt @@ -0,0 +1,35 @@ +if(BUILD_TOOLS) + +project(animaImageToMask) + +## ############################################################################# +## List Sources +## ############################################################################# + +list_source_files(${PROJECT_NAME} + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +## add executable +## ############################################################################# + +add_executable(${PROJECT_NAME} + ${${PROJECT_NAME}_CFILES} + ) + + +## ############################################################################# +## Link +## ############################################################################# + +target_link_libraries(${PROJECT_NAME} + ${ITKIO_LIBRARIES} + ) + +## ############################################################################# +## install +## ############################################################################# + +set_exe_install_rules(${PROJECT_NAME}) + +endif() diff --git a/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx b/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx new file mode 100644 index 000000000..6de93ddeb --- /dev/null +++ b/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx @@ -0,0 +1,108 @@ +#include +#include +#include + +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + TCLAP::CmdLine cmd("INRIA / IRISA - VisAGeS/Empenn Team", ' ',ANIMA_VERSION); + + TCLAP::ValueArg inArg("i","inputfile","input image",true,"","input image",cmd); + TCLAP::ValueArg outArg("o","outputfile","output mask",true,"","output mask",cmd); + + try + { + cmd.parse(argc,argv); + } + catch (TCLAP::ArgException& e) + { + std::cerr << "Error: " << e.error() << "for argument " << e.argId() << std::endl; + return(1); + } + + typedef itk::Image ImageType; + typedef itk::Image Image4DType; + typedef itk::VectorImage VectorImageType; + + itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(inArg.getValue().c_str(), + itk::IOFileModeEnum::ReadMode); + + imageIO->SetFileName(inArg.getValue()); + imageIO->ReadImageInformation(); + + bool vectorImage = (imageIO->GetNumberOfComponents() > 1); + + if (vectorImage) + { + // Vectorial case + VectorImageType::Pointer image = anima::readImage (inArg.getValue()); + + ImageType::Pointer outImage = ImageType::New(); + outImage->Initialize(); +// outImage->SetNumberOfComponentsPerPixel(image->GetNumberOfComponentsPerPixel()); + outImage->SetDirection(image->GetDirection()); + outImage->SetSpacing(image->GetSpacing()); + outImage->SetOrigin(image->GetOrigin()); + + VectorImageType::RegionType region = image->GetLargestPossibleRegion(); + outImage->SetRegions(region); + outImage->Allocate(); + + VectorImageType::PixelType zeroVec(image->GetNumberOfComponentsPerPixel()); + zeroVec.Fill(0); + + itk::ImageRegionIterator inItr(image,region); + itk::ImageRegionIterator outItr(outImage,outImage->GetLargestPossibleRegion()); + + while (!outItr.IsAtEnd()) + { + if(inItr.Get() == zeroVec) + outItr.Set(0); + else + outItr.Set(1); + + ++inItr; + ++outItr; + } + + anima::writeImage (outArg.getValue(),outImage); + + return EXIT_SUCCESS; + } + + ImageType::Pointer image = anima::readImage (inArg.getValue()); + + ImageType::Pointer outImage = ImageType::New(); + outImage->Initialize(); + outImage->SetDirection(image->GetDirection()); + outImage->SetSpacing(image->GetSpacing()); + outImage->SetOrigin(image->GetOrigin()); + + ImageType::RegionType largestRegion = image->GetLargestPossibleRegion(); + outImage->SetRegions(largestRegion); + outImage->Allocate(); + outImage->FillBuffer(0.0); + + itk::ImageRegionIterator inItr(image,image->GetLargestPossibleRegion()); + itk::ImageRegionIterator outItr(outImage,outImage->GetLargestPossibleRegion()); + + while (!outItr.IsAtEnd()) + { + if(inItr.Get() == 0.0) + outItr.Set(0); + else + outItr.Set(1); + + ++inItr; + ++outItr; + } + + anima::writeImage (outArg.getValue(),outImage); + + return EXIT_SUCCESS; +} From d2cf60b5160882c80f45c3031a455a6746a78dc5 Mon Sep 17 00:00:00 2001 From: Gregoire Ville Date: Tue, 9 Jul 2024 11:46:30 +0200 Subject: [PATCH 2/2] Comment and clean Thomas' code --- .../image_to_mask/animaImageToMask.cxx | 95 +++++++++++++------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx b/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx index 6de93ddeb..dd2fc78b6 100644 --- a/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx +++ b/Anima/math-tools/common_tools/image_to_mask/animaImageToMask.cxx @@ -8,13 +8,19 @@ #include +/** + * @brief Converts an input image (either vectorial or not) into a mask + * The output mask will be 0 in the voxels where the input image is 0 (or a null vector) and 1 elsewhere + */ int main(int argc, char **argv) { TCLAP::CmdLine cmd("INRIA / IRISA - VisAGeS/Empenn Team", ' ',ANIMA_VERSION); + //Define arguments TCLAP::ValueArg inArg("i","inputfile","input image",true,"","input image",cmd); TCLAP::ValueArg outArg("o","outputfile","output mask",true,"","output mask",cmd); + //Try to parse try { cmd.parse(argc,argv); @@ -25,84 +31,113 @@ int main(int argc, char **argv) return(1); } - typedef itk::Image ImageType; + //Define types + typedef itk::Image ImageType; typedef itk::Image Image4DType; typedef itk::VectorImage VectorImageType; + //Read input image itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(inArg.getValue().c_str(), itk::IOFileModeEnum::ReadMode); imageIO->SetFileName(inArg.getValue()); imageIO->ReadImageInformation(); + //Initialize the output image (which is a mask) and allocate memory + ImageType::Pointer outImage = ImageType::New(); + + //Determine if the input image is a vector image (each voxel value is a vector) or not bool vectorImage = (imageIO->GetNumberOfComponents() > 1); if (vectorImage) { - // Vectorial case + //Case of a vector image + + //Read input image and store in the correct format VectorImageType::Pointer image = anima::readImage (inArg.getValue()); - ImageType::Pointer outImage = ImageType::New(); + //Set the output image with the same properties as the input image outImage->Initialize(); -// outImage->SetNumberOfComponentsPerPixel(image->GetNumberOfComponentsPerPixel()); outImage->SetDirection(image->GetDirection()); outImage->SetSpacing(image->GetSpacing()); outImage->SetOrigin(image->GetOrigin()); + //Allocate the correct size for output image. region (image->GetLargestPossibleRegion()) is the whole image VectorImageType::RegionType region = image->GetLargestPossibleRegion(); outImage->SetRegions(region); outImage->Allocate(); + //Create a vector with as many components as there are for each voxel, and with each component equal to 0 VectorImageType::PixelType zeroVec(image->GetNumberOfComponentsPerPixel()); zeroVec.Fill(0); + //Create iterators on input and output images itk::ImageRegionIterator inItr(image,region); itk::ImageRegionIterator outItr(outImage,outImage->GetLargestPossibleRegion()); + //Main algorithm while (!outItr.IsAtEnd()) { if(inItr.Get() == zeroVec) + { + //The voxel in the input image is a constant vector equal to 0, so this voxel in the output mask will be 0. outItr.Set(0); + } else + { + //The voxel in the input image is not a constant vector equal to 0, so this voxel in the output mask will be 1. outItr.Set(1); + } + //Move to following voxel ++inItr; ++outItr; } - - anima::writeImage (outArg.getValue(),outImage); - - return EXIT_SUCCESS; } + else + { + //Case of a non-vector image + + //Read input image and store in the correct format + ImageType::Pointer image = anima::readImage (inArg.getValue()); - ImageType::Pointer image = anima::readImage (inArg.getValue()); - - ImageType::Pointer outImage = ImageType::New(); - outImage->Initialize(); - outImage->SetDirection(image->GetDirection()); - outImage->SetSpacing(image->GetSpacing()); - outImage->SetOrigin(image->GetOrigin()); + //Set the output image with the same properties as the input image + outImage->Initialize(); + outImage->SetDirection(image->GetDirection()); + outImage->SetSpacing(image->GetSpacing()); + outImage->SetOrigin(image->GetOrigin()); - ImageType::RegionType largestRegion = image->GetLargestPossibleRegion(); - outImage->SetRegions(largestRegion); - outImage->Allocate(); - outImage->FillBuffer(0.0); + //Allocate the correct size for output image. largestRegion (image->GetLargestPossibleRegion()) is the whole image + ImageType::RegionType largestRegion = image->GetLargestPossibleRegion(); + outImage->SetRegions(largestRegion); + outImage->Allocate(); + outImage->FillBuffer(0.0); - itk::ImageRegionIterator inItr(image,image->GetLargestPossibleRegion()); - itk::ImageRegionIterator outItr(outImage,outImage->GetLargestPossibleRegion()); + //Create iterators on input and output images + itk::ImageRegionIterator inItr(image,image->GetLargestPossibleRegion()); + itk::ImageRegionIterator outItr(outImage,outImage->GetLargestPossibleRegion()); - while (!outItr.IsAtEnd()) - { - if(inItr.Get() == 0.0) - outItr.Set(0); - else - outItr.Set(1); + //Main algorithm + while (!outItr.IsAtEnd()) + { + if(inItr.Get() == 0.0) + { + //The voxel in the input image is 0, so this voxel in the output mask will be 0. + outItr.Set(0); + } + else + { + //The voxel in the input image is not 0, so this voxel in the output mask will be 1. + outItr.Set(1); + } - ++inItr; - ++outItr; + //Move to following voxel + ++inItr; + ++outItr; + } } + //Write output image and exit anima::writeImage (outArg.getValue(),outImage); - return EXIT_SUCCESS; }