00001 /*!@file Image/MathOps.C Mathematical operations on Image */ 00002 // //////////////////////////////////////////////////////////////////// // 00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00004 // University of Southern California (USC) and the iLab at USC. // 00005 // See http://iLab.usc.edu for information about this project. // 00006 // //////////////////////////////////////////////////////////////////// // 00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00009 // in Visual Environments, and Applications'' by Christof Koch and // 00010 // Laurent Itti, California Institute of Technology, 2001 (patent // 00011 // pending; application number 09/912,225 filed July 23, 2001; see // 00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00013 // //////////////////////////////////////////////////////////////////// // 00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00015 // // 00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00017 // redistribute it and/or modify it under the terms of the GNU General // 00018 // Public License as published by the Free Software Foundation; either // 00019 // version 2 of the License, or (at your option) any later version. // 00020 // // 00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00024 // PURPOSE. See the GNU General Public License for more details. // 00025 // // 00026 // You should have received a copy of the GNU General Public License // 00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00029 // Boston, MA 02111-1307 USA. // 00030 // //////////////////////////////////////////////////////////////////// // 00031 // 00032 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu> 00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/MathOps.C $ 00034 // $Id: MathOps.C 14665 2011-03-31 23:34:38Z dberg $ 00035 00036 #ifndef IMAGE_MATHOPS_C_DEFINED 00037 #define IMAGE_MATHOPS_C_DEFINED 00038 00039 #include "Image/MathOps.H" 00040 00041 // WARNING: Try not include any other "Image*Ops.H" headers here -- if 00042 // you find that you are needing such a header, then the function 00043 // you're writing probably belongs outside Image_MathOps.C. 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> // for std::accumulate(), etc. 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 // Optimized implementations using SSE2/SSE for some canonical datatypes: 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 /* This is more succinct but unfortunately does not seem to get 00175 inlined into efficient code: 00176 00177 std::transform(a.begin(), a.end(), result.beginw(), squareOf<T>); 00178 00179 so instead we use an explicit loop 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 // Optimized absDiff implementations using SSE2 for some canonical datatypes: 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 // 0 to 100 percent only: 00661 ASSERT((trans >= 0.0F) && (trans <= 100.0F)); 00662 // images must be same size: 00663 ASSERT(top.isSameSize(bottom)); 00664 00665 // result is the same size as the input images: 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 //sumX[x] += (float)*ptr; 00700 //sumY[y] += (float)*ptr; 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 // can't just do ASSERT(rsq<=1.0) because that's susceptible to 00795 // floating-point errors where rsq ends up slightly greater than 1.0 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 // switch to next row in inputs: 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 // compute mean and standard deviation over each feature type 00887 00888 LINFO("Getting base stats"); 00889 00890 // Run over each FRAME 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 // Run over each FEATURE 00902 while(iibaseImages != ibaseImages->end()) 00903 { 00904 typename Image<T>::const_iterator iiibaseImages = iibaseImages->begin(); 00905 00906 // Run over each PIXEL 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 // Run over each FEATURE 00925 while(ibaseMean != baseMean.endw()) 00926 { 00927 if((baseN > 0) && (*ibaseSS > 0)) 00928 { 00929 // mean 00930 *ibaseMean = *ibaseMean/baseN; 00931 // stddev 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 // compute product covariance 00948 // Run over each FRAME 00949 while(ibaseImages != baseImages.end()) 00950 { 00951 typename std::vector<Image<T> >::const_iterator iibaseImages 00952 = ibaseImages->begin(); 00953 // Run over each FEATURE 00954 for(ushort i = 0; i < baseDim; i++, ++iibaseImages) 00955 { 00956 // Run over each PIXEL 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 // Run over each OTHER FEATURE 00965 for(ushort j = 0; j < baseDim; j++, ++iicbaseImages) 00966 { 00967 // compute product sum over each X*Y 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 // compute final covaraince 00981 if(returnR) 00982 { 00983 // Normalized true pearson R correlation 00984 for(uint i = 0; i < baseDim; i++) 00985 { 00986 for(uint j = 0; j < baseDim; j++) 00987 { 00988 // compute (sum(X*Y)/N - Xbar*Ybar) / Xstd*Ystd 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 // Un-normalized eigen matrix for Likelyhood est 00999 // Used in Mahalanobis distance computation as well 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 // compute sum(X*Y)/N - Xbar*Ybar 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 // matrix must be square 01022 if(baseCorr.getWidth() != baseCorr.getHeight()) 01023 LFATAL("ERROR matrix is not square %d x %d", 01024 baseCorr.getWidth(),baseCorr.getHeight()); 01025 01026 // hold the matrix dims 01027 // const T dims = baseCorr.getWidth(); 01028 // first compute the inverse eigen matrix 01029 const Image<T> invCorr = matrixInv(baseCorr); 01030 // compute the determinant of the eigen matrix 01031 // In this case, it is just the product of the eigen values 01032 // WE take the log sum rather than product to keep the number sane 01033 01034 //const T detCorr = static_cast<T>(sqrt(matrixDet(baseCorr))); 01035 //T logDetCorr = static_cast<T>(log(sqrt((2*M_PI)/baseCorr.getVal(0,0)))); 01036 //T detCorr = static_cast<T>(1/(pow((2*M_PI),(dims/2)))); 01037 T logDetCorr = 0; 01038 for(ushort i = 0; i < (ushort)baseCorr.getWidth(); i++) 01039 { 01040 //LINFO("** baseCorr %f",baseCorr.getVal(i,i)); 01041 logDetCorr += static_cast<T>(log(1.0/sqrt((2.0*M_PI)*baseCorr.getVal(i,i)))); 01042 //LINFO("** logDetCorr %f",logDetCorr); 01043 } 01044 01045 //LINFO("logDetCorr %f",logDetCorr); 01046 // compute the easy left hand side of the guassian 01047 const T LHS = static_cast<T>(logDetCorr); 01048 //LINFO("LHS computed as %f",LHS); 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 // create column difference x - mu matrix 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 // for each feature, compute x - mu 01076 *idiffMatrix = ibaseImages->getVal(i,j) - *ibaseMean; 01077 ++ibaseImages; ++ibaseMean; ++idiffMatrix; 01078 } 01079 // compute Mahalanobis distance (x - mu)*iSIG*(x - mu) 01080 const T RHS = static_cast<T>(sum(matrixMult( 01081 clamped_convert<Image<T> > 01082 (vmMult(transpose(diffMatrix),invCorr)) 01083 ,diffMatrix))); 01084 //LINFO("RHS computed as %f",RHS); 01085 const T newRHS = static_cast<T>((-1.0/2.0) * RHS); 01086 //LINFO("new RHS %f",newRHS); 01087 //LINFO("LHS %f",LHS); 01088 01089 // compute final p(x) 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 // Normalized true pearson R correlation 01169 for(uint i = 0; i < baseDim; i++) 01170 { 01171 for(uint j = 0; j < baseDim; j++) 01172 { 01173 // compute (sum(X*Y)/N - Xbar*Ybar) / Xstd*Ystd from 01174 // the eigen matrix values 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 //LINFO("vect[%d] = %g",i,vect[i]); 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 // there was nobody at home? 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 // if the input is blank, let's return blank: 01434 if (oldmin == oldmax) return ima; 01435 01436 // let's compute the remapping coeffs and do some checking that we 01437 // actually can remap: 01438 float a = float(oldmin), b = float(oldmid), c = float(oldmax); 01439 float d = float(newmin), e = float(newmid), f = float(newmax); 01440 01441 // here are the polynomial coefficients, straight out of 01442 // Mathematica. They are not optimized for computation speed, but we 01443 // don't really care here as we only need to compute them once. They 01444 // all need to be divided by the denominator below: 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 // here we optimize the computation for speed: 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 // get oldmin and oldmax from the source image: 01487 T oldmin, oldmax; getMinMax(src, oldmin, oldmax); 01488 01489 // call the general squash: 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 // get oldmin and oldmax from the source image: 01499 T oldmin, oldmax; getMinMax(src, oldmin, oldmax); 01500 01501 // call the general squash: 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 // this is very similar to randShuffle() in saliency.C: 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 //First find upper and lower bounds on image values 01574 //apply an exponent bias if needed 01575 if(bias != 1.0F) 01576 for(a = ima.beginw(); a != ima.endw(); ++a) 01577 { 01578 *a = *a * *a; 01579 //*a = pow(*a,bias); 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 // determin which pixels are selected based upon there 01596 // relation to min/max values 01597 for (unsigned int i = 0; i < siz; i ++) 01598 { 01599 // higher order bits (better) 01600 salVal = ((minVal)+((maxVal)*rand()/(RAND_MAX+1.0))); 01601 // lower order bits (faster) 01602 //salVal = (*minVal)+(rand() % (int)*maxVal); 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()) // a += b * coeff 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 // a = b * coeff 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 // need to keep the increment in a separate statement; if we do 01717 // "*aptr *= *aptr++", then it's undefined whether the "*=" 01718 // happens before or after the "++" (thanks to g++ 4.0 for 01719 // catching this with a warning!) 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; // forget it 01752 01753 float increment = 1.0 / (float)(size + 1); 01754 // top lines: 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 // normal lines: start again from beginning to attenuate corners twice: 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 // bottom lines 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; // forget it 01807 01808 typename Image<T>::iterator const data = a.beginw(); 01809 01810 // do the first line explicitly: 01811 for (int i = 0; i < a.getWidth(); ++i) 01812 data[i] = value; 01813 01814 // then copy to next lines: 01815 for (int y = 1; y < siz; ++y) 01816 safecopy(data + (y * a.getWidth()), 01817 data, 01818 a.getWidth()); 01819 01820 // then do the vertical borders explicitly: 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 // finally do the bottom lines as a copy of the top lines 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 //Adds power noise on an input image 01873 //beta = 0 for white noise (flat) 01874 //beta = -1 for pink noise (1/f) 01875 //beta = -2 fo brown noise (1/f^2) 01876 01877 typedef std::complex<float> complexf; 01878 01879 int inputW = src.getWidth(), inputH = src.getHeight(); 01880 const int N = inputW > inputH ? inputW : inputH; //max dimension 01881 01882 // ifft takes a half plane in the positive x direction 01883 // so we need to pass it coordinates for 01884 // 0 < x <= N, -N/2 <= y <= N/2 (excluding 0) 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)); //twice as wide in the x-direction 01918 const Image<double> fullImg = ieng.ifft(tempCmplxImg); 01919 //fullImg = remapRange(fullImg,rangeOf(fullImg),Range<T_or_RGB>((T_or_RGB)0,(T_or_RGB)255); 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); // a bit wasteful but less bogus that numeric_limits 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); // a bit wasteful but less bogus that numeric_limits 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 // we need initial values for the min_in and max_in that come from 02001 // within the mask, and initial values for min_out and max_out that 02002 // come from outside the mask. So in this first loop we just start 02003 // scanning the image until we have found these: 02004 02005 // let's use the first point, it's either in or out: 02006 if (*mptr++) { 02007 // ok, we got the values for inside, let's look for the outside ones: 02008 min_in = *aptr; max_in = *aptr++; 02009 while (aptr != stop) 02010 { 02011 if (*mptr++) { // inside the mask? update our inside values 02012 if (*aptr < min_in) min_in = *aptr; 02013 else if (*aptr > max_in) max_in = *aptr; 02014 } else { // outside the mask? initialize outside vals and move on 02015 min_out = *aptr; max_out = *aptr++; break; 02016 } 02017 ++aptr; 02018 } 02019 } else { 02020 // ok, we got the values for outside, let's look for the inside ones: 02021 min_out = *aptr; max_out = *aptr++; 02022 while (aptr != stop) 02023 { 02024 if (*mptr++) { // inside the mask? initialize inside vals and move on 02025 min_in = *aptr; max_in = *aptr++; break; 02026 } else { // outside the mask? update our values 02027 if (*aptr < min_out) min_out = *aptr; 02028 else if (*aptr > max_out) max_out = *aptr; 02029 } 02030 ++aptr; 02031 } 02032 } 02033 02034 // we are now ready to finish up the iterations, knowing that both 02035 // the inside and outside values have been initialized and just need 02036 // updating: 02037 while (aptr != stop) 02038 { 02039 if (*mptr++) { // inside the mask? 02040 if (*aptr < min_in) min_in = *aptr; 02041 else if (*aptr > max_in) max_in = *aptr; 02042 } else { // outside the mask 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 // we need initial values for mi and ma that come from within the 02085 // mask. So in this first loop we just start scanning the image 02086 // until we hit a non-zero pixel in the mask: 02087 while (aptr != stop && *mptr == 0) { aptr ++; mptr ++; } 02088 02089 // mask was empty? 02090 if (aptr == stop) { mi = T(0); ma = T(0); avg = T(0); return; } 02091 02092 // set initial mi/ma/sum values: 02093 mi = *aptr; sum = *aptr; ma = *aptr ++; mptr ++; area ++; 02094 02095 // loop over the remainder of the image: 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 // we need initial values for mi and ma that come from within the 02125 // mask. So in this first loop we just start scanning the image 02126 // until we hit a non-zero pixel in the mask: 02127 while (aptr != stop && *mptr <= 0.0F) { aptr ++; mptr ++; } 02128 02129 // mask was empty? 02130 if (aptr == stop) 02131 { mi = T(0); ma = T(0); sum = TF(0); area = TF(0); return; } 02132 02133 // set initial mi/ma values: 02134 mi = *aptr; ma = *aptr ++; mptr ++; 02135 02136 // loop over the remainder of the image: 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 // check if the original range is empty; NOTE: don't try to check 02268 // (oldmax-oldmin)==0.0 here, because that will fail if oldmin=inf 02269 // and oldmax=inf, since inf-inf=nan, whereas a test of inf==inf 02270 // will still yield true 02271 if (oldmax == oldmin) 02272 { 02273 // OK, the input image was uniform, so let's just change it to 02274 // be uniform at the min of the desired new scale. 02275 02276 // NOTE: Another sensible approach in this case might be to set 02277 // the new image to the midpoint of the new range, but this 02278 // causes backward-compatibility problems, particularly in cases 02279 // where we expect input images containing all 0's to stay at 0 02280 // rather than shifting to a higher non-zero value after 02281 // rescaling. 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; // outside the image 02311 if (i > 0 && sptr[-1] > val) return false; // (i-1,j) is higher 02312 if (i < w-1 && sptr[1] > val) return false; // (i+1,j) is higher 02313 if (j > 0 && sptr[-w] > val) return false; // (i,j-1) is higher 02314 if (j < h-1 && sptr[w] > val) return false; // (i,j+1) is higher 02315 02316 // no neighbor was higher, so we must be the highest: 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 // it's still a no-op with thresh = 0 but we won't report an 02375 // LERROR() here since 0 is a convenient default value when no 02376 // threshold should be applied... 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 // Sigmoidal normalization: f(x)=x^g/(s+x^h) 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) //nothing to approximate 02617 return points; 02618 02619 std::vector<Point2D<int> > vt(points.size()); 02620 std::vector<int> mk(points.size(), 0); 02621 02622 //Vertex reduction within tolerance of prior vertex cluster 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 //Douglas-Peucker polyine simplification 02633 02634 mk[0] = mk[k-1] = 1; 02635 recursePolyDP(tol, vt, 0, k-1, mk); 02636 02637 //get the output 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) // there is nothing to simplify 02652 return; 02653 02654 // check for adequate approximation by segment S from v[j] to v[k] 02655 int maxi = j; // index of vertex farthest from S 02656 float maxd2 = 0; // distance squared of farthest vertex 02657 float tol2 = tol * tol; // tolerance squared 02658 02659 //Segment S = {v[j], v[k]}; // segment from v[j] to v[k] 02660 02661 //Vector u = S.P1 - S.P0; 02662 Point2D<int> SP0 = v[k]; 02663 Point2D<int> SP1 = v[j]; 02664 Point2D<int> u = SP1 - SP0; // segment direction vector 02665 02666 double cu = u.i*u.i + u.j*u.j; // segment length squared 02667 02668 // test each vertex v[i] for max distance from S 02669 // compute using the Feb 2001 Algorithm's dist_Point_to_Segment() 02670 // Note: this works in any dimension (2D, 3D, ...) 02671 Point2D<int> w; 02672 Point2D<int> Pb; // base of perpendicular from v[i] to S 02673 double b, cw, dv2; // dv2 = distance v[i] to S squared 02674 02675 for (int i=j+1; i<k; i++) 02676 { 02677 // compute distance squared 02678 w = v[i] - SP0; 02679 cw = w.i*u.i + w.j*u.j; //dot product 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 // test with current max distance squared 02690 if (dv2 <= maxd2) 02691 continue; 02692 // v[i] is a new max vertex 02693 maxi = i; 02694 maxd2 = dv2; 02695 } 02696 if (maxd2 > tol2) // error is worse than the tolerance 02697 { 02698 // split the polyline at the farthest vertex from S 02699 mk[maxi] = 1; // mark v[maxi] for the simplified polyline 02700 // recursively simplify the two subpolylines at v[maxi] 02701 recursePolyDP( tol, v, j, maxi, mk ); // polyline v[j] to v[maxi] 02702 recursePolyDP( tol, v, maxi, k, mk ); // polyline v[maxi] to v[k] 02703 } 02704 // else the approximation is OK, so ignore intermediate vertices 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; // index of min point P[] in bin (>=0 or NONE) 02716 int max; // index of max point P[] in bin (>=0 or NONE) 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; // the current point being considered 02737 int bot=0, top=(-1); // indices for bottom and top of the stack 02738 02739 // Get the points with (1) min-max x-coord, and (2) min-max y-coord 02740 for (int i=1; i<n; i++) { 02741 cP = &P[i]; 02742 if (cP->i <= xmin) { 02743 if (cP->i < xmin) { // new xmin 02744 xmin = cP->i; 02745 minmin = minmax = i; 02746 } 02747 else { // another xmin 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) { // new xmax 02756 xmax = cP->i; 02757 maxmin = maxmax = i; 02758 } 02759 else { // another xmax 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) { // degenerate case: all x-coords == xmin 02768 H[++top] = P[minmin]; // a point, or 02769 if (minmax != minmin) // a nontrivial segment 02770 H[++top] = P[minmax]; 02771 H.resize(top+1); 02772 return H; 02773 } 02774 02775 // Next, get the max and min points in the k range bins 02776 Bin* B = new Bin[k+2]; // first allocate the bins 02777 B[0].min = minmin; B[0].max = minmax; // set bin 0 02778 B[k+1].min = maxmin; B[k+1].max = maxmax; // set bin k+1 02779 for (int b=1; b<=k; b++) { // initially nothing is in the other bins 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) // already have bins 0 and k+1 02785 continue; 02786 // check if a lower or upper point 02787 if (isLeft( P[minmin], P[maxmin], *cP) < 0) { // below lower line 02788 b = (int)( k * (cP->i - xmin) / (xmax - xmin) ) + 1; // bin # 02789 if (B[b].min == NONE) // no min point in this range 02790 B[b].min = i; // first min 02791 else if (cP->j < P[B[b].min].j) 02792 B[b].min = i; // new min 02793 continue; 02794 } 02795 if (isLeft( P[minmax], P[maxmax], *cP) > 0) { // above upper line 02796 b = (int)( k * (cP->i - xmin) / (xmax - xmin) ) + 1; // bin # 02797 if (B[b].max == NONE) // no max point in this range 02798 B[b].max = i; // first max 02799 else if (cP->j > P[B[b].max].j) 02800 B[b].max = i; // new max 02801 continue; 02802 } 02803 } 02804 02805 // Now, use the chain algorithm to get the lower and upper hulls 02806 // the output array H[] will be used as the stack 02807 // First, compute the lower hull on the stack H 02808 for (int i=0; i <= k+1; ++i) 02809 { 02810 if (B[i].min == NONE) // no min point in this range 02811 continue; 02812 cP = &P[ B[i].min ]; // select the current min point 02813 02814 while (top > 0) // there are at least 2 points on the stack 02815 { 02816 // test if current point is left of the line at the stack top 02817 if (isLeft( H[top-1], H[top], *cP) > 0) 02818 break; // cP is a new hull vertex 02819 else 02820 top--; // pop top point off stack 02821 } 02822 H[++top] = *cP; // push current point onto stack 02823 } 02824 02825 // Next, compute the upper hull on the stack H above the bottom hull 02826 if (maxmax != maxmin) // if distinct xmax points 02827 H[++top] = P[maxmax]; // push maxmax point onto stack 02828 bot = top; // the bottom point of the upper hull stack 02829 for (int i=k; i >= 0; --i) 02830 { 02831 if (B[i].max == NONE) // no max point in this range 02832 continue; 02833 cP = &P[ B[i].max ]; // select the current max point 02834 02835 while (top > bot) // at least 2 points on the upper stack 02836 { 02837 // test if current point is left of the line at the stack top 02838 if (isLeft( H[top-1], H[top], *cP) > 0) 02839 break; // current point is a new hull vertex 02840 else 02841 top--; // pop top point off stack 02842 } 02843 H[++top] = *cP; // push current point onto stack 02844 } 02845 if (minmax != minmin) 02846 H[++top] = P[minmin]; // push joining endpoint onto stack 02847 02848 delete B; // free bins before returning 02849 H.resize(top+1); 02850 return H; 02851 } 02852 02853 02854 // Include the explicit instantiations 02855 #include "inst/Image/MathOps.I" 02856 02857 // additional explicit instantiations: 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 /* So things look consistent in everyone's emacs... */ 02893 /* Local Variables: */ 02894 /* indent-tabs-mode: nil */ 02895 /* End: */ 02896 02897 #endif // !IMAGE_MATHOPS_C_DEFINED