ColorOps.C

Go to the documentation of this file.
00001 /*!@file Image/ColorOps.C Color operations on Image
00002  */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/ColorOps.C $
00036 // $Id: ColorOps.C 14762 2011-05-03 01:13:16Z siagian $
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"  // for lowPass3()
00046 #include "Image/Image.H"
00047 #include "Image/MathOps.H"    // for countThresh(), inplaceNormalize(), ...
00048 #include "Image/Pixels.H"
00049 #include "Image/ShapeOps.H"   // for decXY()
00050 #include "Image/Transforms.H" // for dct()
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), // background
00156                      PixRGB<float>(0.0f, 255.0f, 0.0f), // positive=green
00157                      PixRGB<float>(255.0f, 0.0f, 0.0f));// negative=red
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), // background
00168                      PixRGB<float>(0.0f, 255.0f, 0.0f), // positive=green
00169                      PixRGB<float>(255.0f, 0.0f, 0.0f));// negative=red
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   // Set intensity as the normalized value of src
00228   // Set hue as the scale of the value of src with red as 0 and
00229   //     violet as 330
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   // 0 to 100 percent only:
00317   ASSERT((trans >= 0.0F) && (trans <= 100.0F));
00318   // images must be same size:
00319   ASSERT(top.isSameSize(bottom));
00320 
00321   // result is the size of the input images:
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   //Taken from Matlab's rgb2gray() function
00461   // T = inv([1.0 0.956 0.621; 1.0 -0.272 -0.647; 1.0 -1.106 1.703]);
00462   // coef = T(1,:)';
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   // eps is given between 0 and 1; modify it according to image size
00518   // we want that eps=0.01 corresponds to a cosine with amplitude 127.5*0.01
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   // red = [r - (g+b)/2]        [.] = clamp between 0 and 255
00640   // green = [g - (r+b)/2]
00641   // blue = [b - (r+g)/2]
00642   // yellow = [2*((r+g)/2 - |r-g| - b)]
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       // first do the luminanceNormalization:
00660       TF lum = r + g + b;
00661       if (lum < thresh3)  // too dark... no response from anybody
00662         { *rgptr++ = zero; *byptr++ = zero; ++aptr; }
00663       else
00664         {
00665           // normalize chroma by luminance:
00666           TF fac = 255.0f / lum;
00667           r *= fac; g *= fac; b *= fac;
00668 
00669           // now compute color opponencies:
00670           // yellow gets a factor 2 to compensate for its previous attenuation
00671           // by luminanceNormalize():
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   // I = max(R,G,B)
00699   // RG = (R-G)/I
00700   // BY = (B-min(R,G))/I
00701   // Dirk Walther, September 2004
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       // first do in = max(R,G,B):
00718       TF in = r;
00719       if (g > in) in = g;
00720       if (b > in) in = b;
00721       if (in < thresh)  // too dark... no response from anybody
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   // this is essentially the same code as the other getRGBY, just
00740   // duplicated for efficiency
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       // first do the luminanceNormalization:
00759       float lum = (r + g + b) / 3.0f;
00760       if (lum < threshf)  // too dark... no response from anybody
00761         { *rptr++=zero; *gptr++=zero; *bptr++=zero; *yptr++=zero; ++aptr; }
00762       else
00763         {
00764           // normalize chroma by luminance:
00765           float fac = 255.0f / (3.0f * lum);
00766           r *= fac; g *= fac; b *= fac;
00767 
00768           // now compute color opponencies:
00769           // yellow gets a factor 2 to compensate for its previous attenuation
00770           // by luminanceNormalize():
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);     // no clamping necessary
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(); //(((rgbColor & 0xf800) >> 11) * 255 / 31);
00885       float G = c.green(); //(((rgbColor & 0x07e0) >> 5) * 255 / 63);
00886       float B = c.blue(); //((rgbColor & 0x001f) * 255 / 31);
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       //-128~127
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   // assert that all images are of same size
00936   ASSERT(limg.isSameSize(aimg));
00937   ASSERT(limg.isSameSize(bimg));
00938 
00939   // range for a, b channels
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   // normalize Lab image
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   // just call get the LAB color conversion algorithm
00974   // then normalize 
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   //typename Image< PixRGB<T> >::const_iterator stop = src.end();
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 // Include the explicit instantiations
01132 #include "inst/Image/ColorOps.I"
01133 
01134 // ######################################################################
01135 /* So things look consistent in everyone's emacs... */
01136 /* Local Variables: */
01137 /* indent-tabs-mode: nil */
01138 /* End: */
01139 
01140 #endif // !IMAGE_COLOROPS_C_DEFINED
Generated on Sun May 8 08:05:06 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3