color.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 * VCGLib                                                            o o     *
00003 * Visual and Computer Graphics Library                            o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2004                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
00021 *                                                                           *
00022 ****************************************************************************/
00023 
00024 #ifndef __VCG_TRI_UPDATE_COLOR
00025 #define __VCG_TRI_UPDATE_COLOR
00026 
00027 #include <limits>
00028 #include <math.h>
00029 #include <time.h>
00030 #include <vcg/space/color4.h>
00031 #include <vcg/math/histogram.h>
00032 #include <vcg/math/perlin_noise.h>
00033 #include <vcg/math/random_generator.h>
00034 #include <vcg/complex/algorithms/clean.h>
00035 #include <vcg/complex/algorithms/stat.h>
00036 
00037 namespace vcg {
00038 namespace tri {
00039 
00052 template <class MeshType>
00053 class UpdateColor
00054 {
00055 public:
00056   typedef typename MeshType::VertexType     VertexType;
00057   typedef typename MeshType::VertexPointer  VertexPointer;
00058   typedef typename MeshType::VertexIterator VertexIterator;
00059   typedef typename MeshType::FaceType       FaceType;
00060   typedef typename MeshType::FacePointer    FacePointer;
00061   typedef typename MeshType::FaceIterator   FaceIterator;
00062   typedef typename MeshType::EdgeIterator   EdgeIterator;
00063 
00064   typedef typename MeshType::ScalarType     ScalarType;
00065   typedef typename MeshType::CoordType      CoordType;
00066 
00067   class ColorAvgInfo
00068   {
00069   public:
00070     unsigned int r;
00071     unsigned int g;
00072     unsigned int b;
00073     unsigned int a;
00074     int cnt;
00075   };
00076 
00079   static int PerVertexConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
00080   {
00081     RequirePerVertexColor(m);
00082 
00083     int cnt=0;
00084     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00085       if(!(*vi).IsD()){
00086         if(!selected || (*vi).IsS())
00087         {
00088           (*vi).C() = vs;
00089           ++cnt;
00090         }
00091       }
00092     return cnt;
00093   }
00094 
00097   static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
00098   {
00099     RequirePerFaceColor(m);
00100     int cnt=0;
00101     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00102       if(!(*fi).IsD()){
00103         if(!selected || (*fi).IsS())
00104         {
00105           (*fi).C() = vs;
00106           ++cnt;
00107         }
00108       }
00109     return cnt;
00110   }
00111 
00117   static void PerVertexFromFace( MeshType &m)
00118   {
00119     RequirePerFaceColor(m);
00120     RequirePerVertexColor(m);
00121 
00122     ColorAvgInfo csi;
00123     csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
00124     SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
00125 
00126     FaceIterator fi;
00127     for(fi=m.face.begin();fi!=m.face.end();++fi)
00128       if(!(*fi).IsD())
00129         for(int j=0;j<3;++j)
00130         {
00131           TD[(*fi).V(j)].r+=(*fi).C()[0];
00132           TD[(*fi).V(j)].g+=(*fi).C()[1];
00133           TD[(*fi).V(j)].b+=(*fi).C()[2];
00134           TD[(*fi).V(j)].a+=(*fi).C()[3];
00135           ++TD[(*fi).V(j)].cnt;
00136         }
00137 
00138     VertexIterator vi;
00139     for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00140       if(!(*vi).IsD() && TD[*vi].cnt>0 )
00141       {
00142         (*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
00143         (*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
00144         (*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
00145         (*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
00146       }
00147   }
00148 
00152   static void PerFaceFromVertex( MeshType &m)
00153   {
00154     RequirePerFaceColor(m);
00155     RequirePerVertexColor(m);
00156 
00157     FaceIterator fi;
00158     for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00159     {
00160       Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
00161                      Color4f::Construct((*fi).V(1)->C()) +
00162                      Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
00163       (*fi).C().Import(avg);
00164     }
00165   }
00166 
00171   static void PerVertexQualityRamp(MeshType &m, float minq=0, float maxq=0)
00172   {
00173     RequirePerVertexQuality(m);
00174     RequirePerVertexColor(m);
00175 
00176     if(minq==maxq)
00177     {
00178       std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
00179       minq=minmax.first;
00180       maxq=minmax.second;
00181     }
00182     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00183           if(!(*vi).IsD())
00184               (*vi).C().SetColorRamp(minq,maxq,(*vi).Q());
00185   }
00186 
00187   
00192   static void PerVertexQualityRampParula(MeshType &m, float minq=0, float maxq=0)
00193   {
00194     RequirePerVertexQuality(m);
00195     RequirePerVertexColor(m);
00196 
00197     if(minq==maxq)
00198     {
00199       std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
00200       minq=minmax.first;
00201       maxq=minmax.second;
00202     }
00203     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00204           if(!(*vi).IsD())
00205               (*vi).C().SetColorRampParula(minq,maxq,(*vi).Q());
00206   }
00207   
00212   static void PerFaceQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false)
00213   {
00214     RequirePerFaceColor(m);
00215     RequirePerFaceQuality(m);
00216 
00217     if(minq==maxq)
00218     {
00219       std::pair<float,float> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
00220       minq=minmax.first;
00221       maxq=minmax.second;
00222     }
00223     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00224       if(!selected || (*fi).IsS())
00225         (*fi).C().SetColorRamp(minq,maxq,(*fi).Q());
00226   }
00227 
00232   static void PerEdgeQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false)
00233   {
00234     RequirePerEdgeColor(m);
00235     RequirePerEdgeQuality(m);
00236 
00237     if(minq==maxq)
00238     {
00239       std::pair<float,float> minmax = Stat<MeshType>::ComputePerEdgeQualityMinMax(m);
00240       minq=minmax.first;
00241       maxq=minmax.second;
00242     }
00243     for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei) if(!(*ei).IsD())
00244       if(!selected || (*ei).IsS())
00245         (*ei).C().SetColorRamp(minq,maxq,(*ei).Q());
00246   }
00247 
00252   static void PerVertexQualityGray(MeshType &m,  float minq,  float maxq)
00253   {
00254     RequirePerVertexColor(m);
00255     RequirePerVertexQuality(m);
00256     if(minq==maxq)
00257     {
00258       std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
00259       minq=minmax.first;
00260       maxq=minmax.second;
00261     }
00262     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00263           if(!(*vi).IsD())
00264               (*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
00265   }
00266 
00271   static void PerFaceQualityGray(MeshType &m, float minq=0, float maxq=0)
00272   {
00273     RequirePerFaceColor(m);
00274     RequirePerFaceQuality(m);
00275 
00276     if(minq==maxq)
00277     {
00278       std::pair<float,float> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
00279       minq=minmax.first;
00280       maxq=minmax.second;
00281     }
00282     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00283           (*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
00284   }
00285 
00297   static void PerVertexBorderFlag( MeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
00298   {
00299     RequirePerVertexColor(m);
00300 
00301     Color4b BaseColor = Color4b::Green;
00302 
00303     PerVertexConstant(m,BaseColor);
00304     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00305       for(int j=0;j<3;++j)
00306       {
00307         if((*fi).IsB(j)){
00308           if( (*fi).V(j)->C() == BaseColor)     (*fi).V(j)->C() = BorderColor;
00309           if( (*fi).V(j)->C() == InternalColor) (*fi).V(j)->C() = MixColor;
00310           if( (*fi).V1(j)->C() == BaseColor)     (*fi).V1(j)->C() = BorderColor;
00311           if( (*fi).V1(j)->C() == InternalColor) (*fi).V1(j)->C() = MixColor;
00312         } else
00313         {
00314           if( (*fi).V(j)->C() == BaseColor)     (*fi).V(j)->C() = InternalColor;
00315           if( (*fi).V(j)->C() == BorderColor) (*fi).V(j)->C() = MixColor;
00316           if( (*fi).V1(j)->C() == BaseColor)     (*fi).V1(j)->C() = InternalColor;
00317           if( (*fi).V1(j)->C() == BorderColor) (*fi).V1(j)->C() = MixColor;
00318         }
00319       }
00320 
00321   }
00322 
00327   static void PerFaceRandomConnectedComponent( MeshType &m)
00328   {
00329     RequirePerFaceColor(m);
00330     RequireFFAdjacency(m);
00331 
00332     std::vector< std::pair<int, typename MeshType::FacePointer> > CCV;
00333     int ScatterSize= std::min (100,tri::Clean<MeshType>::ConnectedComponents(m, CCV)); // number of random color to be used. Never use too many.
00334 
00335     ConnectedComponentIterator<MeshType> ci;
00336     for(unsigned int i=0;i<CCV.size();++i)
00337     {
00338       Color4b BaseColor = Color4b::Scatter(ScatterSize, i%ScatterSize,.4f,.7f);
00339       std::vector<typename MeshType::FacePointer> FPV;
00340       for(ci.start(m,CCV[i].second);!ci.completed();++ci)
00341         (*ci)->C()=BaseColor;
00342     }
00343   }
00344 
00349   static void PerFaceRandom(MeshType &m)
00350   {
00351     RequirePerFaceColor(m);
00352     FaceIterator fi;
00353     Color4b BaseColor = Color4b::Black;
00354     PerFaceConstant(m,BaseColor);
00355     int id_num=0;
00356     for(fi=m.face.begin();fi!=m.face.end();++fi)
00357       if(!(*fi).IsD())
00358       {
00359         id_num++;
00360         if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
00361         for(int j=0;j<3;++j)
00362           if((*fi).IsF(j))
00363           {
00364             assert(!IsBorder((*fi),j));
00365             (*fi).FFp(j)->C()= (*fi).C();
00366           }
00367       }
00368   }
00369 
00377 static void PerVertexPerlinNoise(MeshType& m, CoordType period, CoordType offset = CoordType(0, 0, 0), bool onSelected = false)
00378 {
00379         RequirePerVertexColor(m);
00380 
00381         CoordType p[3];
00382         
00383         for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
00384                 if(!(*vi).IsD())
00385                         if ((!onSelected) || ((*vi).IsS()))
00386                         {
00387                                 // perlin noise is defined in 022
00388                                 p[0] = (vi->P()/period[0])+offset;
00389                                 p[1] = (vi->P()/period[1])+offset;
00390                                 p[2] = (vi->P()/period[2])+offset;
00391                                 (*vi).C() = Color4b(    int(127+128.0*math::Perlin::Noise(p[0][0],p[0][1],p[0][2])),
00392                                                                                 int(127+128.0*math::Perlin::Noise(p[1][0],p[1][1],p[1][2])),
00393                                                                                 int(127+128.0*math::Perlin::Noise(p[2][0],p[2][1],p[2][2])),
00394                                                                                 255 );
00395                         }
00396 
00397 }
00398 
00402 static void PerVertexAddNoise(MeshType& m, int noiseBits, bool onSelected=false)
00403 {
00404         RequirePerVertexColor(m);
00405 
00406         if(noiseBits>8) noiseBits = 8;
00407         if(noiseBits<1) return;
00408 
00409         math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(time(NULL));
00410         for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
00411                 if(!(*vi).IsD())
00412                         if ((!onSelected) || ((*vi).IsS()))
00413                         {
00414                                 (*vi).C()[0] = math::Clamp<int>((*vi).C()[0] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
00415                                 (*vi).C()[1] = math::Clamp<int>((*vi).C()[1] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
00416                                 (*vi).C()[2] = math::Clamp<int>((*vi).C()[2] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
00417                         }
00418         
00419 }
00420 
00421 
00424 static int PerVertexThresholding(MeshType &m, float threshold, Color4b c1 = Color4<unsigned char>::Black, Color4b c2 = Color4<unsigned char>::White, const bool ProcessSelected=false)
00425 {
00426   RequirePerVertexColor(m);
00427 
00428   int counter=0;
00429   VertexIterator vi;
00430   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00431   {
00432     if(!(*vi).IsD()) //if it has not been deleted...
00433     {
00434       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00435       {
00436         float value = ComputeLightness((*vi).C());
00437 
00438         if(value<=threshold) (*vi).C() = c1;
00439         else (*vi).C() = c2;
00440         ++counter;
00441       }
00442     }
00443   }
00444   return counter;
00445 }
00446 
00447 // Computes the lightness value for a specified color. lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
00448 static float ComputeLightness(Color4b c)
00449 {
00450   float min_rgb = (float)math::Min(c[0],c[1],c[2]);
00451   float max_rgb = (float)math::Max(c[0],c[1],c[2]);
00452   return (max_rgb + min_rgb)/2;
00453 }
00454 
00457 static int PerVertexBrightness(MeshType &m, float amount, const bool ProcessSelected=false)
00458 {
00459   RequirePerVertexColor(m);
00460 
00461   int counter=0;
00462     VertexIterator vi;
00463     for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00464     {
00465         if(!(*vi).IsD()) //if it has not been deleted...
00466         {
00467             if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00468       {
00469         (*vi).C() = Color4b(
00470                             math::Clamp(int((*vi).C()[0]+amount),0,255),
00471                             math::Clamp(int((*vi).C()[1]+amount),0,255),
00472                             math::Clamp(int((*vi).C()[2]+amount),0,255),
00473                             255);
00474         ++counter;
00475       }
00476     }
00477   }
00478     return counter;
00479 }
00480 
00483 static int PerVertexContrast(MeshType &m, float factor, const bool ProcessSelected=false)
00484 {
00485       RequirePerVertexColor(m);
00486 
00487   int counter=0;
00488   VertexIterator vi;
00489   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00490   {
00491     if(!(*vi).IsD()) //if it has not been deleted...
00492     {
00493       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00494       {
00495         (*vi).C() = ColorMul((*vi).C(),factor);
00496         ++counter;
00497       }
00498     }
00499   }
00500   return counter;
00501 }
00502 
00503 //Performs contrast operations on color, i.e expands or compress the histogram around
00504 //the midpoint value.  NewValue = (OldValue - 128) ◊ factor + 128
00505 static Color4b ColorMul(Color4b c, float factor)
00506 {
00507   return Color4b( ValueMul(c[0], factor), ValueMul(c[1], factor), ValueMul(c[2], factor), 1);
00508 }
00509 
00510 static int ValueMul(int value, float factor)
00511 {
00512   return math::Clamp<int>((int)((value - 128)*factor + 128), 0, 255);
00513 }
00514 
00523 static int PerVertexBrightnessContrast(MeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
00524 {
00525       RequirePerVertexColor(m);
00526 
00527   int counter=0;
00528   VertexIterator vi;
00529   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00530   {
00531     if(!(*vi).IsD()) //if it has not been deleted...
00532     {
00533       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00534       {
00535         (*vi).C() = ColorBrightnessContrast((*vi).C(),brightness,contrast);
00536         ++counter;
00537       }
00538     }
00539   }
00540   return counter;
00541 }
00542 
00543 static Color4b ColorBrightnessContrast(Color4b c, float brightness, float contrast)
00544 {
00545   return Color4b( ValueBrightnessContrast(c[0], brightness, contrast),
00546                                     ValueBrightnessContrast(c[1], brightness, contrast),
00547                                     ValueBrightnessContrast(c[2], brightness, contrast), 1 );
00548 }
00549 
00550 static int ValueBrightnessContrast(unsigned char ivalue, float brightness, float contrast)
00551 {
00552     float value = float(ivalue)/255.0f;
00553   if (brightness < 0.0)  value = value * ( 1.0 + brightness);
00554                     else value = value + ((1.0 - value) * brightness);
00555     value = (value - 0.5) * (tan ((contrast + 1) * M_PI/4) ) + 0.5;
00556     return math::Clamp<int>(255.0*value, 0, 255);
00557 }
00558 
00563 static int PerVertexInvert(MeshType &m, const bool ProcessSelected=false)
00564 {
00565       RequirePerVertexColor(m);
00566 
00567   int counter=0;
00568   for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi) //scan all the vertex...
00569   {
00570     if(!(*vi).IsD()) //if it has not been deleted...
00571     {
00572       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00573       {
00574         Color4b &c=(*vi).C();
00575         c=Color4b( 255-c[0],255-c[1],255-c[2], 1);
00576         ++counter;
00577       }
00578     }
00579   }
00580   return counter;
00581 }
00582 
00586 static int PerVertexGamma(MeshType &m, float gamma, const bool ProcessSelected=false)
00587 {
00588       RequirePerVertexColor(m);
00589 
00590   int counter=0;
00591 
00592   VertexIterator vi;
00593   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00594   {
00595     if(!(*vi).IsD()) //if it has not been deleted...
00596     {
00597       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00598       {
00599         (*vi).C() = ColorPow((*vi).C(), 1/gamma);
00600         ++counter;
00601       }
00602     }
00603   }
00604   return counter;
00605 }
00606 
00607 //computes the standard gamma transformation on a given color, according to NewVal = OldVal^(1/gamma)
00608 static Color4b ColorPow(Color4b c, float exponent)
00609 {
00610   return vcg::Color4b(
00611                       math::Clamp((int)( ValuePow(float(c[0])/255, exponent)*255), 0, 255),
00612                       math::Clamp((int)( ValuePow(float(c[1])/255, exponent)*255), 0, 255),
00613                       math::Clamp((int)( ValuePow(float(c[2])/255, exponent)*255), 0, 255),
00614                       255);
00615 }
00616 
00617 static float ValuePow(float value, float exponent)
00618 {
00619   return powf(value, exponent);
00620 }
00621 
00622 //useful bit masks for RGB channels, used for Levels filter.
00623 enum rgbChMask {ALL_CHANNELS = 7, RED_CHANNEL = 4, GREEN_CHANNEL = 2, BLUE_CHANNEL = 1, NO_CHANNELS = 0 };
00624 
00633 static int PerVertexLevels(MeshType &m, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask, const bool ProcessSelected=false)
00634 {
00635       RequirePerVertexColor(m);
00636 
00637   int counter=0;
00638   VertexIterator vi;
00639   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00640   {
00641     if(!(*vi).IsD()) //if it has not been deleted...
00642     {
00643       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00644       {
00645         (*vi).C() = ColorLevels((*vi).C(), gamma, in_min, in_max, out_min, out_max, rgbMask);
00646         ++counter;
00647       }
00648     }
00649   }
00650   return counter;
00651 }
00652 
00653 //Performs levels transformation on each channel set to 1 in the rgbMask.
00654 static Color4b ColorLevels(Color4b c, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask)
00655 {
00656   unsigned char r = c[0], g = c[1], b = c[2];
00657   if(rgbMask & RED_CHANNEL) r = ValueLevels(c[0], gamma, in_min, in_max, out_min, out_max);
00658   if(rgbMask & GREEN_CHANNEL) g = ValueLevels(c[1], gamma, in_min, in_max, out_min, out_max);
00659   if(rgbMask & BLUE_CHANNEL) b = ValueLevels(c[2], gamma, in_min, in_max, out_min, out_max);
00660   return Color4b(r, g, b, 255);
00661 }
00662 
00663 //Transform on levels
00664 static int ValueLevels(int value, float gamma, float in_min, float in_max, float out_min, float out_max)
00665 {
00666   float fvalue = value/255.0f;
00667   // normalize
00668   fvalue = math::Clamp<float>(fvalue - in_min, 0.0f, 1.0f) / math::Clamp<float>(in_max - in_min, 1.0f/255.0f, 1.0f);
00669   // transform gamma
00670   fvalue = powf(fvalue,1/gamma);
00671   // rescale range
00672   fvalue = fvalue * (out_max - out_min) + out_min;
00673   //back in interval [0,255] and clamp
00674   return math::Clamp<int>((int)(fvalue * 255), 0, 255);
00675 }
00676 
00682 static int PerVertexColourisation(MeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
00683 {
00684       RequirePerVertexColor(m);
00685 
00686   int counter=0;
00687   VertexIterator vi;
00688   for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00689   {
00690     if(!(*vi).IsD()) //if it has not been deleted...
00691     {
00692       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00693       {
00694         (*vi).C() = ColorApplyDiff((*vi).C(), c, intensity);
00695         ++counter;
00696       }
00697     }
00698   }
00699   return counter;
00700 }
00701 
00702 // Perform colourisation operation.
00703 // For each channel C:
00704 // newC = origC + intensity * (newC - origC)
00705 static Color4b ColorApplyDiff(Color4b old_color, Color4b new_color, float intensity)
00706 {
00707   return Color4b( ValueApplyDiff(old_color[0], new_color[0], intensity),
00708                   ValueApplyDiff(old_color[1], new_color[1], intensity),
00709                   ValueApplyDiff(old_color[2], new_color[2], intensity), 255);
00710 }
00711 
00712 static int ValueApplyDiff(int old_value, int new_value, float intensity)
00713 {
00714   return  math::Clamp<int>((int)(old_value + intensity * (new_value - old_value)), 0, 255);
00715 }
00716 
00717 //An useful ENUM to hold all desaturation methods.
00718 enum DesaturationMethods {M_LIGHTNESS = 0, M_LUMINOSITY = 1, M_AVERAGE = 2};
00719 
00729 static int PerVertexDesaturation(MeshType &m, int method, const bool ProcessSelected=false)
00730 {
00731       RequirePerVertexColor(m);
00732 
00733   int counter=0;
00734   VertexIterator vi;
00735   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00736   {
00737     if(!(*vi).IsD()) //if it has not been deleted...
00738     {
00739       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00740       {
00741         (*vi).C() = ColorDesaturate((*vi).C(), method);
00742         ++counter;
00743       }
00744     }
00745   }
00746   return counter;
00747 }
00748 
00749 //Desature the color. Ausiliary functions to calculate lightness/luminosity/average.
00750 static Color4b ColorDesaturate(Color4b c, int method)
00751 {
00752   switch(method){
00753     case M_LIGHTNESS:{
00754       int val = (int)ComputeLightness(c);
00755       return Color4b( val, val, val, 255);
00756     }
00757     case M_AVERAGE:{
00758       int val = (int)ComputeAvgLightness(c);
00759       return Color4b( val, val, val, 255);
00760     }
00761     case M_LUMINOSITY:{
00762       int val = (int)ComputeLuminosity(c);
00763       return Color4b( val, val, val, 255);
00764     }
00765     default: assert(0);
00766   }
00767 }
00768 
00769 //ausiliary function to compute average lightness. value = (R+G+B)/3
00770 static float ComputeAvgLightness(Color4b c)
00771 {
00772     return float(c[0]+c[1]+c[2])/3.0f;
00773 }
00774 
00775 //ausiliary function to compute luminosity. value = 0.21*R+0.71*G+0.7*B
00776 static float ComputeLuminosity(Color4b c)
00777 {
00778     return float(0.2126f*c[0]+0.7152f*c[1]+0.0722f*c[2]);
00779 }
00780 
00786 static int PerVertexEqualize(MeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
00787 {
00788       RequirePerVertexColor(m);
00789 
00790   //declares , resets and set up 4 histograms, for Red, Green, Blue and Lightness
00791   Histogramf Hl, Hr, Hg, Hb;
00792   Hl.Clear(); Hr.Clear(); Hg.Clear(); Hb.Clear();
00793   Hl.SetRange(0, 255, 255); Hr.SetRange(0, 255, 255); Hg.SetRange(0, 255, 255); Hb.SetRange(0, 255, 255);
00794 
00795   int counter=0;
00796   VertexIterator vi;
00797 
00798   //Scan the mesh to build the histograms
00799   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00800   {
00801     if(!(*vi).IsD()) //if it has not been deleted...
00802     {
00803       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, put it in the histograms
00804       {
00805         float v = ComputeLightness((*vi).C())+0.5; //compute and round lightness value
00806         Hl.Add(v); Hr.Add((float)(*vi).C()[0]); Hg.Add((float)(*vi).C()[1]); Hb.Add((float)(*vi).C()[2]);
00807       }
00808     }
00809   }
00810 
00811   //for each histogram, compute the cumulative distribution function, and build a lookup table
00812     int cdf_l[256], cdf_r[256], cdf_g[256], cdf_b[256];
00813     cdf_l[0] = Hl.BinCount(0); cdf_r[0] = Hr.BinCount(0); cdf_g[0] = Hg.BinCount(0); cdf_b[0] = Hb.BinCount(0);
00814     for(int i=1; i<256; i++){
00815     cdf_l[i] = Hl.BinCount(float(i)) + cdf_l[i-1];
00816     cdf_r[i] = Hr.BinCount(float(i)) + cdf_r[i-1];
00817     cdf_g[i] = Hg.BinCount(float(i)) + cdf_g[i-1];
00818     cdf_b[i] = Hb.BinCount(float(i)) + cdf_b[i-1];
00819   }
00820 
00821   //this loop aaplies the transformation to colors
00822   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00823   {
00824     if(!(*vi).IsD()) //if it has not been deleted...
00825     {
00826       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00827       {
00828         (*vi).C()=ColorEqualize((*vi).C(), cdf_l, cdf_r, cdf_g, cdf_b, rgbMask);
00829         ++counter;
00830       }
00831     }
00832   }
00833   return counter;
00834 }
00835 
00836 //Applies equalization to the components of the color according to rgbmask
00837 static Color4b ColorEqualize(Color4b c, int cdf_l[256], int cdf_r[256], int cdf_g[256], int cdf_b[256], unsigned int rgbMask)
00838 {
00839   unsigned char r = c[0], g = c[1], b = c[2];
00840   if(rgbMask == NO_CHANNELS) //in this case, equalization is done on lightness
00841   {
00842     int v = ValueEqualize(cdf_l[(int)(ComputeLightness(c)+0.5f)], cdf_l[0], cdf_l[255]);
00843     return Color4b(v, v, v, 255); //return the equalized gray color
00844   }
00845   if(rgbMask & RED_CHANNEL) r = ValueEqualize(cdf_r[c[0]], cdf_r[0], cdf_r[255]); //Equalizes red
00846   if(rgbMask & GREEN_CHANNEL) g = ValueEqualize(cdf_g[c[1]], cdf_g[0], cdf_g[255]); //Equalizes green
00847   if(rgbMask & BLUE_CHANNEL) b = ValueEqualize(cdf_b[c[2]], cdf_b[0], cdf_b[255]); //Equalizes blue
00848   return Color4b(r, g, b, 255); //return the equalized color
00849 }
00850 
00851 //Compute the equalized value
00852 static int ValueEqualize(int cdfValue, int cdfMin, int cdfMax)
00853 {
00854   return int(float((cdfValue - cdfMin)/float(cdfMax - cdfMin)) * 255.0f);
00855 }
00856 
00862 static int PerVertexWhiteBalance(MeshType &m, Color4b userColor, const bool ProcessSelected=false)
00863 {
00864       RequirePerVertexColor(m);
00865 
00866   Color4b unbalancedWhite= userColor;
00867   int counter=0;
00868   VertexIterator vi;
00869 
00870   //in this loop the transformation is applied to the mesh
00871   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
00872   {
00873     if(!(*vi).IsD()) //if it has not been deleted...
00874     {
00875       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
00876       {
00877         (*vi).C()=ColorWhiteBalance((*vi).C(),unbalancedWhite);
00878         ++counter;
00879       }
00880     }
00881   }
00882   return counter;
00883 }
00884 
00885 //Balnce the white of the color, applying a correction factor based on the unbalancedWhite color.
00886 static Color4b ColorWhiteBalance(Color4b c, Color4b unbalancedWhite)
00887 {
00888   //sanity check to avoid division by zero...
00889   if(unbalancedWhite[0]==0) unbalancedWhite[0]=1;
00890   if(unbalancedWhite[1]==0) unbalancedWhite[1]=1;
00891   if(unbalancedWhite[2]==0) unbalancedWhite[2]=1;
00892 
00893   return Color4b(
00894                  math::Clamp<int>((int)(c[0]*(255.0f/unbalancedWhite[0])), 0, 255),
00895                  math::Clamp<int>((int)(c[1]*(255.0f/unbalancedWhite[1])), 0, 255),
00896                  math::Clamp<int>((int)(c[2]*(255.0f/unbalancedWhite[2])), 0, 255),
00897                  255);
00898 }
00899 
00900 };
00901 
00902 }// end namespace
00903 }// end namespace
00904 #endif


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:29:38