00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef IMAGE_MATHOPS_C_DEFINED
00037 #define IMAGE_MATHOPS_C_DEFINED
00038
00039 #include "Image/MathOps.H"
00040
00041
00042
00043
00044 #include "Image/Image.H"
00045 #include "Image/Pixels.H"
00046 #include "Image/Range.H"
00047 #include "Image/MatrixOps.H"
00048 #include "Image/CutPaste.H"
00049 #include "Image/FourierEngine.H"
00050 #include "Util/Assert.H"
00051 #include "Util/MathFunctions.H"
00052 #include "Util/safecopy.H"
00053 #include "Util/FileUtil.H"
00054 #include "rutz/trace.h"
00055
00056 #include <algorithm>
00057 #include <cmath>
00058 #include <climits>
00059 #include <cfloat>
00060 #include <numeric>
00061
00062 #if defined(INVT_USE_MMX) || defined(INVT_USE_SSE) || defined(INVT_USE_SSE2)
00063 #include "Util/mmx-sse.H"
00064 #endif
00065
00066
00067 template <class T>
00068 double sum(const Image<T>& a)
00069 {
00070 GVX_TRACE(__PRETTY_FUNCTION__);
00071 return std::accumulate(a.begin(), a.end(), 0.0);
00072 }
00073
00074
00075
00076 #ifdef INVT_USE_SSE
00077 double sum(const Image<double> &a)
00078 {
00079 double d;
00080 sse_sum((const double *)(a.begin()), &d, a.getSize());
00081 return d;
00082 }
00083 #endif
00084 #ifdef INVT_USE_SSE2
00085 double sum(const Image<float> &a)
00086 {
00087 double d;
00088 sse2_sum((const float *)(a.begin()), &d, a.getSize());
00089 return d;
00090 }
00091
00092 double sum(const Image<int> &a)
00093 {
00094 double d;
00095 sse2_sum((const int *)(a.begin()), &d, a.getSize());
00096 return d;
00097 }
00098
00099 double sum(const Image<byte> &a)
00100 {
00101 double d;
00102 sse2_sum((const byte *)(a.begin()), &d, a.getSize());
00103 return d;
00104 }
00105 #endif
00106
00107
00108
00109 template <class T>
00110 double mean(const Image<T>& a)
00111 {
00112 GVX_TRACE(__PRETTY_FUNCTION__);
00113 ASSERT(a.getSize() > 0);
00114 return sum(a) / double(a.getSize());
00115 }
00116
00117
00118 template<class T>
00119 double stdev(const Image<T>& a)
00120 {
00121 GVX_TRACE(__PRETTY_FUNCTION__);
00122 ASSERT(a.getSize() > 1);
00123
00124 typename Image<T>::const_iterator aptr = a.begin(), stop = a.end();
00125
00126 double sum = 0.0;
00127 double avg = mean(a);
00128
00129 while (aptr != stop)
00130 {
00131 double val = ((double)(*aptr++)) - avg;
00132 sum += val * val;
00133 }
00134 return sqrt(sum / ((double)(a.getSize() - 1)));
00135 }
00136
00137
00138 template <class T>
00139 Range<T> rangeOf(const Image<T>& img)
00140 {
00141 GVX_TRACE(__PRETTY_FUNCTION__);
00142 return std::for_each(img.begin(), img.end(), Range<T>());
00143 }
00144
00145
00146 template <class T>
00147 Image<T> remapRange(const Image<T>& img,
00148 const Range<T>& from, const Range<T>& to)
00149 {
00150 GVX_TRACE(__PRETTY_FUNCTION__);
00151 Image<T> result(img.getDims(), NO_INIT);
00152
00153 typename Image<T>::const_iterator sptr = img.begin();
00154 typename Image<T>::iterator dptr = result.beginw(), stop = result.endw();
00155
00156 double scale = double(to.range()) / double(from.range());
00157
00158 while (dptr != stop)
00159 {
00160 *dptr = to.min() + T((*sptr - from.min()) * scale);
00161 ++sptr; ++dptr;
00162 }
00163
00164 return result;
00165 }
00166
00167
00168 template <class T>
00169 Image<T> squared(const Image<T>& a)
00170 {
00171 GVX_TRACE(__PRETTY_FUNCTION__);
00172 Image<T> result(a.getDims(), NO_INIT);
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 typename Image<T>::const_iterator sptr = a.begin();
00183 typename Image<T>::iterator dptr = result.beginw();
00184 typename Image<T>::iterator stop = result.endw();
00185
00186 while (dptr != stop)
00187 {
00188 *dptr++ = (*sptr) * (*sptr);
00189 ++sptr;
00190 }
00191 return result;
00192 }
00193
00194 namespace
00195 {
00196 template <class T>
00197 struct ToPow
00198 {
00199 double pp;
00200 ToPow(double p) : pp(p) {}
00201 T operator()(T x) { return clamped_convert<T>(pow(x, pp)); }
00202 };
00203
00204 template <class T>
00205 struct EpsInv
00206 {
00207 double ee;
00208 EpsInv(T e) : ee(e) {}
00209 T operator()(T x) {
00210 if (fabs(x) > ee) return clamped_convert<T>(1.0F / x);
00211 else return T();
00212 }
00213 };
00214 }
00215
00216
00217 template <class T>
00218 Image<typename promote_trait<T,float>::TP>
00219 toPower(const Image<T>& a, double pow)
00220 {
00221 GVX_TRACE(__PRETTY_FUNCTION__);
00222 Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
00223 std::transform(a.begin(), a.end(), result.beginw(), ToPow<T>(pow));
00224 return result;
00225 }
00226
00227
00228 template <class T>
00229 Image<typename promote_trait<T,float>::TP>
00230 toPowerRegion(const Image<T>& a, double pwr, std::vector<Point2D<int> > region)
00231 {
00232 GVX_TRACE(__PRETTY_FUNCTION__);
00233
00234 Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
00235 result = a;
00236 Point2D<int> temp;
00237 typename std::vector<Point2D<int> >::iterator vptr = region.begin();
00238 while(vptr!=region.end())
00239 {
00240 temp = *vptr++;
00241 result.setVal(temp,pow(result.getVal(temp),pwr));
00242 }
00243
00244 return result;
00245 }
00246
00247
00248 namespace
00249 {
00250 template <class T> inline T abs_helper(const T& x)
00251 { return (x > 0) ? x : -x; }
00252 }
00253
00254 template <class T>
00255 Image<T> abs(const Image<T>& a)
00256 {
00257 GVX_TRACE(__PRETTY_FUNCTION__);
00258 Image<T> result(a.getDims(), NO_INIT);
00259 std::transform(a.begin(), a.end(), result.beginw(), abs_helper<T>);
00260 return result;
00261 }
00262
00263
00264 template <class T>
00265 Image<typename promote_trait<T,float>::TP>
00266 hmaxActivation(const Image<T>& a, const float sigma)
00267 {
00268 GVX_TRACE(__PRETTY_FUNCTION__);
00269 typedef typename promote_trait<T, float>::TP TF;
00270 Image<TF> result(a.getDims(), NO_INIT);
00271 float sq = 0.5F / (sigma * sigma);
00272 int siz = a.getSize();
00273 typename Image<T>::const_iterator sptr = a.begin();
00274 typename Image<TF>::iterator dptr = result.beginw();
00275
00276 for (int i = 0; i < siz; i ++)
00277 *dptr++ = clamped_convert<TF>(exp((*sptr++) * sq));
00278
00279 return result;
00280 }
00281
00282
00283 namespace
00284 {
00285 template <class T>
00286 inline T scalarAbsDiff(const T& t1,
00287 const T& t2)
00288 {
00289 if (t1 < t2) return T(t2 - t1);
00290 else return T(t1 - t2);
00291 }
00292
00293 template <class T>
00294 inline PixRGB<T> scalarAbsDiff(const PixRGB<T>& t1,
00295 const PixRGB<T>& t2)
00296 {
00297 return PixRGB<T>(scalarAbsDiff(t1.p[0], t2.p[0]),
00298 scalarAbsDiff(t1.p[1], t2.p[1]),
00299 scalarAbsDiff(t1.p[2], t2.p[2]));
00300 }
00301 }
00302
00303 template <class T>
00304 Image<T> absDiff(const Image<T>& b, const Image<T>& c)
00305 {
00306 GVX_TRACE(__PRETTY_FUNCTION__);
00307 ASSERT(c.isSameSize(b));
00308
00309 Image<T> result(b.getDims(), NO_INIT);
00310
00311 typename Image<T>::const_iterator bptr = b.begin();
00312 typename Image<T>::const_iterator cptr = c.begin();
00313 typename Image<T>::iterator dptr = result.beginw();
00314 typename Image<T>::iterator stop = result.endw();
00315
00316 while (dptr != stop)
00317 *dptr++ = scalarAbsDiff(*bptr++, *cptr++);
00318
00319 return result;
00320 }
00321
00322
00323
00324 #ifdef INVT_USE_SSE2
00325 Image<byte> absDiff(const Image<byte>& b, const Image<byte> &c)
00326 {
00327 Image<byte> result(b.getDims(), NO_INIT);
00328 sse2_absDiff((const byte *)(b.begin()),(const byte *)(c.begin()),
00329 (byte *)(result.beginw()), b.getSize());
00330 return result;
00331 }
00332
00333 Image<float> absDiff(const Image<float>& b, const Image<float> &c)
00334 {
00335 Image<float> result(b.getDims(), NO_INIT);
00336 sse2_absDiff((const float *)(b.begin()),(float *)(c.begin()),(float *)
00337 (result.beginw()), b.getSize());
00338 return result;
00339 }
00340
00341 Image<int> absDiff(const Image<int>& b, const Image<int> &c)
00342 {
00343 Image<int> result(b.getDims(), NO_INIT);
00344 sse2_absDiff((const int *)(b.begin()),(const int *)(c.begin()),
00345 (int *)(result.beginw()), b.getSize());
00346 return result;
00347 }
00348 #endif
00349 #ifdef INVT_USE_SSE
00350 Image<double> absDiff(const Image<double>& b, const Image<double> &c)
00351 {
00352 Image<double> result(b.getDims(), NO_INIT);
00353 sse_absDiff((const double *)(b.begin()),(double *)(c.begin()),
00354 (double *)(result.beginw()), b.getSize());
00355 return result;
00356 }
00357 #endif
00358
00359
00360
00361 namespace
00362 {
00363 template <class T>
00364 inline T scalarClampedDiff(const T& t1,
00365 const T& t2)
00366 {
00367 if (t1 < t2) return T(0);
00368 else return T(t1 - t2);
00369 }
00370
00371 template <class T>
00372 inline PixRGB<T> scalarClampedDiff(const PixRGB<T>& t1,
00373 const PixRGB<T>& t2)
00374 {
00375 return PixRGB<T>(scalarClampedDiff(t1.p[0], t2.p[0]),
00376 scalarClampedDiff(t1.p[1], t2.p[1]),
00377 scalarClampedDiff(t1.p[2], t2.p[2]));
00378 }
00379 }
00380
00381 template <class T>
00382 Image<T> clampedDiff(const Image<T>& b, const Image<T>& c)
00383 {
00384 GVX_TRACE(__PRETTY_FUNCTION__);
00385 ASSERT(c.isSameSize(b));
00386
00387 Image<T> result(b.getDims(), NO_INIT);
00388
00389 typename Image<T>::const_iterator bptr = b.begin();
00390 typename Image<T>::const_iterator cptr = c.begin();
00391 typename Image<T>::iterator dptr = result.beginw();
00392 typename Image<T>::iterator stop = result.endw();
00393
00394 while (dptr != stop)
00395 *dptr++ = scalarClampedDiff(*bptr++, *cptr++);
00396
00397 return result;
00398 }
00399
00400 #ifdef INVT_USE_SSE
00401
00402
00403
00404 Image<float> clampedDiff(const Image<float>& b, const Image<float>& c)
00405 {
00406 GVX_TRACE(__PRETTY_FUNCTION__);
00407 ASSERT(c.isSameSize(b));
00408
00409 Image<float> result(b.getDims(), NO_INIT);
00410
00411 const float *bptr= b.begin();
00412 const float *cptr= c.begin();
00413
00414 sse_clampedDiff(bptr, cptr,
00415 (float *) (result.beginw()), b.getSize());
00416
00417 return result;
00418 }
00419
00420
00421
00422
00423 Image<byte> clampedDiff(const Image<byte>& b, const Image<byte>& c)
00424 {
00425 GVX_TRACE(__PRETTY_FUNCTION__);
00426 ASSERT(c.isSameSize(b));
00427
00428 Image<byte> result(b.getDims(), NO_INIT);
00429
00430 const byte *aptr = (const_cast <byte *> (b.begin()));
00431 const byte *bptr = (const_cast <byte *> (c.begin()));
00432 byte *dptr= (const_cast <byte *> (result.beginw()));
00433
00434 sse_clampedDiff( aptr, bptr, dptr, b.getSize());
00435
00436 return result;
00437 }
00438
00439
00440
00441 Image<int> clampedDiff(const Image<int>& b, const Image<int>& c)
00442 {
00443 GVX_TRACE(__PRETTY_FUNCTION__);
00444 ASSERT(c.isSameSize(b));
00445
00446 Image<int> result(b.getDims(), NO_INIT);
00447
00448 const int *bptr = (const_cast <int *> (b.begin()));
00449 const int *cptr = (const_cast <int *> (c.begin()));
00450 int *dptr = (const_cast <int *> (result.beginw()));
00451
00452 sse_clampedDiff(bptr, cptr, dptr, b.getSize());
00453
00454 return result;
00455 }
00456
00457
00458 #endif
00459
00460
00461 template <class T>
00462 Image<T> binaryReverse(const Image<T>& a, const T val)
00463 {
00464 GVX_TRACE(__PRETTY_FUNCTION__);
00465 Image<T> result(a.getDims(), NO_INIT);
00466
00467 typename Image<T>::const_iterator aptr = a.begin();
00468 typename Image<T>::iterator dptr = result.beginw();
00469 typename Image<T>::iterator stop = result.endw();
00470 while (dptr != stop)
00471 {
00472 *dptr++ = val - *aptr++;
00473 }
00474
00475 return result;
00476 }
00477
00478
00479 template <class T>
00480 Image<T> average(const Image<T>& b, const Image<T>& c)
00481 {
00482 GVX_TRACE(__PRETTY_FUNCTION__);
00483 ASSERT(b.isSameSize(c));
00484 Image<T> result(b.getDims(), NO_INIT);
00485 typename Image<T>::iterator aptr = result.beginw();
00486 typename Image<T>::iterator stop = result.endw();
00487 typename Image<T>::const_iterator bptr = b.begin();
00488 typename Image<T>::const_iterator cptr = c.begin();
00489
00490 while (aptr != stop)
00491 *aptr++ = (T)( (*bptr++ * 0.5F) + (*cptr++ * 0.5F) );
00492
00493 return result;
00494 }
00495
00496
00497
00498 template <class T>
00499 Image<T> averageWeighted(Image<T>& a, const Image<T>& b, T *aWeight)
00500 {
00501 GVX_TRACE(__PRETTY_FUNCTION__);
00502 ASSERT(a.isSameSize(b));
00503 typename Image<T>::iterator aptr;
00504 typename Image<T>::const_iterator bptr = b.begin();
00505 for(aptr = a.beginw(); aptr != a.endw(); ++aptr, ++bptr)
00506 *aptr = (((*aptr)*(*aWeight))+(*bptr))/(1+(*aWeight));
00507 return a;
00508 }
00509
00510 namespace
00511 {
00512 template <class T>
00513 T element_wise_max(const T& t1, const T& t2)
00514 {
00515 return std::max(t1, t2);
00516 }
00517
00518 template <class T>
00519 PixRGB<T> element_wise_max(const PixRGB<T>& t1,
00520 const PixRGB<T>& t2)
00521 {
00522 return PixRGB<T>(std::max(t1.red(), t2.red()),
00523 std::max(t1.green(), t2.green()),
00524 std::max(t1.blue(), t2.blue()));
00525 }
00526 }
00527
00528
00529 template <class T>
00530 Image<T> takeMax(const Image<T>& a, const Image<T>& b)
00531 {
00532 GVX_TRACE(__PRETTY_FUNCTION__);
00533 ASSERT(a.isSameSize(b));
00534
00535 Image<T> result(a.getDims(), NO_INIT);
00536
00537 typename Image<T>::const_iterator aptr = a.begin();
00538 typename Image<T>::const_iterator bptr = b.begin();
00539 typename Image<T>::iterator dptr = result.beginw();
00540 typename Image<T>::iterator stop = result.endw();
00541
00542 while (dptr != stop)
00543 {
00544 *dptr++ = element_wise_max(*aptr++, *bptr++);
00545 }
00546
00547 return result;
00548 }
00549
00550
00551
00552 template <class T>
00553 void takeLinkedMax(const Image<T>& a1, const Image<T>& a2, const Image<T>& b1, const Image<T>& b2, Image<T>& aout, Image<T>& bout)
00554 {
00555 GVX_TRACE(__PRETTY_FUNCTION__);
00556 ASSERT(a1.isSameSize(a2));
00557 ASSERT(b1.isSameSize(b2));
00558 ASSERT(a1.isSameSize(aout));
00559 ASSERT(aout.isSameSize(bout));
00560 ASSERT(a1.isSameSize(b1));
00561
00562 typename Image<T>::const_iterator a1ptr = a1.begin();
00563 typename Image<T>::const_iterator a2ptr = a2.begin();
00564 typename Image<T>::const_iterator b1ptr = b1.begin();
00565 typename Image<T>::const_iterator b2ptr = b2.begin();
00566 typename Image<T>::iterator aoutptr = aout.beginw(), stop = aout.endw();
00567 typename Image<T>::iterator boutptr = bout.beginw();
00568
00569 while (aoutptr != stop)
00570 {
00571 if(*a1ptr > *a2ptr)
00572 {
00573 *aoutptr=*a1ptr;
00574 *boutptr=*b1ptr;
00575 }
00576 else
00577 {
00578 *aoutptr=*a2ptr;
00579 *boutptr=*b2ptr;
00580 }
00581 a1ptr++; a2ptr++;
00582 b1ptr++; b2ptr++;
00583 aoutptr++; boutptr++;
00584 }
00585
00586 }
00587
00588
00589
00590
00591 template <class T>
00592 Image<T> takeMin(const Image<T>& a, const Image<T>& b)
00593 {
00594 GVX_TRACE(__PRETTY_FUNCTION__);
00595 ASSERT(a.isSameSize(b));
00596
00597 Image<T> result(a.getDims(), NO_INIT);
00598
00599 typename Image<T>::const_iterator aptr = a.begin();
00600 typename Image<T>::const_iterator bptr = b.begin();
00601 typename Image<T>::iterator dptr = result.beginw();
00602 typename Image<T>::iterator stop = result.endw();
00603
00604 while (dptr != stop)
00605 {
00606 *dptr++ = std::min(*aptr++, *bptr++);
00607 }
00608
00609 return result;
00610 }
00611
00612
00613 template <class T>
00614 Image<T> quadEnergy(const Image<T>& img1, const Image<T>& img2)
00615 {
00616 GVX_TRACE(__PRETTY_FUNCTION__);
00617 ASSERT(img1.isSameSize(img2));
00618
00619 Image<T> result(img1.getDims(), NO_INIT);
00620
00621 typename Image<T>::const_iterator s1ptr = img1.begin();
00622 typename Image<T>::const_iterator s2ptr = img2.begin();
00623 typename Image<T>::iterator dptr = result.beginw();
00624 typename Image<T>::iterator stop = result.endw();
00625 typedef typename promote_trait<T, float>::TP TF;
00626 while (dptr != stop)
00627 {
00628 const TF s1( *s1ptr++ );
00629 const TF s2( *s2ptr++ );
00630 *dptr++ = T(sqrt(s1 * s1 + s2 * s2));
00631 }
00632
00633 return result;
00634 }
00635
00636
00637 template <class T>
00638 double RMSerr(const Image<T>& arr1, const Image<T>& arr2)
00639 {
00640 GVX_TRACE(__PRETTY_FUNCTION__);
00641 ASSERT(arr1.initialized() && arr2.initialized());
00642 ASSERT(arr1.isSameSize(arr2));
00643
00644 typename Image<T>::const_iterator ap1 = arr1.begin();
00645 typename Image<T>::const_iterator ap2 = arr2.begin();
00646 typename Image<T>::const_iterator stop2 = arr2.end();
00647
00648 double err = 0.0f;
00649 while (ap2 != stop2)
00650 { double v = *ap1++ - *ap2++; err += v * v; }
00651 return sqrt(err / double(arr1.getSize()));
00652 }
00653
00654
00655 template <class T>
00656 Image<T> overlay(const Image<T>& top, const Image<T>& bottom,
00657 const float trans)
00658 {
00659 GVX_TRACE(__PRETTY_FUNCTION__);
00660
00661 ASSERT((trans >= 0.0F) && (trans <= 100.0F));
00662
00663 ASSERT(top.isSameSize(bottom));
00664
00665
00666 Image<T> result(top.getDims(), NO_INIT);
00667
00668 typename Image<T>::const_iterator tptr = top.begin();
00669 typename Image<T>::const_iterator bptr = bottom.begin();
00670 typename Image<T>::iterator dptr = result.beginw();
00671 typename Image<T>::iterator stop = result.endw();
00672 float tfac = trans * 0.01F;
00673 while (dptr != stop)
00674 {
00675 *dptr = T((*tptr) - ( (*tptr) - (*bptr) ) * tfac);
00676 ++dptr; ++bptr; ++tptr;
00677 }
00678
00679 return result;
00680 }
00681
00682
00683 template <class T>
00684 float sumXY(const Image<T>& img, std::vector<float>& sumX,
00685 std::vector<float>& sumY)
00686 {
00687 GVX_TRACE(__PRETTY_FUNCTION__);
00688 int w = img.getWidth(), h = img.getHeight();
00689 sumX.resize(w,0.0F);
00690 sumY.resize(h,0.0F);
00691 std::vector<float>::iterator sX, sY = sumY.begin();
00692 float sum = 0.0F;
00693 typename Image<T>::const_iterator ptr = img.begin();
00694 for (int y = 0; y < h; y++)
00695 {
00696 sX = sumX.begin();
00697 for (int x = 0; x < w; x++)
00698 {
00699
00700
00701 *sX += (float)*ptr;
00702 *sY += (float)*ptr;
00703 sum += (float)*ptr++;
00704 ++sX;
00705 }
00706 ++sY;
00707 }
00708
00709 return sum;
00710 }
00711
00712
00713 template <class T>
00714 double distance(const Image<T> &img1, const Image<T> &img2)
00715 {
00716 GVX_TRACE(__PRETTY_FUNCTION__);
00717 ASSERT(img1.isSameSize(img2));
00718 double d = 0.0;
00719 typename Image<T>::const_iterator ptr1 = img1.begin(),
00720 ptr2 = img2.begin(), e = img1.end();
00721 while(ptr1 != e) {
00722 d += (*ptr1 - *ptr2) * (*ptr1 - *ptr2);
00723 ptr1 ++; ptr2 ++;
00724 }
00725 return sqrt(d);
00726 }
00727
00728
00729 template <class T>
00730 double distance(const Image<T> &img1, const Image<T> &img2,
00731 const Image<float> &weight)
00732 {
00733 GVX_TRACE(__PRETTY_FUNCTION__);
00734 ASSERT(img1.isSameSize(img2) && img1.isSameSize(weight));
00735
00736 double d = 0.0;
00737 typename Image<T>::const_iterator ptr1 = img1.begin(),
00738 ptr2 = img2.begin(), e = img1.end();
00739 Image<float>::const_iterator w = weight.begin();
00740
00741 while(ptr1 != e) {
00742 d += *w * (*ptr1 - *ptr2) * (*ptr1 - *ptr2);
00743 ptr1 ++; ptr2 ++; w ++;
00744 }
00745 return sqrt(d);
00746 }
00747
00748
00749 double corrcoef(const Image<float>& img1, const Image<float>& img2)
00750 {
00751 GVX_TRACE(__PRETTY_FUNCTION__);
00752 ASSERT(img1.initialized());
00753 ASSERT(img2.initialized());
00754 ASSERT(img1.isSameSize(img2));
00755
00756 Image<float>::const_iterator p1 = img1.begin();
00757 Image<float>::const_iterator p2 = img2.begin();
00758 const Image<float>::const_iterator stop1 = img1.end();
00759
00760 double sum1 = 0.0;
00761 double sum2 = 0.0;
00762
00763 double sumsq1 = 0.0;
00764 double sumsq2 = 0.0;
00765
00766 double sumprod = 0.0;
00767
00768 while (p1 != stop1)
00769 {
00770 sum1 += (*p1);
00771 sum2 += (*p2);
00772 sumsq1 += double(*p1) * double(*p1);
00773 sumsq2 += double(*p2) * double(*p2);
00774 sumprod += double(*p1) * double(*p2);
00775
00776 ++p1;
00777 ++p2;
00778 }
00779
00780 const int n = img1.getSize();
00781
00782 const double avg1 = sum1 / n;
00783 const double avg2 = sum2 / n;
00784
00785 const double rsq =
00786 ((sumsq1 - n*avg1*avg1) != 0.0 && (sumsq2 - n*avg2*avg2) != 0.0)
00787 ? (squareOf(sumprod - n*avg1*avg2)
00788 /
00789 ( (sumsq1 - n*avg1*avg1) * (sumsq2 - n*avg2*avg2) ))
00790 : 0.0;
00791
00792 ASSERT(rsq >= 0.0);
00793
00794
00795
00796 ASSERT(rsq-1.0 < 1.0e-5);
00797
00798 return rsq;
00799 }
00800
00801
00802 template <class T>
00803 double corrpatch(const Image<T>& img1, const Point2D<int>& topleft1,
00804 const Dims& patchdims, const Image<T>& img2,
00805 const Point2D<int>& topleft2, const double eps)
00806 {
00807 GVX_TRACE(__PRETTY_FUNCTION__);
00808
00809 if (patchdims.sz() == 0) return 0.0;
00810 ASSERT(img1.rectangleOk(Rectangle(topleft1, patchdims)));
00811 ASSERT(img2.rectangleOk(Rectangle(topleft2, patchdims)));
00812
00813 const int pw = patchdims.w(), ph = patchdims.h();
00814 const int i1w = img1.getWidth(), i2w = img2.getWidth();
00815
00816 typename Image<T>::const_iterator p1 = img1.begin() + topleft1.j * i1w + topleft1.i;
00817 typename Image<T>::const_iterator p2 = img2.begin() + topleft2.j * i2w + topleft2.i;
00818 const int stride1 = i1w - pw, stride2 = i2w - pw;
00819
00820 double sum1 = 0.0, sum2 = 0.0, sumsq1 = 0.0, sumsq2 = 0.0, sumprod = 0.0;
00821
00822 for (int j = 0; j < ph; j ++)
00823 {
00824 for (int i = 0; i < pw; i ++)
00825 {
00826 const double val1 = double(*p1++), val2 = (*p2++);
00827
00828 sum1 += val1;
00829 sum2 += val2;
00830 sumsq1 += val1 * val1;
00831 sumsq2 += val2 * val2;
00832 sumprod += val1 * val2;
00833 }
00834
00835
00836 p1 += stride1; p2 += stride2;
00837 }
00838
00839 const double n = double(pw * ph);
00840 const double avg1 = sum1 / n, avg2 = sum2 / n;
00841
00842 const double denom1 = sumsq1 - n * avg1 * avg1;
00843 const double denom2 = sumsq2 - n * avg2 * avg2;
00844
00845 if (fabs(denom1) < eps || fabs(denom2) < eps)
00846 {
00847 if (fabs(denom1) < eps && fabs(denom2) < eps) return 1.0;
00848 return 0.0;
00849 }
00850
00851 return (sumprod - n * avg1 * avg2) / sqrt(denom1 * denom2);
00852 }
00853
00854
00855 template <class T>
00856 void corrEigenMatrix(const std::vector<std::vector<Image<T> > > &baseImages,
00857 Image<T> &baseCorr, Image<T> &baseMean,
00858 Image<T> &baseSTD, Image<T> &baseSS,
00859 uint &baseN, bool returnR = false)
00860 {
00861
00862
00863 const ushort baseDim = baseImages[0].size();
00864
00865 baseMean.resize(baseDim,1);
00866 baseSS.resize(baseDim,1);
00867 baseSTD.resize(baseDim,1);
00868 baseCorr.resize(baseDim,baseDim);
00869
00870 for(ushort i = 0; i < baseDim; i++)
00871 {
00872 baseMean.setVal(i,0,0.0);
00873 baseSS.setVal(i,0,0.0);
00874 baseSTD.setVal(i,0,0.0);
00875 for(ushort j = 0; j < baseDim; j++)
00876 {
00877 baseCorr.setVal(i,j,0.0);
00878 }
00879 }
00880
00881 baseN = 0;
00882
00883 typename std::vector<std::vector<Image<T> > >::const_iterator ibaseImages
00884 = baseImages.begin();
00885
00886
00887
00888 LINFO("Getting base stats");
00889
00890
00891 while(ibaseImages != baseImages.end())
00892 {
00893 typename std::vector<Image<T> >::const_iterator iibaseImages
00894 = ibaseImages->begin();
00895 typename Image<T>::iterator ibaseMean = baseMean.beginw();
00896 typename Image<T>::iterator ibaseSS = baseSS.beginw();
00897 typename Image<T>::iterator ibaseSTD = baseSTD.beginw();
00898
00899 baseN += iibaseImages->getHeight() * iibaseImages->getWidth();
00900
00901
00902 while(iibaseImages != ibaseImages->end())
00903 {
00904 typename Image<T>::const_iterator iiibaseImages = iibaseImages->begin();
00905
00906
00907 while(iiibaseImages != iibaseImages->end())
00908 {
00909 *ibaseSS += static_cast<T>(pow(*iiibaseImages,2));
00910 *ibaseMean += *iiibaseImages;
00911 ++iiibaseImages;
00912 }
00913 ++iibaseImages;
00914 ++ibaseMean; ++ibaseSS; ++ibaseSTD;
00915 }
00916 ++ibaseImages;
00917 }
00918
00919 LINFO("Getting final base stats");
00920
00921 typename Image<T>::iterator ibaseMean = baseMean.beginw();
00922 typename Image<T>::iterator ibaseSS = baseSS.beginw();
00923 typename Image<T>::iterator ibaseSTD = baseSTD.beginw();
00924
00925 while(ibaseMean != baseMean.endw())
00926 {
00927 if((baseN > 0) && (*ibaseSS > 0))
00928 {
00929
00930 *ibaseMean = *ibaseMean/baseN;
00931
00932 *ibaseSTD = static_cast<T>(sqrt((*ibaseSS/baseN) - pow(*ibaseMean,2)));
00933 }
00934 else
00935 {
00936 *ibaseMean = 0;
00937 *ibaseSTD = 0;
00938 }
00939 ++ibaseMean; ++baseN; ++ibaseSS; ++ibaseSTD;
00940 }
00941
00942 ibaseImages = baseImages.begin();
00943
00944
00945
00946 LINFO("computing product covariance");
00947
00948
00949 while(ibaseImages != baseImages.end())
00950 {
00951 typename std::vector<Image<T> >::const_iterator iibaseImages
00952 = ibaseImages->begin();
00953
00954 for(ushort i = 0; i < baseDim; i++, ++iibaseImages)
00955 {
00956
00957 for(int x = 0; x < iibaseImages->getWidth(); x++)
00958 {
00959 for(int y = 0; y < iibaseImages->getHeight(); y++)
00960 {
00961 const T base = iibaseImages->getVal(x,y);
00962 typename std::vector<Image<T> >::const_iterator iicbaseImages
00963 = ibaseImages->begin();
00964
00965 for(ushort j = 0; j < baseDim; j++, ++iicbaseImages)
00966 {
00967
00968 T corrVal = baseCorr.getVal(i,j);
00969 corrVal += base * iicbaseImages->getVal(x,y);
00970 baseCorr.setVal(i,j,corrVal);
00971 }
00972 }
00973 }
00974 }
00975 ++ibaseImages;
00976 }
00977
00978 LINFO("Computing final covariance");
00979
00980
00981 if(returnR)
00982 {
00983
00984 for(uint i = 0; i < baseDim; i++)
00985 {
00986 for(uint j = 0; j < baseDim; j++)
00987 {
00988
00989 T val = baseCorr.getVal(i,j);
00990 val = ((val/baseN) - (baseMean[i] * baseMean[j])) /
00991 (baseSTD[i] * baseSTD[j]);
00992 baseCorr.setVal(i,j,val);
00993 }
00994 }
00995 }
00996 else
00997 {
00998
00999
01000 for(uint i = 0; i < baseDim; i++)
01001 {
01002 for(uint j = 0; j < baseDim; j++)
01003 {
01004 T val = baseCorr.getVal(i,j);
01005
01006 val = (val/baseN) - (baseMean[i] * baseMean[j]);
01007 baseCorr.setVal(i,j,val);
01008 }
01009 }
01010 }
01011 }
01012
01013
01014 template <class T>
01015 void getLikelyhoodImage(const std::vector<Image<T> > &baseImages,
01016 const Image<T> &baseCorr, const Image<T> &baseMean,
01017 const bool returnLogLikelyhood,
01018 Image<T> &likelyhoodImage,
01019 Image<T> &nonNormalizedLImage)
01020 {
01021
01022 if(baseCorr.getWidth() != baseCorr.getHeight())
01023 LFATAL("ERROR matrix is not square %d x %d",
01024 baseCorr.getWidth(),baseCorr.getHeight());
01025
01026
01027
01028
01029 const Image<T> invCorr = matrixInv(baseCorr);
01030
01031
01032
01033
01034
01035
01036
01037 T logDetCorr = 0;
01038 for(ushort i = 0; i < (ushort)baseCorr.getWidth(); i++)
01039 {
01040
01041 logDetCorr += static_cast<T>(log(1.0/sqrt((2.0*M_PI)*baseCorr.getVal(i,i))));
01042
01043 }
01044
01045
01046
01047 const T LHS = static_cast<T>(logDetCorr);
01048
01049
01050
01051 likelyhoodImage.resize(baseImages[0].getWidth(),
01052 baseImages[0].getHeight());
01053
01054 nonNormalizedLImage.resize(baseImages[0].getWidth(),
01055 baseImages[0].getHeight());
01056
01057
01058 Image<T> diffMatrix;
01059 diffMatrix.resize(1,baseCorr.getWidth());
01060
01061 for(uint i = 0; i < (uint)baseImages[0].getWidth(); i++)
01062 {
01063 for(uint j = 0; j < (uint)baseImages[0].getHeight(); j++)
01064 {
01065
01066 typename Image<T>::iterator idiffMatrix =
01067 diffMatrix.beginw();
01068 typename Image<T>::const_iterator ibaseMean =
01069 baseMean.begin();
01070 typename std::vector<Image<T> >::const_iterator ibaseImages =
01071 baseImages.begin();
01072
01073 while(ibaseImages != baseImages.end())
01074 {
01075
01076 *idiffMatrix = ibaseImages->getVal(i,j) - *ibaseMean;
01077 ++ibaseImages; ++ibaseMean; ++idiffMatrix;
01078 }
01079
01080 const T RHS = static_cast<T>(sum(matrixMult(
01081 clamped_convert<Image<T> >
01082 (vmMult(transpose(diffMatrix),invCorr))
01083 ,diffMatrix)));
01084
01085 const T newRHS = static_cast<T>((-1.0/2.0) * RHS);
01086
01087
01088
01089
01090 if(returnLogLikelyhood)
01091 {
01092 nonNormalizedLImage.setVal(i,j,newRHS);
01093 const T Px = static_cast<T>(LHS + newRHS);
01094 likelyhoodImage.setVal(i,j,Px);
01095 }
01096 else
01097 {
01098 nonNormalizedLImage.setVal(i,j,exp(newRHS));
01099 const T Px = static_cast<T>(exp(LHS + newRHS));
01100 likelyhoodImage.setVal(i,j,Px);
01101 }
01102 }
01103 }
01104 }
01105
01106
01107 template <class T>
01108 Image<T> getNormalizedBayesImage(const Image<T> classImage1,
01109 const Image<T> classImage2,
01110 const bool usingLogLikelyhood,
01111 const T beta,
01112 const T classPrior1,
01113 const T classPrior2,
01114 const T bias)
01115 {
01116 if(classImage1.getHeight() != classImage2.getHeight())
01117 LFATAL("classImage1 height %d != classImage2 height %d",
01118 classImage1.getHeight(),classImage2.getHeight());
01119 if(classImage1.getWidth() != classImage2.getWidth())
01120 LFATAL("classImage1 width %d != classImage2 width %d",
01121 classImage1.getWidth(),classImage2.getWidth());
01122 Image<T> returnImage;
01123 returnImage.resize(classImage1.getWidth(),
01124 classImage1.getHeight());
01125
01126 typename Image<T>::iterator ireturnImage = returnImage.beginw();
01127 typename Image<T>::const_iterator iclassImage1 = classImage1.begin();
01128 typename Image<T>::const_iterator iclassImage2 = classImage2.begin();
01129
01130 if(usingLogLikelyhood)
01131 {
01132 while(ireturnImage != returnImage.end())
01133 {
01134 const T a = static_cast<T>(*iclassImage1 - *iclassImage2 +
01135 log(classPrior1/classPrior2));
01136 *ireturnImage = static_cast<T>((1.0/(1.0 + exp(-1.0*a*beta))) * bias);
01137 ++ireturnImage; ++iclassImage1; ++iclassImage2;
01138 }
01139 }
01140 else
01141 {
01142 while(ireturnImage != returnImage.end())
01143 {
01144 const T a = static_cast<T>(log(((*iclassImage1)*classPrior1)/
01145 (*iclassImage2)*classPrior2));
01146 *ireturnImage = static_cast<T>((1.0/(1.0 + exp(-1.0*a*beta))) * bias);
01147 ++ireturnImage; ++iclassImage1; ++iclassImage2;
01148 }
01149 }
01150
01151 return returnImage;
01152 }
01153
01154
01155 template <class T>
01156 Image<T> getPearsonRMatrix(const Image<T> &eigenMatrix,
01157 const Image<T> &STDMatrix)
01158 {
01159 if(eigenMatrix.getWidth() != eigenMatrix.getHeight())
01160 LFATAL("eigenMatrix not square width %d != height %d",
01161 eigenMatrix.getWidth(),eigenMatrix.getHeight());
01162
01163 uint baseDim = eigenMatrix.getWidth();
01164
01165 Image<T> returnImage;
01166 returnImage.resize(eigenMatrix.getWidth(),eigenMatrix.getHeight());
01167
01168
01169 for(uint i = 0; i < baseDim; i++)
01170 {
01171 for(uint j = 0; j < baseDim; j++)
01172 {
01173
01174
01175 T val = eigenMatrix.getVal(i,j);
01176 val = val / (STDMatrix[i] * STDMatrix[j]);
01177 returnImage.setVal(i,j,val);
01178 }
01179 }
01180 return returnImage;
01181 }
01182
01183
01184 template <class T>
01185 void getAugmentedBeliefBayesImage(const Image<T> &bayesImage,
01186 const Image<T> &beliefImage1,
01187 const Image<T> &beliefImage2,
01188 const T medianPoint,
01189 Image<T> &beliefImage,
01190 Image<T> &beliefValue)
01191 {
01192 beliefImage.resize(bayesImage.getWidth(), bayesImage.getHeight());
01193 beliefValue.resize(bayesImage.getWidth(), bayesImage.getHeight());
01194
01195 typename Image<T>::const_iterator ibayesImage = bayesImage.begin();
01196 typename Image<T>::const_iterator ibeliefImage1 = beliefImage1.begin();
01197 typename Image<T>::const_iterator ibeliefImage2 = beliefImage2.begin();
01198 typename Image<T>::iterator ibeliefImage = beliefImage.beginw();
01199 typename Image<T>::iterator ibeliefValue = beliefValue.beginw();
01200
01201 float min = FLT_MAX;
01202 float max = FLT_MIN;
01203
01204
01205 while(ibeliefValue != beliefValue.endw())
01206 {
01207 *ibeliefValue = static_cast<T>(*ibeliefImage1 + *ibeliefImage2);
01208 if(*ibeliefValue > max)
01209 max = static_cast<float>(*ibeliefValue);
01210 if(*ibeliefValue < min)
01211 min = static_cast<float>(*ibeliefValue);
01212 ++ibeliefImage1; ++ibeliefImage2; ++ibeliefValue;
01213 }
01214
01215 ibeliefValue = beliefValue.beginw();
01216
01217 const T interval = static_cast<T>(max - min);
01218 const T minT = static_cast<T>(min);
01219
01220 while(ibeliefValue != beliefValue.endw())
01221 {
01222 *ibeliefValue = static_cast<T>(exp(((*ibeliefValue - minT)/interval)-1));
01223 ++ibeliefValue;
01224 }
01225 ibeliefImage1 = beliefImage1.begin();
01226 ibeliefImage2 = beliefImage2.begin();
01227 ibeliefValue = beliefValue.beginw();
01228
01229 while(ibayesImage != bayesImage.end())
01230 {
01231 const T diff = static_cast<T>(
01232 fabs(static_cast<float>(*ibayesImage - medianPoint)));
01233 const T aug = diff * *ibeliefValue;
01234
01235 if(*ibayesImage >= medianPoint)
01236 *ibeliefImage = medianPoint + aug;
01237 else
01238 *ibeliefImage = medianPoint - aug;
01239
01240 ++ibayesImage; ++ibeliefImage1; ++ibeliefImage2; ++ibeliefImage;
01241 ++ibeliefValue;
01242 }
01243 }
01244
01245
01246 template <class T>
01247 double pSNR(const Image<T> &img1, const Image<T> &img2)
01248 {
01249 GVX_TRACE(__PRETTY_FUNCTION__);
01250 double sigma2 = distance(img1, img2);
01251 sigma2 = sigma2 * sigma2 / double(img1.getSize());
01252 return 10.0 * log10(255.0*255.0 / sigma2);
01253 }
01254
01255
01256 template <class T>
01257 double pSNR(const Image<T> &img1, const Image<T> &img2,
01258 const Image<float>& weight)
01259 {
01260 GVX_TRACE(__PRETTY_FUNCTION__);
01261 double sigma2 = distance(img1, img2, weight);
01262 sigma2 = sigma2 * sigma2 / double(img1.getSize());
01263 return 10.0 * log10(255.0*255.0 / sigma2);
01264 }
01265
01266
01267 template <class T>
01268 Image<typename promote_trait<T,float>::TP> sqrt(const Image<T>& a)
01269 {
01270 GVX_TRACE(__PRETTY_FUNCTION__);
01271 Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01272 typename Image<T>::const_iterator src = a.begin(), stop = a.end();
01273 typename Image<typename promote_trait<T,float>::TP>::iterator
01274 dest = result.beginw();
01275 while(src != stop) *dest++ = sqrt(*src++);
01276 return result;
01277 }
01278
01279
01280 template <class T>
01281 Image<typename promote_trait<T,float>::TP> inverse(const Image<T>& a,
01282 const T eps)
01283 {
01284 GVX_TRACE(__PRETTY_FUNCTION__);
01285 Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01286 std::transform(a.begin(), a.end(), result.beginw(), EpsInv<T>(eps));
01287 return result;
01288 }
01289
01290
01291 template <class T>
01292 Image<typename promote_trait<T,float>::TP> exp(const Image<T>& a)
01293 {
01294 GVX_TRACE(__PRETTY_FUNCTION__);
01295 Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01296 typename Image<T>::const_iterator src = a.begin(), stop = a.end();
01297 typename Image<typename promote_trait<T,float>::TP>::iterator
01298 dest = result.beginw();
01299 while(src != stop) *dest++ = exp(*src++);
01300 return result;
01301 }
01302
01303
01304 template <class T>
01305 Image<typename promote_trait<T,float>::TP> negexp(const Image<T>& a)
01306 {
01307 GVX_TRACE(__PRETTY_FUNCTION__);
01308 Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01309 typename Image<T>::const_iterator src = a.begin(), stop = a.end();
01310 typename Image<typename promote_trait<T,float>::TP>::iterator
01311 dest = result.beginw();
01312 while(src != stop) *dest++ = exp( - (*src++));
01313 return result;
01314 }
01315
01316
01317 template <class T>
01318 Image<typename promote_trait<T,float>::TP> log(const Image<T>& src)
01319 {
01320 GVX_TRACE(__PRETTY_FUNCTION__);
01321 typedef typename promote_trait<T,float>::TP TF;
01322 Image<TF> result(src.getDims(), NO_INIT);
01323 typename Image<T>::const_iterator sptr = src.begin();
01324 typename Image<TF>::iterator dptr = result.beginw();
01325 typename Image<TF>::iterator stop = result.endw();
01326
01327 while (dptr != stop)
01328 *dptr++ = log(*sptr++);
01329
01330 return result;
01331 }
01332
01333
01334 template <class T>
01335 Image<typename promote_trait<T,float>::TP> log10(const Image<T>& src)
01336 {
01337 GVX_TRACE(__PRETTY_FUNCTION__);
01338 typedef typename promote_trait<T,float>::TP TF;
01339 Image<TF> result(src.getDims(), NO_INIT);
01340 typename Image<T>::const_iterator sptr = src.begin();
01341 typename Image<TF>::iterator dptr = result.beginw();
01342 typename Image<TF>::iterator stop = result.endw();
01343
01344 while (dptr != stop)
01345 *dptr++ = log10(*sptr++);
01346
01347 return result;
01348 }
01349
01350
01351 template <class T>
01352 bool getCentroidFirstLast(std::vector<T> vect, float& centroid,
01353 int& first, int& last)
01354 {
01355 GVX_TRACE(__PRETTY_FUNCTION__);
01356 double sum = 0.0;
01357 double mi = 0.0;
01358 bool before = true;
01359 const T zero = T();
01360
01361 typename std::vector<T>::iterator vit = vect.begin();
01362
01363 for (uint i = 0; i < vect.size(); ++i, ++vit)
01364 {
01365
01366 mi += (*vit * i);
01367 sum += *vit;
01368 if (before) first = i;
01369 if (*vit != zero)
01370 {
01371 before = false;
01372 last = i;
01373 }
01374 }
01375
01376
01377 if (before)
01378 {
01379 centroid = -1.0F; first = -1; last = -1;
01380 return false;
01381 }
01382
01383 if (sum == 0.0)
01384 LFATAL("The sum of non-zero numbers is zero - don't know how "
01385 "to compute the center of mass in this case.");
01386
01387 centroid = mi / sum;
01388 return true;
01389 }
01390
01391
01392 template <class T>
01393 Point2D<int> centroid(const Image<T>& img, Rectangle& boundingBox,
01394 float& cenX, float& cenY)
01395 {
01396 GVX_TRACE(__PRETTY_FUNCTION__);
01397 std::vector<float> sumx, sumy;
01398 sumXY(img, sumx, sumy);
01399 int firstX, lastX, firstY, lastY;
01400 cenX = 0.0F; cenY = 0.0F;
01401
01402 bool success = getCentroidFirstLast(sumx, cenX, firstX, lastX);
01403 success |= getCentroidFirstLast(sumy, cenY, firstY, lastY);
01404
01405 if (!success)
01406 {
01407 boundingBox = Rectangle();
01408 return Point2D<int>(-1,-1);
01409 }
01410
01411 boundingBox = Rectangle::tlbrI(firstY, firstX, lastY, lastX);
01412 return Point2D<int>(int(cenX + 0.5F), int(cenY + 0.5F));
01413 }
01414
01415
01416 template <class T>
01417 Point2D<int> centroid(const Image<T>& img)
01418 {
01419 GVX_TRACE(__PRETTY_FUNCTION__);
01420 Rectangle boundingBox;
01421 float cenX, cenY;
01422 return centroid(img, boundingBox, cenX, cenY);
01423 }
01424
01425
01426 template<class T>
01427 Image<T> squash(const Image<T>& ima,
01428 const T oldmin, const T newmin,
01429 const T oldmid, const T newmid,
01430 const T oldmax, const T newmax)
01431 {
01432 GVX_TRACE(__PRETTY_FUNCTION__);
01433
01434 if (oldmin == oldmax) return ima;
01435
01436
01437
01438 float a = float(oldmin), b = float(oldmid), c = float(oldmax);
01439 float d = float(newmin), e = float(newmid), f = float(newmax);
01440
01441
01442
01443
01444
01445 float q0 = c*c*(b*(b-c)*(b-c)*(-4.0F*a*a + 3.0F*a*b + 2.0F*a*c - b*c)*d +
01446 a*a*(a-c)*(a-c)*(a-c)*e) + a*a*(a-b)*(a-b)*b*
01447 (a*(b-2.0F*c) + c*(-3.0F*b + 4.0F*c))*f;
01448 float q1 = 2.0F*a*c*(c*c*c*c*(e-d) - 3.0F*b*b*b*b*(d-f) +
01449 4.0F*b*b*b*c*(d-f) + 2.0F*a*a*a*c*(e-f) + a*a*a*a*(f-e)+
01450 2.0F*a*(c*c*c*(d-e) + 2.0F*b*b*b*(d-f) +
01451 3.0F*b*b*c*(f-d)));
01452 float q2 = a*a*a*a*a*(e-f) + a*a*a*a*c*(e-f) + 8.0F*a*a*a*c*c*(f-e) +
01453 (a+c)*(c*c*c*c*(d-e) + 3.0F*b*b*b*b*(d-f) + 4.0F*b*b*b*c*(f-d)) -
01454 4.0F*a*a*(2.0F*c*c*c*(d-e) + b*b*b*(d-f) + 3.0F*b*c*c*(f-d));
01455 float q3 = 2.0F*(c*c*c*c*(e-d) + 2.0F*a*a*(b-c)*(b-c)*(d-f) +
01456 2.0F*b*b*c*c*(d-f) + 2.0F*a*a*a*c*(e-f) +
01457 b*b*b*b*(f-d) + a*a*a*a*(f-e) +
01458 2.0F*a*c*(c*c*(d-e) + b*b*(d-f) + 2.0F*b*c*(f-d)));
01459 float q4 = -3.0F*a*b*b*d + 2.0F*b*b*b*d + 6.0F*a*b*c*d - 3.0F*b*b*c*d -
01460 3.0F*a*c*c*d + c*c*c*d + a*a*a*e - 3.0F*a*a*c*e + 3.0F*a*c*c*e -
01461 c*c*c*e - (a-b)*(a-b)*(a + 2.0F*b - 3.0F*c)*f;
01462
01463 float denom = (a-b)*(a-b)*(a-c)*(a-c)*(a-c)*(b-c)*(b-c);
01464 if (fabs(denom) < 1.0e-5F)
01465 { LERROR("Zero denominator - cannot remap - RETURNING INPUT"); return ima;}
01466 q0 /= denom; q1 /= denom; q2 /= denom; q3 /= denom; q4 /= denom;
01467
01468 Image<T> result(ima.getDims(), NO_INIT);
01469 typename Image<T>::const_iterator src = ima.begin(), stop = ima.end();
01470 typename Image<T>::iterator dest = result.beginw();
01471 while(src != stop) {
01472 float val = float(*src++);
01473
01474 val = q0 + val*(q1 + val*(q2 + val*(q3 + val*q4)));
01475 *dest++ = clamped_convert<T>(val);
01476 }
01477 return result;
01478 }
01479
01480
01481 template<class T>
01482 Image<T> squash(const Image<T>& src, const T newmin,
01483 const T oldmid, const T newmid, const T newmax)
01484 {
01485 GVX_TRACE(__PRETTY_FUNCTION__);
01486
01487 T oldmin, oldmax; getMinMax(src, oldmin, oldmax);
01488
01489
01490 return squash(src, oldmin, newmin, oldmid, newmid, oldmax, newmax);
01491 }
01492
01493
01494 template<class T>
01495 Image<T> squash(const Image<T>& src, const T oldmid, const T newmid)
01496 {
01497 GVX_TRACE(__PRETTY_FUNCTION__);
01498
01499 T oldmin, oldmax; getMinMax(src, oldmin, oldmax);
01500
01501
01502 return squash(src, oldmin, oldmin, oldmid, newmid, oldmax, oldmax);
01503 }
01504
01505
01506 template <class T, class TT>
01507 Image<TT> thresholdedMix(const Image<T>& mask, const T& thresh,
01508 const Image<TT>& lower, const Image<TT>& higher)
01509 {
01510 GVX_TRACE(__PRETTY_FUNCTION__);
01511 ASSERT(mask.isSameSize(lower) && mask.isSameSize(higher));
01512
01513 Image<TT> result(mask.getDims(), NO_INIT);
01514 typename Image<T>::const_iterator msrc = mask.begin(), mstop = mask.end();
01515 typename Image<TT>::const_iterator
01516 lsrc = lower.begin(), hsrc = higher.begin();
01517 typename Image<TT>::iterator dest = result.beginw();
01518
01519 while(msrc != mstop) {
01520 if (*msrc >= thresh) *dest = *hsrc; else *dest = *lsrc;
01521 msrc ++; lsrc++; hsrc++; dest ++;
01522 }
01523
01524 return result;
01525 }
01526
01527
01528 Image<float> logSig(const Image<float>& ima, float o, float b)
01529 {
01530 GVX_TRACE(__PRETTY_FUNCTION__);
01531 Image<float> result(ima.getDims(), NO_INIT);
01532 Image<float>::const_iterator ptr = ima.begin();
01533 Image<float>::iterator res = result.beginw();
01534 Image<float>::iterator stop = result.endw();
01535 for ( ; res != stop; ++ptr, ++res)
01536 *res = 1.0f / (1.0f + expf(b*(o-*ptr)));
01537 return result;
01538 }
01539
01540
01541 template <class T>
01542 Image<T> scramble(const Image<T>& ima)
01543 {
01544 GVX_TRACE(__PRETTY_FUNCTION__);
01545 const int siz = ima.getSize(); ASSERT(siz > 0);
01546 Image<T> result = ima; typename Image<T>::iterator a = result.beginw();
01547
01548
01549 for (int i = 0; i < siz; i ++)
01550 {
01551 T tmp = a[i];
01552 int idx = i + randomUpToNotIncluding(siz - i);
01553 a[i] = a[idx]; a[idx] = tmp;
01554 }
01555
01556 return result;
01557 }
01558
01559
01560 int32 findMonteMap(Image<float>& ima,
01561 std::vector<Point2D<int> >* coords,
01562 int decimation, float bias = 1.0F)
01563 {
01564 GVX_TRACE(__PRETTY_FUNCTION__);
01565 const unsigned int siz = (unsigned)ima.getSize(); ASSERT(siz > 0);
01566 std::vector<Point2D<int> >::iterator itr;
01567 ASSERT(siz <= coords->size());
01568 Image<float>::iterator a = ima.beginw();
01569
01570 float minVal = *a;
01571 float maxVal = 0;
01572
01573
01574
01575 if(bias != 1.0F)
01576 for(a = ima.beginw(); a != ima.endw(); ++a)
01577 {
01578 *a = *a * *a;
01579
01580 }
01581
01582 for(a = ima.beginw(); a != ima.endw(); ++a)
01583 {
01584 if(*a > maxVal)
01585 maxVal = *a;
01586 if(*a < minVal)
01587 minVal = *a;
01588 }
01589
01590 a = ima.beginw();
01591 itr = coords->begin();
01592 int32 counter = 0;
01593 float salVal = 0.0F;
01594
01595
01596
01597 for (unsigned int i = 0; i < siz; i ++)
01598 {
01599
01600 salVal = ((minVal)+((maxVal)*rand()/(RAND_MAX+1.0)));
01601
01602
01603 if(*a > salVal)
01604 {
01605 *itr = Point2D<int>(i % ima.getWidth(), i/ima.getWidth());
01606 ++itr;
01607 counter++;
01608 }
01609 ++a;
01610 }
01611
01612 return counter;
01613 }
01614
01615
01616 int32 makeSparceMap(std::vector<Point2D<int> >* coords, std::vector<Point2D<int>*>* cmap,
01617 std::vector<Point2D<int> >* Oldcoords,
01618 std::vector<bool>* keep, int inPoints, int outPoints)
01619 {
01620 GVX_TRACE(__PRETTY_FUNCTION__);
01621 ASSERT(coords->size() >= cmap->size());
01622 std::vector<Point2D<int>*>::iterator icmap;
01623 std::vector<Point2D<int> >::iterator icoords;
01624 std::vector<Point2D<int> >::iterator iOldcoords;
01625 std::vector<bool>::iterator ikeep;
01626 int interval = inPoints/(outPoints+1);
01627 int mod = 0;
01628 int count = 0;
01629 icoords = coords->begin();
01630 iOldcoords = Oldcoords->begin();
01631 icmap = cmap->begin();
01632 ikeep = keep->begin();
01633 for(int i = 0; i < inPoints; i++)
01634 {
01635 if(mod == 0)
01636 {
01637 if(*ikeep == false)
01638 *icmap = &*icoords;
01639 else
01640 *icmap = &*iOldcoords;
01641 ++icmap;
01642 ++ikeep;
01643 ++iOldcoords;
01644 count++;
01645 }
01646 else
01647 {
01648 if(mod == interval)
01649 mod = -1;
01650 }
01651 mod++;
01652 ++icoords;
01653 }
01654 return count;
01655 }
01656
01657
01658 int32 makeCoordArray(std::vector<Point2D<int> >* coords, unsigned int initX, unsigned int initY, unsigned int sizeX, unsigned int sizeY)
01659 {
01660 GVX_TRACE(__PRETTY_FUNCTION__);
01661 coords->resize(initX*initY);
01662 std::vector<Point2D<int> >::iterator icoords = coords->begin();
01663 float scaleX = sizeX / initX;
01664 float scaleY = sizeY / initY;
01665 for(unsigned int i = 0; i < initX; i++)
01666 {
01667 for(unsigned int j = 0; j < initY; j++)
01668 {
01669 icoords->i = (int)(i*scaleX);
01670 icoords->j = (int)(j*scaleY);
01671 }
01672 }
01673 return initX*initY;
01674 }
01675
01676
01677 template <class T>
01678 void inplaceAddWeighted(Image<T>& a,
01679 const Image<T>& b, const float coeff)
01680 {
01681 GVX_TRACE(__PRETTY_FUNCTION__);
01682 ASSERT(b.initialized());
01683 if (a.initialized())
01684 {
01685 ASSERT(a.isSameSize(b));
01686 typename Image<T>::iterator aptr = a.beginw();
01687 typename Image<T>::const_iterator bptr = b.begin();
01688 typename Image<T>::const_iterator stop = b.end();
01689
01690 while (bptr != stop)
01691 *aptr++ += (T)(*bptr++ * coeff);
01692 }
01693 else
01694 {
01695 a = Image<T>(b.getDims(), NO_INIT);
01696 typename Image<T>::iterator aptr = a.beginw();
01697 typename Image<T>::const_iterator bptr = b.begin();
01698 typename Image<T>::const_iterator stop = b.end();
01699
01700 while (bptr != stop)
01701 *aptr++ = (T)(*bptr++ * coeff);
01702 }
01703 }
01704
01705
01706 template <class T>
01707 void inplaceSquare(Image<T>& a)
01708 {
01709 GVX_TRACE(__PRETTY_FUNCTION__);
01710 typename Image<T>::iterator aptr = a.beginw();
01711 typename Image<T>::iterator stop = a.endw();
01712 while (aptr != stop)
01713 {
01714 (*aptr) *= (*aptr);
01715
01716
01717
01718
01719
01720 ++aptr;
01721 }
01722 }
01723
01724
01725 void inplaceReplaceVal(Image<byte>& dest,
01726 const byte& from, const byte& to)
01727 {
01728 GVX_TRACE(__PRETTY_FUNCTION__);
01729 Image<byte>::iterator
01730 aptr = dest.beginw(),
01731 endptr = dest.endw();
01732
01733 while (aptr != endptr)
01734 {
01735 if (*aptr == from) *aptr = to;
01736 ++aptr;
01737 }
01738 }
01739
01740
01741 template <class T>
01742 void inplaceAttenuateBorders(Image<T>& a, int size)
01743 {
01744 GVX_TRACE(__PRETTY_FUNCTION__);
01745 ASSERT(a.initialized());
01746
01747 Dims dims = a.getDims();
01748
01749 if (size * 2 > dims.w()) size = dims.w() / 2;
01750 if (size * 2 > dims.h()) size = dims.h() / 2;
01751 if (size < 1) return;
01752
01753 float increment = 1.0 / (float)(size + 1);
01754
01755 float coeff = increment;
01756 typename Image<T>::iterator aptr = a.beginw();
01757 for (int y = 0; y < size; y ++)
01758 {
01759 for (int x = 0; x < dims.w(); x ++)
01760 {
01761 *aptr = (T)( (*aptr) * coeff );
01762 ++aptr;
01763 }
01764 coeff += increment;
01765 }
01766
01767 aptr = a.beginw();
01768 for (int y = 0; y < dims.h(); y ++)
01769 {
01770 coeff = increment;
01771 for (int x = 0; x < size; x ++)
01772 {
01773 *(aptr + dims.w() - 1 - x * 2) =
01774 (T)(*(aptr + dims.w() - 1 - x * 2) * coeff);
01775
01776 *aptr = (T)( (*aptr) * coeff );
01777 ++aptr;
01778 coeff += increment;
01779 }
01780 aptr += dims.w() - size;
01781 }
01782
01783 aptr = a.beginw() + (dims.h() - size) * dims.w();
01784 coeff = increment * (float)size;
01785 for (int y = dims.h() - size; y < dims.h(); y ++)
01786 {
01787 for (int x = 0; x < dims.w(); ++x)
01788 {
01789 *aptr = (T)( (*aptr) * coeff );
01790 ++aptr;
01791 }
01792 coeff -= increment;
01793 }
01794 }
01795
01796
01797 template <class T>
01798 void inplaceSetBorders(Image<T>& a,
01799 const int size, const T value)
01800 {
01801 GVX_TRACE(__PRETTY_FUNCTION__);
01802 ASSERT(a.initialized());
01803 int siz = size;
01804 if (size * 2 > a.getWidth()) siz = a.getWidth() / 2;
01805 if (size * 2 > a.getHeight()) siz = a.getHeight() / 2;
01806 if (siz < 1) return;
01807
01808 typename Image<T>::iterator const data = a.beginw();
01809
01810
01811 for (int i = 0; i < a.getWidth(); ++i)
01812 data[i] = value;
01813
01814
01815 for (int y = 1; y < siz; ++y)
01816 safecopy(data + (y * a.getWidth()),
01817 data,
01818 a.getWidth());
01819
01820
01821 for (int y = siz; y < a.getHeight() - siz; ++y)
01822 {
01823 typename Image<T>::iterator aptr = data + (y * a.getWidth());
01824 for (int x = 0; x < siz; ++x)
01825 {
01826 aptr[x] = value;
01827 aptr[a.getWidth() - 1 - x] = value;
01828 }
01829 }
01830
01831
01832 safecopy(data + (a.getHeight() - siz) * a.getWidth(),
01833 data,
01834 siz * a.getWidth());
01835 }
01836
01837
01838 void inplaceSpeckleNoise(Image<byte>& dest,
01839 const float thresh, const int size,
01840 const byte noise_color, bool random_color)
01841 {
01842 GVX_TRACE(__PRETTY_FUNCTION__);
01843 ASSERT(dest.initialized()); ASSERT(size >= 1);
01844
01845 if (random_color)
01846 {
01847 for (int j = 0; j <= dest.getHeight() - size; j += size)
01848 for (int i = 0; i <= dest.getWidth() - size; i += size)
01849 if (randomDouble() < thresh) {
01850 byte rcol = clamped_convert<byte>(noise_color * randomDouble());
01851 for (int k = j; k < j + size; k ++)
01852 for (int l = i; l < i + size; l ++)
01853 dest.setVal(l, k, rcol);
01854 }
01855 }
01856 else
01857 {
01858 for (int j = 0; j <= dest.getHeight() - size; j += size)
01859 for (int i = 0; i <= dest.getWidth() - size; i += size)
01860 if (randomDouble() < thresh)
01861 for (int k = j; k < j + size; k ++)
01862 for (int l = i; l < i + size; l ++)
01863 dest.setVal(l, k, noise_color);
01864 }
01865 }
01866
01867
01868 template <class T>
01869 Image<typename promote_trait<T,float>::TP>
01870 addPowerNoise(const Image<T>& src, double beta)
01871 {
01872
01873
01874
01875
01876
01877 typedef std::complex<float> complexf;
01878
01879 int inputW = src.getWidth(), inputH = src.getHeight();
01880 const int N = inputW > inputH ? inputW : inputH;
01881
01882
01883
01884
01885 std::vector<float> xaxis(N), yaxis(N), u(N*N), v(N*N);
01886 int crnt = 0;
01887 for(int i = 0; i < N; i++)
01888 {
01889 xaxis[i] = i+1;
01890 if(i < N/2)
01891 yaxis[i] = i+1;
01892 else
01893 yaxis[i] = i-N;
01894 }
01895
01896 for(int i=0; i<N; i++)
01897 for(int j=0; j<N; j++)
01898 {
01899 u[crnt] = xaxis[j];
01900 v[crnt] = yaxis[i];
01901 crnt++;
01902 }
01903
01904 Image<complexf> tempCmplxImg(N,N,NO_INIT);
01905 typename Image<complexf>::iterator cmplxItr = tempCmplxImg.beginw();
01906 float spectrum, phi;
01907 srand(time(NULL));
01908 for(int i=0; i < N*N; i++)
01909 {
01910 spectrum = pow((u[i]*u[i]) + (v[i]*v[i]),beta);
01911
01912 phi = 2*M_PI*((double)rand()/((double)(RAND_MAX)+(double)(1)) );
01913 *cmplxItr++ = complexf(pow(spectrum,0.5),0.0) *
01914 complexf(cos(phi),sin(phi));
01915 }
01916
01917 FourierInvEngine<double> ieng(Dims(2*N-1, N));
01918 const Image<double> fullImg = ieng.ifft(tempCmplxImg);
01919
01920
01921 Image<typename promote_trait<T, double>::TP> mask = crop(fullImg,Point2D<int>(0,0),Dims(inputW,inputH));
01922
01923 return src + mask;
01924 }
01925
01926
01927 float getLocalMax(const Image<float>& src,
01928 const Point2D<int>& center, const int radius)
01929 {
01930 GVX_TRACE(__PRETTY_FUNCTION__);
01931 ASSERT(src.initialized());
01932 float val = src.getVal(center);
01933 const int r2 = radius * radius, ci = center.i, cj = center.j;
01934 for (int y = -radius; y <= radius; y ++)
01935 {
01936 int bound = int(sqrtf(float(r2 - y*y)));
01937 int sj = y + cj;
01938 for (int x = -bound; x <= bound; x ++)
01939 {
01940 int si = x + ci;
01941 if (src.coordsOk(si, sj))
01942 { float v = src.getVal(si, sj); if (v > val) val = v; }
01943 }
01944 }
01945 return val;
01946 }
01947
01948
01949 float getLocalAvg(const Image<float>& src,
01950 const Point2D<int>& center, const int radius)
01951 {
01952 GVX_TRACE(__PRETTY_FUNCTION__);
01953 ASSERT(src.initialized());
01954 float val = src.getVal(center);
01955 int count = 0;
01956 const int r2 = radius * radius, ci = center.i, cj = center.j;
01957 for (int y = -radius; y <= radius; y ++)
01958 {
01959 int bound = int(sqrtf(float(r2 - y*y)));
01960 int sj = y + cj;
01961 for (int x = -bound; x <= bound; x ++)
01962 {
01963 int si = x + ci;
01964 if (src.coordsOk(si, sj))
01965 { val += src.getVal(si, sj); ++count; }
01966 }
01967 }
01968 return count == 0? 0: val / (float)count;
01969 }
01970
01971
01972 template<class T>
01973 void getMinMax(const Image<T>& src, T& xmini, T& xmaxi)
01974 {
01975 GVX_TRACE(__PRETTY_FUNCTION__);
01976 ASSERT(src.initialized());
01977 typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
01978 xmini = *aptr; xmaxi = *aptr++;
01979 while (aptr != stop)
01980 {
01981 if (*aptr < xmini) xmini = *aptr;
01982 else if (*aptr > xmaxi) xmaxi = *aptr;
01983 ++aptr;
01984 }
01985 }
01986
01987
01988 template <class T>
01989 void getMaskedMinMax(const Image<T>& src, const Image<byte>& mask,
01990 T& min_in, T& max_in, T& min_out, T& max_out)
01991 {
01992 GVX_TRACE(__PRETTY_FUNCTION__);
01993 ASSERT(src.initialized());
01994 ASSERT(mask.initialized());
01995 ASSERT(src.isSameSize(mask));
01996
01997 typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
01998 Image<byte>::const_iterator mptr = mask.begin();
01999
02000
02001
02002
02003
02004
02005
02006 if (*mptr++) {
02007
02008 min_in = *aptr; max_in = *aptr++;
02009 while (aptr != stop)
02010 {
02011 if (*mptr++) {
02012 if (*aptr < min_in) min_in = *aptr;
02013 else if (*aptr > max_in) max_in = *aptr;
02014 } else {
02015 min_out = *aptr; max_out = *aptr++; break;
02016 }
02017 ++aptr;
02018 }
02019 } else {
02020
02021 min_out = *aptr; max_out = *aptr++;
02022 while (aptr != stop)
02023 {
02024 if (*mptr++) {
02025 min_in = *aptr; max_in = *aptr++; break;
02026 } else {
02027 if (*aptr < min_out) min_out = *aptr;
02028 else if (*aptr > max_out) max_out = *aptr;
02029 }
02030 ++aptr;
02031 }
02032 }
02033
02034
02035
02036
02037 while (aptr != stop)
02038 {
02039 if (*mptr++) {
02040 if (*aptr < min_in) min_in = *aptr;
02041 else if (*aptr > max_in) max_in = *aptr;
02042 } else {
02043 if (*aptr < min_out) min_out = *aptr;
02044 else if (*aptr > max_out) max_out = *aptr;
02045 }
02046 ++aptr;
02047 }
02048 }
02049
02050
02051 template<class T>
02052 void getMinMaxAvg(const Image<T>& src, T& xmini, T& xmaxi, T& xavg)
02053 {
02054 GVX_TRACE(__PRETTY_FUNCTION__);
02055 ASSERT(src.initialized());
02056 typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02057 double avg = 0.0;
02058 xmini = *aptr; xmaxi = *aptr++;
02059 while (aptr != stop)
02060 {
02061 if (*aptr < xmini) xmini = *aptr;
02062 else if (*aptr > xmaxi) xmaxi = *aptr;
02063 avg += (double)(*aptr);
02064 aptr++;
02065 }
02066 xavg = clamped_convert<T>(avg / double(src.getSize()));
02067 }
02068
02069
02070 template <class T>
02071 void getMaskedMinMaxAvg(const Image<T>& src, const Image<byte> &mask,
02072 T& mi, T& ma, T& avg)
02073 {
02074 GVX_TRACE(__PRETTY_FUNCTION__);
02075 ASSERT(src.initialized());
02076 ASSERT(src.isSameSize(mask));
02077
02078 typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02079 typename Image<byte>::const_iterator mptr = mask.begin();
02080 typedef typename promote_trait<T,T>::TP TF;
02081
02082 TF sum(0); uint area = 0;
02083
02084
02085
02086
02087 while (aptr != stop && *mptr == 0) { aptr ++; mptr ++; }
02088
02089
02090 if (aptr == stop) { mi = T(0); ma = T(0); avg = T(0); return; }
02091
02092
02093 mi = *aptr; sum = *aptr; ma = *aptr ++; mptr ++; area ++;
02094
02095
02096 while (aptr != stop) {
02097 if (*mptr) {
02098 if (*aptr < mi) mi = *aptr; else if (*aptr > ma) ma = *aptr;
02099 sum += *aptr; area ++;
02100 }
02101 aptr++; mptr++;
02102 }
02103
02104 if (area) avg = clamped_convert<T>(sum / area); else avg = T(0);
02105 }
02106
02107
02108 template <class T>
02109 void getMaskedMinMaxSumArea(const Image<T>& src, const Image<float> &mask,
02110 T& mi, T& ma,
02111 typename promote_trait<T,float>::TP &sum,
02112 typename promote_trait<T,float>::TP &area)
02113 {
02114 GVX_TRACE(__PRETTY_FUNCTION__);
02115 ASSERT(src.initialized());
02116 ASSERT(src.isSameSize(mask));
02117
02118 typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02119 typename Image<float>::const_iterator mptr = mask.begin();
02120 typedef typename promote_trait<T,float>::TP TF;
02121
02122 sum = TF(0); area = TF(0);
02123
02124
02125
02126
02127 while (aptr != stop && *mptr <= 0.0F) { aptr ++; mptr ++; }
02128
02129
02130 if (aptr == stop)
02131 { mi = T(0); ma = T(0); sum = TF(0); area = TF(0); return; }
02132
02133
02134 mi = *aptr; ma = *aptr ++; mptr ++;
02135
02136
02137 while (aptr != stop) {
02138 if (*mptr > 0.0F) {
02139 if (*aptr < mi) mi = *aptr; else if (*aptr > ma) ma = *aptr;
02140 sum += *aptr * TF(*mptr); area += TF(*mptr);
02141 }
02142 aptr++; mptr++;
02143 }
02144 }
02145
02146
02147 template<class T>
02148 void getMinMaxAvgEtc(const Image<T>& src, T& xmini, T& xmaxi, T& xavg, T& xstd,
02149 ushort& minPosX, ushort& minPosY,
02150 ushort& maxPosX, ushort& maxPosY,
02151 uint& pixCount)
02152 {
02153 GVX_TRACE(__PRETTY_FUNCTION__);
02154 ASSERT(src.initialized());
02155 typename Image<T>::const_iterator aptr = src.begin();
02156 double avg = 0.0;
02157 double ss = 0.0;
02158 pixCount = 0;
02159 const ushort width = src.getWidth();
02160 xmini = *aptr; xmaxi = *aptr++;
02161 while (aptr != src.end())
02162 {
02163 if (*aptr < xmini)
02164 {
02165 xmini = *aptr;
02166 minPosX = (ushort)(pixCount%width);
02167 minPosY = (ushort)floor(pixCount/width);
02168 }
02169 else if (*aptr > xmaxi)
02170 {
02171 xmaxi = *aptr;
02172 maxPosX = (ushort)(pixCount%width);
02173 maxPosY = (ushort)floor(pixCount/width);
02174 }
02175 avg += (double)(*aptr);
02176 ss += (double)(pow(*aptr,2));
02177 aptr++; pixCount++;
02178 }
02179 xavg = clamped_convert<T>(avg / double(src.getSize()));
02180 xstd = clamped_convert<T>(sqrt((ss/double(src.getSize())) - pow(xavg,2)));
02181 }
02182
02183
02184 template<class T>
02185 bool isFinite(const Image<T>& src)
02186 {
02187 GVX_TRACE(__PRETTY_FUNCTION__);
02188 ASSERT(src.initialized());
02189 typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02190 while (aptr != stop)
02191 {
02192 if (::isFinite(*aptr) == false) return false;
02193 aptr++;
02194 }
02195 return true;
02196 }
02197
02198
02199 template<class T>
02200 void findMax(const Image<T>& src, Point2D<int>& p, T& maxval)
02201 {
02202 GVX_TRACE(__PRETTY_FUNCTION__);
02203 ASSERT(src.initialized());
02204 typename Image<T>::const_iterator aptr = src.begin();
02205 const int w = src.getWidth(), h = src.getHeight();
02206 p.i = 0; p.j = 0; maxval = *aptr;
02207 for (int j = 0; j < h; j ++)
02208 for (int i = 0; i < w; i ++)
02209 {
02210 if (*aptr > maxval) { maxval = *aptr; p.i = i; p.j = j; }
02211 aptr++;
02212 }
02213 }
02214
02215
02216 template<class T>
02217 void findMin(const Image<T>& src, Point2D<int>& p, T& minval)
02218 {
02219 GVX_TRACE(__PRETTY_FUNCTION__);
02220 ASSERT(src.initialized());
02221 typename Image<T>::const_iterator aptr = src.begin();
02222 const int w = src.getWidth(), h = src.getHeight();
02223 p.i = 0; p.j = 0; minval = *aptr;
02224 for (int j = 0; j < h; j ++)
02225 for (int i = 0; i < w; i ++)
02226 {
02227 if (*aptr < minval) { minval = *aptr; p.i = i; p.j = j; }
02228 aptr++;
02229 }
02230 }
02231
02232
02233 template <class T>
02234 void inplaceClamp(Image<T>& dst, const T cmin, const T cmax)
02235 {
02236 GVX_TRACE(__PRETTY_FUNCTION__);
02237 typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02238 while (aptr != stop)
02239 {
02240 if (*aptr < cmin) *aptr = cmin;
02241 else if (*aptr > cmax) *aptr = cmax;
02242 ++aptr;
02243 }
02244 }
02245
02246
02247 template <class T>
02248 void inplaceNormalize(Image<T>& dst, const T nmin, const T nmax)
02249 {
02250 GVX_TRACE(__PRETTY_FUNCTION__);
02251 T oldmin, oldmax;
02252 inplaceNormalize(dst, nmin, nmax, oldmin, oldmax);
02253 }
02254
02255
02256 template <class T>
02257 void inplaceNormalize(Image<T>& dst, const T nmin, const T nmax,
02258 T& oldmin, T& oldmax)
02259 {
02260 GVX_TRACE(__PRETTY_FUNCTION__);
02261 if (!dst.initialized()) return;
02262
02263 typedef typename promote_trait<T, float>::TP TF;
02264
02265 getMinMax(dst, oldmin, oldmax);
02266
02267
02268
02269
02270
02271 if (oldmax == oldmin)
02272 {
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282 dst.clear(nmin);
02283 return;
02284 }
02285 const TF scale = TF(oldmax) - TF(oldmin);
02286 const TF nscale = (TF(nmax) - TF(nmin)) / scale;
02287
02288 typename Image<T>::iterator aptr = dst.beginw();
02289 typename Image<T>::iterator stop = dst.endw();
02290 const TF oldminf = TF(oldmin);
02291
02292 while (aptr != stop)
02293 {
02294 *aptr = nmin + T( (TF(*aptr) - oldminf) * nscale );
02295 ++aptr;
02296 }
02297 }
02298
02299
02300 template <class T>
02301 bool isLocalMax(const Image<T>& src, const Point2D<int>& p)
02302 {
02303 GVX_TRACE(__PRETTY_FUNCTION__);
02304 typename Image<T>::const_iterator sptr = src.begin();
02305 const int w = src.getWidth(), h = src.getHeight();
02306 const int i = p.i, j = p.j;
02307 sptr += i + w * j;
02308 T val = *sptr;
02309
02310 if (src.coordsOk(p) == false) return false;
02311 if (i > 0 && sptr[-1] > val) return false;
02312 if (i < w-1 && sptr[1] > val) return false;
02313 if (j > 0 && sptr[-w] > val) return false;
02314 if (j < h-1 && sptr[w] > val) return false;
02315
02316
02317 return true;
02318 }
02319
02320
02321 template <class T>
02322 void inplaceRectify(Image<T>& dst)
02323 {
02324 GVX_TRACE(__PRETTY_FUNCTION__);
02325
02326 typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02327 T zero = T();
02328 while (aptr != stop)
02329 {
02330 if (*aptr < zero) *aptr = zero;
02331 ++aptr;
02332 }
02333 }
02334
02335
02336 template <class T>
02337 void splitPosNeg(const Image<T>& src,
02338 Image<T>& pos, Image<T>& neg)
02339 {
02340 GVX_TRACE(__PRETTY_FUNCTION__);
02341 pos.resize(src.getDims(), NO_INIT);
02342 neg.resize(src.getDims(), NO_INIT);
02343 typename Image<T>::const_iterator sptr = src.begin(), stop = src.end();
02344 typename Image<T>::iterator pptr = pos.beginw(), nptr = neg.beginw();
02345
02346 T zero = T();
02347 while (sptr != stop)
02348 if (*sptr <= zero) { *nptr++ = - (*sptr++); *pptr++ = zero; }
02349 else { *nptr++ = zero; *pptr++ = *sptr++; }
02350 }
02351
02352
02353 template <class T>
02354 void inplaceLowThresh(Image<T>& dst, const T thresh, const T val)
02355 {
02356 GVX_TRACE(__PRETTY_FUNCTION__);
02357 typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02358
02359 while (aptr != stop)
02360 {
02361 if (*aptr < thresh) *aptr = val;
02362 ++aptr;
02363 }
02364 }
02365
02366
02367 template <class T>
02368 void inplaceLowThreshAbs(Image<T>& dst, const T thresh, const T val)
02369 {
02370 GVX_TRACE(__PRETTY_FUNCTION__);
02371 if (thresh <= T(0))
02372 {
02373 if (thresh == T(0))
02374
02375
02376
02377 return;
02378
02379 LERROR("With thresh = %f < 0.0, this is a no-op -- IGNORED",
02380 double(thresh));
02381 }
02382
02383 typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02384
02385 while (aptr != stop)
02386 {
02387 if (std::abs(*aptr) < thresh) *aptr = val;
02388 ++aptr;
02389 }
02390 }
02391
02392
02393 template <class T>
02394 void inplaceSigmoid(Image<T>& dst,
02395 const float g, const float h, const float s)
02396 {
02397 GVX_TRACE(__PRETTY_FUNCTION__);
02398
02399 typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02400
02401 while (aptr != stop) {
02402 T val = clamped_convert<T>(pow(*aptr, g) / (s + pow(*aptr, h)));
02403 *aptr++ = val;
02404 }
02405 }
02406
02407
02408 template <class T>
02409 int emptyArea(const Image<T>& src)
02410 {
02411 GVX_TRACE(__PRETTY_FUNCTION__);
02412 return std::count(src.begin(), src.end(), T());
02413 }
02414
02415
02416 template <class T>
02417 int countThresh(const Image<T>& src, const T thresh, const bool absol)
02418 {
02419 GVX_TRACE(__PRETTY_FUNCTION__);
02420 int nb = 0;
02421 typename Image<T>::const_iterator ap = src.begin(), stop = src.end();
02422
02423 if (absol)
02424 {
02425 float threshd = (float)thresh;
02426 while (ap != stop)
02427 {
02428 if (fabs(float(*ap)) > threshd) ++nb;
02429 ++ap;
02430 }
02431 }
02432 else
02433 {
02434 while (ap != stop)
02435 if (*ap++ > thresh) ++nb;
02436 }
02437
02438 return nb;
02439 }
02440
02441
02442 Image<float> meanRow(const Image<float>& inp)
02443 {
02444 GVX_TRACE(__PRETTY_FUNCTION__);
02445 ASSERT(inp.getHeight() > 0);
02446
02447 Image<float> result(inp.getWidth(), 1, ZEROS);
02448
02449 const int w = inp.getWidth();
02450 const int h = inp.getHeight();
02451
02452 Point2D<int> loc;
02453
02454 for (loc.j = 0; loc.j < h; ++loc.j)
02455 for (loc.i = 0; loc.i < w; ++loc.i)
02456 result[Point2D<int>(loc.i,0)] += inp[loc];
02457
02458 result /= inp.getHeight();
02459
02460 return result;
02461 }
02462
02463
02464 Image<float> stdevRow(const Image<float>& M)
02465 {
02466 GVX_TRACE(__PRETTY_FUNCTION__);
02467
02468 const Image<float> u = meanRow(M);
02469
02470 const int w = M.getWidth();
02471 const int h = M.getHeight();
02472
02473 Image<float> ssq(M.getWidth(), 1, ZEROS);
02474
02475 Image<float>::iterator const dptr = ssq.beginw();
02476 Image<float>::const_iterator const uptr = u.begin();
02477 Image<float>::const_iterator Mptr = M.begin();
02478
02479 for (int y = 0; y < h; ++y)
02480 for (int x = 0; x < w; ++x)
02481 {
02482 dptr[x] += (*Mptr - uptr[x]) * (*Mptr - uptr[x]);
02483 ++Mptr;
02484 }
02485
02486 ASSERT(h > 1);
02487 ssq /= float(h - 1);
02488
02489 return sqrt(ssq);
02490 }
02491
02492
02493 Image<float> addRow(const Image<float>& M, const Image<float>& v)
02494 {
02495 GVX_TRACE(__PRETTY_FUNCTION__);
02496
02497 ASSERT(M.getWidth() == v.getWidth());
02498 ASSERT(v.getHeight() == 1);
02499
02500 const int w = M.getWidth();
02501 const int h = M.getHeight();
02502
02503 Image<float> result(M.getDims(), NO_INIT);
02504
02505 Image<float>::iterator dptr = result.beginw();
02506 Image<float>::const_iterator Mptr = M.begin();
02507 Image<float>::const_iterator const vptr = v.begin();
02508
02509 for (int y = 0; y < h; ++y)
02510 for (int x = 0; x < w; ++x)
02511 {
02512 *dptr = (*Mptr) + vptr[x];
02513 ++dptr;
02514 ++Mptr;
02515 }
02516
02517 return result;
02518 }
02519
02520
02521 Image<float> subtractRow(const Image<float>& M, const Image<float>& v)
02522 {
02523 GVX_TRACE(__PRETTY_FUNCTION__);
02524
02525 ASSERT(M.getWidth() == v.getWidth());
02526 ASSERT(v.getHeight() == 1);
02527
02528 const int w = M.getWidth();
02529 const int h = M.getHeight();
02530
02531 Image<float> result(M.getDims(), NO_INIT);
02532
02533 Image<float>::iterator dptr = result.beginw();
02534 Image<float>::const_iterator Mptr = M.begin();
02535 Image<float>::const_iterator const vptr = v.begin();
02536
02537 for (int y = 0; y < h; ++y)
02538 for (int x = 0; x < w; ++x)
02539 {
02540 *dptr = (*Mptr) - vptr[x];
02541 ++dptr;
02542 ++Mptr;
02543 }
02544
02545 return result;
02546 }
02547
02548
02549 Image<float> multiplyRow(const Image<float>& M, const Image<float>& v)
02550 {
02551 GVX_TRACE(__PRETTY_FUNCTION__);
02552
02553 ASSERT(M.getWidth() == v.getWidth());
02554 ASSERT(v.getHeight() == 1);
02555
02556 const int w = M.getWidth();
02557 const int h = M.getHeight();
02558
02559 Image<float> result(M.getDims(), NO_INIT);
02560
02561 Image<float>::iterator dptr = result.beginw();
02562 Image<float>::const_iterator Mptr = M.begin();
02563 Image<float>::const_iterator const vptr = v.begin();
02564
02565 for (int y = 0; y < h; ++y)
02566 for (int x = 0; x < w; ++x)
02567 {
02568 *dptr = (*Mptr) * vptr[x];
02569 ++dptr;
02570 ++Mptr;
02571 }
02572
02573 return result;
02574 }
02575
02576
02577 Image<float> divideRow(const Image<float>& M, const Image<float>& v)
02578 {
02579 GVX_TRACE(__PRETTY_FUNCTION__);
02580
02581 ASSERT(M.getWidth() == v.getWidth());
02582 ASSERT(v.getHeight() == 1);
02583
02584 const int w = M.getWidth();
02585 const int h = M.getHeight();
02586
02587 Image<float> result(M.getDims(), NO_INIT);
02588
02589 Image<float>::iterator dptr = result.beginw();
02590 Image<float>::const_iterator Mptr = M.begin();
02591 Image<float>::const_iterator const vptr = v.begin();
02592
02593 for (int y = 0; y < h; ++y)
02594 for (int x = 0; x < w; ++x)
02595 {
02596 *dptr =
02597 vptr[x] == 0.0f
02598 ? 0.0f
02599 : (*Mptr) / vptr[x];
02600 ++dptr;
02601 ++Mptr;
02602 }
02603
02604 return result;
02605 }
02606
02607
02608 std::vector<Point2D<int> > approxPolyDP(std::vector<Point2D<int> >& points, float tol)
02609 {
02610
02611 std::vector<Point2D<int> > result;
02612
02613 float tol2 = tol * tol;
02614 uint i,k, pv;
02615
02616 if (points.size() < 2)
02617 return points;
02618
02619 std::vector<Point2D<int> > vt(points.size());
02620 std::vector<int> mk(points.size(), 0);
02621
02622
02623 vt[0] = points[0];
02624 for(i=k=1, pv = 0; i<points.size(); i++)
02625 {
02626 if (points[i].squdist(points[pv]) < tol2)
02627 continue;
02628 vt[k++] = points[i];
02629 pv = i;
02630 }
02631
02632
02633
02634 mk[0] = mk[k-1] = 1;
02635 recursePolyDP(tol, vt, 0, k-1, mk);
02636
02637
02638 for(i=0; i<k; i++)
02639 {
02640 if (mk[i])
02641 result.push_back(vt[i]);
02642 }
02643
02644 return result;
02645
02646 }
02647
02648 void recursePolyDP(float tol, std::vector<Point2D<int> >& v, int j, int k, std::vector<int>& mk)
02649 {
02650
02651 if (k <= j+1)
02652 return;
02653
02654
02655 int maxi = j;
02656 float maxd2 = 0;
02657 float tol2 = tol * tol;
02658
02659
02660
02661
02662 Point2D<int> SP0 = v[k];
02663 Point2D<int> SP1 = v[j];
02664 Point2D<int> u = SP1 - SP0;
02665
02666 double cu = u.i*u.i + u.j*u.j;
02667
02668
02669
02670
02671 Point2D<int> w;
02672 Point2D<int> Pb;
02673 double b, cw, dv2;
02674
02675 for (int i=j+1; i<k; i++)
02676 {
02677
02678 w = v[i] - SP0;
02679 cw = w.i*u.i + w.j*u.j;
02680 if ( cw <= 0 )
02681 dv2 = v[i].squdist(SP0);
02682 else if ( cu <= cw )
02683 dv2 = v[i].squdist(SP1);
02684 else {
02685 b = cw / cu;
02686 Pb = SP0 + Point2D<int>(int(u.i*b), int(u.j*b));
02687 dv2 = v[i].squdist(Pb);
02688 }
02689
02690 if (dv2 <= maxd2)
02691 continue;
02692
02693 maxi = i;
02694 maxd2 = dv2;
02695 }
02696 if (maxd2 > tol2)
02697 {
02698
02699 mk[maxi] = 1;
02700
02701 recursePolyDP( tol, v, j, maxi, mk );
02702 recursePolyDP( tol, v, maxi, k, mk );
02703 }
02704
02705 return;
02706 }
02707
02708
02709 namespace
02710 {
02711 const int NONE = -1;
02712
02713 typedef struct range_bin Bin;
02714 struct range_bin {
02715 int min;
02716 int max;
02717 };
02718
02719
02720 inline float
02721 isLeft( Point2D<float> P0, Point2D<float> P1, Point2D<float> P2 )
02722 {
02723 return (P1.i - P0.i)*(P2.j - P0.j) - (P2.i - P0.i)*(P1.j - P0.j);
02724 }
02725
02726 }
02727
02728 std::vector<Point2D<float> > approximateHull(std::vector<Point2D<float> > P, int accuracy)
02729 {
02730 std::vector<Point2D<float> >H(P.size());
02731 int n = P.size();
02732 int k = accuracy;
02733 int minmin=0, minmax=0;
02734 int maxmin=0, maxmax=0;
02735 float xmin = P[0].i, xmax = P[0].i;
02736 Point2D<float>* cP;
02737 int bot=0, top=(-1);
02738
02739
02740 for (int i=1; i<n; i++) {
02741 cP = &P[i];
02742 if (cP->i <= xmin) {
02743 if (cP->i < xmin) {
02744 xmin = cP->i;
02745 minmin = minmax = i;
02746 }
02747 else {
02748 if (cP->j < P[minmin].j)
02749 minmin = i;
02750 else if (cP->j > P[minmax].j)
02751 minmax = i;
02752 }
02753 }
02754 if (cP->i >= xmax) {
02755 if (cP->i > xmax) {
02756 xmax = cP->i;
02757 maxmin = maxmax = i;
02758 }
02759 else {
02760 if (cP->j < P[maxmin].j)
02761 maxmin = i;
02762 else if (cP->j > P[maxmax].j)
02763 maxmax = i;
02764 }
02765 }
02766 }
02767 if (xmin == xmax) {
02768 H[++top] = P[minmin];
02769 if (minmax != minmin)
02770 H[++top] = P[minmax];
02771 H.resize(top+1);
02772 return H;
02773 }
02774
02775
02776 Bin* B = new Bin[k+2];
02777 B[0].min = minmin; B[0].max = minmax;
02778 B[k+1].min = maxmin; B[k+1].max = maxmax;
02779 for (int b=1; b<=k; b++) {
02780 B[b].min = B[b].max = NONE;
02781 }
02782 for (int b, i=0; i<n; i++) {
02783 cP = &P[i];
02784 if (cP->i == xmin || cP->i == xmax)
02785 continue;
02786
02787 if (isLeft( P[minmin], P[maxmin], *cP) < 0) {
02788 b = (int)( k * (cP->i - xmin) / (xmax - xmin) ) + 1;
02789 if (B[b].min == NONE)
02790 B[b].min = i;
02791 else if (cP->j < P[B[b].min].j)
02792 B[b].min = i;
02793 continue;
02794 }
02795 if (isLeft( P[minmax], P[maxmax], *cP) > 0) {
02796 b = (int)( k * (cP->i - xmin) / (xmax - xmin) ) + 1;
02797 if (B[b].max == NONE)
02798 B[b].max = i;
02799 else if (cP->j > P[B[b].max].j)
02800 B[b].max = i;
02801 continue;
02802 }
02803 }
02804
02805
02806
02807
02808 for (int i=0; i <= k+1; ++i)
02809 {
02810 if (B[i].min == NONE)
02811 continue;
02812 cP = &P[ B[i].min ];
02813
02814 while (top > 0)
02815 {
02816
02817 if (isLeft( H[top-1], H[top], *cP) > 0)
02818 break;
02819 else
02820 top--;
02821 }
02822 H[++top] = *cP;
02823 }
02824
02825
02826 if (maxmax != maxmin)
02827 H[++top] = P[maxmax];
02828 bot = top;
02829 for (int i=k; i >= 0; --i)
02830 {
02831 if (B[i].max == NONE)
02832 continue;
02833 cP = &P[ B[i].max ];
02834
02835 while (top > bot)
02836 {
02837
02838 if (isLeft( H[top-1], H[top], *cP) > 0)
02839 break;
02840 else
02841 top--;
02842 }
02843 H[++top] = *cP;
02844 }
02845 if (minmax != minmin)
02846 H[++top] = P[minmin];
02847
02848 delete B;
02849 H.resize(top+1);
02850 return H;
02851 }
02852
02853
02854
02855 #include "inst/Image/MathOps.I"
02856
02857
02858 template double sum(const Image<double>&);
02859 template double mean(const Image<double>&);
02860 template double stdev(const Image<double>&);
02861 template Range<double> rangeOf(const Image<double>&);
02862 template Image<double> remapRange(const Image<double>&,
02863 const Range<double>&, const Range<double>&);
02864 template Image<double> takeMax(const Image<double>& a, const Image<double>& b);
02865 template Image<int> takeMax(const Image<int>& a, const Image<int>& b);
02866 template void findMax(const Image<double>& src, Point2D<int>& p, double& maxval);
02867 template void getMinMax<int>(const Image<int>&, int&, int&);
02868 template void getMinMax<double>(const Image<double>&, double&, double&);
02869 template void inplaceLowThresh(Image<int>& dst, const int thresh, const int val);
02870 template void inplaceLowThreshAbs(Image<int>& dst, const int thresh, const int val);
02871 template void inplaceRectify(Image<int>&);
02872 template void inplaceRectify(Image<double>&);
02873 template void inplaceClamp(Image<double>&, double, double);
02874 template Image<double> abs(const Image<double>&);
02875 template Image<double> exp(const Image<double>&);
02876 template Image<double> log(const Image<double>&);
02877 template Image<double> log10(const Image<double>&);
02878 template Image<byte> thresholdedMix(const Image<float>&,
02879 const float&,
02880 const Image<byte>&,
02881 const Image<byte>&);
02882 template Image<double> toPower(const Image<double>&, double);
02883 template Image<double> addPowerNoise(const Image<double>&, double);
02884
02885 template double RMSerr(const Image<double>&, const Image<double>&);
02886 template Image<int> absDiff(const Image<int>& b, const Image<int>& c);
02887 template void inplaceNormalize(Image<double>&, double, double);
02888 template void inplaceNormalize(Image<double>&, double, double,
02889 double&, double&);
02890
02891
02892
02893
02894
02895
02896
02897 #endif // !IMAGE_MATHOPS_C_DEFINED