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
00039 #ifndef IMAGE_COLOROPS_C_DEFINED
00040 #define IMAGE_COLOROPS_C_DEFINED
00041
00042 #include "Image/ColorOps.H"
00043
00044 #include "Image/ColorMap.H"
00045 #include "Image/FilterOps.H"
00046 #include "Image/Image.H"
00047 #include "Image/MathOps.H"
00048 #include "Image/Pixels.H"
00049 #include "Image/ShapeOps.H"
00050 #include "Image/Transforms.H"
00051 #include "Util/Assert.H"
00052 #include "Util/MathFunctions.H"
00053 #include "Util/log.H"
00054 #include "rutz/trace.h"
00055
00056 #include <algorithm>
00057 #include <cmath>
00058
00059
00060 template <class T>
00061 Image<PixRGB<T> > makeRGB(const Image<T>& red,
00062 const Image<T>& green,
00063 const Image<T>& blue)
00064 {
00065 GVX_TRACE(__PRETTY_FUNCTION__);
00066 ASSERT(red.isSameSize(green) && red.isSameSize(blue));
00067
00068 Image<PixRGB<T> > result(red.getDims(), NO_INIT);
00069 typename Image<PixRGB<T> >::iterator aptr = result.beginw();
00070 typename Image<PixRGB<T> >::iterator stop = result.endw();
00071
00072 typename Image<T>::const_iterator rptr = red.begin();
00073 typename Image<T>::const_iterator gptr = green.begin();
00074 typename Image<T>::const_iterator bptr = blue.begin();
00075
00076 while (aptr != stop)
00077 {
00078 *aptr++ = PixRGB<T>(*rptr++, *gptr++, *bptr++);
00079 }
00080
00081 return result;
00082 }
00083
00084
00085 Image< PixRGB<byte> > colorize(const Image<byte>& img, const ColorMap& cmap)
00086 {
00087 GVX_TRACE(__PRETTY_FUNCTION__);
00088 if (cmap.getWidth() != 256) LFATAL("Need a ColorMap with 256 entries");
00089
00090 Image< PixRGB<byte> > result(img.getDims(), NO_INIT);
00091 Image<byte>::const_iterator src = img.begin(), stop = img.end();
00092 Image< PixRGB<byte> >::iterator dst = result.beginw();
00093
00094 const Image<PixRGB<byte> >::const_iterator cmapptr = cmap.begin();
00095
00096 while (src != stop)
00097 *dst++ = cmapptr[*src++];
00098
00099 return result;
00100 }
00101
00102
00103 void inplaceColorSpeckleNoise(Image< PixRGB<byte> >& dest, const int num)
00104 {
00105 GVX_TRACE(__PRETTY_FUNCTION__);
00106 ASSERT(dest.initialized());
00107 const int w = dest.getWidth(), h = dest.getHeight();
00108
00109 for (int i = 0; i < num; ++i)
00110 {
00111 int x = randomUpToNotIncluding(w);
00112 int y = randomUpToNotIncluding(h);
00113 dest.setVal(x, y,
00114 PixRGB<byte>(randomUpToIncluding(255),
00115 randomUpToIncluding(255),
00116 randomUpToIncluding(255)));
00117 }
00118 }
00119
00120
00121 template <class T>
00122 void getComponents(const Image<PixRGB<T> >& src,
00123 Image<T>& red, Image<T>& green, Image<T>& blue)
00124 {
00125 GVX_TRACE(__PRETTY_FUNCTION__);
00126 ASSERT(src.initialized());
00127
00128 red = Image<T>(src.getDims(), NO_INIT);
00129 green = Image<T>(src.getDims(), NO_INIT);
00130 blue = Image<T>(src.getDims(), NO_INIT);
00131
00132 typename Image<T>::iterator rptr = red.beginw();
00133 typename Image<T>::iterator gptr = green.beginw();
00134 typename Image<T>::iterator bptr = blue.beginw();
00135
00136 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00137 typename Image<PixRGB<T> >::const_iterator stop = src.end();
00138
00139 while (aptr != stop)
00140 {
00141 *rptr++ = aptr->red();
00142 *gptr++ = aptr->green();
00143 *bptr++ = aptr->blue();
00144 ++aptr;
00145 }
00146 }
00147
00148
00149 Image<PixRGB<float> > normalizeRGPolar(const Image<float>& src,
00150 const float max,
00151 const float min)
00152 {
00153 GVX_TRACE(__PRETTY_FUNCTION__);
00154 return stainPosNeg(src, std::max(fabs(min), fabs(max)),
00155 PixRGB<float>(0.0f),
00156 PixRGB<float>(0.0f, 255.0f, 0.0f),
00157 PixRGB<float>(255.0f, 0.0f, 0.0f));
00158 }
00159
00160
00161 Image<PixRGB<float> > normalizeRGPolarAuto(const Image<float>& src)
00162 {
00163 GVX_TRACE(__PRETTY_FUNCTION__);
00164 float max, min;
00165 getMinMax(src,min,max);
00166 return stainPosNeg(src, std::max(fabs(min), fabs(max)),
00167 PixRGB<float>(0.0f),
00168 PixRGB<float>(0.0f, 255.0f, 0.0f),
00169 PixRGB<float>(255.0f, 0.0f, 0.0f));
00170 }
00171
00172
00173 Image<PixRGB<float> > normalizeWithScale(const Image<float>& src,
00174 const float min = 0.0F,
00175 const float max = 255.0F,
00176 const float clamp = 255.0F,
00177 const char baseColor = 1,
00178 const char normColor = 3)
00179 {
00180 ASSERT(src.initialized());
00181 ASSERT(baseColor < 4);
00182 ASSERT(normColor < 4);
00183 ASSERT(normColor != baseColor);
00184 ASSERT(clamp > 0.0F);
00185 float mi,ma;
00186 getMinMax(src,mi,ma);
00187 const float scale = max - min;
00188 const float nscale = (ma - mi) / scale;
00189 Image<PixRGB<float> > outImage;
00190 outImage.resize(src.getWidth(),src.getHeight());
00191
00192 Image<float>::const_iterator aptr = src.begin();
00193 Image<float>::const_iterator stop = src.end();
00194 Image<PixRGB<float> >::iterator optr = outImage.beginw();
00195 while (aptr != stop)
00196 {
00197 if(*aptr > clamp || *aptr < 0.0F)
00198 (*optr).p[(uint)baseColor] = clamp;
00199 else
00200 (*optr).p[(uint)baseColor] = *aptr;
00201 (*optr).p[(uint)normColor] = min + ((*aptr - mi)*nscale);
00202 ++aptr; ++optr;
00203 }
00204 return outImage;
00205 }
00206
00207
00208 Image<PixRGB<float> > normalizeScaleRainbow(const Image<float>& src,
00209 const float min = 0.0F,
00210 const float max = 255.0F)
00211 {
00212 ASSERT(src.initialized());
00213 ASSERT(max > min);
00214
00215 Image<PixHSV<float> > scaleImage;
00216
00217 scaleImage.resize(src.getWidth(),src.getHeight());
00218
00219 float mi, ma;
00220 getMinMax(src,mi,ma);
00221 const float interval = ma - mi;
00222 const float mult = 330.0/(max - min);
00223
00224 Image<PixHSV<float> >::iterator aptr = scaleImage.beginw();
00225 Image<float>::const_iterator sptr = src.begin();
00226
00227
00228
00229
00230
00231 while(sptr != src.end())
00232 {
00233 if(*sptr < min) { aptr->setH(1); aptr->setS(1.0); aptr->setV(0); }
00234 else if(*sptr > max){ aptr->setH(1); aptr->setS(1.0); aptr->setV(255); }
00235 else
00236 {
00237 aptr->setH(mult * (*sptr - min));
00238 aptr->setS(100.0);
00239 aptr->setV(((*sptr - mi)/interval) * 255.0);
00240 }
00241 ++aptr; ++sptr;
00242 }
00243
00244 Image<PixRGB<float> > dest; dest.resize(src.getWidth(),src.getHeight());
00245
00246 aptr = scaleImage.beginw();
00247 Image<PixRGB<float> >::iterator dptr = dest.beginw();
00248
00249 while(aptr != scaleImage.end()) *dptr++ = PixRGB<float>(*aptr++);
00250
00251 return dest;
00252 }
00253
00254
00255 template <class T>
00256 Image<PixRGB<T> > stain(const Image<T>& src, PixRGB<float> color)
00257 {
00258 GVX_TRACE(__PRETTY_FUNCTION__);
00259 Image<PixRGB<T> > result(src.getDims(), NO_INIT);
00260
00261 typename Image<T>::const_iterator sptr = src.begin();
00262 typename Image<PixRGB<T> >::iterator dptr = result.beginw(),
00263 stop = result.endw();
00264
00265 while (dptr != stop)
00266 {
00267 *dptr = PixRGB<T>(color * (*sptr));
00268 ++sptr;
00269 ++dptr;
00270 }
00271
00272 return result;
00273 }
00274
00275
00276 Image<PixRGB<float> > stainPosNeg(const Image<float>& src,
00277 const float maxval,
00278 const PixRGB<float>& background,
00279 const PixRGB<float>& pos_stain,
00280 const PixRGB<float>& neg_stain)
00281 {
00282 GVX_TRACE(__PRETTY_FUNCTION__);
00283
00284 Image<PixRGB<float> > result(src.getDims(), NO_INIT);
00285
00286 Image<PixRGB<float> >::iterator dptr = result.beginw();
00287 Image<PixRGB<float> >::iterator stop = result.endw();
00288 Image<float>::const_iterator sptr = src.begin();
00289
00290 if(maxval > 0)
00291 {
00292 while (dptr != stop)
00293 {
00294 const float ratio = (*sptr++/maxval);
00295 if (ratio > 0)
00296 *dptr++ = pos_stain * ratio + background * (1.0f - ratio);
00297 else
00298 *dptr++ = neg_stain * (-ratio) + background * (1.0f + ratio);
00299 }
00300 }
00301 else
00302 {
00303 while (dptr != stop)
00304 *dptr++ = PixRGB<float>(0,0,0);
00305 }
00306
00307 return result;
00308 }
00309
00310
00311 Image<PixRGB<float> > overlayStain(const Image<float>& top,
00312 const Image<float>& bottom,
00313 const float trans, const char channel)
00314 {
00315 GVX_TRACE(__PRETTY_FUNCTION__);
00316
00317 ASSERT((trans >= 0.0F) && (trans <= 100.0F));
00318
00319 ASSERT(top.isSameSize(bottom));
00320
00321
00322 Image<PixRGB<float> > result(top.getDims(), NO_INIT);
00323
00324 Image<PixRGB<float> >::iterator
00325 dptr = result.beginw(),
00326 stop = result.endw();
00327
00328 Image<float>::const_iterator
00329 tptr = top.begin(),
00330 bptr = bottom.begin();
00331
00332 float tfac = trans * 0.01F;
00333
00334 while (dptr != stop)
00335 {
00336 float top_val = *tptr++;
00337
00338 PixRGB<float> pix;
00339
00340 if(channel == 'r'){pix.setRed(top_val);pix.setGreen(0);pix.setBlue(0);}
00341 if(channel == 'g'){pix.setRed(0);pix.setGreen(top_val);pix.setBlue(0);}
00342 if(channel == 'b'){pix.setRed(0);pix.setGreen(0);pix.setBlue(top_val);}
00343
00344 *dptr++ = pix - ( pix - (*bptr++) ) * tfac;
00345 }
00346
00347 return result;
00348 }
00349
00350
00351 template <class T>
00352 void getMinMaxC(const Image<PixRGB<T> >& src, T& mi, T& ma)
00353 {
00354 GVX_TRACE(__PRETTY_FUNCTION__);
00355 ASSERT(src.initialized());
00356 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00357 typename Image<PixRGB<T> >::const_iterator stop = src.end();
00358
00359 mi = aptr->red(); ma = aptr->red();
00360
00361 while (aptr != stop)
00362 {
00363 T x = aptr->red();
00364 if (x < mi) mi = x; else if (x > ma) ma = x;
00365
00366 x = aptr->green();
00367 if (x < mi) mi = x; else if (x > ma) ma = x;
00368
00369 x = aptr->blue();
00370 if (x < mi) mi = x; else if (x > ma) ma = x;
00371
00372 ++aptr;
00373 }
00374 }
00375
00376
00377 template <class T>
00378 PixRGB<float> meanRGB(const Image<PixRGB<T> >& src)
00379 {
00380 GVX_TRACE(__PRETTY_FUNCTION__);
00381 ASSERT(src.initialized());
00382
00383 typename Image<PixRGB<T> >::const_iterator sptr = src.begin();
00384 typename Image<PixRGB<T> >::const_iterator stop = src.end();
00385
00386 PixRGB<float> meanRGB;
00387 while (sptr != stop)
00388 {
00389 meanRGB[0] += sptr->p[0];
00390 meanRGB[1] += sptr->p[1];
00391 meanRGB[2] += sptr->p[2];
00392 ++sptr;
00393 }
00394
00395 meanRGB[0] /= src.size();
00396 meanRGB[1] /= src.size();
00397 meanRGB[2] /= src.size();
00398
00399 return meanRGB;
00400 }
00401
00402
00403 template <>
00404 Image<byte> luminance(const Image<PixRGB<byte> >& src)
00405 {
00406 GVX_TRACE(__PRETTY_FUNCTION__);
00407 ASSERT(src.initialized());
00408
00409 Image<byte> result(src.getDims(), NO_INIT);
00410
00411 Image<PixRGB<byte> >::const_iterator aptr = src.begin();
00412
00413 Image<byte>::iterator dptr = result.beginw();
00414 Image<byte>::iterator stop = result.endw();
00415
00416 while (dptr != stop)
00417 {
00418 *dptr++ = (aptr->p[0] + aptr->p[1] + aptr->p[2]) / 3;
00419 ++aptr;
00420 }
00421
00422 return result;
00423 }
00424
00425
00426 template <class T>
00427 Image<T> luminance(const Image<PixRGB<T> >& src)
00428 {
00429 GVX_TRACE(__PRETTY_FUNCTION__);
00430 ASSERT(src.initialized());
00431
00432 Image<T> result(src.getDims(), NO_INIT);
00433
00434 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00435
00436 typename Image<T>::iterator dptr = result.beginw();
00437 typename Image<T>::iterator stop = result.endw();
00438
00439 while (dptr != stop)
00440 *dptr++ = (*aptr++).luminance();
00441
00442 return result;
00443 }
00444
00445
00446 template <class T>
00447 Image<T> luminance(const Image<T>& src)
00448 { return src; }
00449
00450
00451
00452 template <class T>
00453 Image<T> luminanceNTSC(const Image<PixRGB<T> >& src)
00454 {
00455 GVX_TRACE(__PRETTY_FUNCTION__);
00456 ASSERT(src.initialized());
00457 Image<T> result(src.getDims(), NO_INIT);
00458
00459 float coef1,coef2,coef3;
00460
00461
00462
00463 coef1 = 0.298936F; coef2 = 0.587043F; coef3 = 0.114021F;
00464
00465
00466 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00467
00468 typename Image<T>::iterator dptr = result.beginw();
00469 typename Image<T>::iterator stop = result.endw();
00470
00471 while (dptr != stop){
00472 *dptr++ = T(round(aptr->p[0]*coef1 + aptr->p[1]*coef2 + aptr->p[2]*coef3));
00473 ++aptr;
00474 }
00475 return result;
00476 }
00477
00478
00479
00480 template <class T>
00481 Image< PixRGB<T> > toRGB(const Image<T>& src)
00482 {
00483 GVX_TRACE(__PRETTY_FUNCTION__);
00484 ASSERT(src.initialized());
00485
00486 Image< PixRGB<T> > result(src.getDims(), NO_INIT);
00487 typename Image<T>::const_iterator aptr = src.begin();
00488 typename Image< PixRGB<T> >::iterator dptr = result.beginw();
00489 typename Image< PixRGB<T> >::iterator stop = result.endw();
00490
00491 while (dptr != stop) *dptr++ = PixRGB<T>(*aptr++);
00492
00493 return result;
00494 }
00495
00496
00497 template <class T>
00498 Image< PixRGB<T> > toRGB(const Image< PixRGB<T> >& src)
00499 { return src; }
00500
00501
00502 template <class T>
00503 Image<float> infoMeasure(const Image<PixRGB<T> >& src,
00504 const float eps, const int size)
00505 {
00506 GVX_TRACE(__PRETTY_FUNCTION__);
00507 ASSERT(src.initialized());
00508
00509 Image< PixRGB<float> > float_copy(src);
00510
00511 Image<float> y, i, q;
00512 getYIQ(float_copy, y, i, q);
00513
00514 i = ::decXY(::lowPass3(i));
00515 q = ::decXY(::lowPass3(q));
00516
00517
00518
00519 float epsy = eps * ((float)(size*size) * 127.5);
00520 float epsiq = epsy / 4.0;
00521
00522 Image<float> result(src.getWidth() / size, src.getHeight() / size, NO_INIT);
00523
00524 for (int offy = 0; offy < src.getHeight(); offy += size)
00525 for (int offx = 0; offx < src.getWidth(); offx += size)
00526 {
00527 Image<float> ydct = dct(y, offx, offy, size);
00528 Image<float> idct = dct(i, offx/2, offy/2, size/2);
00529 Image<float> qdct = dct(q, offx/2, offy/2, size/2);
00530
00531 result.setVal(offx/size, offy/size,
00532 (float(countThresh(ydct, epsy)) +
00533 4.0 * float(countThresh(idct, epsiq)) +
00534 4.0 * float(countThresh(qdct, epsiq)))
00535 / (3.0 * float(size*size)));
00536 }
00537
00538 return result;
00539 }
00540
00541
00542 template <class T> inline
00543 void getYIQ(const Image<PixRGB<T> >& src,
00544 Image<T>& y, Image<T>& i, Image<T>& q)
00545 {
00546 GVX_TRACE(__PRETTY_FUNCTION__);
00547 ASSERT(src.initialized());
00548 y = Image<T>(src.getDims(), NO_INIT);
00549 i = Image<T>(src.getDims(), NO_INIT);
00550 q = Image<T>(src.getDims(), NO_INIT);
00551
00552 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00553 typename Image<PixRGB<T> >::const_iterator stop = src.end();
00554
00555 typename Image<T>::iterator yptr = y.beginw();
00556 typename Image<T>::iterator iptr = i.beginw();
00557 typename Image<T>::iterator qptr = q.beginw();
00558
00559 while (aptr != stop)
00560 {
00561 T yy, ii, qq;
00562 PixYIQ<T>(*aptr++).getYIQ(yy, ii, qq);
00563 *yptr++ = yy;
00564 *iptr++ = ii;
00565 *qptr++ = qq;
00566 }
00567 }
00568
00569
00570 template <class T> inline
00571 void getJpegYUV(const Image<PixRGB<T> >& src,
00572 Image<T>& y, Image<T>& u, Image<T>& v)
00573 {
00574 GVX_TRACE(__PRETTY_FUNCTION__);
00575 ASSERT(src.initialized());
00576 y = Image<T>(src.getDims(), NO_INIT);
00577 u = Image<T>(src.getDims(), NO_INIT);
00578 v = Image<T>(src.getDims(), NO_INIT);
00579
00580 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00581 typename Image<PixRGB<T> >::const_iterator stop = src.end();
00582
00583 typename Image<T>::iterator yptr = y.beginw();
00584 typename Image<T>::iterator uptr = u.beginw();
00585 typename Image<T>::iterator vptr = v.beginw();
00586
00587 while (aptr != stop)
00588 {
00589 const PixJpegYUV<T> yuvpix(*aptr++);
00590 *yptr++ = yuvpix.Y();
00591 *uptr++ = yuvpix.U();
00592 *vptr++ = yuvpix.V();
00593 }
00594 }
00595
00596
00597 template <class T>
00598 Image<PixRGB<T> > luminanceNormalize(const Image<PixRGB<T> >& src,
00599 const T thresh)
00600 {
00601 GVX_TRACE(__PRETTY_FUNCTION__);
00602 ASSERT(src.initialized());
00603
00604 Image<PixRGB<T> > result(src.getDims(), NO_INIT);
00605
00606 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00607 typename Image<PixRGB<T> >::const_iterator stop = src.end();
00608
00609 typename Image<PixRGB<T> >::iterator dptr = result.beginw();
00610 const PixRGB<T> zero(T(0));
00611
00612 while (aptr != stop)
00613 {
00614 float v = float(aptr->luminance());
00615 if (v >= thresh)
00616 {
00617 const float fac = 255.0 / (v * 3.0);
00618 dptr->setRed ( T(float(aptr->red()) * fac) );
00619 dptr->setGreen( T(float(aptr->green()) * fac) );
00620 dptr->setBlue ( T(float(aptr->blue()) * fac) );
00621 }
00622 else
00623 *dptr = zero;
00624
00625 ++aptr; ++dptr;
00626 }
00627
00628 return result;
00629 }
00630
00631
00632 template <class T>
00633 void getRGBY(const Image<PixRGB<T> >& src,
00634 Image<typename promote_trait<T, float>::TP>& rg,
00635 Image<typename promote_trait<T, float>::TP>& by,
00636 const typename promote_trait<T, float>::TP thresh)
00637 {
00638 GVX_TRACE(__PRETTY_FUNCTION__);
00639
00640
00641
00642
00643
00644 ASSERT(src.initialized());
00645 typedef typename promote_trait<T, float>::TP TF;
00646 rg = Image<TF>(src.getDims(), NO_INIT);
00647 by = Image<TF>(src.getDims(), NO_INIT);
00648
00649 typename Image< PixRGB<T> >::const_iterator aptr = src.begin();
00650 typename Image< PixRGB<T> >::const_iterator stop = src.end();
00651
00652 typename Image<TF>::iterator rgptr = rg.beginw(), byptr = by.beginw();
00653 TF zero = TF(); TF thresh3 = 3.0F * thresh;
00654
00655 while (aptr != stop)
00656 {
00657 TF r = TF(aptr->red()), g = TF(aptr->green()), b = TF(aptr->blue());
00658
00659
00660 TF lum = r + g + b;
00661 if (lum < thresh3)
00662 { *rgptr++ = zero; *byptr++ = zero; ++aptr; }
00663 else
00664 {
00665
00666 TF fac = 255.0f / lum;
00667 r *= fac; g *= fac; b *= fac;
00668
00669
00670
00671
00672 TF red = r - 0.5f * (g + b), green = g - 0.5f * (r + b);
00673 TF blue = b - 0.5f * (r + g), yellow = -2.0f * (blue + fabs(r-g));
00674
00675 if (red < 0.0f) red = 0.0f;
00676 else if (red > 255.0f) red = 255.0f;
00677 if (green < 0.0f) green = 0.0f;
00678 else if (green > 255.0f) green = 255.0f;
00679 if (blue < 0.0f) blue = 0.0f;
00680 else if (blue > 255.0f) blue = 255.0f;
00681 if (yellow < 0.0f) yellow=0.0f;
00682 else if (yellow > 255.0f) yellow=255.0f;
00683
00684 *rgptr++ = red - green; *byptr++ = blue - yellow;
00685 ++aptr;
00686 }
00687 }
00688 }
00689
00690
00691 template <class T>
00692 void getRGBYsimple(const Image<PixRGB<T> >& src,
00693 Image<typename promote_trait<T, float>::TP>& rg,
00694 Image<typename promote_trait<T, float>::TP>& by,
00695 const typename promote_trait<T, float>::TP thresh)
00696 {
00697 GVX_TRACE(__PRETTY_FUNCTION__);
00698
00699
00700
00701
00702 ASSERT(src.initialized());
00703 typedef typename promote_trait<T, float>::TP TF;
00704 rg = Image<TF>(src.getDims(), NO_INIT);
00705 by = Image<TF>(src.getDims(), NO_INIT);
00706
00707 typename Image< PixRGB<T> >::const_iterator aptr = src.begin();
00708 typename Image< PixRGB<T> >::const_iterator stop = src.end();
00709
00710 typename Image<TF>::iterator rgptr = rg.beginw(), byptr = by.beginw();
00711 TF zero = TF();
00712
00713 while (aptr != stop)
00714 {
00715 TF r = aptr->red(), g = aptr->green(), b = aptr->blue();
00716
00717
00718 TF in = r;
00719 if (g > in) in = g;
00720 if (b > in) in = b;
00721 if (in < thresh)
00722 { *rgptr++ = zero; *byptr++ = zero; ++aptr; }
00723 else
00724 {
00725 TF y = (r < g) ? r : g;
00726 *rgptr++ = (r - g) / in;
00727 *byptr++ = (b - y) / in;
00728 ++aptr;
00729 }
00730 }
00731 }
00732
00733
00734 template <class T>
00735 void getRGBY(const Image<PixRGB<T> >& src, Image<T>& rr, Image<T>& gg,
00736 Image<T>& bb, Image<T>& yy, const T thresh)
00737 {
00738 GVX_TRACE(__PRETTY_FUNCTION__);
00739
00740
00741 ASSERT(src.initialized());
00742 rr = Image<T>(src.getDims(), NO_INIT);
00743 gg = Image<T>(src.getDims(), NO_INIT);
00744 bb = Image<T>(src.getDims(), NO_INIT);
00745 yy = Image<T>(src.getDims(), NO_INIT);
00746
00747 typename Image< PixRGB<T> >::const_iterator aptr = src.begin();
00748 typename Image< PixRGB<T> >::const_iterator stop = src.end();
00749 typename Image<T>::iterator rptr = rr.beginw(), gptr = gg.beginw(),
00750 bptr = bb.beginw(), yptr = yy.beginw();
00751
00752 T zero = T(); float threshf = float(thresh);
00753
00754 while (aptr != stop)
00755 {
00756 float r = aptr->red(), g = aptr->green(), b = aptr->blue();
00757
00758
00759 float lum = (r + g + b) / 3.0f;
00760 if (lum < threshf)
00761 { *rptr++=zero; *gptr++=zero; *bptr++=zero; *yptr++=zero; ++aptr; }
00762 else
00763 {
00764
00765 float fac = 255.0f / (3.0f * lum);
00766 r *= fac; g *= fac; b *= fac;
00767
00768
00769
00770
00771 float red = r - 0.5f * (g + b), green = g - 0.5f * (r + b);
00772 float blue = b - 0.5f * (r + g), yellow = -2.0f * (blue + fabs(r-g));
00773
00774 if (red < 0.0f) red = 0.0f;
00775 else if (red > 255.0f) red = 255.0f;
00776 if (green < 0.0f) green = 0.0f;
00777 else if (green > 255.0f) green = 255.0f;
00778 if (blue < 0.0f) blue = 0.0f;
00779 else if (blue > 255.0f) blue = 255.0f;
00780 if (yellow < 0.0f) yellow=0.0f;
00781 else if (yellow > 255.0f) yellow=255.0f;
00782
00783 *rptr++ = T(red);
00784 *gptr++ = T(green);
00785 *bptr++ = T(blue);
00786 *yptr++ = T(yellow);
00787
00788 ++aptr;
00789 }
00790 }
00791 }
00792
00793
00794 template <class T>
00795 void getRGBY(const Image<PixRGB<T> >& src,
00796 Image<T>& rg, Image<T>& by,
00797 Image<T>& sat, Image<T>& val,
00798 const ushort H2SVtype)
00799 {
00800 GVX_TRACE(__PRETTY_FUNCTION__);
00801 ASSERT(src.initialized());
00802 typename Image<PixRGB<T> >::const_iterator aptr = src.begin();
00803
00804 rg = Image<T>(src.getDims(), NO_INIT);
00805 by = Image<T>(src.getDims(), NO_INIT);
00806 sat = Image<T>(src.getDims(), NO_INIT);
00807 val = Image<T>(src.getDims(), NO_INIT);
00808
00809 typename Image<T>::iterator rptr = rg.beginw(), bptr = by.beginw(),
00810 sptr = sat.beginw(), vptr = val.beginw();
00811
00812 while(aptr != src.end())
00813 {
00814 if(H2SVtype == 1)
00815 {
00816 PixH2SV1<T> pix = PixH2SV1<T>(*aptr++);
00817 *rptr++ = pix.H2(); *bptr++ = pix.H1();
00818 *sptr++ = pix.S(); *vptr++ = pix.V();
00819 }
00820 else if(H2SVtype == 2)
00821 {
00822 PixH2SV2<T> pix = PixH2SV2<T>(*aptr++);
00823 *rptr++ = pix.H2(); *bptr++ = pix.H1();
00824 *sptr++ = pix.S(); *vptr++ = pix.V();
00825 }
00826 else
00827 {
00828 LFATAL("This type of H2SV pixel not yet supported");
00829 }
00830 }
00831 }
00832
00833
00834 template <class T>
00835 void getDKL(const Image<PixRGB<T> >& src,
00836 Image<typename promote_trait<T, float>::TP>& dimg,
00837 Image<typename promote_trait<T, float>::TP>& kimg,
00838 Image<typename promote_trait<T, float>::TP>& limg)
00839 {
00840 GVX_TRACE(__PRETTY_FUNCTION__);
00841
00842 ASSERT(src.initialized());
00843 typedef typename promote_trait<T, float>::TP TF;
00844 dimg = Image<TF>(src.getDims(), NO_INIT);
00845 kimg = Image<TF>(src.getDims(), NO_INIT);
00846 limg = Image<TF>(src.getDims(), NO_INIT);
00847
00848 typename Image< PixRGB<T> >::const_iterator aptr = src.begin(), stop = src.end();
00849 typename Image<TF>::iterator dptr = dimg.beginw(), kptr = kimg.beginw(), lptr = limg.beginw();
00850
00851 while (aptr != stop)
00852 {
00853 const PixDKL<TF> p(*aptr++);
00854 *dptr++ = p.D();
00855 *kptr++ = p.K();
00856 *lptr++ = p.L();
00857 }
00858 }
00859
00860
00861 template <class T>
00862 void getLAB(const Image<PixRGB<T> >& src,
00863 Image<typename promote_trait<T, float>::TP>& limg,
00864 Image<typename promote_trait<T, float>::TP>& aimg,
00865 Image<typename promote_trait<T, float>::TP>& bimg)
00866 {
00867 GVX_TRACE(__PRETTY_FUNCTION__);
00868
00869 ASSERT(src.initialized());
00870 typedef typename promote_trait<T, float>::TP TF;
00871 limg = Image<TF>(src.getDims(), NO_INIT);
00872 aimg = Image<TF>(src.getDims(), NO_INIT);
00873 bimg = Image<TF>(src.getDims(), NO_INIT);
00874
00875 typename Image< PixRGB<T> >::const_iterator aptr = src.begin(), stop = src.end();
00876 typename Image<TF>::iterator dptr = limg.beginw(), kptr = aimg.beginw(), lptr = bimg.beginw();
00877
00878 while (aptr != stop)
00879 {
00880
00881 const PixRGB<byte> c(*aptr++);
00882 float X, Y, Z, fX, fY, fZ;
00883 int L,a,b;
00884 float R = c.red();
00885 float G = c.green();
00886 float B = c.blue();
00887
00888 X = 0.412453 * R + 0.357580 * G + 0.180423 * B;
00889 Y = 0.212671 * R + 0.715160 * G + 0.072169 * B;
00890 Z = 0.019334 * R + 0.119193 * G + 0.950227 * B;
00891
00892 X /= (255 * 0.950456);
00893 Y /= 255;
00894 Z /= (255 * 1.088754);
00895
00896 if (Y > 0.008856){
00897 fY = pow(Y, 1.0 / 3.0);
00898 L = (int)(116.0 * fY - 16.0 + 0.5);
00899 }else{
00900 fY = 7.787 * Y + 16.0 / 116.0;
00901 L = (int)(903.3 * Y + 0.5);
00902 }
00903
00904
00905 if (X > 0.008856)
00906 fX = pow(X, 1.0 / 3.0);
00907 else
00908 fX = 7.787 * X + 16.0 / 116.0;
00909
00910 if (Z > 0.008856)
00911 fZ = pow(Z, 1.0 / 3.0);
00912 else
00913 fZ = 7.787 * Z + 16.0 / 116.0;
00914
00915 a = (int)(500.0 * (fX - fY) + 0.5);
00916 b = (int)(200.0 * (fY - fZ) + 0.5);
00917
00918
00919 *dptr++ = L;
00920 *kptr++ = a;
00921 *lptr++ = b;
00922
00923
00924 }
00925 }
00926
00927
00928 void normalizeLAB
00929 (Image<float>& limg,
00930 Image<float>& aimg,
00931 Image<float>& bimg)
00932 {
00933 GVX_TRACE(__PRETTY_FUNCTION__);
00934
00935
00936 ASSERT(limg.isSameSize(aimg));
00937 ASSERT(limg.isSameSize(bimg));
00938
00939
00940 const float ab_min = -73;
00941 const float ab_max = 95;
00942 const float ab_range = ab_max - ab_min;
00943
00944 Image<float>::iterator lptr = limg.beginw(), stop = limg.endw();
00945 Image<float>::iterator aptr = aimg.beginw(), bptr = bimg.beginw();
00946
00947
00948 while (lptr != stop)
00949 {
00950 float l_val = *lptr / 100.0F;
00951 float a_val = (*aptr - ab_min) / ab_range;
00952 float b_val = (*bptr - ab_min) / ab_range;
00953
00954 if (l_val < 0) { l_val = 0.0F; } else if (l_val > 1) { l_val = 1.0F; }
00955 if (a_val < 0) { a_val = 0.0F; } else if (a_val > 1) { a_val = 1.0F; }
00956 if (b_val < 0) { b_val = 0.0F; } else if (b_val > 1) { b_val = 1.0F; }
00957
00958 *lptr++ = l_val;
00959 *aptr++ = a_val;
00960 *bptr++ = b_val;
00961 }
00962 }
00963
00964
00965 template <class T>
00966 void getNormalizedLAB(const Image<PixRGB<T> >& src,
00967 Image<typename promote_trait<T, float>::TP>& limg,
00968 Image<typename promote_trait<T, float>::TP>& aimg,
00969 Image<typename promote_trait<T, float>::TP>& bimg)
00970 {
00971 GVX_TRACE(__PRETTY_FUNCTION__);
00972
00973
00974
00975 getLAB(src, limg,aimg,bimg);
00976 normalizeLAB(limg, aimg, bimg);
00977 }
00978
00979
00980 Image< PixRGB<byte> > contrastModulate(const Image< PixRGB<byte> >& img,
00981 const Image<float>& mask,
00982 float baseContrast,
00983 byte baseBright)
00984 {
00985 GVX_TRACE(__PRETTY_FUNCTION__);
00986 ASSERT(img.isSameSize(mask));
00987 ASSERT((baseContrast >= 0.0) && (baseContrast <= 1.0));
00988
00989 Image<float> contrast(mask);
00990 inplaceClamp(contrast, 0.01f, 1.0f);
00991 inplaceNormalize(contrast, 0.0f, 1.0f-baseContrast);
00992 contrast += baseContrast;
00993 Image<float> base(contrast * (-baseBright));
00994 base += baseBright;
00995
00996 return img * contrast + base;
00997 }
00998
00999
01000 template <class T>
01001 double pSNRcolor(const Image< PixRGB<T> >& img1,
01002 const Image< PixRGB<T> >& img2)
01003 {
01004 GVX_TRACE(__PRETTY_FUNCTION__);
01005 ASSERT(img1.isSameSize(img2));
01006 Image<T> r1, g1, b1, r2, g2, b2; int siz = img1.getSize();
01007 getComponents(img1, r1, g1, b1); getComponents(img2, r2, g2, b2);
01008 double mser = distance(r1, r2); mser = mser * mser / double(siz);
01009 double mseg = distance(g1, g2); mseg = mseg * mseg / double(siz);
01010 double mseb = distance(b1, b2); mseb = mseb * mseb / double(siz);
01011
01012 double mse = (mser + mseg + mseb) / 3.0;
01013
01014 return 10.0 * log10(255.0 * 255.0 / mse);
01015 }
01016
01017
01018 template <class T>
01019 double pSNRcolor(const Image< PixRGB<T> >& img1,
01020 const Image< PixRGB<T> >& img2,
01021 const Image<float>& weight)
01022 {
01023 GVX_TRACE(__PRETTY_FUNCTION__);
01024 ASSERT(img1.isSameSize(img2));
01025 Image<T> r1, g1, b1, r2, g2, b2; int siz = img1.getSize();
01026 getComponents(img1, r1, g1, b1); getComponents(img2, r2, g2, b2);
01027 double mser = distance(r1, r2, weight); mser = mser * mser / double(siz);
01028 double mseg = distance(g1, g2, weight); mseg = mseg * mseg / double(siz);
01029 double mseb = distance(b1, b2, weight); mseb = mseb * mseb / double(siz);
01030
01031 double mse = (mser + mseg + mseb) / 3.0;
01032
01033 return 10.0 * log10(255.0 * 255.0 / mse);
01034 }
01035
01036
01037 template <class T>
01038 Image< PixRGB<T> > normalizeRGB(const Image< PixRGB<T> >& img,
01039 PixRGB<T> min,
01040 PixRGB<T> max)
01041 {
01042 GVX_TRACE(__PRETTY_FUNCTION__);
01043 Image<T> r,g,b;
01044 getComponents(img, r, g, b);
01045 inplaceNormalize(r, min.red(), max.red());
01046 inplaceNormalize(g, min.green(), max.green());
01047 inplaceNormalize(b, min.blue(), max.blue());
01048 return makeRGB(r, g, b);
01049 }
01050
01051
01052 template <class T>
01053 Image<T> maxRGB(const Image< PixRGB<T> >& img)
01054 {
01055 GVX_TRACE(__PRETTY_FUNCTION__);
01056 Image<T> r,g,b;
01057 getComponents(img, r, g, b);
01058 return takeMax(r, takeMax(g, b));
01059 }
01060
01061
01062 template <class T>
01063 Image< PixRGB<T> > colorStain (const Image<T>& src,
01064 const T& min, const T& max,
01065 const PixRGB<T>& color)
01066 {
01067 GVX_TRACE(__PRETTY_FUNCTION__);
01068 float fmin = (float)min;
01069 float fdiff = (float)(max - min);
01070 ASSERT (fdiff != 0.0F);
01071
01072 Image < PixRGB<T> > result(src.getDims(), NO_INIT);
01073 typename Image<T>::const_iterator sptr, stop = src.end();
01074
01075 typename Image< PixRGB<T> >::iterator rptr = result.beginw();
01076
01077 for (sptr = src.begin(); sptr != stop; ++sptr, ++rptr)
01078 {
01079 *rptr = color;
01080 *rptr *= ((float)(*sptr) - fmin) / fdiff;
01081 }
01082 return result;
01083 }
01084
01085
01086 void RGBtoCIE(const PixRGB<byte>& rgbColor,
01087 float& cr, float& cg, float& intens)
01088 {
01089 GVX_TRACE(__PRETTY_FUNCTION__);
01090 PixRGB<float> fpix(rgbColor);
01091 intens = (fpix.red() + fpix.green() + fpix.blue());
01092 if (intens > 0.0f)
01093 {
01094 cr = fpix.red() / intens;
01095 cg = fpix.green() / intens;
01096 }
01097 else
01098 {
01099 cr = 0.0f;
01100 cg = 0.0f;
01101 }
01102 }
01103
01104
01105 Image<float> hueDistance(const Image< PixRGB<byte> >& img,
01106 float muR, float muG,
01107 float sigR, float sigG, float rho)
01108 {
01109 GVX_TRACE(__PRETTY_FUNCTION__);
01110 Image<float> result(img.getDims(), NO_INIT);
01111 Image< PixRGB<byte> >::const_iterator iptr, stop = img.end();
01112 Image<float>::iterator rptr = result.beginw();
01113
01114 float sR2 = 1/sigR/sigR;
01115 float sG2 = 1/sigG/sigG;
01116 float sRG = 2*rho/sigG/sigR;
01117
01118 for (iptr = img.begin(); iptr != stop; ++iptr, ++rptr)
01119 {
01120 float cr, cg, intens;
01121 RGBtoCIE(*iptr,cr,cg,intens);
01122 *rptr = exp(-0.5f*((cr-muR)*(cr-muR)*sR2 + (cg-muG)*(cg-muG)*sG2
01123 - (cr-muR)*(cg-muG)*sRG));
01124 }
01125 return result;
01126 }
01127
01128 template void getMinMaxC(const Image<PixRGB<int> >& src, int& mi, int& ma);
01129 template void getMinMaxC(const Image<PixRGB<double> >& src, double& mi, double& ma);
01130
01131
01132 #include "inst/Image/ColorOps.I"
01133
01134
01135
01136
01137
01138
01139
01140 #endif // !IMAGE_COLOROPS_C_DEFINED