$darkmode
VCG Library
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 
37 namespace vcg {
38 namespace tri {
39 
52 template <class MeshType>
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  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;
75  unsigned int g;
76  unsigned int b;
77  unsigned int a;
78  int cnt;
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  csi.r = csi.g = csi.b = csi.cnt = 0;
144  SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert, csi);
145 
146  ForEachTetra(m, [&] (TetraType & t) {
147  for (int i = 0; i < 4; ++i)
148  {
149  TD[t.V(i)].r += t.C()[0];
150  TD[t.V(i)].g += t.C()[1];
151  TD[t.V(i)].b += t.C()[2];
152  TD[t.V(i)].a += t.C()[3];
153  TD[t.V(i)].cnt += 1;
154  }
155  });
156 
157  ForEachVertex(m, [&] (VertexType & v) {
158  v.C()[0] = TD[v].r / TD[v].cnt;
159  v.C()[1] = TD[v].g / TD[v].cnt;
160  v.C()[2] = TD[v].b / TD[v].cnt;
161  v.C()[3] = TD[v].a / TD[v].cnt;
162  });
163  }
164 
170  static void PerVertexFromFace( MeshType &m)
171  {
172  RequirePerFaceColor(m);
173  RequirePerVertexColor(m);
174 
175  ColorAvgInfo csi;
176  csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
177  SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
178 
179  FaceIterator fi;
180  for(fi=m.face.begin();fi!=m.face.end();++fi)
181  if(!(*fi).IsD())
182  for(int j=0;j<3;++j)
183  {
184  TD[(*fi).V(j)].r+=(*fi).C()[0];
185  TD[(*fi).V(j)].g+=(*fi).C()[1];
186  TD[(*fi).V(j)].b+=(*fi).C()[2];
187  TD[(*fi).V(j)].a+=(*fi).C()[3];
188  ++TD[(*fi).V(j)].cnt;
189  }
190 
191  VertexIterator vi;
192  for(vi=m.vert.begin();vi!=m.vert.end();++vi)
193  if(!(*vi).IsD() && TD[*vi].cnt>0 )
194  {
195  (*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
196  (*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
197  (*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
198  (*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
199  }
200  }
201 
205  static void PerFaceFromVertex( MeshType &m)
206  {
207  RequirePerFaceColor(m);
208  RequirePerVertexColor(m);
209 
210  FaceIterator fi;
211  for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
212  {
213  Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
214  Color4f::Construct((*fi).V(1)->C()) +
215  Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
216  (*fi).C().Import(avg);
217  }
218  }
219 
224  static void PerVertexQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., vcg::ColorMap cmap = vcg::ColorMap::RGB)
225  {
226  RequirePerVertexQuality(m);
227  RequirePerVertexColor(m);
228 
229  if(minq == maxq)
230  {
231  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
232  minq=minmax.first;
233  maxq=minmax.second;
234  }
235  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
236  if(!(*vi).IsD()) {
237  (*vi).C() = vcg::GetColorMapping((*vi).Q(), minq, maxq, cmap);
238  }
239  }
240 
241 
246  static void PerVertexQualityRampParula(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0.)
247  {
248  RequirePerVertexQuality(m);
249  RequirePerVertexColor(m);
250 
251  if(minq == maxq)
252  {
253  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
254  minq=minmax.first;
255  maxq=minmax.second;
256  }
257  for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
258  if(!(*vi).IsD())
259  (*vi).C().SetColorRampParula(minq, maxq, (*vi).Q());
260  }
261 
266  static void PerTetraQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB)
267  {
268  RequirePerTetraColor(m);
269  RequirePerTetraQuality(m);
270 
271  if(minq == maxq)
272  {
273  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerTetraQualityMinMax(m);
274  minq=minmax.first;
275  maxq=minmax.second;
276  }
277 
278  ForEachTetra(m, [&] (TetraType & t){
279  if (!selected || t.IsS())
280  t.C() = vcg::GetColorMapping(t.Q(), minq, maxq, cmap);
281  });
282  }
287  static void PerFaceQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB)
288  {
289  RequirePerFaceColor(m);
290  RequirePerFaceQuality(m);
291 
292  if(minq == maxq)
293  {
294  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
295  minq=minmax.first;
296  maxq=minmax.second;
297  }
298  for(FaceIterator fi = m.face.begin();fi != m.face.end(); ++fi)
299  if(!(*fi).IsD())
300  if(!selected || (*fi).IsS())
301  (*fi).C() = vcg::GetColorMapping((*fi).Q(), minq, maxq, cmap);
302  }
303 
308  static void PerEdgeQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB)
309  {
310  RequirePerEdgeColor(m);
311  RequirePerEdgeQuality(m);
312 
313  if(minq == maxq)
314  {
315  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerEdgeQualityMinMax(m);
316  minq=minmax.first;
317  maxq=minmax.second;
318  }
319  for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei) if(!(*ei).IsD())
320  if(!selected || (*ei).IsS())
321  (*ei).C() = vcg::GetColorMapping((*ei).Q(), minq, maxq, cmap);
322  }
323 
328  static void PerVertexQualityGray(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0)
329  {
330  RequirePerVertexColor(m);
331  RequirePerVertexQuality(m);
332  if(minq==maxq)
333  {
334  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
335  minq=minmax.first;
336  maxq=minmax.second;
337  }
338  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
339  if(!(*vi).IsD())
340  (*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
341  }
342 
347  static void PerFaceQualityGray(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0)
348  {
349  RequirePerFaceColor(m);
350  RequirePerFaceQuality(m);
351 
352  if(minq==maxq)
353  {
354  std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
355  minq=minmax.first;
356  maxq=minmax.second;
357  }
358  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
359  (*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
360  }
361 
373  static void PerVertexBorderFlag( MeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
374  {
375  RequirePerVertexColor(m);
376 
377  Color4b BaseColor = Color4b::Green;
378 
379  PerVertexConstant(m,BaseColor);
380  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
381  for(int j=0;j<3;++j)
382  {
383  if((*fi).IsB(j)){
384  if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = BorderColor;
385  if( (*fi).V(j)->C() == InternalColor) (*fi).V(j)->C() = MixColor;
386  if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = BorderColor;
387  if( (*fi).V1(j)->C() == InternalColor) (*fi).V1(j)->C() = MixColor;
388  } else
389  {
390  if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = InternalColor;
391  if( (*fi).V(j)->C() == BorderColor) (*fi).V(j)->C() = MixColor;
392  if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = InternalColor;
393  if( (*fi).V1(j)->C() == BorderColor) (*fi).V1(j)->C() = MixColor;
394  }
395  }
396 
397  }
398 
403  static void PerFaceRandomConnectedComponent( MeshType &m)
404  {
405  RequirePerFaceColor(m);
406  RequireFFAdjacency(m);
407 
408  std::vector< std::pair<int, typename MeshType::FacePointer> > CCV;
409  int ScatterSize= std::min (100,tri::Clean<MeshType>::ConnectedComponents(m, CCV)); // number of random color to be used. Never use too many.
410 
412  for(unsigned int i=0;i<CCV.size();++i)
413  {
414  Color4b BaseColor = Color4b::Scatter(ScatterSize, i%ScatterSize,.4f,.7f);
415  std::vector<typename MeshType::FacePointer> FPV;
416  for(ci.start(m,CCV[i].second);!ci.completed();++ci)
417  (*ci)->C()=BaseColor;
418  }
419  }
420 
425  static void PerFaceRandom(MeshType &m)
426  {
427  RequirePerFaceColor(m);
428  FaceIterator fi;
429  Color4b BaseColor = Color4b::Black;
430  PerFaceConstant(m,BaseColor);
431  int id_num=0;
432  for(fi=m.face.begin();fi!=m.face.end();++fi)
433  if(!(*fi).IsD())
434  {
435  id_num++;
436  if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
437  for(int j=0;j<3;++j)
438  if((*fi).IsF(j))
439  {
440  assert(!IsBorder((*fi),j));
441  (*fi).FFp(j)->C()= (*fi).C();
442  }
443  }
444  }
445 
452  static void PerVertexPerlinNoise(MeshType& m, CoordType period, CoordType offset = CoordType(0, 0, 0), bool onSelected = false)
453  {
454  RequirePerVertexColor(m);
455 
456  CoordType p[3];
457 
458  for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
459  if(!(*vi).IsD())
460  if ((!onSelected) || ((*vi).IsS()))
461  {
462  // perlin noise is defined in 022
463  p[0] = (vi->P()/period[0])+offset;
464  p[1] = (vi->P()/period[1])+offset;
465  p[2] = (vi->P()/period[2])+offset;
466  (*vi).C() = Color4b( int(127+128.0*math::Perlin::Noise(p[0][0],p[0][1],p[0][2])),
467  int(127+128.0*math::Perlin::Noise(p[1][0],p[1][1],p[1][2])),
468  int(127+128.0*math::Perlin::Noise(p[2][0],p[2][1],p[2][2])),
469  255 );
470  }
471 
472  }
473 
474 
479  static void PerVertexPerlinColoring(MeshType& m, ScalarType period, CoordType offset = CoordType(0, 0, 0), Color4b color1 = Color4b::Black, Color4b color2 = Color4b::White, bool onSelected = false)
480  {
481  RequirePerVertexColor(m);
482 
483  CoordType p;
484 
485  for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
486  if (!(*vi).IsD())
487  if ((!onSelected) || ((*vi).IsS()))
488  {
489  // perlin noise is defined in 022
490  p = (vi->P() / period) + offset;
491  double factor = (math::Perlin::Noise(p[0], p[1], p[2]) + 1.0) / 2.0;
492 
493  int rr = (color1[0] * factor) + (color2[0] * (1.0 - factor));
494  int gg = (color1[1] * factor) + (color2[1] * (1.0 - factor));
495  int bb = (color1[2] * factor) + (color2[2] * (1.0 - factor));
496  int aa = (color1[3] * factor) + (color2[3] * (1.0 - factor));
497 
498  (*vi).C() = Color4b(rr, gg, bb, aa);
499  }
500  }
501 
505  static void PerVertexAddNoise(MeshType& m, int noiseBits, bool onSelected=false)
506  {
507  RequirePerVertexColor(m);
508 
509  if(noiseBits>8) noiseBits = 8;
510  if(noiseBits<1) return;
511 
512  math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(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:347
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:328
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:373
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:287
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:205
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:403
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:266
static void PerVertexFromFace(MeshType &m)
Transfer face color onto vertex color.
Definition: color.h:170
static int PerVertexInvert(MeshType &m, const bool ProcessSelected=false)
Invert the colors of the mesh.
Definition: color.h:666
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:479
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:246
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:308
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:452
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:425
static void PerVertexAddNoise(MeshType &m, int noiseBits, bool onSelected=false)
Simple Noise adding function. It simply add signed noise to the color of the mesh....
Definition: color.h:505
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:224
void ForEachTetra(const MeshType &m, Callable action)
Definition: foreach.h:270
void ForEachVertex(const MeshType &m, Callable action)
Definition: foreach.h:126
Definition: namespaces.dox:6