vil_math.h
Go to the documentation of this file.
1 #ifndef vil_math_h_
2 #define vil_math_h_
3 //:
4 // \file
5 // \brief Various mathematical manipulations of 2D images
6 // \author Tim Cootes
7 
8 #include <vector>
9 #include <cmath>
10 #include <algorithm>
11 #include <cassert>
12 #ifdef _MSC_VER
13 # include <vcl_msvc_warnings.h>
14 #endif
15 #include <vil/vil_image_view.h>
16 #include <vil/vil_image_resource.h>
17 #include <vil/vil_view_as.h>
18 #include <vil/vil_plane.h>
19 #include <vil/vil_transform.h>
20 #include <vil/vil_config.h>
21 
22 #ifdef VXL_HAS_SSE2_HARDWARE_SUPPORT
23 #include "vil_math_sse.h"
24 #endif
25 
26 //: Compute minimum and maximum values over view
27 template<class T>
28 inline void vil_math_value_range(const vil_image_view<T>& view, T& min_value, T& max_value)
29 {
30  if (view.size()==0)
31  {
32  min_value = 0;
33  max_value = 0;
34  return;
35  }
36 
37  min_value = *(view.top_left_ptr());
38  max_value = min_value;
39 
40  unsigned ni = view.ni();
41  unsigned nj = view.nj();
42  unsigned np = view.nplanes();
43 
44  for (unsigned p=0;p<np;++p)
45  for (unsigned j=0;j<nj;++j)
46  for (unsigned i=0;i<ni;++i)
47  {
48  const T pixel = view(i,j,p);
49  if (pixel<min_value)
50  min_value=pixel;
51  else if (pixel>max_value)
52  max_value=pixel;
53  }
54 }
55 
56 //: Compute minimum and maximum values over view
57 template <>
59  vil_rgb<vxl_byte>& min_value, vil_rgb<vxl_byte>& max_value)
60 {
61  vil_image_view<vxl_byte> plane_view = vil_view_as_planes(rgb_view);
62  // Get range for each plane in turn
63  vil_math_value_range(vil_plane(plane_view,0),min_value.r,max_value.r);
64  vil_math_value_range(vil_plane(plane_view,1),min_value.g,max_value.g);
65  vil_math_value_range(vil_plane(plane_view,2),min_value.b,max_value.b);
66 }
67 
68 //: Compute minimum and maximum values over view
69 template <>
70 inline void vil_math_value_range(const vil_image_view<vil_rgb<float> >& rgb_view,
71  vil_rgb<float>& min_value, vil_rgb<float>& max_value)
72 {
73  vil_image_view<float> plane_view = vil_view_as_planes(rgb_view);
74  // Get range for each plane in turn
75  vil_math_value_range(vil_plane(plane_view,0),min_value.r,max_value.r);
76  vil_math_value_range(vil_plane(plane_view,1),min_value.g,max_value.g);
77  vil_math_value_range(vil_plane(plane_view,2),min_value.b,max_value.b);
78 }
79 
80 
81 //: Compute the values corresponding to several percentiles of the range of im.
82 // Percentiles are expressed as fraction, e.g. 0.05, or 0.95.
83 // \param im The image to examine.
84 // \param fraction The fractions of the data range (from the lower end).
85 // \retval value The image data values corresponding to the specified percentiles.
86 // \relatesalso vil_image_view
87 // \note This function requires the sorting of large parts of the image data
88 // and can be very expensive in terms of both processing and memory.
89 template <class T>
91  const std::vector<double>& fraction,
92  std::vector<T>& value)
93 {
94  value.clear();
95 
96  // Test for invalid inputs
97  if (im.size()==0)
98  {
99  return;
100  }
101  const std::size_t nfrac = fraction.size();
102  for (std::size_t f=0; f<nfrac; ++f)
103  {
104  if (fraction[f]<0.0 || fraction[f]>1.0)
105  return;
106  }
107 
108  // Copy the pixel values into a list.
109  unsigned ni = im.ni();
110  unsigned nj = im.nj();
111  unsigned np = im.nplanes();
112  std::ptrdiff_t istep = im.istep();
113  std::ptrdiff_t jstep = im.jstep();
114  std::ptrdiff_t pstep = im.planestep();
115  std::vector<T> data(ni*nj*np);
116 
117  typename std::vector<T>::iterator it = data.begin();
118  const T* plane = im.top_left_ptr();
119  for (unsigned int p=0; p<np; ++p, plane+=pstep)
120  {
121  const T* row = plane;
122  for (unsigned int j=0; j<nj; ++j, row+=jstep)
123  {
124  const T* pixel = row;
125  for (unsigned int i=0; i<ni; ++i, pixel+=istep)
126  {
127  *it = *pixel;
128  it++;
129  }
130  }
131  }
132  const std::size_t npix = data.size();
133 
134  // Get the nth_element corresponding to the specified fractions
135  value.resize(nfrac);
136  for (unsigned f=0; f<nfrac; ++f)
137  {
138  unsigned index = static_cast<unsigned>(fraction[f]*npix - 0.5);
139  typename std::vector<T>::iterator index_it = data.begin() + index;
140  std::nth_element(data.begin(), index_it, data.end());
141  value[f] = *index_it;
142  }
143 }
144 
145 
146 //: Compute the value corresponding to a percentile of the range of im.
147 // Percentile is expressed as fraction, e.g. 0.05, or 0.95.
148 // \param im The image to examine.
149 // \param fraction The fraction of the data range (from the lower end).
150 // \retval value The image data value corresponding to the specified percentile.
151 // \relatesalso vil_image_view
152 // \note This function requires the sorting of large parts of the image data
153 // and can be very expensive in terms of both processing and memory.
154 template <class T>
156  const double fraction,
157  T& value)
158 {
159  std::vector<double> fractions(1, fraction);
160  std::vector<T> values;
161  vil_math_value_range_percentiles(im, fractions, values);
162  if (values.size() > 0)
163  value = values[0]; // Bounds-checked access in case previous line failed.
164 }
165 
166 
167 //: Sum of squared differences between two images
168 // \relatesalso vil_image_view
169 template <class imT, class sumT>
170 inline sumT vil_math_ssd(const vil_image_view<imT>& imA, const vil_image_view<imT>& imB, sumT /*dummy*/)
171 {
172  assert(imA.ni() == imB.ni() && imB.nj() == imB.nj() && imA.nplanes() == imB.nplanes());
173  sumT ssd=0;
174  for (unsigned p=0;p<imA.nplanes();++p)
175  for (unsigned j=0;j<imA.nj();++j)
176  for (unsigned i=0;i<imA.ni();++i)
177  {
178  const sumT v = ((sumT)imA(i,j,p) - (sumT)imB(i,j,p));
179  ssd += v*v;
180  }
181  return ssd;
182 }
183 
184 //: Sum squared magnitude differences between two complex images
185 // \relatesalso vil_image_view
186 template <class imT, class sumT>
187 inline sumT
188 vil_math_ssd_complex(const vil_image_view<std::complex<imT> >& imA,
189  const vil_image_view<std::complex<imT> >& imB,
190  sumT /*dummy*/)
191 {
192  assert(imA.ni() == imB.ni() && imB.nj() == imB.nj() && imA.nplanes() == imB.nplanes());
193  sumT ssd=0;
194  for (unsigned p=0;p<imA.nplanes();++p)
195  for (unsigned j=0;j<imA.nj();++j)
196  for (unsigned i=0;i<imA.ni();++i)
197  {
198  const std::complex<imT> d = imA(i,j,p) - imB(i,j,p);
199  ssd += sumT( d.real()*d.real() + d.imag()*d.imag() );
200  }
201  return ssd;
202 }
203 
204 //: Calc the mean of each pixel over all the planes.
205 // \relatesalso vil_image_view
206 template<class aT, class sumT>
208  vil_image_view<sumT>& dest)
209 {
210  if (src.nplanes()==1 && src.is_a()==dest.is_a())
211  {
212  dest.deep_copy(src);
213  return;
214  }
215  dest.set_size(src.ni(), src.nj(), 1);
216  for (unsigned j=0;j<src.nj();++j)
217  for (unsigned i=0;i<src.ni();++i)
218  {
219  sumT sum=0;
220  for (unsigned p=0;p<src.nplanes();++p)
221  sum += (sumT) src(i,j,p);
222  dest(i,j) = (sumT)( sum / src.nplanes() );
223  }
224 }
225 
226 //: Calc the mean of each pixel over all the planes.
227 // \relatesalso vil_image_view
228 template<class inT, class outT, class sumT>
230  vil_image_view<outT>& dest,
231  sumT /*dummy*/)
232 {
233  dest.set_size(src.ni(), src.nj(), 1);
234  for (unsigned j=0;j<src.nj();++j)
235  for (unsigned i=0;i<src.ni();++i)
236  {
237  sumT sum=0;
238  for (unsigned p=0;p<src.nplanes();++p)
239  sum += static_cast<sumT>(src(i,j,p));
240  dest(i,j) = static_cast<outT>(sum / src.nplanes());
241  }
242 }
243 
244 //: Sum of elements in plane p of image
245 // \relatesalso vil_image_view
246 template<class imT, class sumT>
247 inline void vil_math_sum(sumT& sum, const vil_image_view<imT>& im, unsigned p)
248 {
249  const imT* row = im.top_left_ptr()+p*im.planestep();
250  std::ptrdiff_t istep = im.istep(),jstep=im.jstep();
251  const imT* row_end = row + im.nj()*jstep;
252  std::ptrdiff_t row_len = im.ni()*im.istep();
253  sum = 0;
254  for (;row!=row_end;row+=jstep)
255  {
256  const imT* v_end = row + row_len;
257  for (const imT* v = row;v!=v_end;v+=istep) sum+=(sumT)(*v);
258  }
259 }
260 
261 //: Mean of elements in plane p of image
262 // \relatesalso vil_image_view
263 template<class imT, class sumT>
264 inline void vil_math_mean(sumT& mean, const vil_image_view<imT>& im, unsigned p)
265 {
266  if (im.size()==0) { mean=0; return; }
267  vil_math_sum(mean,im,p);
268  mean/=(sumT)(im.ni()*im.nj());
269 }
270 
271 // helper function for reporting an error without cluttering the
272 // header with unnecessary includes.
274 
275 //: Median of elements in plane p of an image.
276 //
277 // For integral types, if the median is half way between two
278 // values, the result will be the floor of the average.
279 //
280 // \relatesalso vil_image_view
281 template<class imT>
282 inline void vil_math_median(imT& median, const vil_image_view<imT>& im, unsigned p)
283 {
285 }
286 // median is unimplemented in the general case (for now).
287 
288 // Purposefully not documented via doxygen; let the general template's
289 // documentation be the documentation.
290 template <>
291 void vil_math_median(vxl_byte& median, const vil_image_view<vxl_byte>& im, unsigned p);
292 
293 
294 //: Sum of squares of elements in plane p of image
295 // \relatesalso vil_image_view
296 template<class imT, class sumT>
297 inline void vil_math_sum_squares(sumT& sum, sumT& sum_sq, const vil_image_view<imT>& im, unsigned p)
298 {
299  const imT* row = im.top_left_ptr()+p*im.planestep();
300  std::ptrdiff_t istep = im.istep(),jstep=im.jstep();
301  const imT* row_end = row + im.nj()*jstep;
302  std::ptrdiff_t row_len = im.ni()*im.istep();
303  sum = 0; sum_sq = 0;
304  for (;row!=row_end;row+=jstep)
305  {
306  const imT* v_end = row + row_len;
307  for (const imT* v = row;v!=v_end;v+=istep) { sum+=*v; sum_sq+=sumT(*v)*sumT(*v); }
308  }
309 }
310 
311 //: Sum of squares of masked elements in plane p of image
312 // \relatesalso vil_image_view
313 template<class imT, class sumT>
314 inline bool vil_math_sum_squares(sumT& sum, sumT& sum_sq, unsigned int & count,
315  const vil_image_view<imT>& im, const vil_image_view<bool> & mask, unsigned p)
316 {
317  count = 0;
318  if ( im.ni() != mask.ni() || im.nj() != mask.nj() || mask.nplanes() != 1)
319  {
320  return false;
321  }
322  const imT* row = im.top_left_ptr()+p*im.planestep();
323  std::ptrdiff_t istep = im.istep(),jstep=im.jstep();
324  const imT* row_end = row + im.nj()*jstep;
325  std::ptrdiff_t row_len = im.ni()*im.istep();
326  const bool* m_row = mask.top_left_ptr()+mask.planestep();
327  std::ptrdiff_t m_istep = mask.istep(), m_jstep=mask.jstep();
328  sum = 0; sum_sq = 0;
329  for (;row!=row_end;row+=jstep, m_row+=m_jstep)
330  {
331  const imT* v_end = row + row_len;
332  const bool* b = m_row;
333  for (const imT* v = row; v!=v_end;v+=istep, b+=m_istep )
334  {
335  if(*b)
336  {
337  ++count;
338  sum+=*v;
339  sum_sq+=sumT(*v)*sumT(*v);
340  }
341  }
342  }
343  return true;
344 }
345 
346 
347 //: Mean and variance of elements in plane p of image
348 // \relatesalso vil_image_view
349 template<class imT, class sumT>
350 inline void vil_math_mean_and_variance(sumT& mean, sumT& var, const vil_image_view<imT>& im, unsigned p)
351 {
352  if (im.size()==0) { mean=0; var=0; return; }
353  sumT sum,sum_sq;
354  vil_math_sum_squares(sum,sum_sq,im,p);
355  mean = sum/float(im.ni()*im.nj());
356  var = sum_sq/float(im.ni()*im.nj()) - mean*mean;
357 }
358 
359 //: Mean and variance of masked elements in plane p of image
360 // \relatesalso vil_image_view
361 template<class imT, class sumT>
362 inline bool vil_math_mean_and_variance(sumT& mean, sumT& var, const vil_image_view<imT>& im,
363  const vil_image_view<bool> & mask, unsigned p)
364 {
365  if (im.size()==0) { mean=0; var=0; return true; }
366  sumT sum,sum_sq;
367  unsigned int count = 0;
368  if(!vil_math_sum_squares(sum,sum_sq, count, im,mask,p))
369  {
370  return false;
371  }
372  mean = sum/float(count);
373  var = sum_sq/float(count) - mean*mean;
374  return true;
375 }
376 
377 //: Mean and variance of masked elements in plane p for vil_image_resource
378 // \relatedalso vil_image_resource
379 template< class sumT >
380 inline bool vil_math_mean_and_variance(sumT& mean, sumT& var, const vil_image_resource_sptr im,
381  const vil_image_view<bool> & mask, unsigned p)
382 {
383  if(im == nullptr || im->get_view() == nullptr)
384  {
385  return false;
386  }
387  switch (im->pixel_format())
388  {
389 #define macro( F , T ) \
390  case F : \
391  return vil_math_mean_and_variance(mean, var, \
392  static_cast<vil_image_view<T >&>(*(im->get_view())), \
393  mask, p); \
394 
395  macro(VIL_PIXEL_FORMAT_BYTE , vxl_byte )
396  macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
397  macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
398  macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
399  macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
400  macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
402  macro(VIL_PIXEL_FORMAT_FLOAT , float )
403  macro(VIL_PIXEL_FORMAT_DOUBLE , double )
404 #undef macro
405  default:
406  return false;
407  }
408  return true;
409 }
410 
411 
412 //: Functor class to compute square roots (returns zero if x<0)
414 {
415  public:
416  vxl_byte operator()(vxl_byte x) const { return static_cast<vxl_byte>(0.5+std::sqrt(double(x))); }
417  unsigned operator()(unsigned x) const { return static_cast<unsigned int>(0.5+std::sqrt(double(x))); }
418  int operator()(int x) const { return x>0?static_cast<int>(0.5+std::sqrt(double(x))):0; }
419  short operator()(short x) const { return x>0?static_cast<short>(0.5+std::sqrt(double(x))):0; }
420  float operator()(float x) const { return x>0?std::sqrt(x):0.0f; }
421  double operator()(double x) const { return x>0?std::sqrt(x):0.0; }
422 };
423 
424 //: Compute square-root of each pixel element (or zero if negative)
425 // \relatesalso vil_image_view
426 template<class T>
427 inline void vil_math_sqrt(vil_image_view<T>& image)
428 {
430 }
431 
432 
433 //: Truncate each pixel value so it fits into range [min_v,max_v]
434 // If value < min_v value=min_v
435 // If value > max_v value=max_v
436 // \relatesalso vil_image_view
437 template<class T>
438 inline void vil_math_truncate_range(vil_image_view<T>& image, T min_v, T max_v)
439 {
440  unsigned ni = image.ni(),nj = image.nj(),np = image.nplanes();
441  std::ptrdiff_t istep=image.istep(),jstep=image.jstep(),pstep = image.planestep();
442  T* plane = image.top_left_ptr();
443  for (unsigned p=0;p<np;++p,plane += pstep)
444  {
445  T* row = plane;
446  for (unsigned j=0;j<nj;++j,row += jstep)
447  {
448  T* pixel = row;
449  for (unsigned i=0;i<ni;++i,pixel+=istep)
450  {
451  if (*pixel<min_v) *pixel=min_v;
452  else if (*pixel>max_v) *pixel=max_v;
453  }
454  }
455  }
456 }
457 
458 //: Functor class to scale by s
460 {
461  double s_;
462 public:
463  vil_math_scale_functor(double s) : s_(s) {}
464  vxl_byte operator()(vxl_byte x) const { return vxl_byte(0.5+s_*x); }
465  unsigned operator()(unsigned x) const { return unsigned(0.5+s_*x); }
466  short operator()(short x) const { double r=s_*x; return short(r<0?r-0.5:r+0.5); }
467  int operator()(int x) const { double r=s_*x; return int(r<0?r-0.5:r+0.5); }
468  float operator()(float x) const { return float(s_*x); }
469  double operator()(double x) const { return s_*x; }
470  std::complex<double> operator()(std::complex<double> x) const { return s_*x; }
471 };
472 
473 
474 //: Functor class to scale by s and translate (offset) by t.
475 // \note Watch out for overflow, especially for smaller types.
476 // \sa vil_math_scale_and_offset_values()
478 {
479 public:
480  //: Constructor
481  // \param s Scaling.
482  // \param t Translation (offset).
483  vil_math_scale_and_translate_functor(const double s, const double t)
484  : s_(s), t_(t) {}
485 
486  vxl_byte operator()(vxl_byte x) const { return vxl_byte(0.5+s_*x+t_); }
487  unsigned operator()(unsigned x) const { return unsigned(0.5+s_*x+t_); }
488  short operator()(short x) const { double r=s_*x+t_; return short(r<0?r-0.5:r+0.5); }
489  int operator()(int x) const { double r=s_*x+t_; return int(r<0?r-0.5:r+0.5); }
490  float operator()(float x) const { return float(s_*x+t_); }
491  double operator()(double x) const { return s_*x+t_; }
492  std::complex<double> operator()(std::complex<double> x) const { return s_*x+t_; } // Not sure if this one makes sense
493 
494 private:
495  double s_;
496  double t_;
497 };
498 
499 
500 //: Functor class to compute logarithms (returns zero if x<=0)
502 {
503  public:
504  vxl_byte operator()(vxl_byte x) const { return static_cast<vxl_byte>(0.5+std::log(double(x))); }
505  unsigned operator()(unsigned x) const { return static_cast<unsigned int>(0.5+std::log(double(x))); }
506  int operator()(int x) const { return x>0?static_cast<int>(0.5+std::log(double(x))):0; }
507  short operator()(short x) const { return x>0?static_cast<short>(0.5+std::log(double(x))):0; }
508  float operator()(float x) const { return x>0?std::log(x):0.0f; }
509  double operator()(double x) const { return x>0?std::log(x):0.0; }
510 };
511 
512 
513 //: Multiply values in-place in image view by scale
514 // \relatesalso vil_image_view
515 template<class T>
516 inline void vil_math_scale_values(vil_image_view<T>& image, double scale)
517 {
519 }
520 
521 //: Multiply values in-place in image view by scale and add offset
522 // \relatesalso vil_image_view
523 template<class imT, class offsetT>
524 inline void vil_math_scale_and_offset_values(vil_image_view<imT>& image, double scale, offsetT offset)
525 {
526  unsigned ni = image.ni(),nj = image.nj(),np = image.nplanes();
527  std::ptrdiff_t istep=image.istep(),jstep=image.jstep(),pstep = image.planestep();
528  imT* plane = image.top_left_ptr();
529  for (unsigned p=0;p<np;++p,plane += pstep)
530  {
531  imT* row = plane;
532  for (unsigned j=0;j<nj;++j,row += jstep)
533  {
534  imT* pixel = row;
535  for (unsigned i=0;i<ni;++i,pixel+=istep) *pixel = imT(scale*(*pixel)+offset);
536  }
537  }
538 }
539 
540 //: Scale and offset values so their mean is zero and their variance is one.
541 // Only works on signed types!
542 template<class imT>
544 {
545  assert(image.nplanes()==1);
546  double mean,var;
547  vil_math_mean_and_variance(mean,var,image,0);
548  double s=0;
549  if (var>0) s = 1.0/std::sqrt(var);
550  vil_math_scale_and_offset_values(image,s,-s*mean);
551 }
552 
553 //: Computes RMS of each pixel over the planes of src image
554 // Dest is a single plane image, $dest(i,j)^2 = 1/np sum_p src(i,j,p)^2$
555 // Summation is performed using type destT
556 template<class srcT, class destT>
557 inline
559  vil_image_view<destT>& dest)
560 {
561  unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
562  dest.set_size(ni,nj,1);
563 
564  std::ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
565  std::ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
566  const srcT* rowA = src.top_left_ptr();
567  destT* rowB = dest.top_left_ptr();
568  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
569  {
570  const srcT* pixelA = rowA;
571  const srcT* end_pixelA = rowA+ni*istepA;
572  destT* pixelB = rowB;
573 
574  if (np==1)
575  {
576  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
577  *pixelB = std::fabs(destT(*pixelA));
578  }
579  else if (np==2)
580  {
581  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
582  {
583  destT sum2 = destT(*pixelA)*(*pixelA)
584  + destT(pixelA[pstepA])*(pixelA[pstepA]);
585  *pixelB = destT(std::sqrt(sum2/2));
586  }
587  }
588  else
589  {
590  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
591  {
592  *pixelB = destT(*pixelA)*destT(*pixelA);
593  const srcT* p=pixelA+pstepA;
594  const srcT* end_p=pixelA+np*pstepA;
595  for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
596  *pixelB = destT(std::sqrt(*pixelB/np));
597  }
598  }
599  }
600 }
601 
602 //: Computes Root Sum of Squares of each pixel over the planes of src image
603 // Dest is a single plane image, $dest(i,j) = sqrt(sum_p src(i,j,p)^2)$
604 // Differs from RMS by the scaling factor sqrt(nplanes)
605 // Summation is performed using type destT
606 template<class srcT, class destT>
607 inline
609  vil_image_view<destT>& dest)
610 {
611  unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
612  dest.set_size(ni,nj,1);
613 
614  std::ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
615  std::ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
616  const srcT* rowA = src.top_left_ptr();
617  destT* rowB = dest.top_left_ptr();
618  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
619  {
620  const srcT* pixelA = rowA;
621  const srcT* end_pixelA = rowA+ni*istepA;
622  destT* pixelB = rowB;
623 
624  if (np==1)
625  {
626  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
627  *pixelB = std::fabs(destT(*pixelA));
628  }
629  else if (np==2)
630  {
631  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
632  {
633  destT sum2 = destT(*pixelA)*(*pixelA)
634  + destT(pixelA[pstepA])*(pixelA[pstepA]);
635  *pixelB = destT(std::sqrt(sum2));
636  }
637  }
638  else
639  {
640  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
641  {
642  *pixelB = destT(*pixelA)*destT(*pixelA);
643  const srcT* p=pixelA+pstepA;
644  const srcT* end_p=pixelA+np*pstepA;
645  for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
646  *pixelB = destT(std::sqrt(*pixelB));
647  }
648  }
649  }
650 }
651 
652 
653 //: Computes sum of squares of each pixel over the planes of src image
654 // Dest is a single plane image, $dest(i,j) = sum_p src(i,j,p)^2$
655 // Summation is performed using type destT
656 template<class srcT, class destT>
657 inline
659  vil_image_view<destT>& dest)
660 {
661  unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
662  dest.set_size(ni,nj,1);
663 
664  std::ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
665  std::ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
666  const srcT* rowA = src.top_left_ptr();
667  destT* rowB = dest.top_left_ptr();
668  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
669  {
670  const srcT* pixelA = rowA;
671  const srcT* end_pixelA = rowA+ni*istepA;
672  destT* pixelB = rowB;
673  if (np==1)
674  {
675  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
676  *pixelB = destT(*pixelA)*(*pixelA);
677  }
678  else if (np==2)
679  {
680  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
681  *pixelB = destT(*pixelA)*(*pixelA)
682  + destT(pixelA[pstepA])*(pixelA[pstepA]);
683  }
684  else
685  {
686  for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
687  {
688  *pixelB = destT(*pixelA)*destT(*pixelA);
689  const srcT* p=pixelA+pstepA;
690  const srcT* end_p=pixelA+np*pstepA;
691  for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
692  }
693  }
694  }
695 }
696 
697 //: Compute sum of two images (im_sum = imA+imB)
698 // \relatesalso vil_image_view
699 template<class aT, class bT, class sumT>
700 inline void vil_math_image_sum(const vil_image_view<aT>& imA,
701  const vil_image_view<bT>& imB,
702  vil_image_view<sumT>& im_sum)
703 {
704  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
705  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
706  im_sum.set_size(ni,nj,np);
707 
708  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
709  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
710  std::ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
711  const aT* planeA = imA.top_left_ptr();
712  const bT* planeB = imB.top_left_ptr();
713  sumT* planeS = im_sum.top_left_ptr();
714  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
715  {
716  const aT* rowA = planeA;
717  const bT* rowB = planeB;
718  sumT* rowS = planeS;
719  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
720  {
721  const aT* pixelA = rowA;
722  const bT* pixelB = rowB;
723  sumT* pixelS = rowS;
724  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
725  *pixelS = sumT(*pixelA)+sumT(*pixelB);
726  }
727  }
728 }
729 
730 //: Compute pixel-wise product of two images (im_prod(i,j) = imA(i,j)*imB(i,j)
731 // If images have the same number of planes,
732 // then im_prod(i,j,p) = imA(i,j,p)*imB(i,j,p).
733 // If imB only has one plane, then im_prod(i,j,p) = imA(i,j,p)*imB(i,j,0).
734 // \relatesalso vil_image_view
735 template<class aT, class bT, class sumT>
737  const vil_image_view<bT>& imB,
738  vil_image_view<sumT>& im_product)
739 {
740  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
741  assert(imB.ni()==ni && imB.nj()==nj);
742  assert(imB.nplanes()==1 || imB.nplanes()==np);
743  im_product.set_size(ni,nj,np);
744 
745  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
746  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
747  std::ptrdiff_t istepP=im_product.istep(),jstepP=im_product.jstep(),
748  pstepP = im_product.planestep();
749 
750  // For one plane case, arrange that im_prod(i,j,p) = imA(i,j,p)*imB(i,j,0)
751  if (imB.nplanes()==1) pstepB=0;
752 
753  const aT* planeA = imA.top_left_ptr();
754  const bT* planeB = imB.top_left_ptr();
755  sumT* planeP = im_product.top_left_ptr();
756  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeP += pstepP)
757  {
758  const aT* rowA = planeA;
759  const bT* rowB = planeB;
760  sumT* rowP = planeP;
761  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowP += jstepP)
762  {
763  const aT* pixelA = rowA;
764  const bT* pixelB = rowB;
765  sumT* pixelP = rowP;
766  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelP+=istepP)
767  *pixelP = sumT(*pixelA)*sumT(*pixelB);
768  }
769  }
770 }
771 
772 //: Compute the max of two images (im_max = max(imA, imB))
773 // \relatesalso vil_image_view
774 template<class aT, class bT, class maxT>
775 inline void vil_math_image_max(const vil_image_view<aT>& imA,
776  const vil_image_view<bT>& imB,
777  vil_image_view<maxT>& im_max)
778 {
779  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
780  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
781  im_max.set_size(ni,nj,np);
782 
783  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
784  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
785  std::ptrdiff_t istepS=im_max.istep(),jstepS=im_max.jstep(),pstepS = im_max.planestep();
786  const aT* planeA = imA.top_left_ptr();
787  const bT* planeB = imB.top_left_ptr();
788  maxT* planeS = im_max.top_left_ptr();
789  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
790  {
791  const aT* rowA = planeA;
792  const bT* rowB = planeB;
793  maxT* rowS = planeS;
794  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
795  {
796  const aT* pixelA = rowA;
797  const bT* pixelB = rowB;
798  maxT* pixelS = rowS;
799  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
800  *pixelS = maxT(std::max(*pixelA, *pixelB));
801  }
802  }
803 }
804 
805 //: Compute the min of two images (im_min = min(imA, imB))
806 // \relatesalso vil_image_view
807 template<class aT, class bT, class minT>
808 inline void vil_math_image_min(const vil_image_view<aT>& imA,
809  const vil_image_view<bT>& imB,
810  vil_image_view<minT>& im_min)
811 {
812  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
813  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
814  im_min.set_size(ni,nj,np);
815 
816  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
817  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
818  std::ptrdiff_t istepS=im_min.istep(),jstepS=im_min.jstep(),pstepS = im_min.planestep();
819  const aT* planeA = imA.top_left_ptr();
820  const bT* planeB = imB.top_left_ptr();
821  minT* planeS = im_min.top_left_ptr();
822  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
823  {
824  const aT* rowA = planeA;
825  const bT* rowB = planeB;
826  minT* rowS = planeS;
827  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
828  {
829  const aT* pixelA = rowA;
830  const bT* pixelB = rowB;
831  minT* pixelS = rowS;
832  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
833  *pixelS = minT(std::min(*pixelA, *pixelB));
834  }
835  }
836 }
837 
838 //: Compute pixel-wise ratio of two images : im_ratio(i,j) = imA(i,j)/imB(i,j)
839 // Pixels cast to type sumT before calculation.
840 // If imB(i,j,p)==0, im_ration(i,j,p)=0
841 //
842 // If images have the same number of planes,
843 // then im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,p).
844 // If imB only has one plane, then im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,0).
845 // \relatesalso vil_image_view
846 template<class aT, class bT, class sumT>
848  const vil_image_view<bT>& imB,
849  vil_image_view<sumT>& im_ratio)
850 {
851  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
852  assert(imB.ni()==ni && imB.nj()==nj);
853  assert(imB.ni()==ni && imB.nj()==nj);
854  assert(imB.nplanes()==1 || imB.nplanes()==np);
855  im_ratio.set_size(ni,nj,np);
856 
857  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
858  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
859  std::ptrdiff_t istepR=im_ratio.istep(),jstepR=im_ratio.jstep(),
860  pstepR = im_ratio.planestep();
861 
862  // For one plane case, arrange that im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,0)
863  if (imB.nplanes()==1) pstepB=0;
864 
865  const aT* planeA = imA.top_left_ptr();
866  const bT* planeB = imB.top_left_ptr();
867  sumT* planeR = im_ratio.top_left_ptr();
868  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeR += pstepR)
869  {
870  const aT* rowA = planeA;
871  const bT* rowB = planeB;
872  sumT* rowR = planeR;
873  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowR += jstepR)
874  {
875  const aT* pixelA = rowA;
876  const bT* pixelB = rowB;
877  sumT* pixelR = rowR;
878  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelR+=istepR)
879  {
880  if (*pixelB==0) *pixelR=0;
881  else *pixelR = sumT(*pixelA)/sumT(*pixelB);
882  }
883  }
884  }
885 }
886 
887 //: Compute difference of two images (im_sum = imA-imB)
888 // \relatesalso vil_image_view
889 template<class aT, class bT, class sumT>
891  const vil_image_view<bT>& imB,
892  vil_image_view<sumT>& im_sum)
893 {
894  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
895  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
896  im_sum.set_size(ni,nj,np);
897 
898  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
899  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
900  std::ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
901  const aT* planeA = imA.top_left_ptr();
902  const bT* planeB = imB.top_left_ptr();
903  sumT* planeS = im_sum.top_left_ptr();
904  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
905  {
906  const aT* rowA = planeA;
907  const bT* rowB = planeB;
908  sumT* rowS = planeS;
909  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
910  {
911  const aT* pixelA = rowA;
912  const bT* pixelB = rowB;
913  sumT* pixelS = rowS;
914  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
915  *pixelS = sumT(*pixelA)-sumT(*pixelB);
916  }
917  }
918 }
919 
920 
921 //: Compute absolute difference of two 1D images (im_sum = |imA-imB|)
922 // \relatesalso vil_image_view
923 template<class aT, class bT, class dT>
925  const aT* pxA, std::ptrdiff_t isA,
926  const bT* pxB, std::ptrdiff_t isB,
927  dT* pxD, std::ptrdiff_t isD,
928  unsigned len)
929 {
930  for (unsigned i =0; i < len; ++i, pxA += isA, pxB += isB, pxD += isD)
931  {
932  // The following construction works for all types, including unsigned
933  *pxD = (*pxA > *pxB) ? (dT)(*pxA - *pxB) : (dT)(*pxB - *pxA);
934  }
935 }
936 
937 
938 //: Compute absolute difference of two 1D images (im_sum = |imA-imB|)
939 // Specialize this function for an optimized implementation
940 template<class aT, class bT, class dT>
942  const aT* pxA, std::ptrdiff_t isA,
943  const bT* pxB, std::ptrdiff_t isB,
944  dT* pxD, std::ptrdiff_t isD,
945  unsigned len)
946 {
947  vil_math_image_abs_difference_1d_generic<aT, bT, dT>(
948  pxA, isA, pxB, isB, pxD, isD, len);
949 }
950 
951 
952 //: Compute absolute difference of two images (im_sum = |imA-imB|)
953 // \relatesalso vil_image_view
954 template<class aT, class bT, class dT>
956  const vil_image_view<bT>& imB,
957  vil_image_view<dT>& imD)
958 {
959  unsigned ni = imA.ni(), nj = imA.nj(), np = imA.nplanes();
960  assert(imB.ni() == ni && imB.nj() == nj && imB.nplanes() == np);
961  imD.set_size(ni, nj, np);
962 
963  std::ptrdiff_t isA=imA.istep(), jsA=imA.jstep(), psA = imA.planestep();
964  std::ptrdiff_t isB=imB.istep(), jsB=imB.jstep(), psB = imB.planestep();
965  std::ptrdiff_t isD=imD.istep(), jsD=imD.jstep(), psD = imD.planestep();
966  const aT* planeA = imA.top_left_ptr();
967  const bT* planeB = imB.top_left_ptr();
968  dT* planeD = imD.top_left_ptr();
969 
970  for (unsigned p = 0; p < np ;++p, planeA += psA, planeB += psB, planeD += psD)
971  {
972  const aT* rowA = planeA;
973  const bT* rowB = planeB;
974 
975  dT* rowD = planeD;
976  for (unsigned j = 0; j < nj; ++j, rowA += jsA, rowB += jsB, rowD += jsD)
977  {
978  vil_math_image_abs_difference_1d<aT,bT,dT>(
979  rowA, isA, rowB, isB, rowD, isD, ni);
980  }
981  }
982 }
983 
984 
985 //: Compute sum of absolute difference between two images (|imA-imB|)
986 // \relatesalso vil_image_view
987 template<class aT, class bT>
989  const vil_image_view<bT>& imB)
990 {
991  double sum=0.0;
992  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
993  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
994 
995  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
996  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
997  const aT* planeA = imA.top_left_ptr();
998  const bT* planeB = imB.top_left_ptr();
999  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
1000  {
1001  const aT* rowA = planeA;
1002  const bT* rowB = planeB;
1003  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
1004  {
1005  const aT* pixelA = rowA;
1006  const bT* pixelB = rowB;
1007  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
1008  {
1009  // The following construction works for all types, including unsigned
1010  sum += (*pixelA>*pixelB?(*pixelA-*pixelB):(*pixelB-*pixelA));
1011  }
1012  }
1013  }
1014  return sum;
1015 }
1016 
1017 //: Compute magnitude of two images taken as vector components, sqrt(A^2 + B^2)
1018 // \relatesalso vil_image_view
1019 template<class aT, class bT, class magT>
1021  const vil_image_view<bT>& imB,
1022  vil_image_view<magT>& im_mag)
1023 {
1024  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
1025  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
1026  im_mag.set_size(ni,nj,np);
1027 
1028  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
1029  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
1030  std::ptrdiff_t istepM=im_mag.istep(),jstepM=im_mag.jstep(),pstepM = im_mag.planestep();
1031  const aT* planeA = imA.top_left_ptr();
1032  const bT* planeB = imB.top_left_ptr();
1033  magT* planeM = im_mag.top_left_ptr();
1034  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeM += pstepM)
1035  {
1036  const aT* rowA = planeA;
1037  const bT* rowB = planeB;
1038  magT* rowM = planeM;
1039  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowM += jstepM)
1040  {
1041  const aT* pixelA = rowA;
1042  const bT* pixelB = rowB;
1043  magT* pixelM = rowM;
1044  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelM+=istepM)
1045  {
1046  // The following construction works for all types, including unsigned
1047  magT mag_sqr = static_cast<magT>((*pixelA)*(*pixelA) + (*pixelB)*(*pixelB));
1048  magT mag = vil_math_sqrt_functor()(mag_sqr);
1049  *pixelM = mag;
1050  }
1051  }
1052  }
1053 }
1054 
1055 //: imA = fa*imA + fb*imB (Useful for moving averages!)
1056 // Can do running sum using vil_add_image_fraction(running_mean,1-f,new_im,f)
1057 // to update current mean by a fraction f of new_im
1058 // \relatesalso vil_image_view
1059 template<class aT, class bT, class scaleT>
1061  const vil_image_view<bT>& imB, scaleT fb)
1062 {
1063  unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
1064  assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
1065 
1066  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
1067  std::ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
1068  aT* planeA = imA.top_left_ptr();
1069  const bT* planeB = imB.top_left_ptr();
1070  for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
1071  {
1072  aT* rowA = planeA;
1073  const bT* rowB = planeB;
1074  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
1075  {
1076  aT* pixelA = rowA;
1077  const bT* pixelB = rowB;
1078  for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
1079  *pixelA = aT(fa*(*pixelA)+fb*(*pixelB));
1080  }
1081  }
1082 }
1083 
1084 //: Compute integral image im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)
1085 // Useful thing for quickly computing mean over large regions,
1086 // as demonstrated in Viola and Jones (CVPR01).
1087 // The sum of elements in the ni x nj square with corner (i,j)
1088 // is given by im_sum(i,j)+im_sum(i+ni,j+nj)-im_sum(i+ni,j)-im_sum(i,j+nj)
1089 // \relatesalso vil_image_view
1090 template<class aT, class sumT>
1092  vil_image_view<sumT>& im_sum)
1093 {
1094  assert(imA.nplanes()==1);
1095  unsigned ni = imA.ni(),nj = imA.nj();
1096  unsigned ni1=ni+1;
1097  unsigned nj1=nj+1;
1098  im_sum.set_size(ni1,nj1,1);
1099 
1100  // Put zeros along first row of im_sum
1101  std::ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep();
1102  sumT* rowS = im_sum.top_left_ptr();
1103  sumT* pixelS = rowS;
1104  for (unsigned i=0;i<ni1;++i,pixelS+=istepS)
1105  *pixelS=0;
1106 
1107  // Now sum from original image (imA)
1108  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep();
1109  const aT* rowA = imA.top_left_ptr();
1110 
1111  sumT sum;
1112  std::ptrdiff_t prev_j = -jstepS;
1113  rowS += jstepS;
1114 
1115  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS)
1116  {
1117  const aT* pixelA = rowA;
1118  pixelS = rowS;
1119  sum = 0;
1120  // set first value at start of each row to zero!
1121  *pixelS = 0;
1122  pixelS+=istepS;
1123  for (unsigned i=1;i<ni1;++i,pixelA+=istepA,pixelS+=istepS)
1124  { sum+= (sumT)(*pixelA); *pixelS=sum + pixelS[prev_j];}
1125  }
1126 }
1127 
1128 //: Compute integral image im_sum_sq(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)^2
1129 // Also computes sum im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)
1130 //
1131 // Useful thing for quickly computing mean and variance over large regions,
1132 // as demonstrated in Viola and Jones (CVPR01).
1133 //
1134 // The sum of elements in the ni x nj square with corner (i,j)
1135 // is given by im_sum(i,j)+im_sum(i+ni,j+nj)-im_sum(i+ni,j)-im_sum(i,j+nj)
1136 //
1137 // Similar result holds for sum of squares, allowing rapid calculation of variance etc.
1138 // \relatesalso vil_image_view
1139 template<class aT, class sumT>
1141  vil_image_view<sumT>& im_sum,
1142  vil_image_view<sumT>& im_sum_sq)
1143 {
1144  assert(imA.nplanes()==1);
1145  unsigned ni = imA.ni(),nj = imA.nj();
1146  unsigned ni1=ni+1;
1147  unsigned nj1=nj+1;
1148  im_sum.set_size(ni1,nj1,1);
1149  im_sum_sq.set_size(ni1,nj1,1);
1150 
1151  // Put zeros along first row of im_sum & im_sum_sq
1152  std::ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep();
1153  std::ptrdiff_t istepS2=im_sum_sq.istep(),jstepS2=im_sum_sq.jstep();
1154  sumT* rowS = im_sum.top_left_ptr();
1155  sumT* rowS2 = im_sum_sq.top_left_ptr();
1156  // im_sum
1157  sumT* pixelS = rowS;
1158  for (unsigned i=0;i<ni1;++i,pixelS+=istepS)
1159  *pixelS=0;
1160 
1161  // im_sum_sq
1162  sumT* pixelS2 = rowS2;
1163  for (unsigned i=0;i<ni1;++i,pixelS2+=istepS2)
1164  *pixelS2=0;
1165 
1166  // Now sum from original image (imA)
1167  std::ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep();
1168  const aT* rowA = imA.top_left_ptr();
1169 
1170  sumT sum,sum2;
1171  std::ptrdiff_t prev_j = -jstepS;
1172  std::ptrdiff_t prev_j2 = -jstepS2;
1173  rowS += jstepS;
1174  rowS2 += jstepS2;
1175 
1176  for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS,rowS2 += jstepS2)
1177  {
1178  const aT* pixelA = rowA;
1179  pixelS = rowS;
1180  pixelS2 = rowS2;
1181  sum = 0;
1182  sum2 = 0;
1183  // set first value at start of each row to zero!
1184  *pixelS = 0;
1185  *pixelS2 = 0;
1186  pixelS+=istepS;
1187  pixelS2+=istepS2;
1188  for (unsigned i=1;i<ni1;++i,pixelA+=istepA,pixelS+=istepS,pixelS2+=istepS2)
1189  {
1190  sum+= (sumT)(*pixelA);
1191  *pixelS=sum + pixelS[prev_j];
1192  sum2+=sumT(*pixelA)*sumT(*pixelA);
1193  *pixelS2 = sum2 + pixelS2[prev_j2];
1194  }
1195  }
1196 }
1197 
1198 
1199 #ifdef VXL_HAS_SSE2_HARDWARE_SUPPORT
1200 #include "vil_math_sse.hxx"
1201 #endif
1202 
1203 #endif // vil_math_h_
unsigned operator()(unsigned x) const
Definition: vil_math.h:505
Various mathematical manipulations of 2D images implemented with SSE intrinsic functions.
void vil_math_integral_image(const vil_image_view< aT > &imA, vil_image_view< sumT > &im_sum)
Compute integral image im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y).
Definition: vil_math.h:1091
std::complex< double > operator()(std::complex< double > x) const
Definition: vil_math.h:470
float operator()(float x) const
Definition: vil_math.h:468
void vil_math_mean(sumT &mean, const vil_image_view< imT > &im, unsigned p)
Mean of elements in plane p of image.
Definition: vil_math.h:264
float operator()(float x) const
Definition: vil_math.h:420
short operator()(short x) const
Definition: vil_math.h:466
double operator()(double x) const
Definition: vil_math.h:469
short operator()(short x) const
Definition: vil_math.h:507
double operator()(double x) const
Definition: vil_math.h:491
void vil_math_image_min(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< minT > &im_min)
Compute the min of two images (im_min = min(imA, imB)).
Definition: vil_math.h:808
void vil_transform(vil_image_view< T > &image, F functor)
Apply a unary operation to each pixel in image.
Definition: vil_transform.h:19
void vil_math_image_max(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< maxT > &im_max)
Compute the max of two images (im_max = max(imA, imB)).
Definition: vil_math.h:775
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
void vil_math_sqrt(vil_image_view< T > &image)
Compute square-root of each pixel element (or zero if negative).
Definition: vil_math.h:427
void vil_math_image_product(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< sumT > &im_product)
Compute pixel-wise product of two images (im_prod(i,j) = imA(i,j)*imB(i,j).
Definition: vil_math.h:736
void vil_math_sum(sumT &sum, const vil_image_view< imT > &im, unsigned p)
Sum of elements in plane p of image.
Definition: vil_math.h:247
void set_size(unsigned ni, unsigned nj) override
resize current planes to ni x nj.
unsigned operator()(unsigned x) const
Definition: vil_math.h:465
STL algorithm like methods.
vxl_byte operator()(vxl_byte x) const
Definition: vil_math.h:486
void vil_math_value_range_percentile(const vil_image_view< T > &im, const double fraction, T &value)
Compute the value corresponding to a percentile of the range of im.
Definition: vil_math.h:155
Functor class to compute square roots (returns zero if x<0).
Definition: vil_math.h:413
Various view conversion functions.
unsigned operator()(unsigned x) const
Definition: vil_math.h:417
std::ptrdiff_t jstep() const
Add this to your pixel pointer to get next j pixel.
unsigned ni() const
Width.
T g
Definition: vil_rgb.h:58
std::complex< double > operator()(std::complex< double > x) const
Definition: vil_math.h:492
void vil_math_median_unimplemented()
Definition: vil_math.cxx:17
void vil_math_mean_over_planes(const vil_image_view< aT > &src, vil_image_view< sumT > &dest)
Calc the mean of each pixel over all the planes.
Definition: vil_math.h:207
unsigned nj() const
Height.
#define v
std::ptrdiff_t planestep() const
Add this to your pixel pointer to get pixel on next plane.
void vil_math_integral_sqr_image(const vil_image_view< aT > &imA, vil_image_view< sumT > &im_sum, vil_image_view< sumT > &im_sum_sq)
Compute integral image im_sum_sq(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)^2.
Definition: vil_math.h:1140
void vil_math_image_vector_mag(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< magT > &im_mag)
Compute magnitude of two images taken as vector components, sqrt(A^2 + B^2).
Definition: vil_math.h:1020
Various mathematical manipulations of 2D images implemented with SSE intrinsic functions.
T b
Definition: vil_rgb.h:58
vxl_byte operator()(vxl_byte x) const
Definition: vil_math.h:416
void vil_math_truncate_range(vil_image_view< T > &image, T min_v, T max_v)
Truncate each pixel value so it fits into range [min_v,max_v].
Definition: vil_math.h:438
vxl_byte operator()(vxl_byte x) const
Definition: vil_math.h:504
void deep_copy(const vil_image_view< T > &src)
Make a copy of the data in src and set this to view it.
void vil_math_image_sum(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< sumT > &im_sum)
Compute sum of two images (im_sum = imA+imB).
Definition: vil_math.h:700
void vil_math_scale_and_offset_values(vil_image_view< imT > &image, double scale, offsetT offset)
Multiply values in-place in image view by scale and add offset.
Definition: vil_math.h:524
float operator()(float x) const
Definition: vil_math.h:490
void vil_math_image_abs_difference_1d_generic(const aT *pxA, std::ptrdiff_t isA, const bT *pxB, std::ptrdiff_t isB, dT *pxD, std::ptrdiff_t isD, unsigned len)
Compute absolute difference of two 1D images (im_sum = |imA-imB|).
Definition: vil_math.h:924
void vil_math_image_abs_difference(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< dT > &imD)
Compute absolute difference of two images (im_sum = |imA-imB|).
Definition: vil_math.h:955
A base class reference-counting view of some image data.
void vil_math_scale_values(vil_image_view< T > &image, double scale)
Multiply values in-place in image view by scale.
Definition: vil_math.h:516
vil_image_view< typename T::value_type > vil_view_as_planes(const vil_image_view< T > &v)
Return a 3-plane view of an RGB image, or a 4-plane view of an RGBA, or a 2-plane view of a complex i...
Definition: vil_view_as.h:26
void vil_math_image_ratio(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< sumT > &im_ratio)
Compute pixel-wise ratio of two images : im_ratio(i,j) = imA(i,j)/imB(i,j).
Definition: vil_math.h:847
int operator()(int x) const
Definition: vil_math.h:467
unsigned long size() const
The number of pixels.
void vil_math_image_abs_difference_1d(const aT *pxA, std::ptrdiff_t isA, const bT *pxB, std::ptrdiff_t isB, dT *pxD, std::ptrdiff_t isD, unsigned len)
Compute absolute difference of two 1D images (im_sum = |imA-imB|).
Definition: vil_math.h:941
std::string is_a() const override
Return class name.
Functor class to scale by s.
Definition: vil_math.h:459
sumT vil_math_ssd_complex(const vil_image_view< std::complex< imT > > &imA, const vil_image_view< std::complex< imT > > &imB, sumT)
Sum squared magnitude differences between two complex images.
Definition: vil_math.h:188
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
vil_image_view< T > vil_plane(const vil_image_view< T > &im, unsigned p)
Return a view of im's plane p.
Definition: vil_plane.h:20
Functor class to compute logarithms (returns zero if x<=0).
Definition: vil_math.h:501
void vil_math_normalise(vil_image_view< imT > &image)
Scale and offset values so their mean is zero and their variance is one.
Definition: vil_math.h:543
short operator()(short x) const
Definition: vil_math.h:419
float operator()(float x) const
Definition: vil_math.h:508
#define macro(F, T)
unsigned nplanes() const
Number of planes.
int operator()(int x) const
Definition: vil_math.h:506
void vil_math_value_range_percentiles(const vil_image_view< T > &im, const std::vector< double > &fraction, std::vector< T > &value)
Compute the values corresponding to several percentiles of the range of im.
Definition: vil_math.h:90
sumT vil_math_ssd(const vil_image_view< imT > &imA, const vil_image_view< imT > &imB, sumT)
Sum of squared differences between two images.
Definition: vil_math.h:170
void vil_math_rms(const vil_image_view< srcT > &src, vil_image_view< destT > &dest)
Computes RMS of each pixel over the planes of src image.
Definition: vil_math.h:558
vxl_byte operator()(vxl_byte x) const
Definition: vil_math.h:464
void vil_math_add_image_fraction(vil_image_view< aT > &imA, scaleT fa, const vil_image_view< bT > &imB, scaleT fb)
imA = fa*imA + fb*imB (Useful for moving averages!).
Definition: vil_math.h:1060
Functor class to scale by s and translate (offset) by t.
Definition: vil_math.h:477
T r
Definition: vil_rgb.h:58
Representation of a generic image source or destination.
void vil_math_median(imT &median, const vil_image_view< imT > &im, unsigned p)
Median of elements in plane p of an image.
Definition: vil_math.h:282
double operator()(double x) const
Definition: vil_math.h:509
vil_math_scale_functor(double s)
Definition: vil_math.h:463
int operator()(int x) const
Definition: vil_math.h:418
unsigned operator()(unsigned x) const
Definition: vil_math.h:487
double operator()(double x) const
Definition: vil_math.h:421
void vil_math_sum_sqr(const vil_image_view< srcT > &src, vil_image_view< destT > &dest)
Computes sum of squares of each pixel over the planes of src image.
Definition: vil_math.h:658
void vil_math_image_difference(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< sumT > &im_sum)
Compute difference of two images (im_sum = imA-imB).
Definition: vil_math.h:890
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.
void vil_math_value_range(const vil_image_view< T > &view, T &min_value, T &max_value)
Compute minimum and maximum values over view.
Definition: vil_math.h:28
short operator()(short x) const
Definition: vil_math.h:488
void vil_math_rss(const vil_image_view< srcT > &src, vil_image_view< destT > &dest)
Computes Root Sum of Squares of each pixel over the planes of src image.
Definition: vil_math.h:608
This is the appropriate pixel type for 24-bit colour images.
Definition: vil_fwd.h:14
vil_math_scale_and_translate_functor(const double s, const double t)
Constructor.
Definition: vil_math.h:483
void vil_math_mean_and_variance(sumT &mean, sumT &var, const vil_image_view< imT > &im, unsigned p)
Mean and variance of elements in plane p of image.
Definition: vil_math.h:350
void vil_math_sum_squares(sumT &sum, sumT &sum_sq, const vil_image_view< imT > &im, unsigned p)
Sum of squares of elements in plane p of image.
Definition: vil_math.h:297