Seg3D  2.4
Seg3D is a free volume segmentation and processing tool developed by the NIH Center for Integrative Biomedical Computing at the University of Utah Scientific Computing and Imaging (SCI) Institute.
grid_common.hxx
1 /*
2  For more information, please see: http://software.sci.utah.edu
3 
4  The MIT License
5 
6  Copyright (c) 2016 Scientific Computing and Imaging Institute,
7  University of Utah.
8 
9 
10  Permission is hereby granted, free of charge, to any person obtaining a
11  copy of this software and associated documentation files (the "Software"),
12  to deal in the Software without restriction, including without limitation
13  the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  and/or sell copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following conditions:
16 
17  The above copyright notice and this permission notice shall be included
18  in all copies or substantial portions of the Software.
19 
20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  DEALINGS IN THE SOFTWARE.
27 */
28 
29 // File : grid_common.hxx
30 // Author : Pavel A. Koshevoy
31 // Created : Wed Jan 10 09:31:00 MDT 2007
32 // Copyright : (C) 2004-2008 University of Utah
33 // Description : code used to refine mesh transform control points
34 
35 #ifndef GRID_COMMON_HXX_
36 #define GRID_COMMON_HXX_
37 
38 // the includes:
39 #include <Core/ITKCommon/common.hxx>
40 #include <Core/ITKCommon/FFT/fft_common.hxx>
41 #include <Core/ITKCommon/Transform/the_grid_transform.hxx>
42 #include <Core/ITKCommon/Transform/itkGridTransform.h>
43 #include <Core/ITKCommon/Optimizers/itkRegularStepGradientDescentOptimizer2.h>
44 #include <Core/ITKCommon/Optimizers/optimizer_observer.hxx>
45 
46 #include <Core/Utils/Log.h>
47 
48 #include <boost/filesystem.hpp>
49 
50 // system includes:
51 #include <sstream>
52 #include <math.h>
53 #include <stdlib.h>
54 #include <algorithm>
55 #include <functional>
56 #include <time.h>
57 
58 // ITK includes:
59 #include <itkCommand.h>
60 #include <itkImageMaskSpatialObject.h>
61 #include <itkImageRegistrationMethod.h>
62 #include <itkMultiResolutionImageRegistrationMethod.h>
63 #include <itkNormalizedCorrelationImageToImageMetric.h>
64 
65 namespace bfs=boost::filesystem;
66 
67 
68 //----------------------------------------------------------------
69 // DEBUG_REFINE_ONE_POINT
70 //
71 // #define DEBUG_REFINE_ONE_POINT
72 
73 //----------------------------------------------------------------
74 // DEBUG_ESTIMATE_DISPLACEMENT
75 //
76 // #define DEBUG_ESTIMATE_DISPLACEMENT
77 
78 #if defined(DEBUG_REFINE_ONE_POINT) || defined(DEBUG_ESTIMATE_DISPLACEMENT)
79 static int COUNTER = 0;
80 #endif
81 
82 
83 //----------------------------------------------------------------
84 // optimizer_t
85 //
87 
88 
89 //----------------------------------------------------------------
90 // setup_grid_transform
91 //
92 extern bool
93 setup_grid_transform(the_grid_transform_t & transform,
94  unsigned int rows,
95  unsigned int cols,
96  const pnt2d_t & tile_min,
97  const pnt2d_t & tile_max,
98  const mask_t * tile_mask,
99  base_transform_t::ConstPointer mosaic_to_tile,
100  unsigned int max_iterations = 100,
101  double min_step_scale = 1e-12,
102  double min_error_sqrd = 1e-16,
103  unsigned int pick_up_pace_steps = 5 // successful steps to pick up pace
104 );
105 
106 //----------------------------------------------------------------
107 // setup_mesh_transform
108 //
109 extern bool
110 setup_mesh_transform(the_mesh_transform_t & transform,
111  unsigned int rows,
112  unsigned int cols,
113  const pnt2d_t & tile_min,
114  const pnt2d_t & tile_max,
115  const mask_t * tile_mask,
116  base_transform_t::ConstPointer mosaic_to_tile,
117  unsigned int max_iterations,
118  double min_step_scale,
119  double min_error_sqrd,
120  unsigned int pick_up_pace_steps);
121 
122 //----------------------------------------------------------------
123 // estimate_displacement
124 //
125 template <class TImage>
126 void
127 estimate_displacement(double & best_metric, // current best metric
128  translate_transform_t::Pointer & best_transform,
129 
130  // origin offset of the small neighborhood of image A
131  // within the large image A:
132  const vec2d_t & offset,
133 
134  const TImage * a, // large image A
135  const TImage * b, // small image B
136 
137  // this could be the size of B (ususally when matching
138  // small neighborhoods in A and B), or the
139  // maximum dimesions of A and B (plain image matching):
140  const typename TImage::SizeType & period_sz,
141 
142  const local_max_t & lm,
143  const double overlap_min = 0.05,
144  const double overlap_max = 1.0,
145  const mask_t * mask_a = NULL,
146  const mask_t * mask_b = NULL,
147 
148  const unsigned int num_perms = 4)
149 {
150  vec2d_t best_offset = best_transform->GetOffset();
151 
152  const unsigned int & w = period_sz[0];
153  const unsigned int & h = period_sz[1];
154 
155  typedef typename TImage::SpacingType spacing_t;
156  spacing_t spacing = b->GetSpacing();
157  double sx = spacing[0];
158  double sy = spacing[1];
159 
160  // evaluate 4 permutation of the maxima:
161  const double x = lm.x_;
162  const double y = lm.y_;
163 
164  const vec2d_t t[] = {
165  vec2d(sx * x, sy * y),
166  vec2d(sx * (x - w), sy * y),
167  vec2d(sx * x, sy * (y - h)),
168  vec2d(sx * (x - w), sy * (y - h))
169  };
170 
171 #ifdef DEBUG_ESTIMATE_DISPLACEMENT
172  static const bfs::path fn_save("/tmp/estimate_displacement-");
173  static int COUNTER2 = 0;
174  bfs::path suffix =
175  the_text_t::number(COUNTER, 3, '0') + "-" +
176  the_text_t::number(COUNTER2, 3, '0') + "-";
177  COUNTER2++;
178 
179  // FIXME:
180  {
181  translate_transform_t::Pointer ti = translate_transform_t::New();
182  ti->SetOffset(-offset);
183  save_rgb<TImage>(fn_save + suffix + "0-init.png",
184  a,
185  b,
186  ti,
187  mask_a,
188  mask_b);
189  }
190 #endif
191 
192  std::ostringstream oss;
193  for (unsigned int i = 0; i < num_perms; i++)
194  {
195  translate_transform_t::Pointer ti = translate_transform_t::New();
196  ti->SetOffset(t[i] - offset);
197 
198  double area_ratio = overlap_ratio<TImage>(a, b, ti);
199  oss << i << ": " << std::setw(3) << static_cast<int>(area_ratio * 100.0) << "% of overlap, ";
200 
201  if (area_ratio < overlap_min || area_ratio > overlap_max)
202  {
203  oss << "skipping..." << std::endl;
204  continue;
205  }
206 
207 //#if 0
208 // typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
209 // // typedef itk::MeanSquaresImageToImageMetric<TImage, TImage> metric_t;
210 // typedef itk::NormalizedCorrelationImageToImageMetric<TImage, TImage>
211 // metric_t;
212 // double metric = eval_metric<metric_t, interpolator_t>(ti,
213 // a,
214 // b,
215 // mask_a,
216 // mask_b);
217 //#else
218  double metric = my_metric<TImage>(area_ratio,
219  a,
220  b,
221  ti,
222  mask_a,
223  mask_b,
224  overlap_min,
225  overlap_max);
226  //#endif
227 
228  oss << metric;
229  if (metric < best_metric)
230  {
231  best_offset = t[i];
232  best_metric = metric;
233  oss << " - better..." << std::endl;
234 
235 #ifdef DEBUG_ESTIMATE_DISPLACEMENT
236  // FIXME:
237  save_rgb<TImage>(fn_save + suffix +
238  the_text_t::number(i + 1) + "-perm.png",
239  a,
240  b,
241  ti,
242  mask_a,
243  mask_b);
244 #endif
245  }
246  else
247  {
248  oss << " - worse..." << std::endl;
249  }
250  }
251 
252  CORE_LOG_MESSAGE(oss.str());
253  best_transform->SetOffset(best_offset);
254 }
255 
256 
257 //----------------------------------------------------------------
258 // match_one_pair
259 //
260 // match two images, find the best matching transform and
261 // return the corresponding match metric value
262 //
263 template <class TImage>
264 double
265 match_one_pair(translate_transform_t::Pointer & best_transform,
266  const TImage * fi,
267  const mask_t * fi_mask,
268 
269  const TImage * mi,
270  const mask_t * mi_mask,
271 
272  // this could be the size of B (ususally when matching
273  // small neighborhoods in A and B), or the
274  // maximum dimesions of A and B (plain image matching):
275  const typename TImage::SizeType & period_sz,
276 
277  const double & overlap_min,
278  const double & overlap_max,
279 
280  image_t::PointType offset_min,
281  image_t::PointType offset_max,
282 
283  const double & lp_filter_r,
284  const double & lp_filter_s,
285 
286  const unsigned int max_peaks,
287  const bool & consider_zero_displacement)
288 {
289  static const vec2d_t offset = vec2d(0, 0);
290  best_transform = NULL;
291 
292  std::list<local_max_t> max_list;
293  unsigned int total_peaks = find_correlation<TImage>(max_list,
294  fi,
295  mi,
296  lp_filter_r,
297  lp_filter_s);
298 
299  unsigned int num_peaks = reject_negligible_maxima(max_list, 2.0);
300  std::ostringstream oss;
301  oss << num_peaks << '/' << total_peaks << " eligible peaks, ";
302 
303  if (num_peaks > max_peaks)
304  {
305  oss << "skipping..." << std::endl;
306  CORE_LOG_MESSAGE(oss.str());
307  return std::numeric_limits<double>::max();
308  }
309 
310  double best_metric = std::numeric_limits<double>::max();
311  best_transform = translate_transform_t::New();
312  best_transform->SetIdentity();
313 
314  if (consider_zero_displacement)
315  {
316  // make sure to consider the no-displacement case:
317  estimate_displacement<TImage>(best_metric,
318  best_transform,
319  offset,
320  fi,
321  mi,
322  period_sz,
323  local_max_t(0, 0, 0, 0),
324  0,
325  1,
326  fi_mask,
327  mi_mask,
328  1); // don't try permutations
329  }
330 
331  // choose the best peak:
332  for (std::list<local_max_t>::iterator j = max_list.begin();
333  j != max_list.end(); ++j)
334  {
335  oss << "evaluating permutations..." << std::endl;
336  const local_max_t & lm = *j;
337 
338  double prev_metric = best_metric;
339  vec2d_t prev_offset = best_transform->GetOffset();
340 
341  estimate_displacement<TImage>(best_metric,
342  best_transform,
343  offset,
344  fi,
345  mi,
346  period_sz,
347  lm, // local maxima record
348  overlap_min,
349  overlap_max,
350  fi_mask,
351  mi_mask);
352 
353  // re-evaluate the overlap in the context of the small neighborhoods:
354  double overlap = overlap_ratio(fi, mi, best_transform);
355  if (overlap < overlap_min || overlap > overlap_max)
356  {
357  best_metric = prev_metric;
358  best_transform->SetOffset(prev_offset);
359  }
360  }
361  CORE_LOG_MESSAGE(oss.str());
362 
363  return best_metric;
364 }
365 
366 
367 //----------------------------------------------------------------
368 // match_one_pair
369 //
370 // match two images, find the best matching transform and
371 // return the corresponding match metric value
372 //
373 template <class TImage>
374 double
375 match_one_pair(translate_transform_t::Pointer & best_transform,
376  const TImage * fi_large,
377  const mask_t * fi_large_mask,
378 
379  const TImage * fi,
380  const mask_t * /* fi_mask */,
381 
382  const TImage * mi,
383  const mask_t * mi_mask,
384 
385  // origin offset of the small fixed image neighborhood
386  // within the full image:
387  const vec2d_t & offset,
388 
389  const double & overlap_min,
390  const double & overlap_max,
391 
392  //image_t::PointType offset_min,
393  //image_t::PointType offset_max,
394 
395  const double & lp_filter_r,
396  const double & lp_filter_s,
397 
398  const unsigned int max_peaks,
399  const bool & consider_zero_displacement)
400 {
401  best_transform = NULL;
402 
403  std::list<local_max_t> max_list;
404  unsigned int total_peaks = find_correlation<TImage>(max_list,
405  fi,
406  mi,
407  lp_filter_r,
408  lp_filter_s);
409 
410  unsigned int num_peaks = reject_negligible_maxima(max_list, 2.0);
411  std::ostringstream oss;
412  oss << num_peaks << '/' << total_peaks << " eligible peaks, ";
413 
414  if (num_peaks > max_peaks)
415  {
416  oss << "skipping..." << std::endl;
417  CORE_LOG_MESSAGE(oss.str());
418  return std::numeric_limits<double>::max();
419  }
420 
421  double best_metric = std::numeric_limits<double>::max();
422  best_transform = translate_transform_t::New();
423  best_transform->SetIdentity();
424 
425  typename TImage::SizeType period_sz = mi->GetLargestPossibleRegion().GetSize();
426 
427  if (consider_zero_displacement)
428  {
429  // make sure to consider the no-displacement case:
430  estimate_displacement<TImage>(best_metric,
431  best_transform,
432  offset,
433  fi_large,
434  mi,
435  period_sz,
436  local_max_t(0, 0, 0, 0),
437  0,
438  1,
439  fi_large_mask,
440  mi_mask,
441  1); // don't try permutations
442  }
443 
444  // choose the best peak:
445  for (std::list<local_max_t>::iterator j = max_list.begin();
446  j != max_list.end(); ++j)
447  {
448  oss << "evaluating permutations..." << std::endl;
449  const local_max_t & lm = *j;
450 
451  double prev_metric = best_metric;
452  vec2d_t prev_offset = best_transform->GetOffset();
453 
454  estimate_displacement<TImage>(best_metric,
455  best_transform,
456  offset,
457  fi_large,
458  mi,
459  period_sz,
460  lm, // local maxima record
461  overlap_min,
462  overlap_max,
463  fi_large_mask,
464  mi_mask);
465 
466  // re-evaluate the overlap in the context of the small neighborhoods:
467  double overlap = overlap_ratio(fi, mi, best_transform);
468  if (overlap < overlap_min || overlap > overlap_max)
469  {
470  best_metric = prev_metric;
471  best_transform->SetOffset(prev_offset);
472  }
473  }
474  CORE_LOG_MESSAGE(oss.str());
475 
476  return best_metric;
477 }
478 
479 
480 //----------------------------------------------------------------
481 // refine_one_point_fft
482 //
483 template <typename TImage>
484 bool
485 refine_one_point_fft(vec2d_t & shift,
486  const pnt2d_t & origin,
487 
488  // the large images and their masks:
489  const TImage * tile_0,
490  const mask_t * mask_0,
491 
492  // the extracted small neighborhoods and their masks:
493  const TImage * img_0,
494  const mask_t * msk_0,
495  const TImage * img_1,
496  const mask_t * msk_1)
497 {
498  // feed the two neighborhoods into the FFT translation estimator:
499  translate_transform_t::Pointer translate;
500  double metric =
501  match_one_pair<TImage>(translate, // best translation transform
502 
503  // fixed image in full:
504  tile_0,
505  mask_0,
506 
507  // fixed image small neighborhood:
508  img_0,
509  msk_0,
510 
511  // moving image small neighborhood:
512  img_1,
513  msk_1,
514 
515  // origin offset of the small fixed image
516  // neighborhood in the large image:
517  vec2d(origin[0], origin[1]),
518 
519  0.25,// overlap min
520  1.0, // overlap max
521  0.5, // low pass filter r
522  0.1, // low pass filter s
523  10, // number of peaks
524  true); // consider the no-displacement case
525 
526 #ifdef DEBUG_REFINE_ONE_POINT
527  static const bfs::path fn_save("/tmp/refine_one_point_fft-");
528  bfs::path suffix = the_text_t::number(COUNTER, 3, '0');
529 
530  save_composite(fn_save + suffix + "-a.png",
531  img_0,
532  img_1,
533  identity_transform_t::New(),
534  true);
535 #endif // DEBUG_REFINE_ONE_POINT
536 
537 #if defined(DEBUG_REFINE_ONE_POINT) || defined(DEBUG_ESTIMATE_DISPLACEMENT)
538  COUNTER++;
539 #endif
540 
541  if (metric == std::numeric_limits<double>::max())
542  {
543  return false;
544  }
545 
546 #ifdef DEBUG_REFINE_ONE_POINT
547  save_composite(fn_save + suffix + "-b.png",
548  img_0,
549  img_1,
550  translate.GetPointer(),
551  true);
552 #endif // DEBUG_REFINE_ONE_POINT
553 
554  shift = -translate->GetOffset();
555  return true;
556 }
557 
558 
559 //----------------------------------------------------------------
560 // refine_one_point_helper
561 //
562 template <typename TImage>
563 bool
564 refine_one_point_helper(const pnt2d_t & center,
565  const pnt2d_t & origin,
566  const double & min_overlap,
567 
568  // the large images and their masks:
569  const TImage * tile_0,
570  const mask_t * mask_0,
571  const TImage * tile_1,
572  const mask_t * mask_1,
573 
574  // transform that maps from the space of
575  // tile 0 to the space of tile 1:
576  const base_transform_t * t_01,
577 
578  // the extracted small neighborhoods and their masks:
579  TImage * img_0,
580  mask_t * msk_0,
581  TImage * img_1,
582  mask_t * msk_1,
583 
584  // neighborhood size and pixel spacing:
585  const typename TImage::SizeType & sz,
586  const typename TImage::SpacingType & sp)
587 {
588  // setup the image interpolators:
589  typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
590  typename interpolator_t::Pointer interpolator[] = {
591  interpolator_t::New(),
592  interpolator_t::New()
593  };
594 
595  interpolator[0]->SetInputImage(tile_0);
596  interpolator[1]->SetInputImage(tile_1);
597 
598  if (!interpolator[0]->IsInsideBuffer(center))
599  {
600  // don't bother extracting neigborhoods if the neighborhood center
601  // doesn't fall inside both images:
602  return false;
603  }
604 
605  // temporaries:
606  pnt2d_t mosaic_pt;
607  pnt2d_t tile_pt;
608  typename TImage::IndexType index;
609 
610  // keep count of pixel in the neighborhood:
611  unsigned int area[] = { 0, 0 };
612 
613  // extract a neighborhood of the given point from both tiles:
614  for (unsigned int y = 0; y < sz[1]; y++)
615  {
616  mosaic_pt[1] = origin[1] + double(y) * sp[1];
617  index[1] = y;
618  for (unsigned int x = 0; x < sz[0]; x++)
619  {
620  mosaic_pt[0] = origin[0] + double(x) * sp[0];
621  index[0] = x;
622 
623  // fixed image:
624  tile_pt = mosaic_pt;
625  if (interpolator[0]->IsInsideBuffer(tile_pt) &&
626  pixel_in_mask<mask_t>(mask_0, tile_pt))
627  {
628  double p = interpolator[0]->Evaluate(tile_pt);
629  img_0->SetPixel(index, (unsigned char)(std::min(255.0, p)));
630  msk_0->SetPixel(index, 1);
631  area[0]++;
632  }
633  else
634  {
635  img_0->SetPixel(index, 0);
636  msk_0->SetPixel(index, 0);
637  }
638 
639  // moving image:
640  tile_pt = t_01->TransformPoint(mosaic_pt);
641  if (interpolator[1]->IsInsideBuffer(tile_pt) &&
642  pixel_in_mask<mask_t>(mask_1, tile_pt))
643  {
644  double p = interpolator[1]->Evaluate(tile_pt);
645  img_1->SetPixel(index, (unsigned char)(std::min(255.0, p)));
646  msk_1->SetPixel(index, 1);
647  area[1]++;
648  }
649  else
650  {
651  img_1->SetPixel(index, 0);
652  msk_1->SetPixel(index, 0);
653  }
654  }
655  }
656 
657  // skip points which don't have enough neighborhood information:
658  double max_area = double(sz[0] * sz[1]);
659  double a[] = {
660  double(area[0]) / max_area,
661  double(area[1]) / max_area
662  };
663 
664  if (a[0] < min_overlap || a[1] < min_overlap)
665  {
666  return false;
667  }
668 
669  return true;
670 }
671 
672 //----------------------------------------------------------------
673 // refine_one_point_fft
674 //
675 template <typename TImage>
676 bool
677 refine_one_point_fft(vec2d_t & shift,
678  const pnt2d_t & center,
679  const pnt2d_t & origin,
680  const double & min_overlap,
681 
682  // the large images and their masks:
683  const TImage * tile_0,
684  const mask_t * mask_0,
685  const TImage * tile_1,
686  const mask_t * mask_1,
687 
688  // transform that maps from the space of
689  // tile 0 to the space of tile 1:
690  const base_transform_t * t_01,
691 
692  // the extracted small neighborhoods and their masks:
693  TImage * img_0,
694  mask_t * msk_0,
695  TImage * img_1,
696  mask_t * msk_1,
697 
698  // neighborhood size and pixel spacing:
699  const typename TImage::SizeType & sz,
700  const typename TImage::SpacingType & sp)
701 {
702  if (!refine_one_point_helper<TImage>(center,
703  origin,
704  min_overlap,
705  tile_0,
706  mask_0,
707  tile_1,
708  mask_1,
709  t_01,
710  img_0,
711  msk_0,
712  img_1,
713  msk_1,
714  sz,
715  sp))
716  {
717  return false;
718  }
719 
720  return refine_one_point_fft<TImage>(shift,
721  origin,
722  tile_0,
723  mask_0,
724  img_0,
725  msk_0,
726  img_1,
727  msk_1);
728 }
729 
730 //----------------------------------------------------------------
731 // refine_one_point_fft
732 //
733 template <typename TImage>
734 bool
735 refine_one_point_fft(vec2d_t & shift,
736  const pnt2d_t & center,
737  const double & min_overlap,
738 
739  const TImage * tile_0,
740  const mask_t * mask_0,
741  const TImage * tile_1,
742  const mask_t * mask_1,
743 
744  // transform that maps from the space of
745  // tile 0 to the space of tile 1:
746  const base_transform_t * t_01,
747 
748  // neighborhood size:
749  const unsigned int & neighborhood)
750 {
751  typename TImage::SpacingType sp = tile_1->GetSpacing();
752  typename TImage::SizeType sz;
753  sz[0] = neighborhood;
754  sz[1] = neighborhood;
755 
756  pnt2d_t origin(center);
757  origin[0] -= 0.5 * double(sz[0]) * sp[0];
758  origin[1] -= 0.5 * double(sz[1]) * sp[1];
759 
760  typename TImage::Pointer img[] = {
761  make_image<TImage>(sz),
762  make_image<TImage>(sz)
763  };
764 
765  mask_t::Pointer msk[] = {
766  make_image<mask_t>(sz),
767  make_image<mask_t>(sz)
768  };
769 
770  img[0]->SetSpacing(sp);
771  img[1]->SetSpacing(sp);
772  msk[0]->SetSpacing(sp);
773  msk[1]->SetSpacing(sp);
774 
775  return refine_one_point_fft<TImage>(shift,
776  center,
777  origin,
778  min_overlap,
779  tile_0,
780  mask_0,
781  tile_1,
782  mask_1,
783  t_01,
784  img[0],
785  msk[0],
786  img[1],
787  msk[1],
788  sz,
789  sp);
790 }
791 
792 //----------------------------------------------------------------
793 // refine_one_point_fft
794 //
795 template <typename TImage>
796 bool
797 refine_one_point_fft(vec2d_t & shift,
798 
799  // the extracted small neighborhoods and their masks:
800  const TImage * img_0,
801  const mask_t * msk_0,
802  const TImage * img_1,
803  const mask_t * msk_1)
804 {
805  typename TImage::SizeType period_sz =
806  img_1->GetLargestPossibleRegion().GetSize();
807 
808  // feed the two neighborhoods into the FFT translation estimator:
809  translate_transform_t::Pointer translate;
810  double metric =
811  match_one_pair<TImage>(translate, // best translation transform
812 
813  // fixed image small neighborhood:
814  img_0,
815  msk_0,
816 
817  // moving image small neighborhood:
818  img_1,
819  msk_1,
820 
821  period_sz,
822 
823  0.25,// overlap min
824  1.0, // overlap max
825  0.5, // low pass filter r
826  0.1, // low pass filter s
827  10, // number of peaks
828  true); // consider the no-displacement case
829 
830 #ifdef DEBUG_REFINE_ONE_POINT
831  static const bfs::path fn_save("/tmp/refine_one_point_fft-");
832  bfs::path suffix = the_text_t::number(COUNTER, 3, '0');
833 
834  save_composite(fn_save + suffix + "-a.png",
835  img_0,
836  img_1,
837  identity_transform_t::New(),
838  true);
839 #endif // DEBUG_REFINE_ONE_POINT
840 
841 #if defined(DEBUG_REFINE_ONE_POINT) || defined(DEBUG_ESTIMATE_DISPLACEMENT)
842  COUNTER++;
843 #endif
844 
845  if (metric == std::numeric_limits<double>::max())
846  {
847  return false;
848  }
849 
850 #ifdef DEBUG_REFINE_ONE_POINT
851  save_composite(fn_save + suffix + "-b.png",
852  img_0,
853  img_1,
854  translate.GetPointer(),
855  true);
856 #endif // DEBUG_REFINE_ONE_POINT
857 
858  shift = -translate->GetOffset();
859  return true;
860 }
861 
862 
863 //----------------------------------------------------------------
864 // extract
865 //
866 // Return the number of pixels in the region in the mask:
867 //
868 template <typename TImage, typename TMask>
869 unsigned int
870 extract(const typename TImage::PointType & origin,
871 
872  const TImage * tile,
873  const TMask * mask,
874 
875  TImage * tile_region,
876  TMask * mask_region,
877 
878  const typename TImage::PixelType & bg =
879  itk::NumericTraits<typename TImage::PixelType>::Zero)
880 {
881  tile_region->SetOrigin(origin);
882  mask_region->SetOrigin(origin);
883 
884  // setup the image interpolator:
885  typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
886  typename interpolator_t::Pointer interpolator = interpolator_t::New();
887  interpolator->SetInputImage(tile);
888 
889  // temporary:
890  typename TImage::PointType tile_pt;
891  typename TImage::PixelType tile_val;
892  typename TMask::IndexType mask_ix;
893  typename TMask::PixelType mask_val;
894 
895  static const typename TMask::PixelType mask_min =
896  itk::NumericTraits<typename TMask::PixelType>::Zero;
897 
898  static const typename TMask::PixelType mask_max =
899  itk::NumericTraits<typename TMask::PixelType>::One;
900 
901  unsigned int num_pixels = 0;
902 
903  typedef itk::ImageRegionIteratorWithIndex<TImage> itex_t;
904  itex_t itex(tile_region, tile_region->GetLargestPossibleRegion());
905  for (itex.GoToBegin(); !itex.IsAtEnd(); ++itex)
906  {
907  tile_val = bg;
908  mask_val = mask_min;
909 
910  tile_region->TransformIndexToPhysicalPoint(itex.GetIndex(), tile_pt);
911  if (interpolator->IsInsideBuffer(tile_pt))
912  {
913  mask_val = mask_max;
914  if (mask != NULL)
915  {
916  mask->TransformPhysicalPointToIndex(tile_pt, mask_ix);
917  mask_val = mask->GetPixel(mask_ix);
918  }
919 
920  if (mask_val != mask_min)
921  {
922  tile_val =
923  (typename TImage::PixelType)(interpolator->Evaluate(tile_pt));
924  num_pixels++;
925  }
926  }
927 
928  itex.Set(tile_val);
929  mask_region->SetPixel(itex.GetIndex(), mask_val);
930  }
931 
932  return num_pixels;
933 }
934 
935 
936 //----------------------------------------------------------------
937 // refine_one_point_helper
938 //
939 template <typename TImage>
940 bool
941 refine_one_point_helper(// the large images and their masks:
942  const TImage * tile_0,
943  const mask_t * mask_0,
944  const TImage * tile_1,
945  const mask_t * mask_1,
946 
947 
948  // mosaic space neighborhood center:
949  const pnt2d_t & center,
950  pnt2d_t & origin,
951 
952  // minimum acceptable neighborhood overlap ratio:
953  const double & min_overlap,
954 
955  // the extracted small neighborhoods and their masks:
956  TImage * img_0,
957  mask_t * msk_0,
958  TImage * img_1,
959  mask_t * msk_1)
960 {
961  const typename TImage::SizeType & sz =
962  img_0->GetLargestPossibleRegion().GetSize();
963  const typename TImage::SpacingType & sp =
964  img_0->GetSpacing();
965 
966  origin[0] = center[0] - (double(sz[0]) * sp[0]) / 2;
967  origin[1] = center[1] - (double(sz[1]) * sp[1]) / 2;
968 
969  pnt2d_t corner[] = {
970  origin + vec2d(sz[0] * sp[0], 0),
971  origin + vec2d(sz[0] * sp[0], sz[1] * sp[1]),
972  origin + vec2d(0, sz[1] * sp[1])
973  };
974 
975  // make sure both tiles overlap the region:
976  typename TImage::IndexType tmp_ix;
977  if (!(tile_0->TransformPhysicalPointToIndex(origin, tmp_ix) ||
978  tile_0->TransformPhysicalPointToIndex(corner[0], tmp_ix) ||
979  tile_0->TransformPhysicalPointToIndex(corner[1], tmp_ix) ||
980  tile_0->TransformPhysicalPointToIndex(corner[2], tmp_ix)) ||
981  !(tile_1->TransformPhysicalPointToIndex(origin, tmp_ix) ||
982  tile_1->TransformPhysicalPointToIndex(corner[0], tmp_ix) ||
983  tile_1->TransformPhysicalPointToIndex(corner[1], tmp_ix) ||
984  tile_1->TransformPhysicalPointToIndex(corner[2], tmp_ix)))
985  {
986  return false;
987  }
988 
989  // keep count of pixel in the neighborhood:
990  unsigned int area[] = { 0, 0 };
991 
992  area[0] = extract<TImage, mask_t>(origin,
993  tile_0,
994  mask_0,
995  img_0,
996  msk_0);
997 
998  area[1] = extract<TImage, mask_t>(origin,
999  tile_1,
1000  mask_1,
1001  img_1,
1002  msk_1);
1003 
1004  // skip points which don't have enough neighborhood information:
1005  double max_area = double(sz[0] * sz[1]);
1006  double a[] = {
1007  double(area[0]) / max_area,
1008  double(area[1]) / max_area
1009  };
1010 
1011  if (a[0] < min_overlap || a[1] < min_overlap)
1012  {
1013  return false;
1014  }
1015 
1016  return true;
1017 }
1018 
1019 //----------------------------------------------------------------
1020 // tiles_intersect
1021 //
1022 template <typename TImage>
1023 bool
1024 tiles_intersect(// the large images and their masks:
1025  const TImage * tile_0,
1026  const TImage * tile_1,
1027 
1028  // transforms from mosaic space to tile space:
1029  const base_transform_t * forward_0,
1030  const base_transform_t * forward_1,
1031 
1032  // mosaic space neighborhood center:
1033  const pnt2d_t & origin,
1034 
1035  // neighborhood size and pixel spacing:
1036  const typename TImage::SizeType & sz,
1037  const typename TImage::SpacingType & sp)
1038 {
1039  pnt2d_t corner[] = {
1040  origin,
1041  origin + vec2d(sz[0] * sp[0], 0),
1042  origin + vec2d(sz[0] * sp[0], sz[1] * sp[1]),
1043  origin + vec2d(0, sz[1] * sp[1])
1044  };
1045 
1046  // temporary:
1047  typename TImage::IndexType tmp_ix;
1048  pnt2d_t tmp_pt;
1049 
1050  // make sure both tiles overlap the region:
1051  bool in[] = { false, false };
1052 
1053  for (unsigned int i = 0; i < 4 && (!in[0] || !in[1]) ; i++)
1054  {
1055  tmp_pt = forward_0->TransformPoint(corner[i]);
1056  in[0] = in[0] || tile_0->TransformPhysicalPointToIndex(tmp_pt, tmp_ix);
1057 
1058  tmp_pt = forward_1->TransformPoint(corner[i]);
1059  in[1] = in[1] || tile_1->TransformPhysicalPointToIndex(tmp_pt, tmp_ix);
1060  }
1061 
1062  return in[0] && in[1];
1063 }
1064 
1065 //----------------------------------------------------------------
1066 // refine_one_point_helper
1067 //
1068 template <typename TImage>
1069 bool
1070 refine_one_point_helper(// the large images and their masks:
1071  const TImage * tile_0,
1072  const mask_t * mask_0,
1073  const TImage * tile_1,
1074  const mask_t * mask_1,
1075 
1076  // transforms from mosaic space to tile space:
1077  const base_transform_t * forward_0,
1078  const base_transform_t * forward_1,
1079 
1080  // mosaic space neighborhood center:
1081  const pnt2d_t & center,
1082 
1083  // minimum acceptable neighborhood overlap ratio:
1084  const double & min_overlap,
1085 
1086  // neighborhood size and pixel spacing:
1087  const typename TImage::SizeType & sz,
1088  const typename TImage::SpacingType & sp,
1089 
1090  // the extracted small neighborhoods and their masks:
1091  TImage * img_0_large,
1092  mask_t * msk_0_large,
1093  TImage * img_0,
1094  mask_t * msk_0,
1095  TImage * img_1,
1096  mask_t * msk_1)
1097 {
1098  pnt2d_t origin = center;
1099  origin[0] -= (double(sz[0]) * sp[0]) / 2;
1100  origin[1] -= (double(sz[1]) * sp[1]) / 2;
1101 
1102  if (!tiles_intersect<TImage>(tile_0,
1103  tile_1,
1104  forward_0,
1105  forward_1,
1106  origin,
1107  sz,
1108  sp))
1109  {
1110  return false;
1111  }
1112 
1113  // setup the image interpolators:
1114  typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
1115  typename interpolator_t::Pointer interpolator[] = {
1116  interpolator_t::New(),
1117  interpolator_t::New()
1118  };
1119 
1120  interpolator[0]->SetInputImage(tile_0);
1121  interpolator[1]->SetInputImage(tile_1);
1122 
1123  // temporaries:
1124  pnt2d_t mosaic_pt;
1125  pnt2d_t tile_pt;
1126  typename TImage::IndexType index;
1127 
1128  // keep count of pixel in the neighborhood:
1129  unsigned int area[] = { 0, 0 };
1130 
1131  // extract a neighborhood of the given point from both tiles:
1132  for (unsigned int y = 0; y < sz[1]; y++)
1133  {
1134  mosaic_pt[1] = origin[1] + double(y) * sp[1];
1135  index[1] = y;
1136  for (unsigned int x = 0; x < sz[0]; x++)
1137  {
1138  mosaic_pt[0] = origin[0] + double(x) * sp[0];
1139  index[0] = x;
1140 
1141  // fixed image:
1142  tile_pt = forward_0->TransformPoint(mosaic_pt);
1143  if (interpolator[0]->IsInsideBuffer(tile_pt) &&
1144  pixel_in_mask<mask_t>(mask_0, tile_pt))
1145  {
1146  double p = interpolator[0]->Evaluate(tile_pt);
1147  img_0->SetPixel(index, (unsigned char)(std::min(255.0, p)));
1148  msk_0->SetPixel(index, 1);
1149  area[0]++;
1150  }
1151  else
1152  {
1153  img_0->SetPixel(index, 0);
1154  msk_0->SetPixel(index, 0);
1155  }
1156 
1157  // moving image:
1158  tile_pt = forward_1->TransformPoint(mosaic_pt);
1159  if (interpolator[1]->IsInsideBuffer(tile_pt) &&
1160  pixel_in_mask<mask_t>(mask_1, tile_pt))
1161  {
1162  double p = interpolator[1]->Evaluate(tile_pt);
1163  img_1->SetPixel(index, (unsigned char)(std::min(255.0, p)));
1164  msk_1->SetPixel(index, 1);
1165  area[1]++;
1166  }
1167  else
1168  {
1169  img_1->SetPixel(index, 0);
1170  msk_1->SetPixel(index, 0);
1171  }
1172  }
1173  }
1174 
1175  // skip points which don't have enough neighborhood information:
1176  double max_area = double(sz[0] * sz[1]);
1177  double a[] = {
1178  double(area[0]) / max_area,
1179  double(area[1]) / max_area
1180  };
1181 
1182  if (a[0] < min_overlap || a[1] < min_overlap)
1183  {
1184  return false;
1185  }
1186 
1187  if (img_0_large != NULL)
1188  {
1189  // extract the larger neighborhood from the fixed tile:
1190  pnt2d_t origin_large(center);
1191  origin_large[0] -= sz[0] * sp[0];
1192  origin_large[1] -= sz[1] * sp[1];
1193 
1194  for (unsigned int y = 0; y < sz[1] * 2; y++)
1195  {
1196  mosaic_pt[1] = origin_large[1] + double(y) * sp[1];
1197  index[1] = y;
1198  for (unsigned int x = 0; x < sz[0] * 2; x++)
1199  {
1200  mosaic_pt[0] = origin_large[0] + double(x) * sp[0];
1201  index[0] = x;
1202 
1203  // fixed image:
1204  tile_pt = forward_0->TransformPoint(mosaic_pt);
1205  if (interpolator[0]->IsInsideBuffer(tile_pt) &&
1206  pixel_in_mask<mask_t>(mask_0, tile_pt))
1207  {
1208  double p = interpolator[0]->Evaluate(tile_pt);
1209  img_0_large->SetPixel(index, (unsigned char)(std::min(255.0, p)));
1210  msk_0_large->SetPixel(index, 1);
1211  }
1212  else
1213  {
1214  img_0_large->SetPixel(index, 0);
1215  msk_0_large->SetPixel(index, 0);
1216  }
1217  }
1218  }
1219  }
1220 
1221  return true;
1222 }
1223 
1224 
1225 //----------------------------------------------------------------
1226 // refine_one_point_fft
1227 //
1228 template <typename TImage>
1229 bool
1230 refine_one_point_fft(vec2d_t & shift,
1231 
1232  // fixed tile, in mosaic space:
1233  const TImage * tile_0,
1234  const mask_t * mask_0,
1235 
1236  // moving tile, in mosaic space:
1237  const TImage * tile_1,
1238  const mask_t * mask_1,
1239 
1240  // mosaic space neighborhood center:
1241  const pnt2d_t & center,
1242 
1243  // minimum acceptable neighborhood overlap ratio:
1244  const double & min_overlap,
1245 
1246  // the extracted small neighborhoods and their masks:
1247  TImage * img_0,
1248  mask_t * msk_0,
1249  TImage * img_1,
1250  mask_t * msk_1)
1251 {
1252  pnt2d_t origin;
1253  if (!refine_one_point_helper<TImage>(tile_0,
1254  mask_0,
1255  tile_1,
1256  mask_1,
1257  center,
1258  origin,
1259  min_overlap,
1260  img_0,
1261  msk_0,
1262  img_1,
1263  msk_1))
1264  {
1265  return false;
1266  }
1267 
1268  return refine_one_point_fft<TImage>(shift,
1269  pnt2d(0, 0), // origin,
1270  tile_0,
1271  mask_0,
1272  img_0,
1273  msk_0,
1274  img_1,
1275  msk_1);
1276 }
1277 
1278 
1279 //----------------------------------------------------------------
1280 // refine_one_point_fft
1281 //
1282 template <typename TImage>
1283 bool
1284 refine_one_point_fft(vec2d_t & shift,
1285 
1286  // the large images and their masks:
1287  const TImage * tile_0,
1288  const mask_t * mask_0,
1289  const TImage * tile_1,
1290  const mask_t * mask_1,
1291 
1292  // transforms from mosaic space to tile space:
1293  const base_transform_t * forward_0,
1294  const base_transform_t * forward_1,
1295 
1296  // mosaic space neighborhood center:
1297  const pnt2d_t & center,
1298 
1299  // minimum acceptable neighborhood overlap ratio:
1300  const double & min_overlap,
1301 
1302  // neighborhood size and pixel spacing:
1303  const typename TImage::SizeType & sz,
1304  const typename TImage::SpacingType & sp,
1305 
1306  // the extracted larger neighborhood:
1307  TImage * img_0_large,
1308  mask_t * msk_0_large,
1309 
1310  // the extracted small neighborhoods and their masks:
1311  TImage * img_0,
1312  mask_t * msk_0,
1313  TImage * img_1,
1314  mask_t * msk_1)
1315 {
1316  if (!refine_one_point_helper<TImage>(tile_0,
1317  mask_0,
1318  tile_1,
1319  mask_1,
1320  forward_0,
1321  forward_1,
1322  center,
1323  min_overlap,
1324  sz,
1325  sp,
1326  img_0_large,
1327  msk_0_large,
1328  img_0,
1329  msk_0,
1330  img_1,
1331  msk_1))
1332  {
1333  return false;
1334  }
1335 
1336  pnt2d_t origin;
1337  origin[0] = sz[0] * sp[0] / 2;
1338  origin[1] = sz[1] * sp[1] / 2;
1339  return refine_one_point_fft<TImage>(shift,
1340  origin,
1341  img_0_large,
1342  msk_0_large,
1343  img_0,
1344  msk_0,
1345  img_1,
1346  msk_1);
1347 }
1348 
1349 
1350 //----------------------------------------------------------------
1351 // refine_one_point_fft
1352 //
1353 template <typename TImage>
1354 bool
1355 refine_one_point_fft(vec2d_t & shift,
1356 
1357  // the large images and their masks:
1358  const TImage * tile_0,
1359  const mask_t * mask_0,
1360  const TImage * tile_1,
1361  const mask_t * mask_1,
1362 
1363  // transforms from mosaic space to tile space:
1364  const base_transform_t * forward_0,
1365  const base_transform_t * forward_1,
1366 
1367  // mosaic space neighborhood center:
1368  const pnt2d_t & center,
1369 
1370  // minimum acceptable neighborhood overlap ratio:
1371  const double & min_overlap,
1372 
1373  // neighborhood size and pixel spacing:
1374  const typename TImage::SizeType & sz,
1375  const typename TImage::SpacingType & sp,
1376 
1377  // the extracted small neighborhoods and their masks:
1378  TImage * img_0,
1379  mask_t * msk_0,
1380  TImage * img_1,
1381  mask_t * msk_1)
1382 {
1383  pnt2d_t origin(center);
1384  origin[0] -= sz[0] * sp[0] / 2;
1385  origin[1] -= sz[1] * sp[1] / 2;
1386 
1387  if (!refine_one_point_helper<TImage>(tile_0,
1388  mask_0,
1389  tile_1,
1390  mask_1,
1391  forward_0,
1392  forward_1,
1393  origin,
1394  min_overlap,
1395  sz,
1396  sp,
1397  NULL,
1398  NULL,
1399  img_0,
1400  msk_0,
1401  img_1,
1402  msk_1))
1403  {
1404  return false;
1405  }
1406 
1407  return refine_one_point_fft<TImage>(shift,
1408  img_0,
1409  msk_0,
1410  img_1,
1411  msk_1);
1412 }
1413 
1414 
1415 //----------------------------------------------------------------
1416 // refine_one_pair
1417 //
1418 template <class TTransform, class TImage>
1419 double
1420 refine_one_pair(typename TTransform::Pointer & t01,
1421 
1422  const TImage * i0,
1423  const mask_t * m0,
1424 
1425  const TImage * i1,
1426  const mask_t * m1,
1427 
1428  const unsigned int levels,
1429  const unsigned int iterations,
1430  const double & min_step,
1431  const double & max_step)
1432 {
1433  // typedef itk::MultiResolutionImageRegistrationMethod<TImage, TImage>
1434  typedef itk::ImageRegistrationMethod<TImage, TImage>
1435  registration_t;
1436 
1437  // setup the registration object:
1438  typename registration_t::Pointer registration = registration_t::New();
1439 
1440  // setup the image interpolator:
1441  typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
1442  registration->SetInterpolator(interpolator_t::New());
1443 
1444  // setup the optimizer:
1445  optimizer_t::Pointer optimizer = optimizer_t::New();
1446  registration->SetOptimizer(optimizer);
1447  optimizer_observer_t<optimizer_t>::Pointer observer =
1449  optimizer->AddObserver(itk::IterationEvent(), observer);
1450  optimizer->SetMinimize(true);
1451  optimizer->SetNumberOfIterations(iterations);
1452  optimizer->SetMinimumStepLength(min_step);
1453  optimizer->SetMaximumStepLength(max_step);
1454  optimizer->SetGradientMagnitudeTolerance(1e-6);
1455  optimizer->SetRelaxationFactor(5e-1);
1456  optimizer->SetPickUpPaceSteps(5);
1457  optimizer->SetBackTracking(true);
1458 
1459  // FIXME: this is probably unnecessary:
1460  typedef optimizer_t::ScalesType optimizer_scales_t;
1461  optimizer_scales_t parameter_scales(t01->GetNumberOfParameters());
1462  parameter_scales.Fill(1.0);
1463 
1464  try { optimizer->SetScales(parameter_scales); }
1465  catch (itk::ExceptionObject &) {}
1466 
1467  // setup the image-to-image metric:
1468  typedef itk::NormalizedCorrelationImageToImageMetric<TImage, TImage>
1469  metric_t;
1470 
1471  typename metric_t::Pointer metric = metric_t::New();
1472  registration->SetMetric(metric);
1473 
1474  registration->SetTransform(t01);
1475  registration->SetInitialTransformParameters(t01->GetParameters());
1476 
1477  // setup the masks:
1478  typedef itk::ImageMaskSpatialObject<2> mask_so_t;
1479  mask_t::ConstPointer fi_mask = m0;
1480  if (m0 != NULL)
1481  {
1482  mask_so_t::Pointer fi_mask_so = mask_so_t::New();
1483  fi_mask_so->SetImage(fi_mask);
1484  metric->SetFixedImageMask(fi_mask_so);
1485  }
1486 
1487  mask_t::ConstPointer mi_mask = m1;
1488  if (m1 != NULL)
1489  {
1490  mask_so_t::Pointer mi_mask_so = mask_so_t::New();
1491  mi_mask_so->SetImage(mi_mask);
1492  metric->SetMovingImageMask(mi_mask_so);
1493  }
1494 
1495  // setup the fixed and moving image:
1496  typename TImage::ConstPointer fi = i0;
1497  typename TImage::ConstPointer mi = i1;
1498 
1499  registration->SetFixedImageRegion(fi->GetLargestPossibleRegion());
1500  registration->SetFixedImage(fi);
1501  registration->SetMovingImage(mi);
1502 
1503  // setup the multi-resolution image pyramids:
1504  // registration->SetNumberOfLevels(levels);
1505 
1506  // evaluate the metric before the registration:
1507  double metric_before =
1508  eval_metric<metric_t, interpolator_t>(t01, fi, mi, fi_mask, mi_mask);
1509  assert(metric_before != std::numeric_limits<double>::max());
1510 
1511  typename TTransform::ParametersType params_before = t01->GetParameters();
1512  std::ostringstream oss;
1513 
1514  // perform the registration:
1515  try
1516  {
1517  oss << std::endl;
1518  registration->StartRegistration();
1519  }
1520  catch (itk::ExceptionObject & exception)
1521  {
1522  oss << "image registration threw an exception: "
1523  << std::endl << exception.what() << std::endl;
1524  }
1525  t01->SetParameters(optimizer->GetBestParams());
1526 
1527  // evaluate the metric after the registration:
1528  double metric_after =
1529  eval_metric<metric_t, interpolator_t>(t01, fi, mi, fi_mask, mi_mask);
1530 
1531  typename TTransform::ParametersType params_after = t01->GetParameters();
1532 
1533  oss << "BEFORE: " << metric_before << std::endl
1534  << "AFTER: " << metric_after << std::endl;
1535 
1536  if (metric_before <= metric_after || metric_after != metric_after)
1537  {
1538  oss << "NOTE: minimization failed, ignoring registration results..." << std::endl;
1539  t01->SetParameters(params_before);
1540  CORE_LOG_MESSAGE(oss.str());
1541  return metric_before;
1542  }
1543 
1544  CORE_LOG_MESSAGE(oss.str());
1545  return metric_after;
1546 }
1547 
1548 
1549 //----------------------------------------------------------------
1550 // refine_one_point_nofft
1551 //
1552 template <typename TImage>
1553 bool
1554 refine_one_point_nofft(vec2d_t & shift,
1555  const pnt2d_t & origin,
1556 
1557  // the large images and their masks:
1558  const TImage * tile_0,
1559  const mask_t * mask_0,
1560 
1561  // the extracted small neighborhood with masks:
1562  const TImage * img_1,
1563  const mask_t * msk_1)
1564 {
1565  // feed the two neighborhoods into the optimizer translation estimator:
1566  translate_transform_t::Pointer translate = translate_transform_t::New();
1567  vec2d_t offset = vec2d(origin[0], origin[1]);
1568  translate->SetOffset(-offset);
1569 
1570  double metric =
1571  refine_one_pair<translate_transform_t, TImage>
1572  (translate,
1573  tile_0,
1574  mask_0,
1575  img_1,
1576  msk_1,
1577  3, // number of pyramid levels
1578  100, // number of iterations
1579  1e-8, // min step
1580  1e+4); // max step
1581 
1582  std::ostringstream oss;
1583 
1584  shift = -(translate->GetOffset() + offset);
1585  oss << "shift: " << shift << std::endl;
1586  CORE_LOG_MESSAGE(oss.str());
1587 
1588 #ifdef DEBUG_REFINE_ONE_POINT
1589  static const bfs::path fn_save("/tmp/refine_one_point_nofft-");
1590  bfs::path suffix = the_text_t::number(COUNTER, 3, '0');
1591  {
1592  translate_transform_t::Pointer t = translate_transform_t::New();
1593  t->SetOffset(-offset);
1594  save_composite(fn_save + suffix + "-a.png",
1595  tile_0,
1596  img_1,
1597  t.GetPointer(),
1598  true);
1599  }
1600 #endif // DEBUG_REFINE_ONE_POINT
1601 
1602 #if defined(DEBUG_REFINE_ONE_POINT) || defined(DEBUG_ESTIMATE_DISPLACEMENT)
1603  COUNTER++;
1604 #endif
1605 
1606  if (metric == std::numeric_limits<double>::max())
1607  {
1608  return false;
1609  }
1610 
1611 #ifdef DEBUG_REFINE_ONE_POINT
1612  save_composite(fn_save + suffix + "-b.png",
1613  tile_0,
1614  img_1,
1615  translate.GetPointer(),
1616  true);
1617 #endif // DEBUG_REFINE_ONE_POINT
1618 
1619  return true;
1620 }
1621 
1622 
1623 //----------------------------------------------------------------
1624 // refine_one_point_nofft
1625 //
1626 template <typename TImage>
1627 bool
1628 refine_one_point_nofft(vec2d_t & shift,
1629  const pnt2d_t & center,
1630  const pnt2d_t & origin,
1631  const double & min_overlap,
1632 
1633  // the large images and their masks:
1634  const TImage * tile_0,
1635  const mask_t * mask_0,
1636  const TImage * tile_1,
1637  const mask_t * mask_1,
1638 
1639  // transform that maps from the space of
1640  // tile 0 to the space of tile 1:
1641  const base_transform_t * t_01,
1642 
1643  // the extracted small neighborhoods and their masks:
1644  TImage * img_0,
1645  mask_t * msk_0,
1646  TImage * img_1,
1647  mask_t * msk_1,
1648 
1649  // neighborhood size and pixel spacing:
1650  const typename TImage::SizeType & sz,
1651  const typename TImage::SpacingType & sp)
1652 {
1653  if (!refine_one_point_helper<TImage>(center,
1654  origin,
1655  min_overlap,
1656  tile_0,
1657  mask_0,
1658  tile_1,
1659  mask_1,
1660  t_01,
1661  img_0,
1662  msk_0,
1663  img_1,
1664  msk_1,
1665  sz,
1666  sp))
1667  {
1668  return false;
1669  }
1670 
1671  // feed the two neighborhoods into the optimizer translation estimator:
1672  translate_transform_t::Pointer translate = translate_transform_t::New();
1673  translate->SetIdentity();
1674 
1675  double metric =
1676  refine_one_pair<translate_transform_t, TImage>
1677  (translate,
1678  img_0,
1679  msk_0,
1680  img_1,
1681  msk_1,
1682  3, // number of pyramid levels
1683  100, // number of iterations
1684  1e-8, // min step
1685  1e+4); // max step
1686 
1687 #ifdef DEBUG_REFINE_ONE_POINT
1688  static const bfs::path fn_save("/tmp/refine_one_point_nofft-");
1689  bfs::path suffix = the_text_t::number(COUNTER, 3, '0');
1690  save_composite(fn_save + suffix + "-a.png",
1691  img_0.GetPointer(),
1692  img_1.GetPointer(),
1693  identity_transform_t::New(),
1694  true);
1695 #endif // DEBUG_REFINE_ONE_POINT
1696 
1697 #if defined(DEBUG_REFINE_ONE_POINT) || defined(DEBUG_ESTIMATE_DISPLACEMENT)
1698  COUNTER++;
1699 #endif
1700 
1701  if (metric == std::numeric_limits<double>::max())
1702  {
1703  return false;
1704  }
1705 
1706 #ifdef DEBUG_REFINE_ONE_POINT
1707  save_composite(fn_save + suffix + "-b.png",
1708  img_0.GetPointer(),
1709  img_1.GetPointer(),
1710  translate.GetPointer(),
1711  true);
1712 #endif // DEBUG_REFINE_ONE_POINT
1713 
1714  shift = -translate->GetOffset();
1715  return true;
1716 }
1717 
1718 //----------------------------------------------------------------
1719 // refine_one_point_nofft
1720 //
1721 template <typename TImage>
1722 bool
1723 refine_one_point_nofft(vec2d_t & shift,
1724  const pnt2d_t & center,
1725  const double & min_overlap,
1726  const TImage * tile_0,
1727  const mask_t * mask_0,
1728  const TImage * tile_1,
1729  const mask_t * mask_1,
1730 
1731  // transform that maps from the space of
1732  // tile 0 to the space of tile 1:
1733  const base_transform_t * t_01,
1734 
1735  // neighborhood size:
1736  const unsigned int & neighborhood)
1737 {
1738  typename TImage::SpacingType sp = tile_1->GetSpacing();
1739  typename TImage::SizeType sz;
1740  sz[0] = neighborhood;
1741  sz[1] = neighborhood;
1742 
1743  pnt2d_t origin(center);
1744  origin[0] -= 0.5 * double(sz[0]) * sp[0];
1745  origin[1] -= 0.5 * double(sz[1]) * sp[1];
1746 
1747  typename TImage::Pointer img[] = {
1748  make_image<TImage>(sz),
1749  make_image<TImage>(sz)
1750  };
1751 
1752  mask_t::Pointer msk[] = {
1753  make_image<mask_t>(sz),
1754  make_image<mask_t>(sz)
1755  };
1756 
1757  img[0]->SetSpacing(sp);
1758  img[1]->SetSpacing(sp);
1759  msk[0]->SetSpacing(sp);
1760  msk[1]->SetSpacing(sp);
1761 
1762  return refine_one_point_nofft<TImage>(shift,
1763  center,
1764  origin,
1765  min_overlap,
1766  tile_0,
1767  mask_0,
1768  tile_1,
1769  mask_1,
1770  t_01,
1771  img[0],
1772  msk[0],
1773  img[1],
1774  msk[1],
1775  sz,
1776  sp);
1777 }
1778 
1779 
1780 #endif // GRID_COMMON_HXX_
Definition: optimizer_observer.hxx:44
Definition: itkRegularStepGradientDescentOptimizer2.h:52
Definition: fft_common.hxx:77
Definition: itkDiscontinuousTransform.h:186
Definition: itkDiscontinuousTransform.h:226