1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18 #ifndef clitkDVHGenericFilter_txx
19 #define clitkDVHGenericFilter_txx
21 /* =================================================
22 * @file clitkDVHGenericFilter.txx
23 * @author Agata Krason <agata.krason@creatis.insa-lyon.fr>
24 * @date 20 November 2013
26 * @brief Dose volume and image histogram
28 ===================================================*/
31 #include "itkBinaryThresholdImageFilter.h"
32 #include "itkMaskImageFilter.h"
33 #include "itkMaskNegatedImageFilter.h"
34 #include "itkNthElementImageAdaptor.h"
35 #include "itkJoinSeriesImageFilter.h"
36 #include "itkMinimumMaximumImageCalculator.h"
39 #include <clitkCommon.h>
40 #include "clitkImageCommon.h"
41 #include "clitkDVHGenericFilter.h"
42 #include "clitkCropLikeImageFilter.h"
43 #include "clitkResampleImageWithOptionsFilter.h"
45 //-------------------------------------------------------------------
50 //-------------------------------------------------------------------
51 template<unsigned int Dimension, unsigned int Components>
53 DVHGenericFilter::UpdateWithDim(std::string PixelType)
55 if (m_Verbose) std::cout << "Image was detected to be "<<Dimension<<"D and "<< PixelType<<" with " << Components << " channel(s)..."<<std::endl;
57 if(PixelType == "short"){
58 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed short..." << std::endl;
59 UpdateWithDimAndPixelType<Dimension, signed short, Components>();
61 else if(PixelType == "unsigned_short"){
62 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl;
63 UpdateWithDimAndPixelType<Dimension, unsigned short, Components>();
66 else if (PixelType == "unsigned_char"){
67 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl;
68 UpdateWithDimAndPixelType<Dimension, unsigned char, Components>();
71 else if(PixelType == "double"){
72 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and double..." << std::endl;
73 UpdateWithDimAndPixelType<Dimension, double, Components>();
76 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl;
77 UpdateWithDimAndPixelType<Dimension, float, Components>();
82 //-------------------------------------------------------------------
83 // Update with the number of dimensions and the pixeltype
84 //-------------------------------------------------------------------
85 template <unsigned int Dimension, class PixelType, unsigned int Components>
87 DVHGenericFilter::UpdateWithDimAndPixelType()
91 typedef unsigned char LabelPixelType;
92 typedef itk::Image<itk::Vector<PixelType, Components>, Dimension> InputImageType;
93 typedef itk::Image<LabelPixelType, Dimension> LabelImageType;
96 typedef itk::ImageFileReader<InputImageType> InputReaderType;
97 typename InputReaderType::Pointer reader = InputReaderType::New();
98 reader->SetFileName( m_InputFileName);
100 typename InputImageType::Pointer input= reader->GetOutput();
102 typedef itk::NthElementImageAdaptor<InputImageType, PixelType> InputImageAdaptorType;
103 typedef itk::Image<PixelType, Dimension> OutputImageType;
105 typename InputImageAdaptorType::Pointer input_adaptor = InputImageAdaptorType::New();
106 input_adaptor->SetImage(input);
109 typedef itk::LabelStatisticsImageFilter<InputImageAdaptorType, LabelImageType> StatisticsImageFilterType;
110 typename StatisticsImageFilterType::Pointer statisticsFilter=StatisticsImageFilterType::New();
111 statisticsFilter->SetInput(input_adaptor);
114 typename LabelImageType::Pointer labelImage;
115 if (m_ArgsInfo.mask_given) {
116 int maskDimension, maskComponents;
117 std::string maskPixelType;
118 ReadImageDimensionAndPixelType(m_ArgsInfo.mask_arg, maskDimension, maskPixelType, maskComponents);
120 if (maskDimension == Dimension - 1) {
121 // Due to a limitation of filter itk::LabelStatisticsImageFilter, InputImageType and LabelImageType
122 // must have the same image dimension. However, we want to support label images with Dl = Di - 1,
123 // so we need to replicate the label image as many times as the size along dimension Di.
125 std::cout << "Replicating label image to match input image's dimension... " << std::endl;
127 typedef itk::Image<LabelPixelType, Dimension - 1> ReducedLabelImageType;
128 typedef itk::ImageFileReader<ReducedLabelImageType> LabelImageReaderType;
129 typedef itk::JoinSeriesImageFilter<ReducedLabelImageType, LabelImageType> JoinImageFilterType;
132 typename LabelImageReaderType::Pointer labelImageReader=LabelImageReaderType::New();
133 labelImageReader->SetFileName(m_ArgsInfo.mask_arg);
134 labelImageReader->Update();
136 typename JoinImageFilterType::Pointer joinFilter = JoinImageFilterType::New();
137 typename InputImageType::SizeType size = input->GetLargestPossibleRegion().GetSize();
138 for (unsigned int i = 0; i < size[Dimension - 1]; i++)
139 joinFilter->PushBackInput(labelImageReader->GetOutput());
141 joinFilter->Update();
142 labelImage = joinFilter->GetOutput();
145 typedef itk::ImageFileReader<LabelImageType> LabelImageReaderType;
146 typename LabelImageReaderType::Pointer labelImageReader=LabelImageReaderType::New();
147 labelImageReader->SetFileName(m_ArgsInfo.mask_arg);
148 labelImageReader->Update();
149 labelImage= labelImageReader->GetOutput();
151 // Check mask sampling/size
152 if (!HaveSameSizeAndSpacing<LabelImageType, InputImageType>(labelImage, input)) {
153 if (m_ArgsInfo.allow_resize_flag) {
154 if (m_ArgsInfo.verbose_flag) {
155 std::cout << "Resize mask image like input" << std::endl;
158 typedef clitk::ResampleImageWithOptionsFilter<LabelImageType> ResamplerType;
159 typename ResamplerType::Pointer resampler = ResamplerType::New();
160 resampler->SetInput(labelImage);
161 resampler->SetOutputSpacing(input->GetSpacing());
162 resampler->SetGaussianFilteringEnabled(false);
164 labelImage = resampler->GetOutput();
165 labelImage->GetSpacing();
166 typedef clitk::CropLikeImageFilter<LabelImageType> FilterType;
167 typename FilterType::Pointer crop = FilterType::New();
168 crop->SetInput(labelImage);
169 crop->SetCropLikeImage(input);
171 labelImage = crop->GetOutput();
172 //writeImage<LabelImageType>(labelImage, "test2.mha");
176 std::cerr << "Mask image has a different size/spacing than input. Abort" << std::endl;
185 labelImage=LabelImageType::New();
186 labelImage->SetRegions(input->GetLargestPossibleRegion());
187 labelImage->SetOrigin(input->GetOrigin());
188 labelImage->SetSpacing(input->GetSpacing());
189 labelImage->Allocate();
190 labelImage->FillBuffer(m_ArgsInfo.label_arg[0]);
192 statisticsFilter->SetLabelInput(labelImage);
194 // Check/compute spacing
195 const typename LabelImageType::SpacingType& spacing = input->GetSpacing();
196 double spacing_cc = (spacing[0]*spacing[1]*spacing[2])/1000;
197 // std::cout<<"Spacing x : "<<spacing[0]<<std::endl;
198 // std::cout<<"Spacing y : "<< spacing[1]<<std::endl;
199 // std::cout<<"Spacing z : "<< spacing[2]<<std::endl;
200 // std::cout <<"spacing_cc : "<< spacing_cc << std::endl;
203 typename LabelImageType::PixelType label;
204 unsigned int numberOfLabels;
205 if (m_ArgsInfo.label_given)
206 numberOfLabels=m_ArgsInfo.label_given;
210 unsigned int firstComponent = 0, lastComponent = 0;
211 if (m_ArgsInfo.channel_arg == -1) {
213 lastComponent = Components - 1;
216 firstComponent = m_ArgsInfo.channel_arg;
217 lastComponent = m_ArgsInfo.channel_arg;
220 for (unsigned int c=firstComponent; c<=lastComponent; c++) {
221 if (m_Verbose) std::cout << std::endl << "Processing channel " << c << std::endl;
223 input_adaptor->SelectNthElement(c);
224 input_adaptor->Update();
226 for (unsigned int k=0; k< numberOfLabels; k++) {
227 label=m_ArgsInfo.label_arg[k];
229 if (m_ArgsInfo.histogram_given)
231 std::cout<<"--------------"<<std::endl;
232 std::cout<<"| Label: |"<<label<<" |"<<std::endl;
233 std::cout<<"--------------"<<std::endl;
235 statisticsFilter->SetUseHistograms(true);
236 statisticsFilter->SetHistogramParameters(m_ArgsInfo.bins_arg, m_ArgsInfo.lower_arg, m_ArgsInfo.upper_arg);
240 if(m_ArgsInfo.dvhistogram_given)
242 statisticsFilter->SetUseHistograms(true);
243 statisticsFilter->SetHistogramParameters(m_ArgsInfo.bins_arg, m_ArgsInfo.lower_arg, m_ArgsInfo.upper_arg);
246 statisticsFilter->Update();
249 if (m_ArgsInfo.histogram_given)
251 if (m_Verbose) std::cout<<"Median: ";
252 std::cout<<statisticsFilter->GetMedian(label)<<std::endl;
254 typename StatisticsImageFilterType::HistogramPointer histogram =statisticsFilter->GetHistogram(label);
257 if (m_Verbose) std::cout<<"Histogram: "<<std::endl;
258 std::cout<<"# MinBin\tMidBin\tMaxBin\tFrequency"<<std::endl;
259 for( int i =0; i <m_ArgsInfo.bins_arg; i++)
260 std::cout<<histogram->GetBinMin(0,i)<<"\t"<<histogram->GetMeasurement(i,0)<<"\t"<<histogram->GetBinMax(0,i)<<"\t"<<histogram->GetFrequency(i)<<std::endl;
262 std::ofstream histogramFile(m_ArgsInfo.histogram_arg);
263 histogramFile<<"#Histogram: "<<std::endl;
264 histogramFile<<"#MinBin\tMidBin\tMaxBin\tFrequency"<<std::endl;
265 for( int i =0; i <m_ArgsInfo.bins_arg; i++)
266 histogramFile<<histogram->GetBinMin(0,i)<<"\t"<<histogram->GetMeasurement(i,0)<<"\t"<<histogram->GetBinMax(0,i)<<"\t"<<histogram->GetFrequency(i)<<std::endl;
270 if(m_ArgsInfo.dvhistogram_given)
272 typename StatisticsImageFilterType::HistogramPointer dvhistogram = statisticsFilter->GetHistogram(label);
275 std::cout<<"Total volume : ";
276 std::cout<<statisticsFilter->GetCount(label)<<" [No. of voxels]"<<std::endl;
277 std::cout<<"Total volume : ";
278 std::cout<<((statisticsFilter->GetCount(label))*spacing_cc)<<" [cc]"<<std::endl;
279 std::cout<<"Dose mean: ";
280 std::cout<<statisticsFilter->GetMean(label)<<" [Gy]"<<std::endl;
281 std::cout<<"Dose min: ";
282 std::cout<<statisticsFilter->GetMinimum(label)<<" [Gy]"<<std::endl;
283 std::cout<<"Dose max: ";
284 std::cout<<statisticsFilter->GetMaximum(label)<<" [Gy]"<<std::endl;
285 std::cout<<" "<<std::endl;
286 std::cout<<"#Dose[Gy] Volume_diff[No. of voxels]] Volume_cumul[No. of voxels] Volume_diff[%] Volume_cumul[%] Volume_diff[cc] Volume_cumul[cc]"<<std::endl;
287 for( int i =0; i <m_ArgsInfo.bins_arg; i++)
289 double percentDiffVolume = ((dvhistogram->GetFrequency(i))*100)/(statisticsFilter->GetCount(label));
290 double popCumulativeVolume = 0;
291 for(int j=0; j<i; j++)
293 popCumulativeVolume+=(dvhistogram->GetFrequency(j));
295 double cumulativeVolume = popCumulativeVolume + (dvhistogram->GetFrequency(i));
296 double percentCumulativeVolume =(cumulativeVolume*100)/(statisticsFilter->GetCount(label)) ;
297 double ccCumulativeVolume = (popCumulativeVolume + (dvhistogram->GetFrequency(i)))*spacing_cc;
298 std::cout<<dvhistogram->GetBinMax(0,i)<<"\t "<<dvhistogram->GetFrequency(i)<<"\t "<<cumulativeVolume<<"\t "<<percentDiffVolume<<"\t "<<percentCumulativeVolume<<"\t "<<((dvhistogram->GetFrequency(i))*spacing_cc)<<"\t "<<ccCumulativeVolume<<std::endl;
302 std::ofstream dvhistogramFile(m_ArgsInfo.dvhistogram_arg);
303 dvhistogramFile<<"Total volume : ";
304 dvhistogramFile<<statisticsFilter->GetCount(label)<<" [No. of voxels]"<<std::endl;
305 dvhistogramFile<<"Total volume : ";
306 dvhistogramFile<<((statisticsFilter->GetCount(label))*spacing_cc)<<" [cc]"<<std::endl;
307 dvhistogramFile<<"Dose mean: ";
308 dvhistogramFile<<statisticsFilter->GetMean(label)<<" [Gy]"<<std::endl;
309 dvhistogramFile<<"Dose min: ";
310 dvhistogramFile<<statisticsFilter->GetMinimum(label)<<" [Gy]"<<std::endl;
311 dvhistogramFile<<"Dose max: ";
312 dvhistogramFile<<statisticsFilter->GetMaximum(label)<<" [Gy]"<<std::endl;
313 dvhistogramFile<<" "<<std::endl;
314 dvhistogramFile<<"#Dose[Gy] Volume_diff[No. of voxels]] Volume_cumul[No. of voxels] Volume_diff[%] Volume_cumul[%] Volume_diff[cc] Volume_cumul[cc]"<<std::endl;
315 for( int i =0; i <m_ArgsInfo.bins_arg; i++)
317 double percentDiffVolume = ((dvhistogram->GetFrequency(i))*100)/(statisticsFilter->GetCount(label));
318 double popCumulativeVolume = 0;
319 for(int j=0; j<i; j++)
321 popCumulativeVolume+=(dvhistogram->GetFrequency(j));
323 double cumulativeVolume = popCumulativeVolume + (dvhistogram->GetFrequency(i));
324 double percentCumulativeVolume =(cumulativeVolume*100)/(statisticsFilter->GetCount(label)) ;
325 double ccCumulativeVolume = (popCumulativeVolume + (dvhistogram->GetFrequency(i)))*spacing_cc;
326 dvhistogramFile<<dvhistogram->GetBinMax(0,i)<<"\t "<<dvhistogram->GetFrequency(i)<<"\t "<<cumulativeVolume<<"\t "<<percentDiffVolume<<"\t "<<percentCumulativeVolume<<"\t "<<((dvhistogram->GetFrequency(i))*spacing_cc)<<"\t "<<ccCumulativeVolume<<std::endl;
338 #endif //#define clitkDVHGenericFilter_txx