From 5ca03ec7d6721080f7d62f765e369f13d077d65d Mon Sep 17 00:00:00 2001 From: tbaudier Date: Thu, 29 Nov 2018 12:02:47 +0100 Subject: [PATCH] Add clitkScintivolStats It use to compute statistics for Scintivol project --- tools/CMakeLists.txt | 5 + tools/clitkScintivolStats.cxx | 214 ++++++++++++++++++++++++++++++++++ tools/clitkScintivolStats.ggo | 23 ++++ 3 files changed, 242 insertions(+) create mode 100644 tools/clitkScintivolStats.cxx create mode 100644 tools/clitkScintivolStats.ggo diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ca366af..0a044fe 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -54,6 +54,11 @@ if(CLITK_BUILD_TOOLS) target_link_libraries(clitkImageInfo clitkCommon) set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkImageInfo) + WRAP_GGO(clitkScintivolStats_GGO_C clitkScintivolStats.ggo) + add_executable(clitkScintivolStats clitkScintivolStats.cxx ${clitkScintivolStats_GGO_C}) + target_link_libraries(clitkScintivolStats clitkCommon) + set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkScintivolStats) + add_executable(clitkImageConvert clitkImageConvert.cxx) target_link_libraries(clitkImageConvert clitkImageConvertLib clitkCommon) set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkImageConvert) diff --git a/tools/clitkScintivolStats.cxx b/tools/clitkScintivolStats.cxx new file mode 100644 index 0000000..af197f7 --- /dev/null +++ b/tools/clitkScintivolStats.cxx @@ -0,0 +1,214 @@ +/*========================================================================= + Program: vv http://www.creatis.insa-lyon.fr/rio/vv + + Authors belong to: + - University of LYON http://www.universite-lyon.fr/ + - Léon Bérard cancer center http://www.centreleonberard.fr + - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the copyright notices for more information. + + It is distributed under dual licence + + - BSD See included LICENSE.txt file + - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html +===========================================================================**/ +#ifndef CLITKSCINTIVOLSTATS_CXX +#define CLITKSCINTIVOLSTATS_CXX + +// clitk include +#include "clitkScintivolStats_ggo.h" +#include "clitkIO.h" +#include "clitkImageCommon.h" +#include "clitkCommon.h" + +#include "itkImageFileReader.h" +#include "itkBinaryImageToLabelMapFilter.h" +#include "itkLabelMapToLabelImageFilter.h" +#include "itkLabelStatisticsImageFilter.h" +#include "itkStatisticsImageFilter.h" +#include "itkExtractImageFilter.h" + +#include + +//-------------------------------------------------------------------= +int main(int argc, char * argv[]) +{ + + // init command line + GGO(clitkScintivolStats, args_info); + CLITK_INIT; + + typedef itk::Image Input3DType; + typedef itk::Image Input2DType; + typedef itk::Image Input3DMaskType; + typedef itk::Image Input2DMaskType; + typedef itk::ImageFileReader InputReader3DType; + typedef itk::ImageFileReader InputReader3DMaskType; + typedef itk::ImageFileReader InputReader2DMaskType; + typedef itk::LabelStatisticsImageFilter LabelStatistics3DImageFilterType; + typedef itk::LabelStatisticsImageFilter LabelStatistics2DImageFilterType; + typedef itk::StatisticsImageFilter Statistics2DImageFilterType; + typedef itk::ExtractImageFilter ExtractImageFilter; + + //Determine nbAcquisitionDynamic1 and nbAcquisitionDynamic2 (ie. the number of slice in dynamic1 and dynamic2) + //Start to open the dynamic1 and dynamic2 and get the 3rd dimension size + InputReader3DType::Pointer readerDynamic1 = InputReader3DType::New(); + readerDynamic1->SetFileName(args_info.dynamic1_arg); + readerDynamic1->Update(); + Input3DType::Pointer dynamic1 = readerDynamic1->GetOutput(); + int nbAcquisitionDynamic1 = dynamic1->GetLargestPossibleRegion().GetSize()[2]; + + InputReader3DType::Pointer readerDynamic2 = InputReader3DType::New(); + readerDynamic2->SetFileName(args_info.dynamic2_arg); + readerDynamic2->Update(); + Input3DType::Pointer dynamic2 = readerDynamic2->GetOutput(); + int nbAcquisitionDynamic2 = dynamic2->GetLargestPossibleRegion().GetSize()[2]; + + //Open the csv file + //If it's scatter or attenuation correction, just append results to the csv file + //If not open it normally and write the number of dynamic acquisition for the first and the second images (given by the ggo and from the dicom tag) + std::ofstream csvFile; + if (args_info.append_flag) + csvFile.open (args_info.output_arg, std::ios::app); + else { + csvFile.open (args_info.output_arg); + csvFile << "1;" << nbAcquisitionDynamic1 << ";" << nbAcquisitionDynamic2 << "\n"; + } + + //Read Tomo image, total and remnant masks + InputReader3DType::Pointer readerTomo = InputReader3DType::New(); + readerTomo->SetFileName(args_info.tomo_arg); + readerTomo->Update(); + Input3DType::Pointer tomo = readerTomo->GetOutput(); + + InputReader3DMaskType::Pointer readerTotalLiver = InputReader3DMaskType::New(); + readerTotalLiver->SetFileName(args_info.totalLiverMask_arg); + readerTotalLiver->Update(); + + InputReader3DMaskType::Pointer readerRemnantLiver = InputReader3DMaskType::New(); + readerRemnantLiver->SetFileName(args_info.remnantLiverMask_arg); + readerRemnantLiver->Update(); + + //Find number of counts in tomo for total Liver and remnant Liver + LabelStatistics3DImageFilterType::Pointer labelStatisticsImageFilterTotalLiver = LabelStatistics3DImageFilterType::New(); + labelStatisticsImageFilterTotalLiver->SetLabelInput(readerTotalLiver->GetOutput()); + labelStatisticsImageFilterTotalLiver->SetInput(tomo); + labelStatisticsImageFilterTotalLiver->Update(); + + LabelStatistics3DImageFilterType::Pointer labelStatisticsImageFilterRemnantLiver = LabelStatistics3DImageFilterType::New(); + labelStatisticsImageFilterRemnantLiver->SetLabelInput(readerRemnantLiver->GetOutput()); + labelStatisticsImageFilterRemnantLiver->SetInput(tomo); + labelStatisticsImageFilterRemnantLiver->Update(); + + //Write them in the csv file + csvFile << args_info.acquisitionTimeTomo_arg << ";" << labelStatisticsImageFilterTotalLiver->GetSum(1) << ";" << labelStatisticsImageFilterRemnantLiver->GetSum(1) << "\n"; + + //Read liver and heart masks for dynamic1 + InputReader2DMaskType::Pointer readerLiver = InputReader2DMaskType::New(); + readerLiver->SetFileName(args_info.liverMask_arg); + readerLiver->Update(); + + InputReader2DMaskType::Pointer readerHeart = InputReader2DMaskType::New(); + readerHeart->SetFileName(args_info.heartMask_arg); + readerHeart->Update(); + + for (unsigned int i=0; iGetLargestPossibleRegion().GetSize()[0]; + size[1] = dynamic1->GetLargestPossibleRegion().GetSize()[1]; + size[2] = 0; + Input3DType::RegionType desiredRegion; + desiredRegion.SetSize(size); + desiredRegion.SetIndex(start); + extractSlice->SetExtractionRegion(desiredRegion); + extractSlice->SetInput(dynamic1); +#if ITK_VERSION_MAJOR >= 4 + extractSlice->SetDirectionCollapseToIdentity(); +#endif + extractSlice->Update(); + + //Find number of counts in dynamic1 slice for Liver and heart + LabelStatistics2DImageFilterType::Pointer labelStatisticsImageFilterLiver = LabelStatistics2DImageFilterType::New(); + labelStatisticsImageFilterLiver->SetLabelInput(readerLiver->GetOutput()); + labelStatisticsImageFilterLiver->SetInput(extractSlice->GetOutput()); + labelStatisticsImageFilterLiver->SetCoordinateTolerance(0.001); + labelStatisticsImageFilterLiver->SetDirectionTolerance(0.001); + labelStatisticsImageFilterLiver->Update(); + + LabelStatistics2DImageFilterType::Pointer labelStatisticsImageFilterHeart = LabelStatistics2DImageFilterType::New(); + labelStatisticsImageFilterHeart->SetLabelInput(readerHeart->GetOutput()); + labelStatisticsImageFilterHeart->SetInput(extractSlice->GetOutput()); + labelStatisticsImageFilterHeart->SetCoordinateTolerance(0.001); + labelStatisticsImageFilterHeart->SetDirectionTolerance(0.001); + labelStatisticsImageFilterHeart->Update(); + + //Find number of counts in dynamic1 slice + Statistics2DImageFilterType::Pointer statisticsImageFilterDynamic1 = Statistics2DImageFilterType::New(); + statisticsImageFilterDynamic1->SetInput(extractSlice->GetOutput()); + statisticsImageFilterDynamic1->Update(); + + //Write them in the csv file + csvFile << timeFrame << ";" << labelStatisticsImageFilterLiver->GetSum(1) << ";" << labelStatisticsImageFilterHeart->GetSum(1) << ";" << statisticsImageFilterDynamic1->GetSum() << "\n"; + } + + //Read parenchyma mask for dynamic2 + InputReader2DMaskType::Pointer readerParenchyma = InputReader2DMaskType::New(); + readerParenchyma->SetFileName(args_info.parenchymaMask_arg); + readerParenchyma->Update(); + + for (unsigned int i=0; iGetLargestPossibleRegion().GetSize()[0]; + size[1] = dynamic2->GetLargestPossibleRegion().GetSize()[1]; + size[2] = 0; + Input3DType::RegionType desiredRegion; + desiredRegion.SetSize(size); + desiredRegion.SetIndex(start); + extractSlice->SetExtractionRegion(desiredRegion); + extractSlice->SetInput(dynamic2); +#if ITK_VERSION_MAJOR >= 4 + extractSlice->SetDirectionCollapseToIdentity(); +#endif + extractSlice->Update(); + + //Find number of counts in dynamic2 slice for parenchyma + LabelStatistics2DImageFilterType::Pointer labelStatisticsImageFilterParenchyma = LabelStatistics2DImageFilterType::New(); + labelStatisticsImageFilterParenchyma->SetLabelInput(readerParenchyma->GetOutput()); + labelStatisticsImageFilterParenchyma->SetInput(extractSlice->GetOutput()); + labelStatisticsImageFilterParenchyma->SetCoordinateTolerance(0.001); + labelStatisticsImageFilterParenchyma->SetDirectionTolerance(0.001); + labelStatisticsImageFilterParenchyma->Update(); + + //Write them in the csv file + csvFile << timeFrame << ";" << labelStatisticsImageFilterParenchyma->GetSum(1) << "\n"; + } + + csvFile.close(); + + // this is the end my friend + return 0; +} +//-------------------------------------------------------------------= + +#endif /* end #define CLITKSCINTIVOLSTATS_CXX */ diff --git a/tools/clitkScintivolStats.ggo b/tools/clitkScintivolStats.ggo new file mode 100644 index 0000000..e99d9ab --- /dev/null +++ b/tools/clitkScintivolStats.ggo @@ -0,0 +1,23 @@ +# file clitkScintivolStats.ggo +package "clitkScintivolStats" +version "1.0" +purpose "Convert an image into another image.\n\tAllow to change the file format and/or the pixel type. \n\tKnown file formats 2D: jpeg png bmp tif mhd hdr vox dcm \n\tKnown file formats 3D: mhd vox hdr dcm\n\tKnown file formats 4D: mhd \n\tKnown images: 2D 3D or 4D, schar, uchar, short, ushort, int, float and double\n\nIf the -o option is not given, the last parameter of the command line is used as output." + +option "config" - "Config file" string no +option "output" o "Output .csv filename" string yes +option "append" - "Append results to .csv file (eg: for scatter)" flag off + +option "dynamic1" - "Dynamique 1 filename (geometrical mean)" string yes +option "frameDurationDynamic1" - "Frame duration for dynamique 1" double yes +option "heartMask" - "Heart mask filename" string yes +option "liverMask" - "Liver mask filename" string yes + +option "dynamic2" - "Dynamique 2 filename (geometrical mean)" string yes +option "frameDurationDynamic2" - "Frame duration for dynamique 2" double yes +option "acquisitionTimeDynamic2" - "Start acquisition time of the dynamic2 after dynamic1" double yes +option "parenchymaMask" - "Parenchyma mask filename" string yes + +option "tomo" - "Tomo image filename" string yes +option "acquisitionTimeTomo" - "Acquisition time for tomo" double yes +option "totalLiverMask" - "Total liver mask filename" string yes +option "remnantLiverMask" - "Remnant liver mask filename" string yes -- 2.45.0