VCG Library
Loading...
Searching...
No Matches
color.h
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/space/colormap.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
37namespace vcg {
38namespace tri {
39
52template <class MeshType>
54{
55public:
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 typedef typename MeshType::TetraType TetraType;
64 typedef typename MeshType::TetraPointer TetraPointer;
65 typedef typename MeshType::TetraIterator TetraIterator;
66
67
68 typedef typename MeshType::ScalarType ScalarType;
69 typedef typename MeshType::CoordType CoordType;
70
72 {
73 public:
74 unsigned int r = 0;
75 unsigned int g = 0;
76 unsigned int b = 0;
77 unsigned int a = 0;
78 int cnt = 0;
79 };
80
83 static int PerVertexConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
84 {
85 RequirePerVertexColor(m);
86
87 int cnt=0;
88 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
89 if(!(*vi).IsD()){
90 if(!selected || (*vi).IsS())
91 {
92 (*vi).C() = vs;
93 ++cnt;
94 }
95 }
96 return cnt;
97 }
98
101 static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
102 {
103 RequirePerFaceColor(m);
104 int cnt=0;
105 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
106 if(!(*fi).IsD()){
107 if(!selected || (*fi).IsS())
108 {
109 (*fi).C() = vs;
110 ++cnt;
111 }
112 }
113 return cnt;
114 }
115
118 static int PerTetraConstant(MeshType & m, Color4b vs = Color4b::White, bool selected = false)
119 {
120 RequirePerTetraColor(m);
121 int cnt = 0;
122 ForEachTetra(m, [&] (TetraType & t) {
123 if (!selected || t.IsS())
124 {
125 t.C() = vs;
126 ++cnt;
127 }
128 });
129 return cnt;
130 }
131
137 static void PerVertexFromTetra(MeshType & m)
138 {
139 RequirePerTetraColor(m);
140 RequirePerVertexColor(m);
141
142 ColorAvgInfo csi;
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
169 static void PerVertexFromFace( MeshType &m)
170 {
171 RequirePerFaceColor(m);
172 RequirePerVertexColor(m);
173
174 ColorAvgInfo csi;
175 SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
176
177 FaceIterator fi;
178 for(fi=m.face.begin();fi!=m.face.end();++fi)
179 if(!(*fi).IsD())
180 for(int j=0;j<3;++j)
181 {
182 TD[(*fi).V(j)].r+=(*fi).C()[0];
183 TD[(*fi).V(j)].g+=(*fi).C()[1];
184 TD[(*fi).V(j)].b+=(*fi).C()[2];
185 TD[(*fi).V(j)].a+=(*fi).C()[3];
186 ++TD[(*fi).V(j)].cnt;
187 }
188
189 VertexIterator vi;
190 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
191 if(!(*vi).IsD() && TD[*vi].cnt>0 )
192 {
193 (*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
194 (*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
195 (*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
196 (*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
197 }
198 }
199
203 static void PerFaceFromVertex( MeshType &m)
204 {
205 RequirePerFaceColor(m);
206 RequirePerVertexColor(m);
207
208 FaceIterator fi;
209 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
210 {
211 Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
212 Color4f::Construct((*fi).V(1)->C()) +
213 Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
214 (*fi).C().Import(avg);
215 }
216 }
217
222 static void PerVertexQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., vcg::ColorMap cmap = vcg::ColorMap::RGB)
223 {
224 RequirePerVertexQuality(m);
225 RequirePerVertexColor(m);
226
227 if(minq == maxq)
228 {
229 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
230 minq=minmax.first;
231 maxq=minmax.second;
232 }
233 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
234 if(!(*vi).IsD()) {
235 (*vi).C() = vcg::GetColorMapping((*vi).Q(), minq, maxq, cmap);
236 }
237 }
238
239
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
264 static void PerTetraQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB)
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() = vcg::GetColorMapping(t.Q(), minq, maxq, cmap);
279 });
280 }
285 static void PerFaceQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB)
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() = vcg::GetColorMapping((*fi).Q(), minq, maxq, cmap);
300 }
301
306 static void PerEdgeQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB)
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() = vcg::GetColorMapping((*ei).Q(), minq, maxq, cmap);
320 }
321
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
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
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
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
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
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
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
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
503 static void PerVertexAddNoise(MeshType& m, int noiseBits, bool onSelected=false, int randSeed=0)
504 {
505 RequirePerVertexColor(m);
506
507 if(noiseBits>8) noiseBits = 8;
508 if(noiseBits<1) return;
509
510 // randSeed==0 keeps the historical behaviour (a different result on every
511 // call); pass a non-zero seed to make the noise exactly reproducible.
512 math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(randSeed ? randSeed : int(time(NULL)));
513 for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
514 if(!(*vi).IsD())
515 if ((!onSelected) || ((*vi).IsS()))
516 {
517 (*vi).C()[0] = math::Clamp<int>((*vi).C()[0] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
518 (*vi).C()[1] = math::Clamp<int>((*vi).C()[1] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
519 (*vi).C()[2] = math::Clamp<int>((*vi).C()[2] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
520 }
521
522 }
523
524
527 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)
528 {
529 RequirePerVertexColor(m);
530
531 int counter=0;
532 VertexIterator vi;
533 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
534 {
535 if(!(*vi).IsD()) //if it has not been deleted...
536 {
537 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
538 {
539 float value = ComputeLightness((*vi).C());
540
541 if(value<=threshold) (*vi).C() = c1;
542 else (*vi).C() = c2;
543 ++counter;
544 }
545 }
546 }
547 return counter;
548 }
549
550 // Computes the lightness value for a specified color. lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
551 static float ComputeLightness(Color4b c)
552 {
553 float min_rgb = (float)math::Min(c[0],c[1],c[2]);
554 float max_rgb = (float)math::Max(c[0],c[1],c[2]);
555 return (max_rgb + min_rgb)/2;
556 }
557
560 static int PerVertexBrightness(MeshType &m, float amount, const bool ProcessSelected=false)
561 {
562 RequirePerVertexColor(m);
563
564 int counter=0;
565 VertexIterator vi;
566 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
567 {
568 if(!(*vi).IsD()) //if it has not been deleted...
569 {
570 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
571 {
572 (*vi).C() = Color4b(
573 math::Clamp(int((*vi).C()[0]+amount),0,255),
574 math::Clamp(int((*vi).C()[1]+amount),0,255),
575 math::Clamp(int((*vi).C()[2]+amount),0,255),
576 255);
577 ++counter;
578 }
579 }
580 }
581 return counter;
582 }
583
586 static int PerVertexContrast(MeshType &m, float factor, const bool ProcessSelected=false)
587 {
588 RequirePerVertexColor(m);
589
590 int counter=0;
591 VertexIterator vi;
592 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
593 {
594 if(!(*vi).IsD()) //if it has not been deleted...
595 {
596 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
597 {
598 (*vi).C() = ColorMul((*vi).C(),factor);
599 ++counter;
600 }
601 }
602 }
603 return counter;
604 }
605
606 //Performs contrast operations on color, i.e expands or compress the histogram around
607 //the midpoint value. NewValue = (OldValue - 128) â—Š factor + 128
608 static Color4b ColorMul(Color4b c, float factor)
609 {
610 return Color4b( ValueMul(c[0], factor), ValueMul(c[1], factor), ValueMul(c[2], factor), 1);
611 }
612
613 static int ValueMul(int value, float factor)
614 {
615 return math::Clamp<int>((int)((value - 128)*factor + 128), 0, 255);
616 }
617
626 static int PerVertexBrightnessContrast(MeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
627 {
628 RequirePerVertexColor(m);
629
630 int counter=0;
631 VertexIterator vi;
632 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
633 {
634 if(!(*vi).IsD()) //if it has not been deleted...
635 {
636 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
637 {
638 (*vi).C() = ColorBrightnessContrast((*vi).C(),brightness,contrast);
639 ++counter;
640 }
641 }
642 }
643 return counter;
644 }
645
646 static Color4b ColorBrightnessContrast(Color4b c, float brightness, float contrast)
647 {
648 return Color4b( ValueBrightnessContrast(c[0], brightness, contrast),
649 ValueBrightnessContrast(c[1], brightness, contrast),
650 ValueBrightnessContrast(c[2], brightness, contrast), 1 );
651 }
652
653 static int ValueBrightnessContrast(unsigned char ivalue, float brightness, float contrast)
654 {
655 float value = float(ivalue)/255.0f;
656 if (brightness < 0.0) value = value * ( 1.0 + brightness);
657 else value = value + ((1.0 - value) * brightness);
658 value = (value - 0.5) * (tan ((contrast + 1) * M_PI/4) ) + 0.5;
659 return math::Clamp<int>(255.0*value, 0, 255);
660 }
661
666 static int PerVertexInvert(MeshType &m, const bool ProcessSelected=false)
667 {
668 RequirePerVertexColor(m);
669
670 int counter=0;
671 for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi) //scan all the vertex...
672 {
673 if(!(*vi).IsD()) //if it has not been deleted...
674 {
675 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
676 {
677 Color4b &c=(*vi).C();
678 c=Color4b( 255-c[0],255-c[1],255-c[2], 1);
679 ++counter;
680 }
681 }
682 }
683 return counter;
684 }
685
689 static int PerVertexGamma(MeshType &m, float gamma, const bool ProcessSelected=false)
690 {
691 RequirePerVertexColor(m);
692
693 int counter=0;
694
695 VertexIterator vi;
696 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
697 {
698 if(!(*vi).IsD()) //if it has not been deleted...
699 {
700 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
701 {
702 (*vi).C() = ColorPow((*vi).C(), 1/gamma);
703 ++counter;
704 }
705 }
706 }
707 return counter;
708 }
709
710 //computes the standard gamma transformation on a given color, according to NewVal = OldVal^(1/gamma)
711 static Color4b ColorPow(Color4b c, float exponent)
712 {
713 return vcg::Color4b(
714 math::Clamp((int)( ValuePow(float(c[0])/255, exponent)*255), 0, 255),
715 math::Clamp((int)( ValuePow(float(c[1])/255, exponent)*255), 0, 255),
716 math::Clamp((int)( ValuePow(float(c[2])/255, exponent)*255), 0, 255),
717 255);
718 }
719
720 static float ValuePow(float value, float exponent)
721 {
722 return powf(value, exponent);
723 }
724
725 //useful bit masks for RGB channels, used for Levels filter.
726 enum rgbChMask {ALL_CHANNELS = 7, RED_CHANNEL = 4, GREEN_CHANNEL = 2, BLUE_CHANNEL = 1, NO_CHANNELS = 0 };
727
736 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)
737 {
738 RequirePerVertexColor(m);
739
740 int counter=0;
741 VertexIterator vi;
742 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
743 {
744 if(!(*vi).IsD()) //if it has not been deleted...
745 {
746 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
747 {
748 (*vi).C() = ColorLevels((*vi).C(), gamma, in_min, in_max, out_min, out_max, rgbMask);
749 ++counter;
750 }
751 }
752 }
753 return counter;
754 }
755
756 //Performs levels transformation on each channel set to 1 in the rgbMask.
757 static Color4b ColorLevels(Color4b c, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask)
758 {
759 unsigned char r = c[0], g = c[1], b = c[2];
760 if(rgbMask & RED_CHANNEL) r = ValueLevels(c[0], gamma, in_min, in_max, out_min, out_max);
761 if(rgbMask & GREEN_CHANNEL) g = ValueLevels(c[1], gamma, in_min, in_max, out_min, out_max);
762 if(rgbMask & BLUE_CHANNEL) b = ValueLevels(c[2], gamma, in_min, in_max, out_min, out_max);
763 return Color4b(r, g, b, 255);
764 }
765
766 //Transform on levels
767 static int ValueLevels(int value, float gamma, float in_min, float in_max, float out_min, float out_max)
768 {
769 float fvalue = value/255.0f;
770 // normalize
771 fvalue = math::Clamp<float>(fvalue - in_min, 0.0f, 1.0f) / math::Clamp<float>(in_max - in_min, 1.0f/255.0f, 1.0f);
772 // transform gamma
773 fvalue = powf(fvalue,1/gamma);
774 // rescale range
775 fvalue = fvalue * (out_max - out_min) + out_min;
776 //back in interval [0,255] and clamp
777 return math::Clamp<int>((int)(fvalue * 255), 0, 255);
778 }
779
785 static int PerVertexColourisation(MeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
786 {
787 RequirePerVertexColor(m);
788
789 int counter=0;
790 VertexIterator vi;
791 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
792 {
793 if(!(*vi).IsD()) //if it has not been deleted...
794 {
795 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
796 {
797 (*vi).C() = ColorApplyDiff((*vi).C(), c, intensity);
798 ++counter;
799 }
800 }
801 }
802 return counter;
803 }
804
805 // Perform colourisation operation.
806 // For each channel C:
807 // newC = origC + intensity * (newC - origC)
808 static Color4b ColorApplyDiff(Color4b old_color, Color4b new_color, float intensity)
809 {
810 return Color4b( ValueApplyDiff(old_color[0], new_color[0], intensity),
811 ValueApplyDiff(old_color[1], new_color[1], intensity),
812 ValueApplyDiff(old_color[2], new_color[2], intensity), 255);
813 }
814
815 static int ValueApplyDiff(int old_value, int new_value, float intensity)
816 {
817 return math::Clamp<int>((int)(old_value + intensity * (new_value - old_value)), 0, 255);
818 }
819
820 //An useful ENUM to hold all desaturation methods.
821 enum DesaturationMethods {M_LIGHTNESS = 0, M_LUMINOSITY = 1, M_AVERAGE = 2};
822
832 static int PerVertexDesaturation(MeshType &m, int method, const bool ProcessSelected=false)
833 {
834 RequirePerVertexColor(m);
835
836 int counter=0;
837 VertexIterator vi;
838 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
839 {
840 if(!(*vi).IsD()) //if it has not been deleted...
841 {
842 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
843 {
844 (*vi).C() = ColorDesaturate((*vi).C(), method);
845 ++counter;
846 }
847 }
848 }
849 return counter;
850 }
851
852 //Desature the color. Ausiliary functions to calculate lightness/luminosity/average.
853 static Color4b ColorDesaturate(Color4b c, int method)
854 {
855 switch(method){
856 case M_LIGHTNESS:{
857 int val = (int)ComputeLightness(c);
858 return Color4b( val, val, val, 255);
859 }
860 case M_AVERAGE:{
861 int val = (int)ComputeAvgLightness(c);
862 return Color4b( val, val, val, 255);
863 }
864 case M_LUMINOSITY:{
865 int val = (int)ComputeLuminosity(c);
866 return Color4b( val, val, val, 255);
867 }
868 default: assert(0);
869 }
870 return Color4b(255, 255, 255, 255);
871 }
872
873 //ausiliary function to compute average lightness. value = (R+G+B)/3
874 static float ComputeAvgLightness(Color4b c)
875 {
876 return float(c[0]+c[1]+c[2])/3.0f;
877 }
878
879 //ausiliary function to compute luminosity. value = 0.21*R+0.71*G+0.7*B
880 static float ComputeLuminosity(Color4b c)
881 {
882 return float(0.2126f*c[0]+0.7152f*c[1]+0.0722f*c[2]);
883 }
884
890 static int PerVertexEqualize(MeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
891 {
892 RequirePerVertexColor(m);
893
894 //declares , resets and set up 4 histograms, for Red, Green, Blue and Lightness
895 Histogramf Hl, Hr, Hg, Hb;
896 Hl.Clear(); Hr.Clear(); Hg.Clear(); Hb.Clear();
897 Hl.SetRange(0, 255, 255); Hr.SetRange(0, 255, 255); Hg.SetRange(0, 255, 255); Hb.SetRange(0, 255, 255);
898
899 int counter=0;
900 VertexIterator vi;
901
902 //Scan the mesh to build the histograms
903 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
904 {
905 if(!(*vi).IsD()) //if it has not been deleted...
906 {
907 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, put it in the histograms
908 {
909 float v = ComputeLightness((*vi).C())+0.5; //compute and round lightness value
910 Hl.Add(v); Hr.Add((float)(*vi).C()[0]); Hg.Add((float)(*vi).C()[1]); Hb.Add((float)(*vi).C()[2]);
911 }
912 }
913 }
914
915 //for each histogram, compute the cumulative distribution function, and build a lookup table
916 int cdf_l[256], cdf_r[256], cdf_g[256], cdf_b[256];
917 cdf_l[0] = Hl.BinCount(0); cdf_r[0] = Hr.BinCount(0); cdf_g[0] = Hg.BinCount(0); cdf_b[0] = Hb.BinCount(0);
918 for(int i=1; i<256; i++){
919 cdf_l[i] = Hl.BinCount(float(i)) + cdf_l[i-1];
920 cdf_r[i] = Hr.BinCount(float(i)) + cdf_r[i-1];
921 cdf_g[i] = Hg.BinCount(float(i)) + cdf_g[i-1];
922 cdf_b[i] = Hb.BinCount(float(i)) + cdf_b[i-1];
923 }
924
925 //this loop aaplies the transformation to colors
926 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
927 {
928 if(!(*vi).IsD()) //if it has not been deleted...
929 {
930 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
931 {
932 (*vi).C()=ColorEqualize((*vi).C(), cdf_l, cdf_r, cdf_g, cdf_b, rgbMask);
933 ++counter;
934 }
935 }
936 }
937 return counter;
938 }
939
940 //Applies equalization to the components of the color according to rgbmask
941 static Color4b ColorEqualize(Color4b c, int cdf_l[256], int cdf_r[256], int cdf_g[256], int cdf_b[256], unsigned int rgbMask)
942 {
943 unsigned char r = c[0], g = c[1], b = c[2];
944 if(rgbMask == NO_CHANNELS) //in this case, equalization is done on lightness
945 {
946 int v = ValueEqualize(cdf_l[(int)(ComputeLightness(c)+0.5f)], cdf_l[0], cdf_l[255]);
947 return Color4b(v, v, v, 255); //return the equalized gray color
948 }
949 if(rgbMask & RED_CHANNEL) r = ValueEqualize(cdf_r[c[0]], cdf_r[0], cdf_r[255]); //Equalizes red
950 if(rgbMask & GREEN_CHANNEL) g = ValueEqualize(cdf_g[c[1]], cdf_g[0], cdf_g[255]); //Equalizes green
951 if(rgbMask & BLUE_CHANNEL) b = ValueEqualize(cdf_b[c[2]], cdf_b[0], cdf_b[255]); //Equalizes blue
952 return Color4b(r, g, b, 255); //return the equalized color
953 }
954
955 //Compute the equalized value
956 static int ValueEqualize(int cdfValue, int cdfMin, int cdfMax)
957 {
958 return int(float((cdfValue - cdfMin)/float(cdfMax - cdfMin)) * 255.0f);
959 }
960
966 static int PerVertexWhiteBalance(MeshType &m, Color4b userColor, const bool ProcessSelected=false)
967 {
968 RequirePerVertexColor(m);
969
970 Color4b unbalancedWhite= userColor;
971 int counter=0;
972 VertexIterator vi;
973
974 //in this loop the transformation is applied to the mesh
975 for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
976 {
977 if(!(*vi).IsD()) //if it has not been deleted...
978 {
979 if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
980 {
981 (*vi).C()=ColorWhiteBalance((*vi).C(),unbalancedWhite);
982 ++counter;
983 }
984 }
985 }
986 return counter;
987 }
988
989 //Balnce the white of the color, applying a correction factor based on the unbalancedWhite color.
990 static Color4b ColorWhiteBalance(Color4b c, Color4b unbalancedWhite)
991 {
992 //sanity check to avoid division by zero...
993 if(unbalancedWhite[0]==0) unbalancedWhite[0]=1;
994 if(unbalancedWhite[1]==0) unbalancedWhite[1]=1;
995 if(unbalancedWhite[2]==0) unbalancedWhite[2]=1;
996
997 return Color4b(
998 math::Clamp<int>((int)(c[0]*(255.0f/unbalancedWhite[0])), 0, 255),
999 math::Clamp<int>((int)(c[1]*(255.0f/unbalancedWhite[1])), 0, 255),
1000 math::Clamp<int>((int)(c[2]*(255.0f/unbalancedWhite[2])), 0, 255),
1001 255);
1002 }
1003
1004};
1005
1006}// end namespace
1007}// end namespace
1008#endif
Definition: color4.h:41
static Color4 Scatter(int range, int value, float Sat=.3f, float Val=.9f)
Definition: color4.h:233
Class of static functions to clean//restore meshs.
Definition: clean.h:165
Generation and processing of per-vertex and per-face colors according to various strategy.
Definition: color.h:54
static int PerVertexEqualize(MeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
Histogram Color Equalization.
Definition: color.h:890
static void PerFaceQualityGray(MeshType &m, ScalarType minq=0, ScalarType maxq=0)
This function colores all the faces of a mesh with a gray shade dependent on the quality.
Definition: color.h:345
static int PerVertexBrightnessContrast(MeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
Apply Brightness and Contrast filter to the mesh, with the given contrast factor and brightness amoun...
Definition: color.h:626
static int PerVertexWhiteBalance(MeshType &m, Color4b userColor, const bool ProcessSelected=false)
Simple white balancing filter.
Definition: color.h:966
static int PerTetraConstant(MeshType &m, Color4b vs=Color4b::White, bool selected=false)
This function colors all (or the selected) tetras of a mesh.
Definition: color.h:118
static int PerVertexBrightness(MeshType &m, float amount, const bool ProcessSelected=false)
Apply the brightness filter, with the given amount, to the mesh.
Definition: color.h:560
static void PerVertexQualityGray(MeshType &m, ScalarType minq=0, ScalarType maxq=0)
This function colores all the vertices of a mesh with a gray shade dependent on the quality.
Definition: color.h:326
static void PerVertexBorderFlag(MeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
Color the vertexes of the mesh that are on the border.
Definition: color.h:371
static void PerFaceQualityRamp(MeshType &m, ScalarType minq=0, ScalarType maxq=0, bool selected=false, vcg::ColorMap cmap=vcg::ColorMap::RGB)
This function colores all the faces of a mesh with a hue color shade dependent on the quality.
Definition: color.h:285
static void PerFaceFromVertex(MeshType &m)
Transfer vertex color onto face color Plain average of the color of the vertexes on a given face.
Definition: color.h:203
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)
Adjusts color levels of the mesh.
Definition: color.h:736
static void PerFaceRandomConnectedComponent(MeshType &m)
This function colores the faces of connected components of a mesh randomly.
Definition: color.h:401
static void PerTetraQualityRamp(MeshType &m, ScalarType minq=0., ScalarType maxq=0., bool selected=false, vcg::ColorMap cmap=vcg::ColorMap::RGB)
This function colores all the faces of a mesh with a hue color shade dependent on the quality.
Definition: color.h:264
static void PerVertexFromFace(MeshType &m)
Transfer face color onto vertex color.
Definition: color.h:169
static int PerVertexInvert(MeshType &m, const bool ProcessSelected=false)
Invert the colors of the mesh.
Definition: color.h:666
static void PerVertexAddNoise(MeshType &m, int noiseBits, bool onSelected=false, int randSeed=0)
Simple Noise adding function. It simply add signed noise to the color of the mesh....
Definition: color.h:503
static void PerVertexFromTetra(MeshType &m)
Transfer tetra color onto vertex color.
Definition: color.h:137
static void PerVertexPerlinColoring(MeshType &m, ScalarType period, CoordType offset=CoordType(0, 0, 0), Color4b color1=Color4b::Black, Color4b color2=Color4b::White, bool onSelected=false)
Perlin Color mixing.
Definition: color.h:477
static int PerVertexConstant(MeshType &m, Color4b vs=Color4b::White, bool selected=false)
This function colors all (or the selected) the vertices of a mesh.
Definition: color.h:83
static int PerVertexDesaturation(MeshType &m, int method, const bool ProcessSelected=false)
Desaturates the mesh according the a chosen desaturation method.
Definition: color.h:832
static void PerVertexQualityRampParula(MeshType &m, ScalarType minq=0., ScalarType maxq=0.)
This function colores all the faces of a mesh with a hue color shade dependent on the quality.
Definition: color.h:244
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)
Reduces vertex color the mesh to two colors according to a threshold.
Definition: color.h:527
static void PerEdgeQualityRamp(MeshType &m, ScalarType minq=0, ScalarType maxq=0, bool selected=false, vcg::ColorMap cmap=vcg::ColorMap::RGB)
This function colores all the edges of a mesh with a hue color shade dependent on the quality.
Definition: color.h:306
static int PerVertexGamma(MeshType &m, float gamma, const bool ProcessSelected=false)
Apply the gamma correction filter, with the given gamma exponet, to the mesh.
Definition: color.h:689
static int PerVertexContrast(MeshType &m, float factor, const bool ProcessSelected=false)
Apply Contrast filter to the mesh with the given contrast factor.
Definition: color.h:586
static void PerVertexPerlinNoise(MeshType &m, CoordType period, CoordType offset=CoordType(0, 0, 0), bool onSelected=false)
Perlin Noise.
Definition: color.h:450
static int PerVertexColourisation(MeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
Colorize the mesh toward a given color.
Definition: color.h:785
static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White, bool selected=false)
This function colors all (or the selected) faces of a mesh.
Definition: color.h:101
static void PerFaceRandom(MeshType &m)
This function colores the face of a mesh randomly.
Definition: color.h:423
static void PerVertexQualityRamp(MeshType &m, ScalarType minq=0., ScalarType maxq=0., vcg::ColorMap cmap=vcg::ColorMap::RGB)
This function colores all the faces of a mesh with a hue color shade dependent on the quality.
Definition: color.h:222
void ForEachTetra(const MeshType &m, Callable action)
Definition: foreach.h:270
void ForEachVertex(const MeshType &m, Callable action)
Definition: foreach.h:126
Definition: color4.h:30