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.
fft_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 : fft_common.hxx
30 // Author : Pavel A. Koshevoy
31 // Created : 2005/11/10 14:05
32 // Copyright : (C) 2004-2008 University of Utah
33 // Description : Helper functions for image alignment (registration)
34 // using phase correlation to find the translation vector.
35 
36 #ifndef FFT_COMMON_HXX_
37 #define FFT_COMMON_HXX_
38 
39 // local includes:
40 #include <Core/ITKCommon/common.hxx>
41 #include <Core/ITKCommon/FFT/fft.hxx>
42 #include <Core/ITKCommon/the_dynamic_array.hxx>
43 
44 // system includes:
45 #include <math.h>
46 #include <list>
47 #include <limits.h>
48 #include <sstream>
49 
50 #ifndef WIN32
51 #include <unistd.h>
52 #endif
53 
54 // namespace access:
55 using namespace itk_fft;
56 
57 //----------------------------------------------------------------
58 // DEBUG_PDF
59 //
60 // #define DEBUG_PDF
61 
62 //#ifdef DEBUG_PDF
64 //#define DEBUG_PDF_PFX the_text_t("PDF-")
65 //#define DEBUG_CLUSTERS
66 //#define DEBUG_MARKERS
67 //extern unsigned int DEBUG_COUNTER1;
68 //extern unsigned int DEBUG_COUNTER2;
69 //#else
70 #define DEBUG_PDF_PFX ""
71 //#endif
72 
73 
74 //----------------------------------------------------------------
75 // local_max_t
76 //
78 {
79  public:
80  local_max_t(const double value,
81  const double x,
82  const double y,
83  const unsigned int area):
84  value_(value),
85  x_(x),
86  y_(y),
87  area_(area)
88  {}
89 
90  inline bool operator == (const local_max_t & lm) const
91  { return (value_ == lm.value_) && (x_ == lm.x_) && (y_ == lm.y_); }
92 
93  inline bool operator < (const local_max_t & lm) const
94  { return value_ < lm.value_; }
95 
96  inline bool operator > (const local_max_t & lm) const
97  { return value_ > lm.value_; }
98 
99  // cluster value:
100  double value_;
101 
102  // center of mass of the cluster:
103  double x_;
104  double y_;
105 
106  // area of the cluster:
107  unsigned int area_;
108 };
109 
110 //----------------------------------------------------------------
111 // operator <<
112 //
113 inline std::ostream &
114 operator << (std::ostream & sout, const local_max_t & lm)
115 {
116  return sout << lm.value_ << '\t'
117  << lm.x_ << '\t'
118  << lm.y_ << '\t'
119  << lm.area_ << std::endl;
120 }
121 
122 //----------------------------------------------------------------
123 // cluster_bbox_t
124 //
126 {
127  public:
129  { reset(); }
130 
131  void reset()
132  {
133  min_[0] = std::numeric_limits<int>::max();
134  min_[1] = std::numeric_limits<int>::max();
135  max_[0] = std::numeric_limits<int>::min();
136  max_[1] = std::numeric_limits<int>::min();
137  }
138 
139  void update(int x, int y)
140  {
141  min_[0] = std::min(min_[0], x);
142  min_[1] = std::min(min_[1], y);
143  max_[0] = std::max(max_[0], x);
144  max_[1] = std::max(max_[1], y);
145  }
146 
147  int min_[2];
148  int max_[2];
149 };
150 
151 //----------------------------------------------------------------
152 // find_maxima_cm
153 //
154 // The percentage below refers to the number of pixels that fall
155 // below the maxima. Thus, the number of pixels above the maxima
156 // is 1 - percentage. This way it is possible to specify a
157 // thresholding value without knowing anything about the image.
158 //
159 // The given image is thresholded, the resulting clusters/blobs
160 // are identified/classified, the center of mass of each cluster
161 // is treated as a maxima in the image.
162 //
163 // Returns the number of maxima found.
164 //
165 extern unsigned int
166 find_maxima_cm(std::list<local_max_t> & max_list,
167  const itk_image_t::Pointer & image,
168  const double percentage = 0.9995,
169  const bfs::path & prefix = DEBUG_PDF_PFX,
170  const bfs::path & suffix= ".png");
171 
172 
173 //----------------------------------------------------------------
174 // find_correlation
175 //
176 template <class TImage>
177 unsigned int
178 find_correlation(std::list<local_max_t> & max_list,
179  const TImage * fi,
180  const TImage * mi,
181  double lp_filter_r,
182  double lp_filter_s)
183 {
184  itk_image_t::Pointer z0 = cast<TImage, itk_image_t>(fi);
185  itk_image_t::Pointer z1 = cast<TImage, itk_image_t>(mi);
186  return find_correlation<itk_image_t>(max_list,
187  z0,
188  z1,
189  lp_filter_r,
190  lp_filter_s);
191 }
192 
193 
194 //----------------------------------------------------------------
195 // find_correlation
196 //
197 template <>
198 unsigned int
199 find_correlation(std::list<local_max_t> & max_list,
200  const itk_image_t * fi,
201  const itk_image_t * mi,
202 
203  // low pass filter parameters
204  // (resampled data requires less smoothing):
205  double lp_filter_r,
206  double lp_filter_s);
207 
208 
209 //----------------------------------------------------------------
210 // find_correlation
211 //
212 // This is a backwards compatibility API
213 //
214 template <class TImage>
215 unsigned int
216 find_correlation(const TImage * fi,
217  const TImage * mi,
218  std::list<local_max_t> & max_list,
219  bool resampled_data)
220 {
221  double lp_filter_r = resampled_data ? 0.9 : 0.5;
222  return find_correlation<TImage>(max_list, fi, mi, lp_filter_r, 0.1);
223 }
224 
225 
226 //----------------------------------------------------------------
227 // threshold_maxima
228 //
229 // Discard maxima whose mass is below a given threshold ratio
230 // of the total mass of all maxima:
231 //
232 void
233 threshold_maxima(std::list<local_max_t> & max_list,
234  const double threshold);
235 
236 //----------------------------------------------------------------
237 // reject_negligible_maxima
238 //
239 // Discard maxima that are worse than the best maxima by a factor
240 // greater than the given threshold ratio:
241 //
242 // Returns the size of the new list.
243 //
244 unsigned int
245 reject_negligible_maxima(std::list<local_max_t> & max_list,
246  const double min_peak = 0.1,
247  const double threshold = 0.3);
248 
249 //----------------------------------------------------------------
250 // overlap_t
251 //
253 {
254  public:
255  overlap_t():
256  id_(~0),
257  overlap_(0.0)
258  {}
259 
260  overlap_t(const unsigned int id, const double overlap):
261  id_(id),
262  overlap_(overlap)
263  {}
264 
265  inline bool operator == (const overlap_t & d) const
266  { return id_ == d.id_; }
267 
268  inline bool operator < (const overlap_t & d) const
269  { return overlap_ < d.overlap_; }
270 
271  inline bool operator > (const overlap_t & d) const
272  { return overlap_ > d.overlap_; }
273 
274  unsigned int id_;
275  double overlap_;
276 };
277 
278 //----------------------------------------------------------------
279 // reject_negligible_overlap
280 //
281 void
282 reject_negligible_overlap(std::list<overlap_t> & ol,
283  const double threshold);
284 
285 
286 //----------------------------------------------------------------
287 // estimate_displacement
288 //
289 template <class TImage>
290 double
291 estimate_displacement(const TImage * a,
292  const TImage * b,
293  const local_max_t & lm,
294  translate_transform_t::Pointer & transform,
295  image_t::PointType offset_min,
296  image_t::PointType offset_max,
297  const double overlap_min = 0.0,
298  const double overlap_max = 1.0,
299  const mask_t * mask_a = NULL,
300  const mask_t * mask_b = NULL)
301 {
302  // FIXME:
303  //#ifdef DEBUG_PDF
304  // the_text_t fn_debug =
305  // the_text_t::number(DEBUG_COUNTER1, 3, '0') + the_text_t("-") +
306  // the_text_t::number(DEBUG_COUNTER2, 1, '0') + the_text_t("-");
307  //#endif
308 
309  itk_image_t::SizeType max_sz = calc_padding<TImage>(a, b);
310  const unsigned int & w = max_sz[0];
311  const unsigned int & h = max_sz[1];
312 
313  // evaluate 4 permutations of the maxima:
314  // typedef itk::NormalizedCorrelationImageToImageMetric<TImage, TImage>
315  typedef itk::MeanSquaresImageToImageMetric<TImage, TImage> metric_t;
316  typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
317 
318  typedef typename TImage::SpacingType spacing_t;
319  spacing_t spacing = a->GetSpacing();
320  double sx = spacing[0];
321  double sy = spacing[1];
322 
323  // evaluate 4 permutation of the maxima:
324  const double x = lm.x_;
325  const double y = lm.y_;
326 
327  const vec2d_t t[] = {
328  vec2d(sx * x, sy * y),
329  vec2d(sx * (x - w), sy * y),
330  vec2d(sx * x, sy * (y - h)),
331  vec2d(sx * (x - w), sy * (y - h))
332  };
333 
334  std::ostringstream oss;
335  double best_metric = std::numeric_limits<double>::max();
336  for (unsigned int i = 0; i < 4; i++)
337  {
338  if ( t[i][0] < offset_min[0] || t[i][0] > offset_max[0] ||
339  t[i][1] < offset_min[1] || t[i][1] > offset_max[1] )
340  {
341  continue;
342  }
343 
344  translate_transform_t::Pointer ti = translate_transform_t::New();
345  ti->SetOffset(t[i]);
346 
347  // FIXME:
348  //#ifdef DEBUG_PDF
349  // the_text_t fn = fn_debug + the_text_t::number(i) + ".png";
350  // save_rgb<TImage>(fn, a, b, ti, mask_a, mask_b);
351  //#endif
352 
353  const double area_ratio = overlap_ratio<TImage>(a, b, ti);
354 
355  int old_precision = oss.precision();
356  oss.precision(2);
357  oss << i << ": " << std::setw(3) << std::fixed << area_ratio * 100.0 << "% of overlap, ";
358  oss.precision(old_precision);
359 
360  if (area_ratio < overlap_min || area_ratio > overlap_max)
361  {
362  oss << "skipping..." << std::endl;
363  continue;
364  }
365 
366  // double metric = eval_metric<metric_t, interpolator_t>(ti, a, b);
367  double metric = my_metric<TImage>(a,
368  b,
369  ti,
370  mask_a,
371  mask_b,
372  overlap_min,
373  overlap_max);
374  oss << std::scientific << metric;
375  if (metric < best_metric)
376  {
377  transform = ti;
378  best_metric = metric;
379  oss << " - better..." << std::endl;
380 
381  //#ifdef DEBUG_PDF
382  // save_rgb<TImage>(fn_debug + the_text_t::number(i) + "-better.png",
383  // a, b, ti, mask_a, mask_b);
384  //#endif
385  }
386  else
387  {
388  oss << " - worse..." << std::endl;
389  }
390  }
391 
392  CORE_LOG_MESSAGE(oss.str());
393  return best_metric;
394 }
395 
396 
397 //----------------------------------------------------------------
398 // match_one_pair
399 //
400 // match two images, find the best matching transform and
401 // return the corresponding match metric value
402 //
403 template <typename TImage, typename TMask>
404 double
405 match_one_pair(const bool images_were_resampled,
406  const bool use_std_mask,
407  const TImage * fi,
408  const TImage * mi,
409  const TMask * fi_mask,
410  const TMask * mi_mask,
411 
412  const double overlap_min,
413  const double overlap_max,
414 
415  image_t::PointType offset_min,
416  image_t::PointType offset_max,
417 
418  translate_transform_t::Pointer & ti,
419  std::list<local_max_t> & peaks,
420  unsigned int & num_peaks,
421  size_t shrink = 1,
422 
423  // ideally this should be one, but radial distortion may
424  // generate several valid peaks (up to 4), so it may be
425  // necessary to consider more peaks for the unmatched images:
426  double min_peak = 0.1,
427  double peak_threshold = 0.3,
428  size_t position = 99)
429 {
430  //#ifdef DEBUG_PDF
431  // DEBUG_COUNTER1++;
432  //#endif
433 
434  ti = NULL;
435 
436  unsigned int total_peaks = 0;
437  if (use_std_mask)
438  {
439  // ugh, blank out 5 percent of the image at the bottom
440  // to cover up the image id:
441  typename TImage::SizeType fi_sz = fi->GetLargestPossibleRegion().GetSize();
442  typename TImage::SizeType mi_sz = mi->GetLargestPossibleRegion().GetSize();
443 
444  unsigned int fi_y = (unsigned int)(0.95 * fi_sz[1]);
445  unsigned int mi_y = (unsigned int)(0.95 * mi_sz[1]);
446 
447  typename TImage::Pointer fi_filled = cast<TImage, TImage>(fi);
448  fill<TImage>(fi_filled, 0, fi_y, fi_sz[0], fi_sz[1] - fi_y, 0);
449 
450  typename TImage::Pointer mi_filled = cast<TImage, TImage>(mi);
451  fill<TImage>(mi_filled, 0, mi_y, mi_sz[0], mi_sz[1] - mi_y, 0);
452 
453  total_peaks = find_correlation<TImage>(fi_filled,
454  mi_filled,
455  peaks,
456  images_were_resampled);
457  }
458  else
459  {
460  total_peaks = find_correlation<TImage>(fi,
461  mi,
462  peaks,
463  images_were_resampled);
464  }
465 
466  num_peaks = reject_negligible_maxima(peaks, min_peak, peak_threshold);
467  double max_v = (*peaks.begin()).value_;
468  //std::cout << num_peaks << '/' <<
469  // total_peaks << " eligible peaks, " <<
470  // max_v << " is the max value of " << min_peak << " min." << std::endl;
471  if (max_v < min_peak || total_peaks == 0 ||
472  (position >= 99 && num_peaks > 16)) {
473  return std::numeric_limits<double>::max();
474  }
475  std::ostringstream oss;
476  oss << num_peaks << '/' << total_peaks << " eligible peaks, ";
477 
478  double best_metric = std::numeric_limits<double>::max();
479  typename TImage::IndexValueType numCols =
480  (typename TImage::IndexValueType)
481  (fi->GetLargestPossibleRegion().GetSize()[1]);
482  typename TImage::IndexValueType numRows =
483  (typename TImage::IndexValueType)
484  (fi->GetLargestPossibleRegion().GetSize()[0]);
485  double rowLen = static_cast<double>(numRows) * shrink;
486  double colLen = static_cast<double>(numCols) * shrink;
487  for (std::list<local_max_t>::iterator j = peaks.begin();
488  j != peaks.end(); ++j)
489  {
490  oss << "evaluating permutations..." << std::endl;
491  const local_max_t & lm = *j;
492 
493  translate_transform_t::Pointer tmp = translate_transform_t::New();
494  double metric = estimate_displacement<TImage>(fi,
495  mi,
496  lm,
497  tmp,
498  offset_min,
499  offset_max,
500  overlap_min,
501  overlap_max,
502  fi_mask,
503  mi_mask);
504  double x = tmp.GetPointer()->GetOffset()[0];
505  double y = tmp.GetPointer()->GetOffset()[1];
506  //std::cout << "metric: " << metric << "x: " << x << ", y: " << y << std::endl;
507  switch (position) {
508  case 4: // matching with the tile above
509  if (x < rowLen * ( - overlap_min) || x > rowLen * ( overlap_min) ||
510  y < colLen * (1. - overlap_max) || y > colLen * (1. - overlap_min) )
511  continue; break;
512  case 1: // matching with the tile to the left
513  if (x < rowLen * (1. - overlap_max) || x > rowLen * (1. - overlap_min) ||
514  y < colLen * ( - overlap_min) || y > colLen * ( overlap_min) )
515  continue; break;
516  case 9: // matching with the tile to the right
517  if (x < rowLen * (overlap_min - 1.) || x > rowLen * (overlap_max - 1.) ||
518  y < colLen * ( - overlap_min) || y > colLen * ( overlap_min) )
519  continue; break;
520  case 6: // matching with the tile bottom
521  if (x < rowLen * ( - overlap_min) || x > rowLen * (overlap_min ) ||
522  y < colLen * (overlap_min - 1.) || y > colLen * (overlap_max - 1.) )
523  continue; break;
524  case 5: continue;
525  default: break;
526  }
527 
528  if (metric < best_metric)
529  {
530  best_metric = metric;
531  ti = tmp;
532  }
533  }
534  //if (ti && ti.GetPointer())
535  // std::cout << "x trans: " << ti.GetPointer()->GetOffset()[0]
536  // << ", y trans: " << ti.GetPointer()->GetOffset()[1] << std::endl;
537 
538  CORE_LOG_MESSAGE(oss.str());
539  return best_metric;
540 }
541 
542 
543 //----------------------------------------------------------------
544 // match_one_pair
545 //
546 // match two images, find the best matching transform and
547 // return the corresponding match metric value
548 //
549 template <typename TImage, typename TMask>
550 double
551 match_one_pair(const bool images_were_resampled,
552  const bool use_std_mask,
553  const TImage * fi,
554  const TImage * mi,
555  const TMask * fi_mask,
556  const TMask * mi_mask,
557 
558  const double overlap_min,
559  const double overlap_max,
560 
561  image_t::PointType offset_min,
562  image_t::PointType offset_max,
563 
564  const unsigned int node_id,
565  translate_transform_t::Pointer & ti,
566  std::pair<unsigned int, std::list<local_max_t> > & peaks,
567  size_t shrink = 1,
568 
569  // ideally this should be one, but radial distortion may
570  // generate several valid peaks (up to 4), so it may be
571  // necessary to consider more peaks for the unmatched images:
572  double min_peak = 0.1,
573  double peak_threshold = 0.3,
574  size_t position = 99)
575 {
576  unsigned int peak_list_size = 0;
577  std::list<local_max_t> peak_list;
578  return match_one_pair<TImage, TMask>(images_were_resampled,
579  use_std_mask,
580  fi,
581  mi,
582  fi_mask,
583  mi_mask,
584  overlap_min,
585  overlap_max,
586  offset_min,
587  offset_max,
588  ti,
589  peak_list,
590  peak_list_size,
591  shrink,
592  min_peak,
593  peak_threshold,
594  position);
595 }
596 
597 //----------------------------------------------------------------
598 // match_one_pair
599 //
600 template <typename TImage, typename TMask>
601 double
602 match_one_pair(const bool images_were_resampled,
603  const bool use_std_mask,
604  const TImage * fi,
605  const TImage * mi,
606  const TMask * fi_mask,
607  const TMask * mi_mask,
608  const double overlap_min,
609  const double overlap_max,
610  image_t::PointType offset_min,
611  image_t::PointType offset_max,
612  translate_transform_t::Pointer & ti)
613 {
614  std::list<local_max_t> peaks;
615  unsigned int num_peaks = 0;
616  return match_one_pair<TImage, TMask>(images_were_resampled,
617  use_std_mask,
618  fi,
619  mi,
620  fi_mask,
621  mi_mask,
622  overlap_min,
623  overlap_max,
624  offset_min,
625  offset_max,
626  ti,
627  peaks,
628  num_peaks);
629 }
630 
631 
632 #endif // FFT_COMMON_HXX_
Definition: fft_common.hxx:252
Definition: fft_common.hxx:125
Definition: fft_common.hxx:77
Definition: fft.cxx:57