5 #include <itkImageFileReader.h>
6 #include <itkImageFileWriter.h>
7 #include <itkMinimumMaximumImageCalculator.h>
8 #include <itkShiftScaleImageFilter.h>
9 #include <itkImageConstIteratorWithIndex.h>
10 #include <itkChangeInformationImageFilter.h>
11 #include <itkSignedMaurerDistanceMapImageFilter.h>
13 #include "clitkGammaIndex_ggo.h"
15 const unsigned int image_dim = 2;
17 typedef itk::Image<float,image_dim> Image;
18 typedef itk::ImageRegionIteratorWithIndex<Image> ImageIterator;
19 typedef itk::ImageRegionConstIteratorWithIndex<Image> ImageConstIterator;
20 typedef itk::ImageFileReader<Image> Reader;
21 typedef itk::MinimumMaximumImageCalculator<Image> MinMaxer;
22 typedef itk::ShiftScaleImageFilter<Image,Image> Normalizer;
23 typedef itk::ChangeInformationImageFilter<Image> Scaler;
25 typedef itk::Image<unsigned char,image_dim+1> ImageBin;
26 typedef itk::Image<float,image_dim+1> ImageMap;
27 typedef itk::SignedMaurerDistanceMapImageFilter<ImageBin,ImageMap> Mapper;
29 template <typename ImageType>
30 void SaveImage(const ImageType *image, const std::string &filename) {
31 typedef typename itk::ImageFileWriter<ImageType> Writer;
32 typename Writer::Pointer writer = Writer::New();
33 writer->SetFileName(filename);
34 writer->SetInput(image);
38 ImageBin::Pointer AllocateImageBin(const Image *reference, const Image *target, unsigned int dose_size, float dose_max) {
39 const Image::RegionType reference_region = reference->GetLargestPossibleRegion();
40 const Image::RegionType target_region = target->GetLargestPossibleRegion();
41 const Image::SpacingType reference_spacing = reference->GetSpacing();
42 const Image::SpacingType target_spacing = target->GetSpacing();
43 const Image::PointType reference_origin = reference->GetOrigin();
44 const Image::PointType target_origin = target->GetOrigin();
46 assert(reference_region == target_region);
47 assert(reference_spacing == target_spacing);
48 assert(reference_origin == target_origin);
50 ImageBin::RegionType region;
51 ImageBin::SpacingType spacing;
52 ImageBin::PointType origin;
53 for (unsigned long kk=0; kk<Image::GetImageDimension(); kk++) {
54 region.SetSize(kk,reference_region.GetSize(kk));
55 region.SetIndex(kk,reference_region.GetIndex(kk));
56 spacing[kk] = reference_spacing[kk];
57 origin[kk] = reference_origin[kk];
59 const unsigned long dose_dimension = Image::GetImageDimension();
60 region.SetSize(dose_dimension,dose_size);
61 region.SetIndex(dose_dimension,0);
62 spacing[dose_dimension] = dose_max/(dose_size-1);
63 origin[dose_dimension] = 0;
65 ImageBin::Pointer map = ImageBin::New();
66 map->SetRegions(region);
67 map->SetSpacing(spacing);
68 map->SetOrigin(origin);
75 Image::Pointer AllocateImageGamma(const Image *target) {
76 const Image::RegionType target_region = target->GetLargestPossibleRegion();
77 const Image::SpacingType target_spacing = target->GetSpacing();
78 const Image::PointType target_origin = target->GetOrigin();
80 Image::Pointer gamma = Image::New();
81 gamma->SetRegions(target_region);
82 gamma->SetSpacing(target_spacing);
83 gamma->SetOrigin(target_origin);
90 void FillImageBin(ImageBin *image_bin, const Image *reference) {
91 ImageConstIterator iterator(reference,reference->GetLargestPossibleRegion());
93 while (!iterator.IsAtEnd()) {
94 Image::PixelType value = iterator.Get();
95 Image::PointType point;
96 reference->TransformIndexToPhysicalPoint(iterator.GetIndex(),point);
98 ImageBin::PointType point_bin;
99 for (unsigned long kk=0; kk<Image::GetImageDimension(); kk++) {
100 point_bin[kk] = point[kk];
102 point_bin[Image::GetImageDimension()] = value;
104 ImageBin::IndexType index_bin;
106 image_bin->TransformPhysicalPointToIndex(point_bin,index_bin);
108 bool found = image_bin->TransformPhysicalPointToIndex(point_bin,index_bin);
112 while (index_bin[Image::GetImageDimension()] >=0 ) {
113 image_bin->SetPixel(index_bin,255);
114 index_bin[Image::GetImageDimension()]--;
121 void FillImageGamma(Image *gamma, const Image *target, const ImageMap *distance) {
122 ImageIterator gamma_iterator(gamma,gamma->GetLargestPossibleRegion());
123 ImageConstIterator target_iterator(target,target->GetLargestPossibleRegion());
124 gamma_iterator.GoToBegin();
125 target_iterator.GoToBegin();
126 while (!target_iterator.IsAtEnd()) {
127 assert(!gamma_iterator.IsAtEnd());
129 Image::PixelType value = target_iterator.Get();
130 Image::PointType point;
131 target->TransformIndexToPhysicalPoint(target_iterator.GetIndex(),point);
133 ImageMap::PointType point_map;
135 for (unsigned long kk=0; kk<Image::GetImageDimension(); kk++) {
136 point_map[kk] = point[kk];
138 point_map[Image::GetImageDimension()] = value;
140 ImageMap::IndexType index_map;
142 distance->TransformPhysicalPointToIndex(point_map,index_map);
144 bool found = distance->TransformPhysicalPointToIndex(point_map,index_map);
148 gamma_iterator.Set(fabsf(distance->GetPixel(index_map)));
155 void TuneScaler(Scaler *scaler,float space_margin) {
156 Scaler::InputImageType::PointType origin = scaler->GetInput()->GetOrigin();
157 Scaler::InputImageType::SpacingType spacing = scaler->GetInput()->GetSpacing();
158 for (unsigned int kk=0; kk<Scaler::InputImageType::GetImageDimension(); kk++) {
159 origin[kk] /= space_margin;
160 spacing[kk] /= space_margin;
163 scaler->SetOutputSpacing(spacing);
164 scaler->SetOutputOrigin(origin);
165 scaler->ChangeSpacingOn();
166 scaler->ChangeOriginOn();
169 Image::PixelType GetImageMaximum(const Image *image) {
170 MinMaxer::Pointer minmaxer = MinMaxer::New();
171 minmaxer->SetImage(image);
172 minmaxer->ComputeMaximum();
173 return minmaxer->GetMaximum();
176 void ComputeGammaRatio(const Image *image) {
177 ImageConstIterator iterator(image,image->GetLargestPossibleRegion());
178 iterator.GoToBegin();
179 unsigned long total = 0;
180 unsigned long over_one = 0;
181 while (!iterator.IsAtEnd()) {
182 Image::PixelType value = iterator.Get();
184 if (value>1) over_one++;
190 cout << "total=" << total << endl;
191 cout << "over_one=" << over_one << endl;
192 cout << "ratio=" << static_cast<float>(over_one)/total << endl;
195 int main(int argc,char * argv[])
197 args_info_clitkGammaIndex args_info;
199 if (cmdline_parser_clitkGammaIndex(argc, argv, &args_info) != 0)
202 if (!args_info.absolute_dose_margin_given && !args_info.relative_dose_margin_given) {
203 std::cerr << "Specify either relative or absolute dose margin" << endl;
207 if (args_info.isodose_number_arg <= 0) {
208 std::cerr << "Specify a valid isodose number (>0)" << endl;
212 bool verbose = args_info.verbose_flag;
214 std::string reference_filename(args_info.reference_arg);
215 std::string target_filename(args_info.target_arg);
216 std::string gamma_filename(args_info.output_arg);
217 float space_margin = args_info.spatial_margin_arg;
218 float dose_rel_margin = args_info.relative_dose_margin_arg;
219 float dose_margin = args_info.absolute_dose_margin_arg;
220 bool use_dose_margin = args_info.absolute_dose_margin_given;
221 unsigned int dose_size = args_info.isodose_number_arg;
224 cout << "reference_filename=" << reference_filename << endl;
225 cout << "target_filename=" << target_filename << endl;
226 cout << "gamma_filename=" << gamma_filename << endl;
227 cout << "dose_size=" << dose_size << endl;
228 cout << "space_margin=" << space_margin << endl;
229 if (use_dose_margin) cout << "dose_margin=" << dose_margin << endl;
230 else cout << "dose_rel_margin=" << dose_rel_margin << endl;
234 Reader::Pointer reference_reader = Reader::New();
235 Reader::Pointer target_reader = Reader::New();
237 reference_reader->SetFileName(reference_filename);
238 target_reader->SetFileName(target_filename);
239 reference_reader->Update();
240 target_reader->Update();
243 // intensity normalisation
244 if (!use_dose_margin) {
245 MinMaxer::PixelType reference_max = GetImageMaximum(reference_reader->GetOutput());
246 //MinMaxer::PixelType target_max = GetImageMaximum(target_reader->GetOutput());
248 dose_margin = reference_max*dose_rel_margin;
250 if (verbose) cout << "dose_margin=" << dose_margin << endl;
254 Normalizer::Pointer reference_normalizer = Normalizer::New();
255 Normalizer::Pointer target_normalizer = Normalizer::New();
257 reference_normalizer->SetShift(0);
258 reference_normalizer->SetScale(1/dose_margin);
259 reference_normalizer->SetInput(reference_reader->GetOutput());
260 reference_normalizer->Update();
262 target_normalizer->SetShift(0);
263 target_normalizer->SetScale(1/dose_margin);
264 target_normalizer->SetInput(target_reader->GetOutput());
265 target_normalizer->Update();
267 //cout << "scale=" << reference_normalizer->GetScale() << "/" << target_normalizer->GetScale() << endl;
268 //cout << "shift=" << reference_normalizer->GetShift() << "/" << target_normalizer->GetShift() << endl;
271 // normalize space coordinates
272 Scaler::Pointer reference_scaler = Scaler::New();
273 Scaler::Pointer target_scaler = Scaler::New();
275 reference_scaler->SetInput(reference_normalizer->GetOutput());
276 TuneScaler(reference_scaler,space_margin);
277 reference_scaler->Update();
279 target_scaler->SetInput(target_normalizer->GetOutput());
280 TuneScaler(target_scaler,space_margin);
281 target_scaler->Update();
283 //SaveImage(reference_scaler->GetOutput(),"norm_reference.mhd");
284 //SaveImage(reference_scaler->GetOutput(),"norm_target.mhd");
287 // compute hyper surface plane
288 float reference_dose_scaled_max = GetImageMaximum(reference_scaler->GetOutput());
289 float target_dose_scaled_max = GetImageMaximum(target_scaler->GetOutput());
290 float dose_scaled_max = reference_dose_scaled_max > target_dose_scaled_max ? reference_dose_scaled_max : target_dose_scaled_max;
291 ImageBin::Pointer image_bin = AllocateImageBin(reference_scaler->GetOutput(),target_scaler->GetOutput(),dose_size,dose_scaled_max);
292 FillImageBin(image_bin,reference_scaler->GetOutput());
293 //SaveImage(image_bin.GetPointer(),"surface.mhd");
295 // compute distance map
296 Mapper::Pointer mapper = Mapper::New();
297 mapper->InsideIsPositiveOn();
298 mapper->SquaredDistanceOff();
299 mapper->UseImageSpacingOn();
300 mapper->SetInput(image_bin);
302 //SaveImage(mapper->GetOutput(),"distance.mhd");
304 // extract gamma index from distance map
305 Image::Pointer image_gamma = AllocateImageGamma(target_normalizer->GetOutput());
306 FillImageGamma(image_gamma,target_scaler->GetOutput(),mapper->GetOutput());
307 SaveImage(image_gamma.GetPointer(),gamma_filename);
309 if (verbose) ComputeGammaRatio(image_gamma);