00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Image/PyramidOps.H"
00039
00040 #include "Image/Image.H"
00041 #include "Image/ImageSet.H"
00042 #include "Image/ImageSetOps.H"
00043 #include "Image/FilterOps.H"
00044 #include "Image/LowPassLpt.H"
00045 #include "Image/Kernels.H"
00046 #include "Image/MathOps.H"
00047 #include "Image/ShapeOps.H"
00048 #include "Image/Transforms.H"
00049 #include "Image/Pixels.H"
00050 #include "Util/Assert.H"
00051 #include "rutz/trace.h"
00052
00053
00054
00055
00056
00057
00058 template <class T>
00059 T getPyrPixel(const ImageSet<T>& pyr,
00060 const Point2D<int>& p, const uint lev)
00061 {
00062 ASSERT(lev < pyr.size());
00063 ASSERT(pyr[0].coordsOk(p));
00064 ASSERT(isDyadic(pyr));
00065
00066 float fac = float(1 << lev);
00067 float ii = float(p.i) / fac, jj = float(p.j) / fac;
00068 int ww = pyr[lev].getWidth() - 1, hh = pyr[lev].getHeight() - 1;
00069 if (ii > ww) ii = ww; if (jj > hh) jj = hh;
00070
00071 return pyr[lev].getValInterp(ii, jj);
00072 }
00073
00074
00075 template <class T>
00076 T getPyrPixelNI(const ImageSet<T>& pyr,
00077 const Point2D<int>& p, const uint lev)
00078 {
00079 ASSERT(lev < pyr.size());
00080 ASSERT(pyr[0].coordsOk(p));
00081 ASSERT(isDyadic(pyr));
00082
00083 int ii = p.i >> lev, jj = p.j >> lev;
00084 int ww = pyr[lev].getWidth() - 1, hh = pyr[lev].getHeight() - 1;
00085 if (ii > ww) ii = ww; if (jj > hh) jj = hh;
00086
00087 return pyr[lev].getVal(ii, jj);
00088 }
00089
00090
00091 template <class T>
00092 T getPyrPixel(const ImageSet<T>& pyr,
00093 const float x, const float y, const float z)
00094 {
00095 ASSERT(isDyadic(pyr));
00096
00097 const uint nlev = pyr.size();
00098
00099
00100
00101 const uint lev1 = int(floor(z)); ASSERT(lev1 < nlev);
00102
00103
00104
00105 const float fac1 = float(1 << lev1);
00106 float ii1 = x / fac1, jj1 = y / fac1;
00107 const float ww1 = float(pyr[lev1].getWidth() - 1);
00108 const float hh1 = float(pyr[lev1].getHeight() - 1);
00109 if (ii1 > ww1) ii1 = ww1;
00110 if (jj1 > hh1) jj1 = hh1;
00111
00112 const T val1 = pyr[lev1].getValInterp(ii1, jj1);
00113
00114
00115
00116 if (lev1 == nlev - 1) return val1;
00117
00118
00119 const uint lev2 = lev1 + 1;
00120 const float fac2 = float(2 << lev2);
00121 float ii2 = x / fac2, jj2 = y / fac2;
00122 float ww2 = float(pyr[lev2].getWidth() - 1);
00123 float hh2 = float(pyr[lev2].getHeight() - 1);
00124 if (ii2 > ww2) ii2 = ww2;
00125 if (jj2 > hh2) jj2 = hh2;
00126
00127 const T val2 = pyr[lev2].getValInterp(ii2, jj2);
00128
00129
00130 const float fz = z - float(lev1);
00131
00132 return T(val1 + (val2 - val1) * fz);
00133 }
00134
00135
00136
00137
00138
00139
00140 template <class T>
00141 ImageSet<T> buildPyrGaussian(const Image<T>& image,
00142 int firstlevel, int depth, int filterSize)
00143 {
00144 GVX_TRACE(__PRETTY_FUNCTION__);
00145 ASSERT(image.initialized());
00146
00147 ImageSet<T> result(depth);
00148
00149 if (0 >= firstlevel)
00150 result[0] = image;
00151
00152 Image<T> a = image;
00153 for (int lev = 1; lev < depth; ++lev)
00154 {
00155 if (filterSize == 5)
00156 {
00157 a = lowPass5yDecY(lowPass5xDecX(a,2),2);
00158 }
00159 else
00160 {
00161 a = decX(lowPassX(filterSize, a));
00162 a = decY(lowPassY(filterSize, a));
00163 }
00164
00165
00166
00167
00168
00169
00170 if (lev >= firstlevel)
00171 result[lev] = a;
00172 }
00173
00174 return result;
00175 }
00176
00177
00178 template <class T>
00179 ImageSet<T> buildRadialPyrGaussian(const Image<T>& image, int firstlevel, int depth)
00180 {
00181 GVX_TRACE(__PRETTY_FUNCTION__);
00182 ASSERT(image.initialized());
00183
00184 ImageSet<T> result(depth);
00185
00186 if (0 >= firstlevel)
00187 result[0] = image;
00188
00189 Image<T> a = image;
00190 for (int lev = 1; lev < depth; ++lev)
00191 {
00192 a = decXY(lowPassLpt5(a, CROSS_HEMI));
00193
00194
00195
00196
00197
00198
00199 if (lev >= firstlevel)
00200 result[lev] = a;
00201 }
00202
00203 return result;
00204 }
00205
00206
00207 template <class T>
00208 ImageSet<T> buildPyrConvolve(const Image<T>& image,
00209 int firstlevel, int depth,
00210 const Image<float>& filter,
00211 ConvolutionBoundaryStrategy boundary)
00212 {
00213 GVX_TRACE(__PRETTY_FUNCTION__);
00214 ASSERT(image.initialized());
00215
00216 ImageSet<T> result(depth);
00217
00218 Image<T> base;
00219 for (int lev = 0; lev < depth; ++lev)
00220 {
00221 if (lev == 0) base = image; else base = decXY(lowPass5(base));
00222
00223 if (lev >= firstlevel)
00224 result[lev] = convolve(base, filter, boundary);
00225 }
00226
00227 return result;
00228 }
00229
00230
00231 template <class T>
00232 ImageSet<T> buildPyrLaplacian(const Image<T>& image,
00233 int firstlevel, int depth, int filterSize)
00234 {
00235 GVX_TRACE(__PRETTY_FUNCTION__);
00236 ASSERT(image.initialized());
00237
00238 ImageSet<T> result(depth);
00239
00240 Image<T> lpf = lowPass(filterSize, image);
00241
00242 if (0 >= firstlevel)
00243 result[0] = image - lpf;
00244
00245 for (int lev = 1; lev < depth; ++lev)
00246 {
00247 const Image<T> dec = decXY(lpf);
00248 lpf = lowPass(filterSize, dec);
00249
00250 if (lev >= firstlevel)
00251 result[lev] = dec - lpf;
00252 }
00253
00254 return result;
00255 }
00256
00257
00258 template <class T>
00259 ImageSet<T> buildPyrOrientedFromLaplacian(const ImageSet<T>& laplacian,
00260 int filterSize,
00261 float theta, float intens,
00262 const bool usetab)
00263 {
00264 int attenuation_width = -1;
00265 float spatial_freq = -1.0;
00266
00267 switch (filterSize)
00268 {
00269 case 5: attenuation_width = 3; spatial_freq = M_PI_2; break;
00270 case 9: attenuation_width = 5; spatial_freq = 2.6; break;
00271 default:
00272 LFATAL("Filter size %d is not supported", filterSize);
00273 }
00274
00275
00276 ImageSet<T> result(laplacian.size());
00277
00278 for (size_t lev = 0; lev < result.size(); ++lev)
00279 {
00280 if (laplacian[lev].initialized())
00281 {
00282 result[lev] = orientedFilter(laplacian[lev], spatial_freq,
00283 theta, intens, usetab);
00284
00285 inplaceAttenuateBorders(result[lev], attenuation_width);
00286 }
00287 }
00288
00289 return result;
00290 }
00291
00292
00293 template <class T>
00294 ImageSet<T> buildPyrOriented(const Image<T>& image,
00295 int firstlevel, int depth, int filterSize,
00296 float theta, float intens,
00297 const bool usetab)
00298 {
00299 GVX_TRACE(__PRETTY_FUNCTION__);
00300 ASSERT(image.initialized());
00301
00302
00303 typedef typename promote_trait<T, float>::TP TF;
00304
00305 const ImageSet<TF> laplacian =
00306 buildPyrLaplacian(Image<TF>(image), firstlevel, depth, filterSize);
00307
00308 const ImageSet<TF> orifilt =
00309 buildPyrOrientedFromLaplacian(laplacian, filterSize, theta,
00310 intens, usetab);
00311
00312 ImageSet<T> result(orifilt.size());
00313 for (size_t i = 0; i < result.size(); ++i)
00314 result[i] = Image<T>(orifilt[i]);
00315
00316 return result;
00317 }
00318
00319
00320 template <class T>
00321 ImageSet<T> buildPyrLocalAvg(const Image<T>& image, int depth)
00322 {
00323 GVX_TRACE(__PRETTY_FUNCTION__);
00324 ASSERT(image.initialized());
00325
00326 ASSERT(depth >= 1);
00327
00328 ImageSet<T> result(depth);
00329
00330
00331 const int scale = int(pow(2.0, depth - 1));
00332 result[depth - 1] = quickLocalAvg(image, scale);
00333
00334 return result;
00335 }
00336
00337
00338 template <class T>
00339 ImageSet<T> buildPyrLocalAvg2x2(const Image<T>& image, int depth)
00340 {
00341 GVX_TRACE(__PRETTY_FUNCTION__);
00342 ASSERT(depth >= 0);
00343
00344 if (depth == 0)
00345 return ImageSet<T>();
00346
00347 ImageSet<T> result(depth);
00348 result[0] = image;
00349
00350 for (int i = 1; i < depth; ++i)
00351 result[i] = quickLocalAvg2x2(result[i-1]);
00352
00353 return result;
00354 }
00355
00356
00357 template <class T>
00358 ImageSet<T> buildPyrLocalMax(const Image<T>& image, int depth)
00359 {
00360 GVX_TRACE(__PRETTY_FUNCTION__);
00361 ASSERT(image.initialized());
00362
00363 ASSERT(depth >= 1);
00364
00365 ImageSet<T> result(depth);
00366
00367
00368 const int scale = int(pow(2.0, depth - 1));
00369 result[depth - 1] = quickLocalMax(image, scale);
00370
00371 return result;
00372 }
00373
00374
00375 template <class T>
00376 ImageSet<T> buildPyrGeneric(const Image<T>& image,
00377 int firstlevel, int depth,
00378 const PyramidType typ, const float gabor_theta,
00379 const float intens)
00380 {
00381 GVX_TRACE(__PRETTY_FUNCTION__);
00382 switch(typ)
00383 {
00384 case Gaussian3: return buildPyrGaussian(image, firstlevel, depth, 3);
00385 case Gaussian5: return buildPyrGaussian(image, firstlevel, depth, 5);
00386 case Gaussian9: return buildPyrGaussian(image, firstlevel, depth, 9);
00387
00388 case Laplacian5: return buildPyrLaplacian(image, firstlevel, depth, 5);
00389 case Laplacian9: return buildPyrLaplacian(image, firstlevel, depth, 9);
00390
00391 case Oriented5: return buildPyrOriented(image, firstlevel, depth, 5, gabor_theta, intens);
00392 case Oriented9: return buildPyrOriented(image, firstlevel, depth, 9, gabor_theta, intens);
00393
00394 case QuickLocalAvg: return buildPyrLocalAvg(image, depth);
00395 case QuickLocalMax: return buildPyrLocalMax(image, depth);
00396
00397 default:
00398 LFATAL("Attempt to create Pyramid of unknown type %d", typ);
00399 }
00400
00401 ASSERT(false);
00402 return ImageSet<T>();
00403 }
00404
00405
00406 ImageSet<float> buildPyrGabor(const ImageSet<float>& gaussianPyr,
00407 float angle, float filter_period,
00408 float elongation, int size, int flags)
00409 {
00410 GVX_TRACE(__PRETTY_FUNCTION__);
00411 const double major_stddev = filter_period / 3.0;
00412 const double minor_stddev = major_stddev * elongation;
00413
00414
00415
00416
00417
00418
00419 const double theta = angle + 90.0f;
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 Image<float> g0 = gaborFilter3(major_stddev, minor_stddev,
00430 filter_period, 0.0f, theta, size);
00431 Image<float> g90 = gaborFilter3(major_stddev, minor_stddev,
00432 filter_period, 90.0f, theta, size);
00433
00434 LDEBUG("angle = %.2f, period = %.2f pix, size = %dx%d pix",
00435 angle, filter_period, g0.getWidth(), g0.getHeight());
00436
00437 Image<float> f0, f90;
00438 ImageSet<float> result(gaussianPyr.size());
00439
00440 for (uint i = 0; i < gaussianPyr.size(); ++i)
00441 {
00442
00443
00444 if (!gaussianPyr[i].initialized())
00445 continue;
00446
00447 if (flags & DO_ENERGY_NORM)
00448 {
00449 Image<float> temp = energyNorm(gaussianPyr[i]);
00450 f0 = optConvolve(temp, g0);
00451 f90 = optConvolve(temp, g90);
00452 }
00453 else
00454 {
00455 f0 = optConvolve(gaussianPyr[i], g0);
00456 f90 = optConvolve(gaussianPyr[i], g90);
00457 }
00458
00459 if (!(flags & NO_ABS))
00460 {
00461 f0 = abs(f0);
00462 f90 = abs(f90);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 result[i] = f0 + f90;
00475
00476 }
00477
00478 return result;
00479 }
00480
00481
00482 ImageSet<float> buildPyrGabor(const Image<float>& img,
00483 int firstlevel, int depth, float angle,
00484 float filter_period, float elongation,
00485 int size, int flags)
00486 {
00487 GVX_TRACE(__PRETTY_FUNCTION__);
00488 ImageSet<float> pyr;
00489
00490
00491 if (flags & DO_LAPLACIAN)
00492 {
00493 pyr = buildPyrLaplacian(img, firstlevel, depth, 9);
00494 }
00495 else
00496 {
00497 pyr = buildPyrGaussian(img, firstlevel, depth, 9);
00498 }
00499
00500 return buildPyrGabor(pyr, angle, filter_period, elongation, size, flags);
00501 }
00502
00503
00504
00505
00506
00507
00508 template <class T>
00509 Image<T> centerSurround(const ImageSet<T>& pyr,
00510 const int lev1, const int lev2,
00511 const bool absol,
00512 const ImageSet<float>* clipPyr)
00513 {
00514 GVX_TRACE(__PRETTY_FUNCTION__);
00515 ASSERT(lev1 >= 0 && lev2 >= 0);
00516 ASSERT(uint(lev1) < pyr.size() && uint(lev2) < pyr.size());
00517
00518 const int largeLev = std::min(lev1, lev2);
00519 const int smallLev = std::max(lev1, lev2);
00520
00521 if (clipPyr != 0 && clipPyr->isNonEmpty())
00522 {
00523 ASSERT((*clipPyr)[largeLev].getDims() == pyr[largeLev].getDims());
00524 ASSERT((*clipPyr)[smallLev].getDims() == pyr[smallLev].getDims());
00525
00526 return
00527 ::centerSurround(Image<T>(pyr[largeLev] * (*clipPyr)[largeLev]),
00528 Image<T>(pyr[smallLev] * (*clipPyr)[smallLev]),
00529 absol);
00530 }
00531 else
00532 return ::centerSurround(pyr[largeLev], pyr[smallLev], absol);
00533 }
00534
00535
00536 template <class T>
00537 void centerSurround(const ImageSet<T>& pyr,
00538 const int lev1, const int lev2,
00539 Image<T>& pos, Image<T>& neg,
00540 const ImageSet<float>* clipPyr)
00541 {
00542 GVX_TRACE(__PRETTY_FUNCTION__);
00543 ASSERT(lev1 >= 0 && lev2 >= 0);
00544 ASSERT(uint(lev1) < pyr.size() && uint(lev2) < pyr.size());
00545
00546 const int largeLev = std::min(lev1, lev2);
00547 const int smallLev = std::max(lev1, lev2);
00548
00549 if (clipPyr != 0 && clipPyr->isNonEmpty())
00550 {
00551 ASSERT((*clipPyr)[largeLev].getDims() == pyr[largeLev].getDims());
00552 ASSERT((*clipPyr)[smallLev].getDims() == pyr[smallLev].getDims());
00553
00554 ::centerSurround(Image<T>(pyr[largeLev] * (*clipPyr)[largeLev]),
00555 Image<T>(pyr[smallLev] * (*clipPyr)[smallLev]),
00556 pos, neg);
00557 }
00558 else
00559 ::centerSurround(pyr[largeLev], pyr[smallLev], pos, neg);
00560 }
00561
00562
00563 template <class T>
00564 Image<T> centerSurroundSingleOpponent(const ImageSet<T>& cpyr,
00565 const ImageSet<T>& spyr,
00566 const int lev1, const int lev2,
00567 const bool absol,
00568 const ImageSet<float>* clipPyr)
00569 {
00570 GVX_TRACE(__PRETTY_FUNCTION__);
00571 ASSERT(lev1 >= 0 && lev2 >= 0);
00572 ASSERT(uint(lev1) < cpyr.size() && uint(lev2) < cpyr.size());
00573 ASSERT(uint(lev1) < spyr.size() && uint(lev2) < spyr.size());
00574
00575 const int largeLev = std::min(lev1, lev2);
00576 const int smallLev = std::max(lev1, lev2);
00577
00578 if (clipPyr != 0 && clipPyr->isNonEmpty())
00579 {
00580 ASSERT((*clipPyr)[largeLev].getDims() == cpyr[largeLev].getDims());
00581 ASSERT((*clipPyr)[smallLev].getDims() == cpyr[smallLev].getDims());
00582 ASSERT((*clipPyr)[largeLev].getDims() == spyr[largeLev].getDims());
00583 ASSERT((*clipPyr)[smallLev].getDims() == spyr[smallLev].getDims());
00584
00585 return
00586 ::centerSurround(Image<T>(cpyr[largeLev] * (*clipPyr)[largeLev]),
00587 Image<T>(spyr[smallLev] * (*clipPyr)[smallLev]),
00588 absol);
00589 }
00590 else
00591 return ::centerSurround(cpyr[largeLev], spyr[smallLev], absol);
00592 }
00593
00594
00595 template <class T>
00596 void centerSurroundSingleOpponent(const ImageSet<T>& cpyr,
00597 const ImageSet<T>& spyr,
00598 const int lev1, const int lev2,
00599 Image<T>& pos, Image<T>& neg,
00600 const ImageSet<float>* clipPyr)
00601 {
00602 GVX_TRACE(__PRETTY_FUNCTION__);
00603 ASSERT(lev1 >= 0 && lev2 >= 0);
00604 ASSERT(uint(lev1) < cpyr.size() && uint(lev2) < cpyr.size());
00605 ASSERT(uint(lev1) < spyr.size() && uint(lev2) < spyr.size());
00606
00607 const int largeLev = std::min(lev1, lev2);
00608 const int smallLev = std::max(lev1, lev2);
00609
00610 if (clipPyr != 0 && clipPyr->isNonEmpty())
00611 {
00612 ASSERT((*clipPyr)[largeLev].getDims() == cpyr[largeLev].getDims());
00613 ASSERT((*clipPyr)[smallLev].getDims() == cpyr[smallLev].getDims());
00614 ASSERT((*clipPyr)[largeLev].getDims() == spyr[largeLev].getDims());
00615 ASSERT((*clipPyr)[smallLev].getDims() == spyr[smallLev].getDims());
00616
00617 ::centerSurround(Image<T>(cpyr[largeLev] * (*clipPyr)[largeLev]),
00618 Image<T>(spyr[smallLev] * (*clipPyr)[smallLev]),
00619 pos, neg);
00620 }
00621 else
00622 ::centerSurround(cpyr[largeLev], spyr[smallLev], pos, neg);
00623 }
00624
00625
00626 template <class T>
00627 Image<T> centerSurroundDiff(const ImageSet<T>& pyr1,
00628 const ImageSet<T>& pyr2,
00629 const int lev1, const int lev2,
00630 const bool absol,
00631 const ImageSet<float>* clipPyr)
00632 {
00633 GVX_TRACE(__PRETTY_FUNCTION__);
00634 ASSERT(lev1 >= 0 && lev2 >= 0);
00635 ASSERT(uint(lev1) < pyr1.size() && uint(lev2) < pyr1.size());
00636
00637 const int largeLev = std::min(lev1, lev2);
00638 const int smallLev = std::max(lev1, lev2);
00639
00640 ASSERT(pyr1[largeLev].getDims() == pyr2[largeLev].getDims());
00641 ASSERT(pyr1[smallLev].getDims() == pyr2[smallLev].getDims());
00642
00643
00644 const Image<T> limg = pyr1[largeLev] - pyr2[largeLev];
00645 const Image<T> simg = pyr1[smallLev] - pyr2[smallLev];
00646
00647 if (clipPyr != 0 && clipPyr->isNonEmpty())
00648 {
00649 ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00650 ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00651
00652 return ::centerSurround(Image<T>(limg * (*clipPyr)[largeLev]),
00653 Image<T>(simg * (*clipPyr)[smallLev]),
00654 absol);
00655 }
00656 else
00657 return ::centerSurround(limg, simg, absol);
00658 }
00659
00660
00661 template <class T>
00662 void centerSurroundDiff(const ImageSet<T>& pyr1,
00663 const ImageSet<T>& pyr2,
00664 const int lev1, const int lev2,
00665 Image<T>& pos, Image<T>& neg,
00666 const ImageSet<float>* clipPyr)
00667 {
00668 GVX_TRACE(__PRETTY_FUNCTION__);
00669 ASSERT(lev1 >= 0 && lev2 >= 0);
00670 ASSERT(uint(lev1) < pyr1.size() && uint(lev2) < pyr1.size());
00671
00672 const int largeLev = std::min(lev1, lev2);
00673 const int smallLev = std::max(lev1, lev2);
00674
00675 ASSERT(pyr1[largeLev].getDims() == pyr2[largeLev].getDims());
00676 ASSERT(pyr1[smallLev].getDims() == pyr2[smallLev].getDims());
00677
00678
00679 const Image<T> limg = pyr1[largeLev] - pyr2[largeLev];
00680 const Image<T> simg = pyr1[smallLev] - pyr2[smallLev];
00681
00682 if (clipPyr != 0 && clipPyr->isNonEmpty())
00683 {
00684 ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00685 ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00686
00687 ::centerSurround(Image<T>(limg * (*clipPyr)[largeLev]),
00688 Image<T>(simg * (*clipPyr)[smallLev]),
00689 pos, neg);
00690 }
00691 else
00692 ::centerSurround(limg, simg, pos, neg);
00693 }
00694
00695
00696 template <class T>
00697 Image<T> centerSurroundDiffSingleOpponent(const ImageSet<T>& cpyr1,
00698 const ImageSet<T>& cpyr2,
00699 const ImageSet<T>& spyr1,
00700 const ImageSet<T>& spyr2,
00701 const int lev1, const int lev2,
00702 const bool absol,
00703 const ImageSet<float>* clipPyr)
00704 {
00705 GVX_TRACE(__PRETTY_FUNCTION__);
00706 ASSERT(lev1 >= 0 && lev2 >= 0);
00707 ASSERT(uint(lev1) < cpyr1.size() && uint(lev2) < cpyr1.size());
00708
00709 const int largeLev = std::min(lev1, lev2);
00710 const int smallLev = std::max(lev1, lev2);
00711
00712 ASSERT(cpyr1[largeLev].getDims() == cpyr2[largeLev].getDims());
00713 ASSERT(cpyr1[smallLev].getDims() == cpyr2[smallLev].getDims());
00714 ASSERT(spyr1[largeLev].getDims() == spyr2[largeLev].getDims());
00715 ASSERT(spyr1[smallLev].getDims() == spyr2[smallLev].getDims());
00716
00717
00718 const Image<T> limg = cpyr1[largeLev] - cpyr2[largeLev];
00719 const Image<T> simg = spyr1[smallLev] - spyr2[smallLev];
00720
00721 if (clipPyr != 0 && clipPyr->isNonEmpty())
00722 {
00723 ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00724 ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00725
00726 return ::centerSurround(Image<T>(limg * (*clipPyr)[largeLev]),
00727 Image<T>(simg * (*clipPyr)[smallLev]),
00728 absol);
00729 }
00730 else
00731 return ::centerSurround(limg, simg, absol);
00732 }
00733
00734
00735 template <class T>
00736 void centerSurroundDiffSingleOpponent(const ImageSet<T>& cpyr1,
00737 const ImageSet<T>& cpyr2,
00738 const ImageSet<T>& spyr1,
00739 const ImageSet<T>& spyr2,
00740 const int lev1, const int lev2,
00741 Image<T>& pos, Image<T>& neg,
00742 const ImageSet<float>* clipPyr)
00743 {
00744 GVX_TRACE(__PRETTY_FUNCTION__);
00745 ASSERT(lev1 >= 0 && lev2 >= 0);
00746 ASSERT(uint(lev1) < cpyr1.size() && uint(lev2) < cpyr1.size());
00747
00748 const int largeLev = std::min(lev1, lev2);
00749 const int smallLev = std::max(lev1, lev2);
00750
00751 ASSERT(cpyr1[largeLev].getDims() == cpyr2[largeLev].getDims());
00752 ASSERT(cpyr1[smallLev].getDims() == cpyr2[smallLev].getDims());
00753 ASSERT(spyr1[largeLev].getDims() == spyr2[largeLev].getDims());
00754 ASSERT(spyr1[smallLev].getDims() == spyr2[smallLev].getDims());
00755
00756
00757 const Image<T> limg = cpyr1[largeLev] - cpyr2[largeLev];
00758 const Image<T> simg = spyr1[smallLev] - spyr2[smallLev];
00759
00760 if (clipPyr != 0 && clipPyr->isNonEmpty())
00761 {
00762 ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00763 ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00764
00765 ::centerSurround(Image<T>(limg * (*clipPyr)[largeLev]),
00766 Image<T>(simg * (*clipPyr)[smallLev]),
00767 pos, neg);
00768 }
00769 else
00770 ::centerSurround(limg, simg, pos, neg);
00771 }
00772
00773
00774 template <class T>
00775 Image<T> weightedBlur(const Image<byte>& modulator, const ImageSet<T>& pyr)
00776 {
00777
00778 ASSERT(pyr.size() > 0);
00779 ASSERT(modulator.getDims() == pyr[0].getDims());
00780
00781
00782
00783
00784
00785
00786
00787 const int w = modulator.getWidth(), h = modulator.getHeight();
00788 Image<T> image(modulator.getDims(), NO_INIT);
00789 Image<byte>::const_iterator mod = modulator.begin();
00790 typename Image<T>::iterator ima = image.beginw();
00791 const int maxdepth = pyr.size() - 1;
00792 const float rstep = (float)(256 / maxdepth);
00793
00794 for (int j = 0; j < h; j ++)
00795 for (int i = 0; i < w; i ++)
00796 {
00797
00798 const float d = (*mod++) / rstep;
00799
00800
00801 const int di = (int)(floor(d));
00802 const float dd = d - (float)di;
00803
00804 const Point2D<int> loc(i, j);
00805 const T pix0 = getPyrPixel(pyr, loc, di);
00806 const T pix1 = getPyrPixel(pyr, loc, std::min(di+1, maxdepth));
00807
00808
00809
00810 *ima++ = clamped_convert<T>(pix0 * (1.0F - dd) + pix1 * dd);
00811 }
00812 return image;
00813 }
00814
00815
00816 template <class T>
00817 Image<T> foveate(const Image<byte>& mask, const ImageSet<T>& pyr)
00818 {
00819
00820 ASSERT(mask.getDims() == pyr[0].getDims());
00821
00822
00823 Image<float> remask = mask;
00824 inplaceNormalize(remask, 0.0f, 255.0f);
00825 inplaceLowThresh(remask, 254.0f, 0.0f);
00826
00827
00828 const int w = remask.getWidth(), h = remask.getHeight();
00829 int maxdist = std::max(w, h) * 3;
00830 float scalefac = float(maxdist) / 255.0f;
00831 remask = chamfer34(remask, float(maxdist)) / scalefac;
00832 Image<byte> modulator = remask;
00833
00834
00835
00836
00837
00838 byte mi, ma; getMinMax(modulator, mi, ma);
00839 if (mi > 0) modulator /= 3;
00840
00841 return weightedBlur(modulator, pyr);
00842 }
00843
00844
00845 #include "inst/Image/PyramidOps.I"
00846
00847 template ImageSet<double> buildPyrLocalAvg2x2(const Image<double>&, int);
00848
00849
00850
00851
00852
00853