24 #ifndef __VCG_TRI_UPDATE_COLOR
25 #define __VCG_TRI_UPDATE_COLOR
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>
51 template <
class MeshType>
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;
67 typedef typename MeshType::ScalarType ScalarType;
68 typedef typename MeshType::CoordType CoordType;
84 RequirePerVertexColor(m);
87 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
89 if(!selected || (*vi).IsS())
100 static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White,
bool selected=
false)
102 RequirePerFaceColor(m);
104 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
106 if(!selected || (*fi).IsS())
117 static int PerTetraConstant(MeshType & m, Color4b vs = Color4b::White,
bool selected =
false)
119 RequirePerTetraColor(m);
121 ForEachTetra(m, [&] (TetraType & t) {
122 if (!selected || t.IsS())
138 RequirePerTetraColor(m);
139 RequirePerVertexColor(m);
142 csi.r = csi.g = csi.b = csi.cnt = 0;
143 SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert, csi);
145 ForEachTetra(m, [&] (TetraType & t) {
146 for (
int i = 0; i < 4; ++i)
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];
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;
171 RequirePerFaceColor(m);
172 RequirePerVertexColor(m);
175 csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
176 SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
179 for(fi=m.face.begin();fi!=m.face.end();++fi)
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;
191 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
192 if(!(*vi).IsD() && TD[*vi].cnt>0 )
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;
206 RequirePerFaceColor(m);
207 RequirePerVertexColor(m);
210 for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
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);
225 RequirePerVertexQuality(m);
226 RequirePerVertexColor(m);
230 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
234 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
236 (*vi).C().SetColorRamp(minq,maxq,(*vi).Q());
246 RequirePerVertexQuality(m);
247 RequirePerVertexColor(m);
251 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
255 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
257 (*vi).C().SetColorRampParula(minq, maxq, (*vi).Q());
264 static void PerTetraQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0.,
bool selected =
false)
266 RequirePerTetraColor(m);
267 RequirePerTetraQuality(m);
271 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerTetraQualityMinMax(m);
276 ForEachTetra(m, [&] (TetraType & t){
277 if (!selected || t.IsS())
278 t.C().SetColorRamp(minq, maxq, t.Q());
285 static void PerFaceQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0,
bool selected =
false)
287 RequirePerFaceColor(m);
288 RequirePerFaceQuality(m);
292 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
296 for(FaceIterator fi = m.face.begin();fi != m.face.end(); ++fi)
298 if(!selected || (*fi).IsS())
299 (*fi).C().SetColorRamp(minq, maxq, (*fi).Q());
306 static void PerEdgeQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0,
bool selected =
false)
308 RequirePerEdgeColor(m);
309 RequirePerEdgeQuality(m);
313 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerEdgeQualityMinMax(m);
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());
328 RequirePerVertexColor(m);
329 RequirePerVertexQuality(m);
332 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
336 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
338 (*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
347 RequirePerFaceColor(m);
348 RequirePerFaceQuality(m);
352 std::pair<ScalarType, ScalarType> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
356 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
357 (*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
371 static void PerVertexBorderFlag( MeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
373 RequirePerVertexColor(m);
375 Color4b BaseColor = Color4b::Green;
378 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
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;
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;
403 RequirePerFaceColor(m);
404 RequireFFAdjacency(m);
406 std::vector< std::pair<int, typename MeshType::FacePointer> > CCV;
409 ConnectedComponentIterator<MeshType> ci;
410 for(
unsigned int i=0;i<CCV.size();++i)
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;
425 RequirePerFaceColor(m);
427 Color4b BaseColor = Color4b::Black;
430 for(fi=m.face.begin();fi!=m.face.end();++fi)
434 if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
439 (*fi).FFp(j)->C()= (*fi).C();
450 static void PerVertexPerlinNoise(MeshType& m, CoordType period, CoordType offset = CoordType(0, 0, 0),
bool onSelected =
false)
452 RequirePerVertexColor(m);
456 for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
458 if ((!onSelected) || ((*vi).IsS()))
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])),
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)
479 RequirePerVertexColor(m);
483 for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
485 if ((!onSelected) || ((*vi).IsS()))
488 p = (vi->P() / period) + offset;
489 double factor = (math::Perlin::Noise(p[0], p[1], p[2]) + 1.0) / 2.0;
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));
496 (*vi).C() = Color4b(rr, gg, bb, aa);
505 RequirePerVertexColor(m);
507 if(noiseBits>8) noiseBits = 8;
508 if(noiseBits<1)
return;
510 math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(time(NULL));
511 for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
513 if ((!onSelected) || ((*vi).IsS()))
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);
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)
527 RequirePerVertexColor(m);
531 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
535 if(!ProcessSelected || (*vi).IsS())
537 float value = ComputeLightness((*vi).C());
539 if(value<=threshold) (*vi).C() = c1;
549 static float ComputeLightness(Color4b c)
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;
560 RequirePerVertexColor(m);
564 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
568 if(!ProcessSelected || (*vi).IsS())
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),
586 RequirePerVertexColor(m);
590 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
594 if(!ProcessSelected || (*vi).IsS())
596 (*vi).C() = ColorMul((*vi).C(),factor);
606 static Color4b ColorMul(Color4b c,
float factor)
608 return Color4b( ValueMul(c[0], factor), ValueMul(c[1], factor), ValueMul(c[2], factor), 1);
611 static int ValueMul(
int value,
float factor)
613 return math::Clamp<int>((int)((value - 128)*factor + 128), 0, 255);
626 RequirePerVertexColor(m);
630 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
634 if(!ProcessSelected || (*vi).IsS())
636 (*vi).C() = ColorBrightnessContrast((*vi).C(),brightness,contrast);
644 static Color4b ColorBrightnessContrast(Color4b c,
float brightness,
float contrast)
646 return Color4b( ValueBrightnessContrast(c[0], brightness, contrast),
647 ValueBrightnessContrast(c[1], brightness, contrast),
648 ValueBrightnessContrast(c[2], brightness, contrast), 1 );
651 static int ValueBrightnessContrast(
unsigned char ivalue,
float brightness,
float contrast)
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);
666 RequirePerVertexColor(m);
669 for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi)
673 if(!ProcessSelected || (*vi).IsS())
675 Color4b &c=(*vi).C();
676 c=Color4b( 255-c[0],255-c[1],255-c[2], 1);
687 static int PerVertexGamma(MeshType &m,
float gamma,
const bool ProcessSelected=
false)
689 RequirePerVertexColor(m);
694 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
698 if(!ProcessSelected || (*vi).IsS())
700 (*vi).C() = ColorPow((*vi).C(), 1/gamma);
709 static Color4b ColorPow(Color4b c,
float exponent)
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),
718 static float ValuePow(
float value,
float exponent)
720 return powf(value, exponent);
724 enum rgbChMask {ALL_CHANNELS = 7, RED_CHANNEL = 4, GREEN_CHANNEL = 2, BLUE_CHANNEL = 1, NO_CHANNELS = 0 };
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)
736 RequirePerVertexColor(m);
740 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
744 if(!ProcessSelected || (*vi).IsS())
746 (*vi).C() = ColorLevels((*vi).C(), gamma, in_min, in_max, out_min, out_max, rgbMask);
755 static Color4b ColorLevels(Color4b c,
float gamma,
float in_min,
float in_max,
float out_min,
float out_max,
unsigned char rgbMask)
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);
765 static int ValueLevels(
int value,
float gamma,
float in_min,
float in_max,
float out_min,
float out_max)
767 float fvalue = value/255.0f;
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);
771 fvalue = powf(fvalue,1/gamma);
773 fvalue = fvalue * (out_max - out_min) + out_min;
775 return math::Clamp<int>((int)(fvalue * 255), 0, 255);
785 RequirePerVertexColor(m);
789 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
793 if(!ProcessSelected || (*vi).IsS())
795 (*vi).C() = ColorApplyDiff((*vi).C(), c, intensity);
806 static Color4b ColorApplyDiff(Color4b old_color, Color4b new_color,
float intensity)
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);
813 static int ValueApplyDiff(
int old_value,
int new_value,
float intensity)
815 return math::Clamp<int>((int)(old_value + intensity * (new_value - old_value)), 0, 255);
819 enum DesaturationMethods {M_LIGHTNESS = 0, M_LUMINOSITY = 1, M_AVERAGE = 2};
832 RequirePerVertexColor(m);
836 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
840 if(!ProcessSelected || (*vi).IsS())
842 (*vi).C() = ColorDesaturate((*vi).C(), method);
851 static Color4b ColorDesaturate(Color4b c,
int method)
855 int val = (int)ComputeLightness(c);
856 return Color4b( val, val, val, 255);
859 int val = (int)ComputeAvgLightness(c);
860 return Color4b( val, val, val, 255);
863 int val = (int)ComputeLuminosity(c);
864 return Color4b( val, val, val, 255);
868 return Color4b(255, 255, 255, 255);
872 static float ComputeAvgLightness(Color4b c)
874 return float(c[0]+c[1]+c[2])/3.0f;
878 static float ComputeLuminosity(Color4b c)
880 return float(0.2126f*c[0]+0.7152f*c[1]+0.0722f*c[2]);
888 static int PerVertexEqualize(MeshType &m,
unsigned int rgbMask,
const bool ProcessSelected=
false)
890 RequirePerVertexColor(m);
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);
901 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
905 if(!ProcessSelected || (*vi).IsS())
907 float v = ComputeLightness((*vi).C())+0.5;
908 Hl.Add(v); Hr.Add((
float)(*vi).C()[0]); Hg.Add((
float)(*vi).C()[1]); Hb.Add((
float)(*vi).C()[2]);
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];
924 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
928 if(!ProcessSelected || (*vi).IsS())
930 (*vi).C()=ColorEqualize((*vi).C(), cdf_l, cdf_r, cdf_g, cdf_b, 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)
941 unsigned char r = c[0], g = c[1], b = c[2];
942 if(rgbMask == NO_CHANNELS)
944 int v = ValueEqualize(cdf_l[(
int)(ComputeLightness(c)+0.5f)], cdf_l[0], cdf_l[255]);
945 return Color4b(v, v, v, 255);
947 if(rgbMask & RED_CHANNEL) r = ValueEqualize(cdf_r[c[0]], cdf_r[0], cdf_r[255]);
948 if(rgbMask & GREEN_CHANNEL) g = ValueEqualize(cdf_g[c[1]], cdf_g[0], cdf_g[255]);
949 if(rgbMask & BLUE_CHANNEL) b = ValueEqualize(cdf_b[c[2]], cdf_b[0], cdf_b[255]);
950 return Color4b(r, g, b, 255);
954 static int ValueEqualize(
int cdfValue,
int cdfMin,
int cdfMax)
956 return int(
float((cdfValue - cdfMin)/
float(cdfMax - cdfMin)) * 255.0f);
966 RequirePerVertexColor(m);
968 Color4b unbalancedWhite= userColor;
973 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
977 if(!ProcessSelected || (*vi).IsS())
979 (*vi).C()=ColorWhiteBalance((*vi).C(),unbalancedWhite);
988 static Color4b ColorWhiteBalance(Color4b c, Color4b unbalancedWhite)
991 if(unbalancedWhite[0]==0) unbalancedWhite[0]=1;
992 if(unbalancedWhite[1]==0) unbalancedWhite[1]=1;
993 if(unbalancedWhite[2]==0) unbalancedWhite[2]=1;
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),