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 #ifndef IMAGE_INTEGERMATHOPS_C_DEFINED
00039 #define IMAGE_INTEGERMATHOPS_C_DEFINED
00040
00041 #include "Image/IntegerMathOps.H"
00042
00043 #include "Image/CutPaste.H"
00044 #include "Image/ImageSetOps.H"
00045 #include "Image/MathOps.H"
00046 #include "Image/Pixels.H"
00047 #include "Image/PyramidCache.H"
00048 #include "Image/ShapeOps.H"
00049 #include "rutz/rand.h"
00050
00051
00052 int intgScaleFromByte(const byte* src, const uint nbits)
00053 {
00054 if (nbits > 8)
00055 return (int(*src) << (nbits - 8));
00056 else if (nbits < 8)
00057 return (int(*src) >> (8 - nbits));
00058
00059 return int(*src);
00060 }
00061
00062
00063 int intgScaleFromFloat(const float* src, const uint nbits)
00064 {
00065 if (nbits > 8)
00066 return (int(*src * (1 << (nbits - 8))));
00067 else if (nbits < 8)
00068 return (int(*src / (1 << (8 - nbits))));
00069
00070 return int(*src);
00071 }
00072
00073
00074 Image<int> intgScaleFromByte(const Image<byte>* src, const uint nbits)
00075 {
00076 if (nbits > 8)
00077 return (Image<int>(*src) * (1 << (nbits - 8)));
00078 else if (nbits < 8)
00079 return (Image<int>(*src) / (1 << (8 - nbits)));
00080
00081 return Image<int>(*src);
00082 }
00083
00084
00085 Image<int> intgScaleFromFloat(const Image<float>* src, const uint nbits)
00086 {
00087 if (nbits > 8)
00088 return (Image<int>(*src * (1 << (nbits - 8))));
00089 else if (nbits < 8)
00090 return (Image<int>(*src / (1 << (8 - nbits))));
00091
00092 return Image<int>(*src);
00093 }
00094
00095
00096 Image<PixRGB<int> > intgScaleFromByte(const Image<PixRGB<byte> >* src, const uint nbits)
00097 {
00098 Image<PixRGB<int> > result(src->getDims(), NO_INIT);
00099 Image<PixRGB<byte> >::const_iterator sptr = src->begin();
00100 Image<PixRGB<int> >::iterator dptr = result.beginw();
00101 Image<PixRGB<int> >::iterator const stop = result.endw();
00102
00103 if (nbits > 8)
00104 {
00105 const int lshift = nbits - 8;
00106 while (dptr != stop)
00107 {
00108 *dptr++ = PixRGB<int>(int(sptr->p[0]) << lshift,
00109 int(sptr->p[1]) << lshift,
00110 int(sptr->p[2]) << lshift);
00111 ++sptr;
00112 }
00113 }
00114 else if (nbits < 8)
00115 {
00116 const int rshift = 8 - nbits;
00117 while (dptr != stop)
00118 {
00119 *dptr++ = PixRGB<int>(int(sptr->p[0]) >> rshift,
00120 int(sptr->p[1]) >> rshift,
00121 int(sptr->p[2]) >> rshift);
00122 ++sptr;
00123 }
00124 }
00125 else
00126 {
00127 while (dptr != stop)
00128 {
00129 *dptr++ = PixRGB<int>(int(sptr->p[0]),
00130 int(sptr->p[1]),
00131 int(sptr->p[2]));
00132 ++sptr;
00133 }
00134 }
00135
00136 return result;
00137 }
00138
00139
00140 Image<int> intgScaleLuminanceFromByte(const Image<PixRGB<byte> >* src, const uint nbits)
00141 {
00142 Image<int> result(src->getDims(), NO_INIT);
00143 Image<PixRGB<byte> >::const_iterator sptr = src->begin();
00144 Image<int>::iterator dptr = result.beginw();
00145 Image<int>::iterator const stop = result.endw();
00146
00147 if (nbits > 8)
00148 while (dptr != stop)
00149 { *dptr++ = ((sptr->p[0] + sptr->p[1] + sptr->p[2]) / 3) << (nbits - 8); ++sptr; }
00150 else if (nbits < 8)
00151 while (dptr != stop)
00152 { *dptr++ = ((sptr->p[0] + sptr->p[1] + sptr->p[2]) / 3) >> (8 - nbits); ++sptr; }
00153 else
00154 while (dptr != stop)
00155 { *dptr++ = (sptr->p[0] + sptr->p[1] + sptr->p[2]) / 3; ++sptr; }
00156
00157 return result;
00158 }
00159
00160
00161 Image<PixRGB<int> > intgScaleFromFloat(const Image<PixRGB<float> >* src, const uint nbits)
00162 {
00163 if (nbits > 8)
00164 return (Image<PixRGB<int> >(*src * (1 << (nbits - 8))));
00165 else if (nbits < 8)
00166 return (Image<PixRGB<int> >(*src / (1 << (8 - nbits))));
00167
00168 return Image<PixRGB<int> >(*src);
00169 }
00170
00171
00172 Image<float> intgScaleToFloat(const Image<int>* src, const uint nbits)
00173 {
00174 if (nbits > 8)
00175 return (Image<float>(*src) / float(1 << (nbits - 8)));
00176 else if (nbits < 8)
00177 return (Image<float>(*src) * (1 << (8 - nbits)));
00178
00179 return Image<float>(*src);
00180 }
00181
00182
00183
00184 Image<int> intgLowPass5xDecX(const Image<int>& src,
00185 const integer_math* imath)
00186 {
00187 const int w = src.getWidth(), h = src.getHeight();
00188
00189 if (w < 2) return src;
00190
00191 const int w2 = w / 2;
00192 ASSERT(w2 > 0);
00193
00194 Image<int> result(w2, h, NO_INIT);
00195
00196 const int filterbits = 4;
00197 const int accumbits = 3;
00198
00199 if ((imath->nbits + filterbits + accumbits) >= (8*sizeof(int) - 1))
00200 (*imath->low_pass_5_x_dec_x_manybits)(src.getArrayPtr(), w, h,
00201 result.getArrayPtr(), w2);
00202 else
00203 (*imath->low_pass_5_x_dec_x_fewbits)(src.getArrayPtr(), w, h,
00204 result.getArrayPtr(), w2);
00205
00206 return result;
00207 }
00208
00209
00210
00211 Image<int> intgLowPass5yDecY(const Image<int>& src,
00212 const integer_math* imath)
00213 {
00214 const int w = src.getWidth(), h = src.getHeight();
00215
00216 if (h < 2) return src;
00217
00218 const int h2 = h / 2;
00219 ASSERT(h2 > 0);
00220
00221 Image<int> result(w, h2, NO_INIT);
00222
00223 const int filterbits = 4;
00224 const int accumbits = 3;
00225
00226 if ((imath->nbits + filterbits + accumbits) >= (8*sizeof(int) - 1))
00227 (*imath->low_pass_5_y_dec_y_manybits)(src.getArrayPtr(), w, h,
00228 result.getArrayPtr(), h2);
00229 else
00230 (*imath->low_pass_5_y_dec_y_fewbits)(src.getArrayPtr(), w, h,
00231 result.getArrayPtr(), h2);
00232
00233 return result;
00234 }
00235
00236
00237 Image<int> intgXFilterClean(const Image<int>& src,
00238 const int* hFilt, const int hfs,
00239 const int shiftbits,
00240 const integer_math* imath)
00241 {
00242 if (hfs == 0)
00243 return src;
00244
00245 int hFiltFlipped[hfs];
00246 int sumh = 0;
00247 for (int x = 0; x < hfs; x ++)
00248 { sumh += hFilt[x]; hFiltFlipped[hfs-1-x] = hFilt[x]; }
00249
00250 ASSERT(sumh == (1 << shiftbits));
00251
00252 const int accumbits = int(ceil(log2(double(hfs))));
00253
00254 Image<int> result(src.getDims(), NO_INIT);
00255
00256 if ((imath->nbits + shiftbits + accumbits) >= (8*sizeof(int) - 1))
00257 {
00258 if (src.getWidth() < hfs)
00259 (*imath->x_filter_clean_small_manybits)
00260 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00261 hFiltFlipped, hfs, shiftbits,
00262 result.getArrayPtr());
00263 else
00264 (*imath->x_filter_clean_manybits)
00265 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00266 hFiltFlipped, hfs, shiftbits,
00267 result.getArrayPtr());
00268 }
00269 else
00270 {
00271 if (src.getWidth() < hfs)
00272 (*imath->x_filter_clean_small_fewbits)
00273 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00274 hFiltFlipped, hfs, shiftbits,
00275 result.getArrayPtr());
00276 else
00277 (*imath->x_filter_clean_fewbits)
00278 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00279 hFiltFlipped, hfs, shiftbits,
00280 result.getArrayPtr());
00281 }
00282
00283 return result;
00284 }
00285
00286
00287 Image<int> intgYFilterClean(const Image<int>& src,
00288 const int* vFilt, const int vfs,
00289 const int shiftbits,
00290 const integer_math* imath)
00291 {
00292 if (vfs == 0)
00293 return src;
00294
00295 int vFiltFlipped[vfs];
00296 int sumv = 0;
00297 for (int x = 0; x < vfs; x ++)
00298 { sumv += vFilt[x]; vFiltFlipped[vfs-1-x] = vFilt[x]; }
00299
00300 ASSERT(sumv == (1 << shiftbits));
00301
00302 const int accumbits = int(ceil(log2(double(vfs))));
00303
00304 Image<int> result(src.getDims(), NO_INIT);
00305
00306 if ((imath->nbits + shiftbits + accumbits) >= (8*sizeof(int) - 1))
00307 {
00308 if (src.getHeight() < vfs)
00309 (*imath->y_filter_clean_small_manybits)
00310 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00311 vFiltFlipped, vfs, shiftbits,
00312 result.getArrayPtr());
00313 else
00314 (*imath->y_filter_clean_manybits)
00315 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00316 vFiltFlipped, vfs, shiftbits,
00317 result.getArrayPtr());
00318 }
00319 else
00320 {
00321 if (src.getHeight() < vfs)
00322 (*imath->y_filter_clean_small_fewbits)
00323 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00324 vFiltFlipped, vfs, shiftbits,
00325 result.getArrayPtr());
00326 else
00327 (*imath->y_filter_clean_fewbits)
00328 (src.getArrayPtr(), src.getWidth(), src.getHeight(),
00329 vFiltFlipped, vfs, shiftbits,
00330 result.getArrayPtr());
00331 }
00332
00333 return result;
00334 }
00335
00336
00337 Image<int> intgLowPass9x(const Image<int>& src,
00338 const integer_math* imath)
00339 {
00340 const int w = src.getWidth(), h = src.getHeight();
00341
00342 if (w < 2) return src;
00343
00344 if (w < 9)
00345 {
00346 const int kernel[9] = { 1, 8, 28, 56, 70, 56, 28, 8, 1 };
00347 const int shiftbits = 8;
00348 return intgXFilterClean(src, kernel, 9, shiftbits, imath);
00349 }
00350
00351 Image<int> result(w, h, NO_INIT);
00352
00353 const int filterbits = 8;
00354 const int accumbits = 4;
00355
00356 if ((imath->nbits + filterbits + accumbits) >= (8*sizeof(int) - 1))
00357 (*imath->low_pass_9_x_manybits)(src.getArrayPtr(), w, h,
00358 result.getArrayPtr());
00359 else
00360 (*imath->low_pass_9_x_fewbits)(src.getArrayPtr(), w, h,
00361 result.getArrayPtr());
00362
00363 return result;
00364 }
00365
00366
00367 Image<int> intgLowPass9y(const Image<int>& src,
00368 const integer_math* imath)
00369 {
00370 const int w = src.getWidth(), h = src.getHeight();
00371
00372 if (h < 2) return src;
00373
00374 if (h < 9)
00375 {
00376 const int kernel[9] = { 1, 8, 28, 56, 70, 56, 28, 8, 1 };
00377 const int shiftbits = 8;
00378 return intgYFilterClean(src, kernel, 9, shiftbits, imath);
00379 }
00380
00381 Image<int> result(w, h, NO_INIT);
00382
00383 const int filterbits = 8;
00384 const int accumbits = 4;
00385
00386 if ((imath->nbits + filterbits + accumbits) >= (8*sizeof(int) - 1))
00387 (*imath->low_pass_9_y_manybits)(src.getArrayPtr(), w, h,
00388 result.getArrayPtr());
00389 else
00390 (*imath->low_pass_9_y_fewbits)(src.getArrayPtr(), w, h,
00391 result.getArrayPtr());
00392
00393 return result;
00394 }
00395
00396
00397 Image<int> intgLowPassX(int filterSize, const Image<int>& src,
00398 const integer_math* imath)
00399 {
00400 switch (filterSize)
00401 {
00402 case 9: return intgLowPass9x(src, imath);
00403 default:
00404 LFATAL("Filter size %d is not supported", filterSize);
00405 }
00406
00407 return Image<int>();
00408 }
00409
00410
00411 Image<int> intgLowPassY(int filterSize, const Image<int>& src,
00412 const integer_math* imath)
00413 {
00414 switch (filterSize)
00415 {
00416 case 9: return intgLowPass9y(src, imath);
00417 default:
00418 LFATAL("Filter size %d is not supported", filterSize);
00419 }
00420
00421 return Image<int>();
00422 }
00423
00424
00425 Image<int> intgLowPass(int filterSize, const Image<int>& src,
00426 const integer_math* imath)
00427 {
00428 return intgLowPassY(filterSize,
00429 intgLowPassX(filterSize, src, imath),
00430 imath);
00431 }
00432
00433
00434 Image<int> intgQuadEnergy(const Image<int>& img1, const Image<int>& img2)
00435 {
00436 ASSERT(img1.isSameSize(img2));
00437
00438 Image<int> result(img1.getDims(), NO_INIT);
00439
00440 Image<int>::const_iterator s1ptr = img1.begin();
00441 Image<int>::const_iterator s2ptr = img2.begin();
00442 Image<int>::iterator dptr = result.beginw();
00443 Image<int>::iterator stop = result.endw();
00444
00445 while (dptr != stop)
00446 {
00447 const int s1 = abs(*s1ptr++);
00448 const int s2 = abs(*s2ptr++);
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 *dptr++ = (s1 > s2) ? (s1 + (s2 >> 1)) : ((s1 >> 1) + s2);
00460 }
00461
00462 return result;
00463 }
00464
00465
00466 Image<int> intgOrientedFilter(const Image<int>& src,
00467 const float k, const float theta,
00468 const integer_math* imath)
00469 {
00470
00471 static IntgTrigTable<256, 8> trig;
00472
00473 const int KBITS = 8;
00474
00475 const int thetaidx = trig.indexDegrees(theta + 90.0);
00476
00477 const double kx = double(k) * trig.costab[thetaidx] / double(1<<trig.nbits);
00478 const double ky = double(k) * trig.sintab[thetaidx] / double(1<<trig.nbits);
00479
00480 const int kxnum = int((kx * (1 << KBITS) * trig.tabsiz) / (2.0*M_PI));
00481 const int kynum = int((ky * (1 << KBITS) * trig.tabsiz) / (2.0*M_PI));
00482
00483 Image<int> re(src.getDims(), NO_INIT), im(src.getDims(), NO_INIT);
00484 Image<int>::const_iterator sptr = src.begin();
00485 Image<int>::iterator reptr = re.beginw(), imptr = im.beginw();
00486
00487
00488 const int w2l = src.getWidth() / 2;
00489 const int w2r = src.getWidth() - w2l;
00490 const int h2l = src.getHeight() / 2;
00491 const int h2r = src.getHeight() - h2l;
00492
00493
00494
00495
00496
00497
00498 ASSERT((std::numeric_limits<int>::max() / (abs(kxnum) + abs(kynum)))
00499 > (w2r + h2r));
00500
00501 ASSERT((2 * trig.nbits + 1) < 8*sizeof(int));
00502
00503 const int mdcutoff =
00504 std::numeric_limits<int>::max() >> (trig.nbits+1);
00505
00506 for (int j = -h2l; j < h2r; ++j)
00507 for (int i = -w2l; i < w2r; ++i)
00508 {
00509 const int arg = (i * kxnum + j * kynum) >> KBITS;
00510
00511 int idx = arg % trig.tabsiz;
00512 if (idx < 0) idx += trig.tabsiz;
00513
00514 const int sval = *sptr++;
00515
00516 if (sval == 0)
00517 {
00518 *reptr++ = 0;
00519 *imptr++ = 0;
00520 }
00521 else if (abs(sval) < mdcutoff)
00522 {
00523 *reptr++ = (sval * trig.costab[idx]) >> (trig.nbits+1);
00524 *imptr++ = (sval * trig.sintab[idx]) >> (trig.nbits+1);
00525 }
00526 else
00527 {
00528 const int val = (sval >> (trig.nbits+1));
00529 *reptr++ = val * trig.costab[idx];
00530 *imptr++ = val * trig.sintab[idx];
00531 }
00532 }
00533
00534 re = intgLowPass(9, re, imath);
00535 im = intgLowPass(9, im, imath);
00536
00537 return intgQuadEnergy(re, im);
00538 }
00539
00540
00541 void intgInplaceAttenuateBorders(Image<int>& a, int size)
00542 {
00543 ASSERT(a.initialized());
00544
00545 Dims dims = a.getDims();
00546
00547 if (size * 2 > dims.w()) size = dims.w() / 2;
00548 if (size * 2 > dims.h()) size = dims.h() / 2;
00549 if (size < 1) return;
00550
00551
00552 int coeff = 1;
00553 Image<int>::iterator aptr = a.beginw();
00554 for (int y = 0; y < size; y ++)
00555 {
00556 for (int x = 0; x < dims.w(); x ++)
00557 {
00558 *aptr = ((*aptr) / (size+1)) * coeff;
00559 ++aptr;
00560 }
00561 ++coeff;
00562 }
00563
00564 aptr = a.beginw();
00565 for (int y = 0; y < dims.h(); y ++)
00566 {
00567 coeff = 1;
00568 for (int x = 0; x < size; x ++)
00569 {
00570 *(aptr + dims.w() - 1 - x * 2) =
00571 (*(aptr + dims.w() - 1 - x * 2) / (size+1)) * coeff;
00572
00573 *aptr = ((*aptr) / (size+1)) * coeff;
00574 ++aptr;
00575 ++coeff;
00576 }
00577 aptr += dims.w() - size;
00578 }
00579
00580 aptr = a.beginw() + (dims.h() - size) * dims.w();
00581 coeff = size;
00582 for (int y = dims.h() - size; y < dims.h(); y ++)
00583 {
00584 for (int x = 0; x < dims.w(); ++x)
00585 {
00586 *aptr = ((*aptr) / (size+1)) * coeff;
00587 ++aptr;
00588 }
00589 --coeff;
00590 }
00591 }
00592
00593
00594 ImageSet<int> intgBuildPyrLaplacian(const Image<int>& image,
00595 int firstlevel, int depth,
00596 int filterSize,
00597 const integer_math* imath)
00598 {
00599 ASSERT(image.initialized());
00600
00601 ImageSet<int> result(depth);
00602
00603
00604
00605
00606 Image<int> lpfima;
00607
00608 for (int lev = 0; lev < depth; ++lev)
00609 {
00610 const Image<int> dec =
00611 lev == 0 ? image : decXY(lpfima);
00612 lpfima = intgLowPass(filterSize, dec, imath);
00613
00614 if (lev >= firstlevel)
00615 result[lev] = dec-lpfima;
00616 }
00617
00618 return result;
00619 }
00620
00621
00622 ImageSet<int> intgBuildPyrOrientedFromLaplacian(const ImageSet<int>& lplc,
00623 const int filterSize,
00624 const float theta,
00625 const integer_math* imath)
00626 {
00627 int attenuation_width = -1;
00628 float spatial_freq = -1.0;
00629
00630 switch (filterSize)
00631 {
00632 case 9: attenuation_width = 5; spatial_freq = 2.6; break;
00633 default:
00634 LFATAL("Filter size %d is not supported", filterSize);
00635 }
00636
00637 ImageSet<int> result(lplc.size());
00638
00639 for (uint lev = 0; lev < lplc.size(); ++lev)
00640 {
00641
00642
00643 if (!lplc[lev].initialized())
00644 continue;
00645
00646 result[lev] = intgOrientedFilter(lplc[lev], spatial_freq, theta,
00647 imath);
00648
00649 intgInplaceAttenuateBorders(result[lev], attenuation_width);
00650 }
00651
00652 return result;
00653 }
00654
00655
00656 ImageSet<int> intgBuildPyrOriented(const Image<int>& image,
00657 int firstlevel, int depth,
00658 int filterSize, float theta,
00659 const integer_math* imath)
00660 {
00661 const ImageSet<int> lplc =
00662 intgBuildPyrLaplacian(image, firstlevel, depth, filterSize, imath);
00663
00664 return intgBuildPyrOrientedFromLaplacian(lplc, filterSize,
00665 theta, imath);
00666 }
00667
00668
00669 ImageSet<int> intgBuildPyrGaussian(const Image<int>& image,
00670 int depth, int filterSize,
00671 const integer_math* imath)
00672 {
00673 ASSERT(image.initialized());
00674
00675 ImageSet<int> result(depth);
00676
00677 result[0] = image;
00678 for (int lev = 1; lev < depth; ++lev)
00679 {
00680 Image<int> a = result.getImage(lev-1);
00681 if (filterSize == 5)
00682 {
00683 a = intgLowPass5xDecX(a,imath);
00684 a = intgLowPass5yDecY(a,imath);
00685 }
00686 else
00687 {
00688 a = decX(intgLowPassX(filterSize, a, imath));
00689 a = decY(intgLowPassY(filterSize, a, imath));
00690 }
00691 result[lev] = a;
00692 }
00693
00694 return result;
00695 }
00696
00697
00698 Image<int> intgDownSize(const Image<int>& src, const Dims& dims,
00699 const int filterWidth,
00700 const integer_math* imath)
00701 {
00702 const int new_w = dims.w();
00703 const int new_h = dims.h();
00704
00705 if (src.getWidth() == new_w && src.getHeight() == new_h) return src;
00706
00707 ASSERT(src.getWidth() / new_w > 1 && src.getHeight() / new_h > 1);
00708
00709 const int wdepth = int(0.5+log(double(src.getWidth() / new_w)) / M_LN2);
00710 const int hdepth = int(0.5+log(double(src.getHeight() / new_h)) / M_LN2);
00711
00712 if (wdepth != hdepth)
00713 LFATAL("arrays must have same proportions");
00714
00715 Image<int> result = src;
00716
00717 for (int i = 0; i < wdepth; ++i)
00718 {
00719 result = decX(intgLowPassX(filterWidth, result, imath));
00720 result = decY(intgLowPassY(filterWidth, result, imath));
00721 }
00722
00723 return result;
00724 }
00725
00726
00727 Image<int> intgRescale(const Image<int>& src, const Dims& dims)
00728 {
00729 const int new_w = dims.w();
00730 const int new_h = dims.h();
00731
00732 ASSERT(src.initialized()); ASSERT(new_w > 0 && new_h > 0);
00733
00734 const int orig_w = src.getWidth();
00735 const int orig_h = src.getHeight();
00736
00737
00738 if (new_w == orig_w && new_h == orig_h) return src;
00739
00740 Image<int> result(new_w, new_h, NO_INIT);
00741 Image<int>::iterator dptr = result.beginw();
00742 Image<int>::const_iterator const sptr = src.begin();
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 for (int j = 0; j < new_h; ++j)
00755 {
00756 const int y_numer = std::max(0, j*2*orig_h+orig_h-new_h);
00757 const int y_denom = 2*new_h;
00758
00759 const int y0 = y_numer / y_denom;
00760 const int y1 = std::min(y0 + 1, orig_h - 1);
00761
00762 const int fy_numer = y_numer - y0 * y_denom;
00763 const int fy_denom = y_denom;
00764 ASSERT(fy_numer == (y_numer % y_denom));
00765
00766 const int wy0 = orig_w * y0;
00767 const int wy1 = orig_w * y1;
00768
00769 for (int i = 0; i < new_w; ++i)
00770 {
00771 const int x_numer = std::max(0, i*2*orig_w+orig_w-new_w);
00772 const int x_denom = 2*new_w;
00773
00774 const int x0 = x_numer / x_denom;
00775 const int x1 = std::min(x0 + 1, orig_w - 1);
00776
00777 const int fx_numer = x_numer - x0 * x_denom;
00778 const int fx_denom = x_denom;
00779 ASSERT(fx_numer == (x_numer % x_denom));
00780
00781 const int
00782 d00( sptr[x0 + wy0] ), d10( sptr[x1 + wy0] ),
00783 d01( sptr[x0 + wy1] ), d11( sptr[x1 + wy1] ),
00784 dx0( d00 + ((d10 - d00) / fx_denom) * fx_numer ),
00785 dx1( d01 + ((d11 - d01) / fx_denom) * fx_numer );
00786
00787 *dptr++ = dx0 + ((dx1 - dx0) / fy_denom) * fy_numer;
00788 }
00789 }
00790 return result;
00791 }
00792
00793
00794 void intgInplaceAddBGnoise(Image<int>& src, int max)
00795 {
00796 const int range = max / 100000;
00797
00798 ASSERT(src.initialized());
00799 const int w = src.getWidth(), h = src.getHeight();
00800
00801
00802 int siz = std::min(w, h) / 10;
00803
00804 Image<int>::iterator sptr = src.beginw() + siz + siz * w;
00805
00806 static rutz::urand rnd;
00807
00808 for (int j = siz; j < h - siz; ++j)
00809 {
00810 for (int i = siz; i < w - siz; ++i)
00811 *sptr++ += rnd.idraw(range);
00812 sptr += siz + siz;
00813 }
00814 }
00815
00816
00817 Image<int> intgMaxNormalize(const Image<int>& src,
00818 const int mi, const int ma, const MaxNormType normtyp)
00819 {
00820
00821 Image<int> result;
00822
00823
00824 switch(normtyp)
00825 {
00826 case VCXNORM_NONE:
00827 result = intgMaxNormalizeNone(src, mi, ma);
00828 break;
00829 case VCXNORM_MAXNORM:
00830 result = intgMaxNormalizeStd(src, mi, ma);
00831 break;
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858 default:
00859 LFATAL("Unknown normalization type: %d", int(normtyp));
00860 }
00861
00862 return result;
00863 }
00864
00865
00866 Image<int> intgMaxNormalizeNone(const Image<int>& src,
00867 const int nmi, const int nma)
00868 {
00869 Image<int> result = src;
00870
00871
00872 inplaceRectify(result);
00873
00874
00875 int mi = nmi;
00876 int ma = nma;
00877 if (mi != 0 || ma != 0)
00878 intgInplaceNormalize(result, nmi, nma, &mi, &ma);
00879
00880 return result;
00881 }
00882
00883
00884 Image<int> intgMaxNormalizeStd(const Image<int>& src,
00885 const int nmi, const int nma)
00886 {
00887 ASSERT(src.initialized());
00888
00889 Image<int> result = src;
00890
00891
00892 inplaceRectify(result);
00893
00894
00895 int mi = nmi;
00896 int ma = nma;
00897 if (nmi != 0 || nma != 0)
00898 intgInplaceNormalize(result, nmi, nma, &mi, &ma);
00899
00900 const int w = result.getWidth();
00901 const int h = result.getHeight();
00902
00903
00904
00905
00906 const int thresh = mi + (ma - mi) / 10;
00907
00908
00909 std::vector<int> vals;
00910 Image<int>::const_iterator const dptr = result.begin();
00911 for (int j = 1; j < h - 1; ++j)
00912 for (int i = 1; i < w - 1; ++i)
00913 {
00914 const int index = i + w * j;
00915 const int val = dptr[index];
00916 if (val >= thresh &&
00917 val >= dptr[index - w] &&
00918 val >= dptr[index + w] &&
00919 val >= dptr[index - 1] &&
00920 val >= dptr[index + 1])
00921 {
00922 vals.push_back(val);
00923 }
00924 }
00925
00926 int lm_mean = 0;
00927 for (size_t i = 0; i < vals.size(); ++i)
00928 lm_mean += (vals[i] / vals.size());
00929
00930 ASSERT(ma >= lm_mean);
00931
00932
00933 if (vals.size() > 1)
00934 {
00935
00936 ASSERT((ma == lm_mean) ||
00937 ((std::numeric_limits<int>::max() / (ma - lm_mean))
00938 > (ma - lm_mean)));
00939
00940 const int factor = ((ma - lm_mean) * (ma - lm_mean)) / ma;
00941 result *= factor;
00942 }
00943 else if (vals.size() == 1)
00944 {
00945 const int factor = ma;
00946 result *= factor;
00947 }
00948 else
00949 {
00950
00951 }
00952
00953 return result;
00954 }
00955
00956
00957 Image<int> intgCenterSurround(const ImageSet<int>& pyr,
00958 int lev1, int lev2, bool absol,
00959 const ImageSet<int>* clipPyr)
00960 {
00961 ASSERT(lev1 >= 0 && lev2 >= 0);
00962 ASSERT(uint(lev1) < pyr.size() && uint(lev2) < pyr.size());
00963
00964 const int largeLev = std::min(lev1, lev2);
00965 const int smallLev = std::max(lev1, lev2);
00966
00967 if (clipPyr != 0 && clipPyr->isNonEmpty())
00968 {
00969 LFATAL("clipping pyramids not supported");
00970
00971 ASSERT((*clipPyr)[largeLev].getDims() == pyr[largeLev].getDims());
00972 ASSERT((*clipPyr)[smallLev].getDims() == pyr[smallLev].getDims());
00973
00974
00975 return
00976 intgCenterSurround(Image<int>(pyr[largeLev] * (*clipPyr)[largeLev]),
00977 Image<int>(pyr[smallLev] * (*clipPyr)[smallLev]),
00978 absol);
00979 }
00980 else
00981 return intgCenterSurround(pyr[largeLev], pyr[smallLev], absol);
00982 }
00983
00984
00985 void intgDoLowThresh(ImageSet<int>& x, int threshold, int newval)
00986 {
00987 for (uint i = 0; i < x.size(); ++i)
00988 inplaceLowThresh(x[i], threshold, newval);
00989 }
00990
00991
00992 void intgDoLowThreshAbs(ImageSet<int>& x, int threshold, int newval)
00993 {
00994 for (uint i = 0; i < x.size(); ++i)
00995 inplaceLowThreshAbs(x[i], threshold, newval);
00996 }
00997
00998
00999 void intgDoRectify(ImageSet<int>& x)
01000 {
01001 for (uint i = 0; i < x.size(); ++i)
01002 inplaceRectify(x[i]);
01003 }
01004
01005
01006 void intgInplaceNormalize(Image<int>& dst, const int nmin, const int nmax,
01007 int* actualmin_p, int* actualmax_p)
01008 {
01009 ASSERT(dst.initialized());
01010 ASSERT(nmax >= nmin);
01011
01012 int mi, ma; getMinMax(dst, mi, ma);
01013 const int scale = ma - mi;
01014 if (scale == 0) { dst.clear(0); return; }
01015 const int nscale = nmax - nmin;
01016
01017 if (nscale == 0) { dst.clear(nmin); return; }
01018
01019 Image<int>::iterator aptr = dst.beginw();
01020 Image<int>::iterator stop = dst.endw();
01021
01022 int actualmin, actualmax;
01023
01024 if (scale == nscale)
01025 {
01026 const int add = nmin - mi;
01027 while (aptr != stop)
01028 {
01029 *aptr += add;
01030 ++aptr;
01031 }
01032
01033 actualmin = nmin;
01034 actualmax = nmax;
01035 }
01036 else if (scale > nscale)
01037 {
01038 const int div = scale / nscale;
01039
01040 while (aptr != stop)
01041 {
01042 *aptr = nmin + ((*aptr - mi) / div);
01043 ++aptr;
01044 }
01045
01046
01047
01048
01049
01050
01051
01052 actualmin = nmin;
01053 actualmax = nmin + (scale / div);
01054 }
01055 else
01056 {
01057 const int mul = nscale / scale;
01058 while (aptr != stop)
01059 {
01060 *aptr = nmin + ((*aptr - mi) * mul);
01061 ++aptr;
01062 }
01063
01064 actualmin = nmin;
01065 actualmax = nmin + (scale * mul);
01066 }
01067
01068
01069
01070 ASSERT(actualmin_p != NULL);
01071 ASSERT(actualmax_p != NULL);
01072 *actualmin_p = actualmin;
01073 *actualmax_p = actualmax;
01074 }
01075
01076
01077 Image<int> intgCenterSurround(const Image<int>& center,
01078 const Image<int>& surround,
01079 const bool absol)
01080 {
01081 const int lw = center.getWidth(), lh = center.getHeight();
01082 const int sw = surround.getWidth(), sh = surround.getHeight();
01083
01084 if (sw > lw || sh > lh) LFATAL("center must be larger than surround");
01085
01086 int scalex = lw / sw, remx = lw - 1 - (lw % sw);
01087 int scaley = lh / sh, remy = lh - 1 - (lh % sh);
01088
01089
01090 Image<int> result(center.getDims(), NO_INIT);
01091
01092
01093 int ci = 0, cj = 0;
01094 Image<int>::const_iterator lptr = center.begin();
01095 Image<int>::const_iterator sptr = surround.begin();
01096 Image<int>::iterator dptr = result.beginw();
01097
01098 if (absol == true)
01099 {
01100 for (int j = 0; j < lh; ++j)
01101 {
01102 for (int i = 0; i < lw; ++i)
01103 {
01104 if (*lptr > *sptr)
01105 *dptr++ = (*lptr++ - *sptr);
01106 else
01107 *dptr++ = (*sptr - *lptr++);
01108
01109 if ((++ci) == scalex && i != remx) { ci = 0; ++sptr; }
01110 }
01111 if (ci) { ci = 0; ++sptr; }
01112 if ((++cj) == scaley && j != remy) cj = 0; else sptr -= sw;
01113 }
01114 }
01115 else
01116 {
01117 for (int j = 0; j < lh; ++j)
01118 {
01119 for (int i = 0; i < lw; ++i)
01120 {
01121 if (*lptr > *sptr)
01122 *dptr++ = (*lptr++ - *sptr);
01123 else
01124 { *dptr++ = 0; lptr++; }
01125
01126 if ((++ci) == scalex && i != remx) { ci = 0; ++sptr; }
01127 }
01128 if (ci) { ci = 0; ++sptr; }
01129 if ((++cj) == scaley && j != remy) cj = 0; else sptr -= sw;
01130 }
01131 }
01132
01133
01134 intgInplaceAttenuateBorders(result, result.getDims().max() / 20);
01135
01136 return result;
01137 }
01138
01139
01140 void intgGetRGBY(const Image<PixRGB<byte> >& src,
01141 Image<int>& rg,
01142 Image<int>& by, const int threshfactor,
01143 const uint inputbits)
01144 {
01145
01146
01147
01148
01149
01150 ASSERT(src.initialized());
01151
01152 rg = Image<int>(src.getDims(), NO_INIT);
01153 by = Image<int>(src.getDims(), NO_INIT);
01154
01155 Image<PixRGB<byte> >::const_iterator aptr = src.begin();
01156 Image<PixRGB<byte> >::const_iterator stop = src.end();
01157
01158 Image<int>::iterator rgptr = rg.beginw(), byptr = by.beginw();
01159
01160 const int bitsaftershift = 8*sizeof(int) - 2;
01161 const int upshift = bitsaftershift - 14;
01162 const int bitsafterdiv = bitsaftershift - 10;
01163 const int finalshift = inputbits - bitsafterdiv;
01164
01165 ASSERT(upshift > 0);
01166
01167 while (aptr != stop)
01168 {
01169 const int r = aptr->p[0];
01170 const int g = aptr->p[1];
01171 const int b = aptr->p[2];
01172 ++aptr;
01173
01174 if (threshfactor*(r+g+b) < 3*255)
01175 { *rgptr++ = 0; *byptr++ = 0; }
01176 else
01177 {
01178
01179 const int lum = r + g + b;
01180
01181
01182 int red = 2*r - g - b;
01183 int green = 2*g - r - b;
01184 int blue = 2*b - r - g;
01185 int yellow = -2*blue - 4*abs(r-g);
01186
01187 if (red < 0) red = 0;
01188 if (green < 0) green = 0;
01189 if (blue < 0) blue = 0;
01190 if (yellow < 0) yellow = 0;
01191
01192
01193
01194
01195
01196
01197
01198
01199 if (finalshift > 0)
01200 {
01201 *rgptr++ = ((3*(red - green) << upshift) / lum) << finalshift;
01202 *byptr++ = ((3*(blue - yellow) << upshift) / lum) << finalshift;
01203 }
01204 else if (finalshift < 0)
01205 {
01206 *rgptr++ = ((3*(red - green) << upshift) / lum) >> (-finalshift);
01207 *byptr++ = ((3*(blue - yellow) << upshift) / lum) >> (-finalshift);
01208 }
01209 else
01210 {
01211 *rgptr++ = (3*(red - green) << upshift) / lum;
01212 *byptr++ = (3*(blue - yellow) << upshift) / lum;
01213 }
01214 }
01215 }
01216 }
01217
01218
01219 Image<int> intgShiftImage(const Image<int>& srcImg,
01220 const int dxnumer, const int dynumer,
01221 const uint denombits)
01222 {
01223
01224 ASSERT(srcImg.initialized());
01225
01226 ASSERT(denombits < 8*sizeof(int));
01227
01228 const int denom = (1 << denombits);
01229
01230
01231 Dims dim(srcImg.getDims());
01232 int w = dim.w(), h = dim.h();
01233 Image<int> retImg(dim, ZEROS);
01234
01235
01236 int xt = dxnumer >= 0
01237 ? (dxnumer >> denombits)
01238 : - ((-dxnumer + denom-1) >> denombits);
01239 int xfrac_numer = dxnumer - (xt << denombits);
01240 int startx = std::max(0,xt);
01241 int endx = std::min(0,xt) + w;
01242 if (xfrac_numer != 0 && abs(denom)/abs(xfrac_numer) > (1 << 30))
01243 xfrac_numer = 0;
01244 else endx--;
01245
01246
01247 int yt = dynumer >= 0
01248 ? (dynumer >> denombits)
01249 : - ((-dynumer + denom-1) >> denombits);
01250 int yfrac_numer = dynumer - (yt << denombits);
01251 int starty = std::max(0,yt);
01252 int endy = std::min(0,yt) + h;
01253 if (yfrac_numer != 0 && abs(denom)/abs(yfrac_numer) > (1 << 30))
01254 yfrac_numer = 0;
01255 else endy--;
01256
01257
01258
01259 if (xfrac_numer == 0 && yfrac_numer == 0)
01260 return shiftClean(srcImg, xt, yt);
01261
01262 if (xfrac_numer > 0)
01263 {
01264 xfrac_numer = denom - xfrac_numer;
01265 xt++;
01266 }
01267
01268 if (yfrac_numer > 0)
01269 {
01270 yfrac_numer = denom - yfrac_numer;
01271 yt++;
01272 }
01273
01274
01275 Image<int>::const_iterator src, src2 = srcImg.begin();
01276 Image<int>::iterator ret, ret2 = retImg.beginw();
01277 if (xt > 0) ret2 += xt;
01278 if (xt < 0) src2 -= xt;
01279 if (yt > 0) ret2 += yt * w;
01280 if (yt < 0) src2 -= yt * w;
01281
01282
01283 for (int y = starty; y < endy; ++y)
01284 {
01285 src = src2; ret = ret2;
01286 for (int x = startx; x < endx; ++x)
01287 {
01288 *ret = (((src[0] >> denombits) * (denom - xfrac_numer)) >> denombits) * (denom - yfrac_numer);
01289 *ret += (((src[1] >> denombits) * xfrac_numer) >> denombits) * (denom - yfrac_numer);
01290 *ret += (((src[w] >> denombits) * (denom - xfrac_numer)) >> denombits) * yfrac_numer;
01291 *ret += (((src[w+1] >> denombits) * xfrac_numer) >> denombits) * yfrac_numer;
01292 ++src; ++ret;
01293 }
01294 src2 += w; ret2 += w;
01295 }
01296 return retImg;
01297 }
01298
01299
01300
01301
01302
01303 IntgGaussianPyrBuilder::IntgGaussianPyrBuilder(const int filter_size,
01304 const integer_math* imath) :
01305 PyrBuilder<int>(),
01306 itsFiltSize(filter_size),
01307 itsImath(imath)
01308 {}
01309
01310 ImageSet<int> IntgGaussianPyrBuilder::build(const Image<int>& img,
01311 const int firstlevel,
01312 const int depth,
01313 PyramidCache<int>* cache)
01314 {
01315 ASSERT(cache != 0);
01316
01317 const ImageSet<int>* const cached =
01318 (cache != 0 && itsFiltSize == 5)
01319 ? cache->gaussian5.get(img)
01320 : 0;
01321
01322 return (cached != 0)
01323 ? *cached
01324 : intgBuildPyrGaussian(img, depth, itsFiltSize, itsImath);
01325 }
01326
01327 IntgGaussianPyrBuilder* IntgGaussianPyrBuilder::clone() const
01328 {
01329 return new IntgGaussianPyrBuilder(*this);
01330 }
01331
01332
01333
01334
01335
01336 IntgOrientedPyrBuilder::IntgOrientedPyrBuilder(const int filter_size,
01337 const float theta,
01338 const integer_math* imath) :
01339 PyrBuilder<int>(),
01340 itsFiltSize(filter_size),
01341 itsAngle(theta),
01342 itsImath(imath)
01343 {}
01344
01345 ImageSet<int> IntgOrientedPyrBuilder::build(const Image<int>& img,
01346 const int firstlevel,
01347 const int depth,
01348 PyramidCache<int>* cache)
01349 {
01350 ASSERT(cache != 0);
01351
01352 const ImageSet<int>* const lplc =
01353 (cache != 0 && itsFiltSize == 9)
01354 ? cache->laplacian9.get(img)
01355 : 0;
01356
01357 return lplc != 0
01358 ? intgBuildPyrOrientedFromLaplacian(*lplc, itsFiltSize, itsAngle,
01359 itsImath)
01360 : intgBuildPyrOriented(img, firstlevel, depth,
01361 itsFiltSize, itsAngle, itsImath);
01362 }
01363
01364 IntgOrientedPyrBuilder* IntgOrientedPyrBuilder::clone() const
01365 {
01366 return new IntgOrientedPyrBuilder(*this);
01367 }
01368
01369
01370
01371
01372 IntgReichardtPyrBuilder::
01373 IntgReichardtPyrBuilder(const int dxnumer, const int dynumer,
01374 const uint denombits,
01375 const integer_math* imath) :
01376 PyrBuilder<int>(),
01377 itsDXnumer(dxnumer), itsDYnumer(dynumer), itsDenomBits(denombits),
01378 itsImath(imath)
01379 {}
01380
01381 ImageSet<int> IntgReichardtPyrBuilder::build(const Image<int>& image,
01382 const int firstlevel,
01383 const int depth,
01384 PyramidCache<int>* cache)
01385 {
01386 const ImageSet<int>* const cached =
01387 cache != 0
01388 ? cache->gaussian5.get(image)
01389 : 0;
01390
01391
01392 ImageSet<int> upyr =
01393 cached != 0
01394 ? *cached
01395 : intgBuildPyrGaussian(image, depth, 5, itsImath);
01396
01397
01398 ImageSet<int> spyr(depth);
01399
01400
01401 for (int i = firstlevel; i < depth; ++i)
01402 spyr[i] = intgShiftImage(upyr[i], itsDXnumer, itsDYnumer,
01403 itsDenomBits);
01404
01405
01406 unshifted.push_back(upyr);
01407 shifted.push_back(spyr);
01408
01409 ImageSet<int> result(depth);
01410
01411
01412
01413 if (unshifted.size() == 1)
01414 {
01415 unshifted.push_back(upyr);
01416 shifted.push_back(spyr);
01417 }
01418
01419
01420 if (unshifted.size() == 3)
01421 {
01422 unshifted.pop_front();
01423 shifted.pop_front();
01424 }
01425
01426
01427 for (int i = firstlevel; i < depth; i++)
01428 {
01429 result[i] = Image<int>(unshifted.back()[i].getDims(), NO_INIT);
01430 const int sz = result[i].getSize();
01431
01432 Image<int>::iterator rptr = result[i].beginw();
01433 Image<int>::const_iterator ubptr = unshifted.back()[i].begin();
01434 Image<int>::const_iterator ufptr = unshifted.front()[i].begin();
01435 Image<int>::const_iterator sbptr = shifted.back()[i].begin();
01436 Image<int>::const_iterator sfptr = shifted.front()[i].begin();
01437
01438
01439 const uint nshift = (itsImath->nbits+1)/2;
01440
01441 for (int j = 0; j < sz; ++j)
01442 rptr[j] =
01443 ((ubptr[j] >> nshift) * (sfptr[j] >> nshift)) -
01444 ((ufptr[j] >> nshift) * (sbptr[j] >> nshift));
01445 }
01446
01447 return result;
01448 }
01449
01450
01451 IntgReichardtPyrBuilder* IntgReichardtPyrBuilder::clone() const
01452 {
01453 return new IntgReichardtPyrBuilder(*this);
01454 }
01455
01456
01457 void IntgReichardtPyrBuilder::reset()
01458 {
01459 shifted.clear();
01460 unshifted.clear();
01461 }
01462
01463
01464
01465
01466
01467
01468
01469
01470 #endif // IMAGE_INTEGERMATHOPS_C_DEFINED