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