1 /****************************************************************************
2 * VCGLib                                                            o o     *
3 * Visual and Computer Graphics Library                            o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2004-2016                                           \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 
24 #ifndef __VCG_TRI_UPDATE_COLOR
25 #define __VCG_TRI_UPDATE_COLOR
26 
27 #include <limits>
28 #include <math.h>
29 #include <time.h>
30 #include <vcg/space/color4.h>
31 #include <vcg/math/histogram.h>
32 #include <vcg/math/perlin_noise.h>
33 #include <vcg/math/random_generator.h>
34 #include <vcg/complex/algorithms/clean.h>
35 #include <vcg/complex/algorithms/stat.h>
36 
37 namespace vcg {
38 namespace tri {
39 
40 /*!
41 \ingroup trimesh
42 
43 \headerfile color.h vcg/complex/algorithms/update/color.h
44 
45 \brief Generation and processing of per-vertex and per-face colors according to various strategy.
46 
47 This class is used to compute per face or per vertex color with respect to a number of algorithms.
48 There is a wide range of algorithms for processing vertex color in a \i photoshop-like mode (changing for example contrast, white balance, gamma)
49 Basic Tools for mapping quality into a color according to standard color ramps are here.
50 */
51 
52 template <class MeshType>
53 class UpdateColor
54 {
55 public:
56   typedef typename MeshType::VertexType     VertexType;
57   typedef typename MeshType::VertexPointer  VertexPointer;
58   typedef typename MeshType::VertexIterator VertexIterator;
59   typedef typename MeshType::FaceType       FaceType;
60   typedef typename MeshType::FacePointer    FacePointer;
61   typedef typename MeshType::FaceIterator   FaceIterator;
62   typedef typename MeshType::EdgeIterator   EdgeIterator;
63 
64   typedef typename MeshType::ScalarType     ScalarType;
65   typedef typename MeshType::CoordType      CoordType;
66 
67   class ColorAvgInfo
68   {
69   public:
70     unsigned int r;
71     unsigned int g;
72     unsigned int b;
73     unsigned int a;
74     int cnt;
75   };
76 
77   /*! \brief This function colores all (or the selected) the vertices of a mesh.
78     */
79   static int PerVertexConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
80   {
81     RequirePerVertexColor(m);
82 
83     int cnt=0;
84     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
85       if(!(*vi).IsD()){
86         if(!selected || (*vi).IsS())
87         {
88           (*vi).C() = vs;
89           ++cnt;
90         }
91       }
92     return cnt;
93   }
94 
95   /*! \brief This function colores all (or the selected) faces of a mesh.
96   */
97   static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
98   {
99     RequirePerFaceColor(m);
100     int cnt=0;
101     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
102       if(!(*fi).IsD()){
103         if(!selected || (*fi).IsS())
104         {
105           (*fi).C() = vs;
106           ++cnt;
107         }
108       }
109     return cnt;
110   }
111 
112   /** \brief Transfer face color onto vertex color
113 
114   Plain average of the color of the faces incident on a given vertex.
115   No adjacency required.
116   */
PerVertexFromFace(MeshType & m)117   static void PerVertexFromFace( MeshType &m)
118   {
119     RequirePerFaceColor(m);
120     RequirePerVertexColor(m);
121 
122     ColorAvgInfo csi;
123     csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
124     SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
125 
126     FaceIterator fi;
127     for(fi=m.face.begin();fi!=m.face.end();++fi)
128       if(!(*fi).IsD())
129         for(int j=0;j<3;++j)
130         {
131           TD[(*fi).V(j)].r+=(*fi).C()[0];
132           TD[(*fi).V(j)].g+=(*fi).C()[1];
133           TD[(*fi).V(j)].b+=(*fi).C()[2];
134           TD[(*fi).V(j)].a+=(*fi).C()[3];
135           ++TD[(*fi).V(j)].cnt;
136         }
137 
138     VertexIterator vi;
139     for(vi=m.vert.begin();vi!=m.vert.end();++vi)
140       if(!(*vi).IsD() && TD[*vi].cnt>0 )
141       {
142         (*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
143         (*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
144         (*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
145         (*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
146       }
147   }
148 
149   /*! \brief Transfer vertex color onto face color
150   Plain average of the color of the vertexes on a given face.
151   */
PerFaceFromVertex(MeshType & m)152   static void PerFaceFromVertex( MeshType &m)
153   {
154     RequirePerFaceColor(m);
155     RequirePerVertexColor(m);
156 
157     FaceIterator fi;
158     for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
159     {
160       Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
161                      Color4f::Construct((*fi).V(1)->C()) +
162                      Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
163       (*fi).C().Import(avg);
164     }
165   }
166 
167   /*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality.
168 
169   If no range of quality is passed it is automatically computed.
170   */
171   static void PerVertexQualityRamp(MeshType &m, float minq=0, float maxq=0)
172   {
173     RequirePerVertexQuality(m);
174     RequirePerVertexColor(m);
175 
176     if(minq==maxq)
177     {
178       std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
179       minq=minmax.first;
180       maxq=minmax.second;
181     }
182     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
183           if(!(*vi).IsD())
184               (*vi).C().SetColorRamp(minq,maxq,(*vi).Q());
185   }
186 
187 
188   /*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality.
189 
190   If no range of quality is passed it is automatically computed.
191   */
192   static void PerVertexQualityRampParula(MeshType &m, float minq=0, float maxq=0)
193   {
194     RequirePerVertexQuality(m);
195     RequirePerVertexColor(m);
196 
197     if(minq==maxq)
198     {
199       std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
200       minq=minmax.first;
201       maxq=minmax.second;
202     }
203     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
204           if(!(*vi).IsD())
205               (*vi).C().SetColorRampParula(minq,maxq,(*vi).Q());
206   }
207 
208   /*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality.
209 
210   If no range of quality is passed it is automatically computed.
211   */
212   static void PerFaceQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false)
213   {
214     RequirePerFaceColor(m);
215     RequirePerFaceQuality(m);
216 
217     if(minq==maxq)
218     {
219       std::pair<float,float> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
220       minq=minmax.first;
221       maxq=minmax.second;
222     }
223     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
224       if(!selected || (*fi).IsS())
225         (*fi).C().SetColorRamp(minq,maxq,(*fi).Q());
226   }
227 
228   /*! \brief This function colores all the edges of a mesh with a hue color shade dependent on the quality.
229 
230   If no range of quality is passed it is automatically computed.
231   */
232   static void PerEdgeQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false)
233   {
234     RequirePerEdgeColor(m);
235     RequirePerEdgeQuality(m);
236 
237     if(minq==maxq)
238     {
239       std::pair<float,float> minmax = Stat<MeshType>::ComputePerEdgeQualityMinMax(m);
240       minq=minmax.first;
241       maxq=minmax.second;
242     }
243     for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei) if(!(*ei).IsD())
244       if(!selected || (*ei).IsS())
245         (*ei).C().SetColorRamp(minq,maxq,(*ei).Q());
246   }
247 
248   /*! \brief This function colores all the vertices of a mesh with a gray shade dependent on the quality.
249 
250   If no range of quality is passed it is automatically computed.
251   */
PerVertexQualityGray(MeshType & m,float minq,float maxq)252   static void PerVertexQualityGray(MeshType &m,  float minq,  float maxq)
253   {
254     RequirePerVertexColor(m);
255     RequirePerVertexQuality(m);
256     if(minq==maxq)
257     {
258       std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
259       minq=minmax.first;
260       maxq=minmax.second;
261     }
262     for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
263           if(!(*vi).IsD())
264               (*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
265   }
266 
267   /*! \brief This function colores all the faces of a mesh with a gray shade dependent on the quality.
268 
269   If no range of quality is passed it is automatically computed.
270   */
271   static void PerFaceQualityGray(MeshType &m, float minq=0, float maxq=0)
272   {
273     RequirePerFaceColor(m);
274     RequirePerFaceQuality(m);
275 
276     if(minq==maxq)
277     {
278       std::pair<float,float> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
279       minq=minmax.first;
280       maxq=minmax.second;
281     }
282     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
283           (*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
284   }
285 
286   /** \brief Color the vertexes of the mesh that are on the border
287 
288 It uses the information in the Vertex flags, and not necessarily any topology.
289 So it just require that you have correctly computed the flags; one way could be the following one:
290 \code
291 vcg::tri::UpdateTopology<Mesh>::FaceFace(m.cm);
292 vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m.cm);
293 vcg::tri::UpdateFlags<Mesh>::VertexBorderFromFaceBorder (m.cm);
294 vcg::tri::UpdateColor<Mesh>::PerVertexBorderFlag(m.cm);
295 \endcode
296 */
297   static void PerVertexBorderFlag( MeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
298   {
299     RequirePerVertexColor(m);
300 
301     Color4b BaseColor = Color4b::Green;
302 
303     PerVertexConstant(m,BaseColor);
304     for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
305       for(int j=0;j<3;++j)
306       {
307         if((*fi).IsB(j)){
308           if( (*fi).V(j)->C() == BaseColor)     (*fi).V(j)->C() = BorderColor;
309           if( (*fi).V(j)->C() == InternalColor) (*fi).V(j)->C() = MixColor;
310           if( (*fi).V1(j)->C() == BaseColor)     (*fi).V1(j)->C() = BorderColor;
311           if( (*fi).V1(j)->C() == InternalColor) (*fi).V1(j)->C() = MixColor;
312         } else
313         {
314           if( (*fi).V(j)->C() == BaseColor)     (*fi).V(j)->C() = InternalColor;
315           if( (*fi).V(j)->C() == BorderColor) (*fi).V(j)->C() = MixColor;
316           if( (*fi).V1(j)->C() == BaseColor)     (*fi).V1(j)->C() = InternalColor;
317           if( (*fi).V1(j)->C() == BorderColor) (*fi).V1(j)->C() = MixColor;
318         }
319       }
320 
321   }
322 
323   /*! \brief This function colores the faces of connected components of a mesh randomly.
324 
325 It require FaceFace Adjacency becouse it relies on the output of the ConnecteComponents();
326 */
PerFaceRandomConnectedComponent(MeshType & m)327   static void PerFaceRandomConnectedComponent( MeshType &m)
328   {
329     RequirePerFaceColor(m);
330     RequireFFAdjacency(m);
331 
332     std::vector< std::pair<int, typename MeshType::FacePointer> > CCV;
333     int ScatterSize= std::min (100,tri::Clean<MeshType>::ConnectedComponents(m, CCV)); // number of random color to be used. Never use too many.
334 
335     ConnectedComponentIterator<MeshType> ci;
336     for(unsigned int i=0;i<CCV.size();++i)
337     {
338       Color4b BaseColor = Color4b::Scatter(ScatterSize, i%ScatterSize,.4f,.7f);
339       std::vector<typename MeshType::FacePointer> FPV;
340       for(ci.start(m,CCV[i].second);!ci.completed();++ci)
341         (*ci)->C()=BaseColor;
342     }
343   }
344 
345   /*! \brief This function colores the face of a mesh randomly.
346 
347 Note: The faux bit is used to color polygonal faces uniformly
348 */
PerFaceRandom(MeshType & m)349   static void PerFaceRandom(MeshType &m)
350   {
351     RequirePerFaceColor(m);
352     FaceIterator fi;
353     Color4b BaseColor = Color4b::Black;
354     PerFaceConstant(m,BaseColor);
355     int id_num=0;
356     for(fi=m.face.begin();fi!=m.face.end();++fi)
357       if(!(*fi).IsD())
358       {
359         id_num++;
360         if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
361         for(int j=0;j<3;++j)
362           if((*fi).IsF(j))
363           {
364             assert(!IsBorder((*fi),j));
365             (*fi).FFp(j)->C()= (*fi).C();
366           }
367       }
368   }
369 
370 /*! \brief Perlin Noise.
371 
372 Simple Perlin noise. To make things weirder each color band can have its own offset and frequency.
373 Period is expressed in absolute terms.
374 So as period it is meaningful could be to use something in the range of 1/10 of the bbox diag.
375 */
376 static void PerVertexPerlinNoise(MeshType& m, CoordType period, CoordType offset = CoordType(0, 0, 0), bool onSelected = false)
377 {
378 	RequirePerVertexColor(m);
379 
380 	CoordType p[3];
381 
382 	for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
383 		if(!(*vi).IsD())
384 			if ((!onSelected) || ((*vi).IsS()))
385 			{
386 				// perlin noise is defined in 022
387 				p[0] = (vi->P()/period[0])+offset;
388 				p[1] = (vi->P()/period[1])+offset;
389 				p[2] = (vi->P()/period[2])+offset;
390 				(*vi).C() = Color4b(	int(127+128.0*math::Perlin::Noise(p[0][0],p[0][1],p[0][2])),
391 										int(127+128.0*math::Perlin::Noise(p[1][0],p[1][1],p[1][2])),
392 										int(127+128.0*math::Perlin::Noise(p[2][0],p[2][1],p[2][2])),
393 										255 );
394 			}
395 
396 }
397 
398 
399 /*! \brief Perlin Color mixing.
400 
401 Simple Perlin color mixing. Color 1 and 2 are mixed according the perlin noise function, with period and offset.
402 */
403 static void PerVertexPerlinColoring(MeshType& m, ScalarType period, CoordType offset = CoordType(0, 0, 0), Color4b color1 = Color4b::Black, Color4b color2 = Color4b::White, bool onSelected = false)
404 {
405 	RequirePerVertexColor(m);
406 
407 	CoordType p;
408 
409 	for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
410 	if (!(*vi).IsD())
411 	if ((!onSelected) || ((*vi).IsS()))
412 	{
413 		// perlin noise is defined in 022
414 		p = (vi->P() / period) + offset;
415 		double factor = (math::Perlin::Noise(p[0], p[1], p[2]) + 1.0) / 2.0;
416 
417 		int rr = (color1[0] * factor) + (color2[0] * (1.0 - factor));
418 		int gg = (color1[1] * factor) + (color2[1] * (1.0 - factor));
419 		int bb = (color1[2] * factor) + (color2[2] * (1.0 - factor));
420 		int aa = (color1[3] * factor) + (color2[3] * (1.0 - factor));
421 
422 		(*vi).C() = Color4b(rr, gg, bb, aa);
423 	}
424 }
425 
426 /*! \brief Simple Noise adding function.
427 It simply add signed noise to the color of the mesh. The noise has uniform distribution and the amplitude is +/-2^(noisebits-1).
428 */
429 static void PerVertexAddNoise(MeshType& m, int noiseBits, bool onSelected=false)
430 {
431 	RequirePerVertexColor(m);
432 
433 	if(noiseBits>8) noiseBits = 8;
434 	if(noiseBits<1) return;
435 
436 	math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(time(NULL));
437 	for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
438 		if(!(*vi).IsD())
439 			if ((!onSelected) || ((*vi).IsS()))
440 			{
441 				(*vi).C()[0] = math::Clamp<int>((*vi).C()[0] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
442 				(*vi).C()[1] = math::Clamp<int>((*vi).C()[1] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
443 				(*vi).C()[2] = math::Clamp<int>((*vi).C()[2] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
444 			}
445 
446 }
447 
448 
449 /*! \brief Reduces vertex color the mesh to two colors according to a threshold.
450   */
451 static int PerVertexThresholding(MeshType &m, float threshold, Color4b c1 = Color4<unsigned char>::Black, Color4b c2 = Color4<unsigned char>::White, const bool ProcessSelected=false)
452 {
453   RequirePerVertexColor(m);
454 
455   int counter=0;
456   VertexIterator vi;
457   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
458   {
459     if(!(*vi).IsD()) //if it has not been deleted...
460     {
461       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
462       {
463         float value = ComputeLightness((*vi).C());
464 
465         if(value<=threshold) (*vi).C() = c1;
466         else (*vi).C() = c2;
467         ++counter;
468       }
469     }
470   }
471   return counter;
472 }
473 
474 // Computes the lightness value for a specified color. lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
ComputeLightness(Color4b c)475 static float ComputeLightness(Color4b c)
476 {
477   float min_rgb = (float)math::Min(c[0],c[1],c[2]);
478   float max_rgb = (float)math::Max(c[0],c[1],c[2]);
479   return (max_rgb + min_rgb)/2;
480 }
481 
482 /*! \brief Apply the brightness filter, with the given amount, to the mesh.
483   */
484 static int PerVertexBrightness(MeshType &m, float amount, const bool ProcessSelected=false)
485 {
486   RequirePerVertexColor(m);
487 
488   int counter=0;
489     VertexIterator vi;
490     for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
491     {
492         if(!(*vi).IsD()) //if it has not been deleted...
493         {
494             if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
495       {
496         (*vi).C() = Color4b(
497                             math::Clamp(int((*vi).C()[0]+amount),0,255),
498                             math::Clamp(int((*vi).C()[1]+amount),0,255),
499                             math::Clamp(int((*vi).C()[2]+amount),0,255),
500                             255);
501         ++counter;
502       }
503     }
504   }
505     return counter;
506 }
507 
508 /*! \brief Apply Contrast filter to the mesh with the given contrast factor.
509   */
510 static int PerVertexContrast(MeshType &m, float factor, const bool ProcessSelected=false)
511 {
512       RequirePerVertexColor(m);
513 
514   int counter=0;
515   VertexIterator vi;
516   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
517   {
518     if(!(*vi).IsD()) //if it has not been deleted...
519     {
520       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
521       {
522         (*vi).C() = ColorMul((*vi).C(),factor);
523         ++counter;
524       }
525     }
526   }
527   return counter;
528 }
529 
530 //Performs contrast operations on color, i.e expands or compress the histogram around
531 //the midpoint value.  NewValue = (OldValue - 128) ◊ factor + 128
ColorMul(Color4b c,float factor)532 static Color4b ColorMul(Color4b c, float factor)
533 {
534   return Color4b( ValueMul(c[0], factor), ValueMul(c[1], factor), ValueMul(c[2], factor), 1);
535 }
536 
ValueMul(int value,float factor)537 static int ValueMul(int value, float factor)
538 {
539   return math::Clamp<int>((int)((value - 128)*factor + 128), 0, 255);
540 }
541 
542 /*! \brief Apply  Brightness and Contrast  filter to the mesh, with the given contrast factor and brightness amount.
543 
544 Performs contrast and brightness operations on color, i.e NewValue = (OldValue - 128) * contrast + 128 + amount
545 The result is clamped just one time after all computations; this get a more accurate result.
546 
547 The formula used here is the one of GIMP.
548 
549   */
550 static int PerVertexBrightnessContrast(MeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
551 {
552       RequirePerVertexColor(m);
553 
554   int counter=0;
555   VertexIterator vi;
556   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
557   {
558     if(!(*vi).IsD()) //if it has not been deleted...
559     {
560       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
561       {
562         (*vi).C() = ColorBrightnessContrast((*vi).C(),brightness,contrast);
563         ++counter;
564       }
565     }
566   }
567   return counter;
568 }
569 
ColorBrightnessContrast(Color4b c,float brightness,float contrast)570 static Color4b ColorBrightnessContrast(Color4b c, float brightness, float contrast)
571 {
572   return Color4b( ValueBrightnessContrast(c[0], brightness, contrast),
573                                     ValueBrightnessContrast(c[1], brightness, contrast),
574                                     ValueBrightnessContrast(c[2], brightness, contrast), 1 );
575 }
576 
ValueBrightnessContrast(unsigned char ivalue,float brightness,float contrast)577 static int ValueBrightnessContrast(unsigned char ivalue, float brightness, float contrast)
578 {
579     float value = float(ivalue)/255.0f;
580   if (brightness < 0.0)  value = value * ( 1.0 + brightness);
581                     else value = value + ((1.0 - value) * brightness);
582     value = (value - 0.5) * (tan ((contrast + 1) * M_PI/4) ) + 0.5;
583     return math::Clamp<int>(255.0*value, 0, 255);
584 }
585 
586 /*! \brief Invert the colors of the mesh.
587 
588   \return the number of changed vertexes (the selected ones)
589   */
590 static int PerVertexInvert(MeshType &m, const bool ProcessSelected=false)
591 {
592       RequirePerVertexColor(m);
593 
594   int counter=0;
595   for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi) //scan all the vertex...
596   {
597     if(!(*vi).IsD()) //if it has not been deleted...
598     {
599       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
600       {
601         Color4b &c=(*vi).C();
602         c=Color4b( 255-c[0],255-c[1],255-c[2], 1);
603         ++counter;
604       }
605     }
606   }
607   return counter;
608 }
609 
610 /*! \brief Apply the gamma correction filter, with the given gamma exponet, to the mesh.
611   \return the number of changed vertexes (the selected ones)
612   */
613 static int PerVertexGamma(MeshType &m, float gamma, const bool ProcessSelected=false)
614 {
615       RequirePerVertexColor(m);
616 
617   int counter=0;
618 
619   VertexIterator vi;
620   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
621   {
622     if(!(*vi).IsD()) //if it has not been deleted...
623     {
624       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
625       {
626         (*vi).C() = ColorPow((*vi).C(), 1/gamma);
627         ++counter;
628       }
629     }
630   }
631   return counter;
632 }
633 
634 //computes the standard gamma transformation on a given color, according to NewVal = OldVal^(1/gamma)
ColorPow(Color4b c,float exponent)635 static Color4b ColorPow(Color4b c, float exponent)
636 {
637   return vcg::Color4b(
638                       math::Clamp((int)( ValuePow(float(c[0])/255, exponent)*255), 0, 255),
639                       math::Clamp((int)( ValuePow(float(c[1])/255, exponent)*255), 0, 255),
640                       math::Clamp((int)( ValuePow(float(c[2])/255, exponent)*255), 0, 255),
641                       255);
642 }
643 
ValuePow(float value,float exponent)644 static float ValuePow(float value, float exponent)
645 {
646   return powf(value, exponent);
647 }
648 
649 //useful bit masks for RGB channels, used for Levels filter.
650 enum rgbChMask {ALL_CHANNELS = 7, RED_CHANNEL = 4, GREEN_CHANNEL = 2, BLUE_CHANNEL = 1, NO_CHANNELS = 0 };
651 
652 /*! \brief Adjusts color levels of the mesh
653 
654   \return the number of changed vertexes (the selected ones)
655 
656 Adjusts color levels of the mesh. Filter can be applied to all RGB channels or to each channel separately.
657 in_min, gamma and in_max are respectively the black point, the gray point and the white point.
658 out_min and out_max are the output level for black and white respectively.
659 */
660 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)
661 {
662       RequirePerVertexColor(m);
663 
664   int counter=0;
665   VertexIterator vi;
666   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
667   {
668     if(!(*vi).IsD()) //if it has not been deleted...
669     {
670       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
671       {
672         (*vi).C() = ColorLevels((*vi).C(), gamma, in_min, in_max, out_min, out_max, rgbMask);
673         ++counter;
674       }
675     }
676   }
677   return counter;
678 }
679 
680 //Performs levels transformation on each channel set to 1 in the rgbMask.
ColorLevels(Color4b c,float gamma,float in_min,float in_max,float out_min,float out_max,unsigned char rgbMask)681 static Color4b ColorLevels(Color4b c, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask)
682 {
683   unsigned char r = c[0], g = c[1], b = c[2];
684   if(rgbMask & RED_CHANNEL) r = ValueLevels(c[0], gamma, in_min, in_max, out_min, out_max);
685   if(rgbMask & GREEN_CHANNEL) g = ValueLevels(c[1], gamma, in_min, in_max, out_min, out_max);
686   if(rgbMask & BLUE_CHANNEL) b = ValueLevels(c[2], gamma, in_min, in_max, out_min, out_max);
687   return Color4b(r, g, b, 255);
688 }
689 
690 //Transform on levels
ValueLevels(int value,float gamma,float in_min,float in_max,float out_min,float out_max)691 static int ValueLevels(int value, float gamma, float in_min, float in_max, float out_min, float out_max)
692 {
693   float fvalue = value/255.0f;
694   // normalize
695   fvalue = math::Clamp<float>(fvalue - in_min, 0.0f, 1.0f) / math::Clamp<float>(in_max - in_min, 1.0f/255.0f, 1.0f);
696   // transform gamma
697   fvalue = powf(fvalue,1/gamma);
698   // rescale range
699   fvalue = fvalue * (out_max - out_min) + out_min;
700   //back in interval [0,255] and clamp
701   return math::Clamp<int>((int)(fvalue * 255), 0, 255);
702 }
703 
704 /*! \brief  Colorize the mesh toward a given color.
705   \return the number of changed vertexes (the selected ones)
706 
707 Colors the mesh. Color is blended to the mesh with the given intensity (0..1 ranged).
708   */
709 static int PerVertexColourisation(MeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
710 {
711       RequirePerVertexColor(m);
712 
713   int counter=0;
714   VertexIterator vi;
715   for(vi=m.vert.begin();vi!=m.vert.end();++vi)
716   {
717     if(!(*vi).IsD()) //if it has not been deleted...
718     {
719       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
720       {
721         (*vi).C() = ColorApplyDiff((*vi).C(), c, intensity);
722         ++counter;
723       }
724     }
725   }
726   return counter;
727 }
728 
729 // Perform colourisation operation.
730 // For each channel C:
731 // newC = origC + intensity * (newC - origC)
ColorApplyDiff(Color4b old_color,Color4b new_color,float intensity)732 static Color4b ColorApplyDiff(Color4b old_color, Color4b new_color, float intensity)
733 {
734   return Color4b( ValueApplyDiff(old_color[0], new_color[0], intensity),
735                   ValueApplyDiff(old_color[1], new_color[1], intensity),
736                   ValueApplyDiff(old_color[2], new_color[2], intensity), 255);
737 }
738 
ValueApplyDiff(int old_value,int new_value,float intensity)739 static int ValueApplyDiff(int old_value, int new_value, float intensity)
740 {
741   return  math::Clamp<int>((int)(old_value + intensity * (new_value - old_value)), 0, 255);
742 }
743 
744 //An useful ENUM to hold all desaturation methods.
745 enum DesaturationMethods {M_LIGHTNESS = 0, M_LUMINOSITY = 1, M_AVERAGE = 2};
746 
747 /*! \brief  Desaturates the mesh according the a chosen desaturation method
748 
749 \return the number of changed vertexes (the selected ones)
750 
751 There are three possibilities
752 - \c M_LIGHTNESS where lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
753 - \c M_LUMINOSITY where luminosity = 0.21*R+0.71*G+0.7*B
754 - \c M_AVERAGE Plain Average
755   */
756 static int PerVertexDesaturation(MeshType &m, int method, const bool ProcessSelected=false)
757 {
758       RequirePerVertexColor(m);
759 
760   int counter=0;
761   VertexIterator vi;
762   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
763   {
764     if(!(*vi).IsD()) //if it has not been deleted...
765     {
766       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
767       {
768         (*vi).C() = ColorDesaturate((*vi).C(), method);
769         ++counter;
770       }
771     }
772   }
773   return counter;
774 }
775 
776 //Desature the color. Ausiliary functions to calculate lightness/luminosity/average.
ColorDesaturate(Color4b c,int method)777 static Color4b ColorDesaturate(Color4b c, int method)
778 {
779   switch(method){
780     case M_LIGHTNESS:{
781       int val = (int)ComputeLightness(c);
782       return Color4b( val, val, val, 255);
783     }
784     case M_AVERAGE:{
785       int val = (int)ComputeAvgLightness(c);
786       return Color4b( val, val, val, 255);
787     }
788     case M_LUMINOSITY:{
789       int val = (int)ComputeLuminosity(c);
790       return Color4b( val, val, val, 255);
791     }
792     default: assert(0);
793   }
794 }
795 
796 //ausiliary function to compute average lightness. value = (R+G+B)/3
ComputeAvgLightness(Color4b c)797 static float ComputeAvgLightness(Color4b c)
798 {
799     return float(c[0]+c[1]+c[2])/3.0f;
800 }
801 
802 //ausiliary function to compute luminosity. value = 0.21*R+0.71*G+0.7*B
ComputeLuminosity(Color4b c)803 static float ComputeLuminosity(Color4b c)
804 {
805     return float(0.2126f*c[0]+0.7152f*c[1]+0.0722f*c[2]);
806 }
807 
808 /*! \brief Histogram Color Equalization.
809   \return the number of changed vertexes (the selected ones)
810 
811 Equalize the histogram of colors. It can equalize any combination of rgb channels or it can work on lightness.
812   */
813 static int PerVertexEqualize(MeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
814 {
815       RequirePerVertexColor(m);
816 
817   //declares , resets and set up 4 histograms, for Red, Green, Blue and Lightness
818   Histogramf Hl, Hr, Hg, Hb;
819   Hl.Clear(); Hr.Clear(); Hg.Clear(); Hb.Clear();
820   Hl.SetRange(0, 255, 255); Hr.SetRange(0, 255, 255); Hg.SetRange(0, 255, 255); Hb.SetRange(0, 255, 255);
821 
822   int counter=0;
823   VertexIterator vi;
824 
825   //Scan the mesh to build the histograms
826   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
827   {
828     if(!(*vi).IsD()) //if it has not been deleted...
829     {
830       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, put it in the histograms
831       {
832         float v = ComputeLightness((*vi).C())+0.5; //compute and round lightness value
833         Hl.Add(v); Hr.Add((float)(*vi).C()[0]); Hg.Add((float)(*vi).C()[1]); Hb.Add((float)(*vi).C()[2]);
834       }
835     }
836   }
837 
838   //for each histogram, compute the cumulative distribution function, and build a lookup table
839     int cdf_l[256], cdf_r[256], cdf_g[256], cdf_b[256];
840     cdf_l[0] = Hl.BinCount(0); cdf_r[0] = Hr.BinCount(0); cdf_g[0] = Hg.BinCount(0); cdf_b[0] = Hb.BinCount(0);
841     for(int i=1; i<256; i++){
842     cdf_l[i] = Hl.BinCount(float(i)) + cdf_l[i-1];
843     cdf_r[i] = Hr.BinCount(float(i)) + cdf_r[i-1];
844     cdf_g[i] = Hg.BinCount(float(i)) + cdf_g[i-1];
845     cdf_b[i] = Hb.BinCount(float(i)) + cdf_b[i-1];
846   }
847 
848   //this loop aaplies the transformation to colors
849   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
850   {
851     if(!(*vi).IsD()) //if it has not been deleted...
852     {
853       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
854       {
855         (*vi).C()=ColorEqualize((*vi).C(), cdf_l, cdf_r, cdf_g, cdf_b, rgbMask);
856         ++counter;
857       }
858     }
859   }
860   return counter;
861 }
862 
863 //Applies equalization to the components of the color according to rgbmask
ColorEqualize(Color4b c,int cdf_l[256],int cdf_r[256],int cdf_g[256],int cdf_b[256],unsigned int rgbMask)864 static Color4b ColorEqualize(Color4b c, int cdf_l[256], int cdf_r[256], int cdf_g[256], int cdf_b[256], unsigned int rgbMask)
865 {
866   unsigned char r = c[0], g = c[1], b = c[2];
867   if(rgbMask == NO_CHANNELS) //in this case, equalization is done on lightness
868   {
869     int v = ValueEqualize(cdf_l[(int)(ComputeLightness(c)+0.5f)], cdf_l[0], cdf_l[255]);
870     return Color4b(v, v, v, 255); //return the equalized gray color
871   }
872   if(rgbMask & RED_CHANNEL) r = ValueEqualize(cdf_r[c[0]], cdf_r[0], cdf_r[255]); //Equalizes red
873   if(rgbMask & GREEN_CHANNEL) g = ValueEqualize(cdf_g[c[1]], cdf_g[0], cdf_g[255]); //Equalizes green
874   if(rgbMask & BLUE_CHANNEL) b = ValueEqualize(cdf_b[c[2]], cdf_b[0], cdf_b[255]); //Equalizes blue
875   return Color4b(r, g, b, 255); //return the equalized color
876 }
877 
878 //Compute the equalized value
ValueEqualize(int cdfValue,int cdfMin,int cdfMax)879 static int ValueEqualize(int cdfValue, int cdfMin, int cdfMax)
880 {
881   return int(float((cdfValue - cdfMin)/float(cdfMax - cdfMin)) * 255.0f);
882 }
883 
884 /*! \brief Simple white balancing filter.
885   \return the number of changed vertexes (the selected ones)
886 
887   It applies a simple white balancing filter. It may works on a provided user color that is supposed to be white.
888   */
889 static int PerVertexWhiteBalance(MeshType &m, Color4b userColor, const bool ProcessSelected=false)
890 {
891       RequirePerVertexColor(m);
892 
893   Color4b unbalancedWhite= userColor;
894   int counter=0;
895   VertexIterator vi;
896 
897   //in this loop the transformation is applied to the mesh
898   for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
899   {
900     if(!(*vi).IsD()) //if it has not been deleted...
901     {
902       if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
903       {
904         (*vi).C()=ColorWhiteBalance((*vi).C(),unbalancedWhite);
905         ++counter;
906       }
907     }
908   }
909   return counter;
910 }
911 
912 //Balnce the white of the color, applying a correction factor based on the unbalancedWhite color.
ColorWhiteBalance(Color4b c,Color4b unbalancedWhite)913 static Color4b ColorWhiteBalance(Color4b c, Color4b unbalancedWhite)
914 {
915   //sanity check to avoid division by zero...
916   if(unbalancedWhite[0]==0) unbalancedWhite[0]=1;
917   if(unbalancedWhite[1]==0) unbalancedWhite[1]=1;
918   if(unbalancedWhite[2]==0) unbalancedWhite[2]=1;
919 
920   return Color4b(
921                  math::Clamp<int>((int)(c[0]*(255.0f/unbalancedWhite[0])), 0, 255),
922                  math::Clamp<int>((int)(c[1]*(255.0f/unbalancedWhite[1])), 0, 255),
923                  math::Clamp<int>((int)(c[2]*(255.0f/unbalancedWhite[2])), 0, 255),
924                  255);
925 }
926 
927 };
928 
929 }// end namespace
930 }// end namespace
931 #endif
932