00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #ifndef __VCG_TRI_UPDATE_COLOR
00064 #define __VCG_TRI_UPDATE_COLOR
00065 #include <limits>
00066 #include <math.h>
00067 #include <vcg/space/color4.h>
00068 #include <vcg/math/histogram.h>
00069 #include <vcg/complex/trimesh/stat.h>
00070 #include <vcg/math/perlin_noise.h>
00071 #include <vcg/math/random_generator.h>
00072
00073 namespace vcg {
00074 namespace tri {
00075
00077
00079
00081
00085 template <class UpdateMeshType>
00086 class UpdateColor
00087 {
00088 public:
00089 typedef UpdateMeshType MeshType;
00090 typedef typename UpdateMeshType::VertexType VertexType;
00091 typedef typename UpdateMeshType::VertexPointer VertexPointer;
00092 typedef typename UpdateMeshType::VertexIterator VertexIterator;
00093 typedef typename UpdateMeshType::FaceType FaceType;
00094 typedef typename UpdateMeshType::FacePointer FacePointer;
00095 typedef typename UpdateMeshType::FaceIterator FaceIterator;
00096
00097
00098
00099 class ColorAvgInfo
00100 {
00101 public:
00102 unsigned int r;
00103 unsigned int g;
00104 unsigned int b;
00105 unsigned int a;
00106 int cnt;
00107 };
00108
00109 static void VertexFromFace( UpdateMeshType &m)
00110 {
00111 ColorAvgInfo csi;
00112 csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
00113 SimpleTempData<typename UpdateMeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
00114
00115 FaceIterator fi;
00116 for(fi=m.face.begin();fi!=m.face.end();++fi)
00117 if(!(*fi).IsD())
00118 for(int j=0;j<3;++j)
00119 {
00120 TD[(*fi).V(j)].r+=(*fi).C()[0];
00121 TD[(*fi).V(j)].g+=(*fi).C()[1];
00122 TD[(*fi).V(j)].b+=(*fi).C()[2];
00123 TD[(*fi).V(j)].a+=(*fi).C()[3];
00124 ++TD[(*fi).V(j)].cnt;
00125 }
00126
00127 VertexIterator vi;
00128 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00129 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00130 {
00131 (*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
00132 (*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
00133 (*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
00134 (*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
00135 }
00136 }
00137
00138 static void FaceFromVertex( UpdateMeshType &m)
00139 {
00140 FaceIterator fi;
00141 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00142 {
00143 Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
00144 Color4f::Construct((*fi).V(1)->C()) +
00145 Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
00146 (*fi).C().Import(avg);
00147 }
00148 }
00149
00150
00151
00153
00164 static void VertexBorderFlag( UpdateMeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
00165 {
00166 Color4b BaseColor = Color4b::Green;
00167
00168 VertexConstant(m,BaseColor);
00169
00170 typename UpdateMeshType::FaceIterator fi;
00171 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00172 for(int j=0;j<3;++j)
00173 if((*fi).IsB(j)){
00174 if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = BorderColor;
00175 if( (*fi).V(j)->C() == InternalColor) (*fi).V(j)->C() = MixColor;
00176 if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = BorderColor;
00177 if( (*fi).V1(j)->C() == InternalColor) (*fi).V1(j)->C() = MixColor;
00178 } else
00179 {
00180 if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = InternalColor;
00181 if( (*fi).V(j)->C() == BorderColor) (*fi).V(j)->C() = MixColor;
00182 if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = InternalColor;
00183 if( (*fi).V1(j)->C() == BorderColor) (*fi).V1(j)->C() = MixColor;
00184 }
00185
00186 }
00187
00190 static void MultiFaceRandom( UpdateMeshType &m)
00191 {
00192 FaceIterator fi;
00193 Color4b BaseColor = Color4b::Black;
00194 FaceConstant(m,BaseColor);
00195 int id_num=0;
00196 for(fi=m.face.begin();fi!=m.face.end();++fi)
00197 if(!(*fi).IsD())
00198 {
00199 id_num++;
00200 if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
00201 for(int j=0;j<3;++j)
00202 if((*fi).IsF(j))
00203 {
00204 assert(!IsBorder((*fi),j));
00205 (*fi).FFp(j)->C()= (*fi).C();
00206 }
00207 }
00208 }
00209
00210 static void FaceBF( UpdateMeshType &m, Color4b vn=Color4b::White, Color4b vb=Color4b::Blue,
00211 Color4b vc=Color4b::Red, Color4b vs=Color4b::LightBlue)
00212 {
00213 typename UpdateMeshType::FaceIterator fi;
00214 for(fi=m.face.begin();fi!=m.face.end();++fi)
00215 if(!(*fi).IsD())
00216 (*fi).C() = vn;
00217
00218 for(fi=m.face.begin();fi!=m.face.end();++fi)
00219 if(!(*fi).IsD())
00220 {
00221 if((*fi).IsS())
00222 (*fi).C() = vs;
00223 else
00224 {
00225 for(int j=0;j<3;++j)
00226 if(*fi.IsManifold(j)){
00227 if((*fi).IsB(j)){
00228 (*fi).C() = vb;
00229 (*fi).C() = vb;
00230 }
00231 }
00232 else
00233 {
00234 (*fi).C() = vc;
00235 (*fi).C() = vc;
00236 }
00237 }
00238 }
00239 }
00240
00241
00242 static int FaceSelected(UpdateMeshType &m, Color4b vs=Color4b::LightBlue)
00243 {
00244 int cnt=0;
00245 typename UpdateMeshType::FaceIterator fi;
00246 for(fi=m.face.begin();fi!=m.face.end();++fi)
00247 if(!(*fi).IsD()){
00248 if((*fi).IsS()) { (*fi).C() = vs; ++cnt; }
00249 else (*fi).C() = Color4b::White;
00250 }
00251 return cnt;
00252 }
00253
00254 static void FaceColorStrip(UpdateMeshType &m, std::vector<FacePointer> &TStripF)
00255 {
00256 vcg::Color4b cc[7]={
00257 vcg::Color4b::White ,
00258 vcg::Color4b::Red ,
00259 vcg::Color4b::Green ,
00260 vcg::Color4b::Blue ,
00261 vcg::Color4b::Cyan ,
00262 vcg::Color4b::Yellow ,
00263 vcg::Color4b::Magenta
00264 };
00265 int cnt=0;
00266
00267 typename std::vector<FacePointer>::iterator fi;
00268 for(fi=TStripF.begin();fi!=TStripF.end();++fi)
00269 if(*fi) (**fi).C().ColorRamp(0,16,cnt);
00270 else cnt=(cnt+1)%16;
00271
00272
00273
00274 }
00275
00276
00277 static int VertexSelected(UpdateMeshType &m, Color4b vs=Color4b::LightBlue)
00278 {
00279 int cnt=0;
00280 typename UpdateMeshType::VertexIterator vi;
00281 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00282 if(!(*vi).IsD()){
00283 if((*vi).IsS()) {(*vi).C() = vs; ++cnt; }
00284 else (*vi).C() = Color4b::White;
00285 }
00286 return cnt;
00287 }
00288
00289 static void VertexConstant(UpdateMeshType &m, Color4b c=Color4b::White)
00290 {
00291 typename UpdateMeshType::VertexIterator vi;
00292 for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
00293 (*vi).C()=c;
00294 }
00295
00296 static void FaceConstant(UpdateMeshType &m, Color4b c=Color4b::White)
00297 {
00298 typename UpdateMeshType::FaceIterator fi;
00299 for(fi=m.face.begin();fi!=m.face.end();++fi)
00300 (*fi).C()=c;
00301 }
00302
00303 static void VertexBorderManifoldFlag(UpdateMeshType &m, Color4b vn=Color4b::White, Color4b vb=Color4b::Blue, Color4b vc=Color4b::Red)
00304 {
00305 typename UpdateMeshType::VertexIterator vi;
00306 for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
00307 (*vi).C()=vn;
00308
00309 typename UpdateMeshType::FaceIterator fi;
00310 for(fi=m.face.begin();fi!=m.face.end();++fi)
00311 if(!(*fi).IsD())
00312 for(int j=0;j<3;++j)
00313 if((*fi).IsManifold(j)){
00314 if((*fi).IsB(j)){
00315 (*fi).V(j)->C()=vb;
00316 (*fi).V1(j)->C()=vb;
00317 }
00318 }
00319 else
00320 {
00321 (*fi).V(j)->C()=vc;
00322 (*fi).V1(j)->C()=vc;
00323 }
00324 }
00325
00326 static void FaceQualityGray(UpdateMeshType &m, float minq, float maxq)
00327 {
00328 typename UpdateMeshType::FaceIterator fi;
00329 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00330 (*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
00331 }
00332
00333 static void FaceQualityGray(UpdateMeshType &m)
00334 {
00335 std::pair<float,float> minmax = Stat<UpdateMeshType>::ComputePerFaceQualityMinMax(m);
00336 FaceQualityGray(m,minmax.first,minmax.second);
00337 }
00338
00339 static void FaceQualityRamp(UpdateMeshType &m,bool selected=false)
00340 {
00341
00342 typename UpdateMeshType::FaceIterator fi;
00343 float minq=std::numeric_limits<float>::max(),
00344 maxq=-std::numeric_limits<float>::max();
00345
00346 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00347 if(!selected || (*fi).IsS())
00348 {
00349 minq=std::min(minq,(*fi).Q());
00350 maxq=std::max(maxq,(*fi).Q());
00351 }
00352
00353 FaceQualityRamp(m,minq,maxq,selected);
00354 }
00355
00356 static void FaceQualityRamp(UpdateMeshType &m, float minq, float maxq,bool selected=false)
00357 {
00358 typename UpdateMeshType::FaceIterator fi;
00359 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00360 if(!selected || (*fi).IsS())
00361 (*fi).C().ColorRamp(minq,maxq,(*fi).Q());
00362 }
00363
00364 static void VertexQualityRamp(UpdateMeshType &m, float minq, float maxq)
00365 {
00366 typename UpdateMeshType::VertexIterator vi;
00367
00368 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00369 if(!(*vi).IsD())
00370 (*vi).C().ColorRamp(minq,maxq,(*vi).Q());
00371 }
00372
00373 static void VertexQualityRamp(UpdateMeshType &m)
00374 {
00375 std::pair<float,float> minmax = Stat<UpdateMeshType>::ComputePerVertexQualityMinMax(m);
00376 VertexQualityRamp(m,minmax.first,minmax.second);
00377 }
00378
00379 static void VertexQualityGray(UpdateMeshType &m, const float minq, const float maxq)
00380 {
00381 typename UpdateMeshType::VertexIterator vi;
00382
00383 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00384 if(!(*vi).IsD())
00385 (*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
00386 }
00387
00388 static void VertexQualityGray(UpdateMeshType &m)
00389 {
00390 std::pair<float,float> minmax = Stat<UpdateMeshType>::ComputePerVertexQualityMinMax( m);
00391 VertexQualityGray(m,minmax.first,minmax.second);
00392 }
00393
00394
00395 static int Filling(UpdateMeshType &m, Color4b c, const bool ProcessSelected=false)
00396 {
00397 int counter=0;
00398 VertexIterator vi;
00399 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00400 {
00401 if(!(*vi).IsD())
00402 {
00403 if(!ProcessSelected || (*vi).IsS())
00404 {
00405 (*vi).C() = c;
00406 ++counter;
00407 }
00408 }
00409 }
00410 return counter;
00411 }
00412
00413
00414 static int Thresholding(UpdateMeshType &m, float threshold, Color4b c1 = Color4<unsigned char>::Black, Color4b c2 = Color4<unsigned char>::White, const bool ProcessSelected=false)
00415 {
00416 int counter=0;
00417 VertexIterator vi;
00418 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00419 {
00420 if(!(*vi).IsD())
00421 {
00422 if(!ProcessSelected || (*vi).IsS())
00423 {
00424 float value = ComputeLightness((*vi).C());
00425
00426 if(value<=threshold) (*vi).C() = c1;
00427 else (*vi).C() = c2;
00428 ++counter;
00429 }
00430 }
00431 }
00432 return counter;
00433 }
00434
00435
00436 static float ComputeLightness(Color4b c)
00437 {
00438 float min_rgb = math::Min((float)c[0],(float)c[1]);
00439 min_rgb = math::Min(min_rgb,(float)c[2]);
00440 float max_rgb = math::Max((float)c[0],(float)c[1]);
00441 max_rgb = math::Max(max_rgb,(float)c[2]);
00442 return (max_rgb + min_rgb)/2;
00443 }
00444
00445
00446 static int Brighting(UpdateMeshType &m, float amount, const bool ProcessSelected=false)
00447 {
00448 int counter=0;
00449 VertexIterator vi;
00450 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00451 {
00452 if(!(*vi).IsD())
00453 {
00454 if(!ProcessSelected || (*vi).IsS())
00455 {
00456 (*vi).C() = Color4b(
00457 math::Clamp(int((*vi).C()[0]+amount),0,255),
00458 math::Clamp(int((*vi).C()[1]+amount),0,255),
00459 math::Clamp(int((*vi).C()[2]+amount),0,255),
00460 255);
00461 ++counter;
00462 }
00463 }
00464 }
00465 return counter;
00466 }
00467
00468
00469 static int Contrast(UpdateMeshType &m, float factor, const bool ProcessSelected=false)
00470 {
00471 int counter=0;
00472 VertexIterator vi;
00473 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00474 {
00475 if(!(*vi).IsD())
00476 {
00477 if(!ProcessSelected || (*vi).IsS())
00478 {
00479 (*vi).C() = ColorMul((*vi).C(),factor);
00480 ++counter;
00481 }
00482 }
00483 }
00484 return counter;
00485 }
00486
00487
00488
00489 static Color4b ColorMul(Color4b c, float factor)
00490 {
00491 return Color4b( ValueMul(c[0], factor), ValueMul(c[1], factor), ValueMul(c[2], factor), 1);
00492 }
00493
00494 static int ValueMul(int value, float factor)
00495 {
00496 return math::Clamp<int>((int)((value - 128)*factor + 128), 0, 255);
00497 }
00498
00499
00500 static int BrightnessContrast(UpdateMeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
00501 {
00502 int counter=0;
00503 VertexIterator vi;
00504 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00505 {
00506 if(!(*vi).IsD())
00507 {
00508 if(!ProcessSelected || (*vi).IsS())
00509 {
00510 (*vi).C() = ColorBrightnessContrast((*vi).C(),brightness,contrast);
00511 ++counter;
00512 }
00513 }
00514 }
00515 return counter;
00516 }
00517
00518
00519
00520
00521 static Color4b ColorBrightnessContrast(Color4b c, float brightness, float contrast)
00522 {
00523 return Color4b( ValueBrightnessContrast(c[0], brightness, contrast),
00524 ValueBrightnessContrast(c[1], brightness, contrast),
00525 ValueBrightnessContrast(c[2], brightness, contrast), 1 );
00526 }
00527
00528 static int ValueBrightnessContrast(unsigned char ivalue, float brightness, float contrast)
00529 {
00530 float value = float(ivalue)/255.0f;
00531 if (brightness < 0.0) value = value * ( 1.0 + brightness);
00532 else value = value + ((1.0 - value) * brightness);
00533 value = (value - 0.5) * (tan ((contrast + 1) * M_PI/4) ) + 0.5;
00534 return math::Clamp<int>(255.0*value, 0, 255);
00535 }
00536
00537
00538 static int Invert(UpdateMeshType &m, const bool ProcessSelected=false)
00539 {
00540 int counter=0;
00541 VertexIterator vi;
00542 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00543 {
00544 if(!(*vi).IsD())
00545 {
00546 if(!ProcessSelected || (*vi).IsS())
00547 {
00548 (*vi).C() = ColorInvert((*vi).C());
00549 ++counter;
00550 }
00551 }
00552 }
00553 return counter;
00554 }
00555
00556
00557 static Color4b ColorInvert(Color4b c)
00558 {
00559 return Color4b( ValueInvert(c[0]), ValueInvert(c[1]), ValueInvert(c[2]), 1);
00560 }
00561
00562 static int ValueInvert(int value)
00563 {
00564 return 255-value;
00565 }
00566
00567 static int Gamma(UpdateMeshType &m, float gamma, const bool ProcessSelected=false)
00568 {
00569 int counter=0;
00570
00571 VertexIterator vi;
00572 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00573 {
00574 if(!(*vi).IsD())
00575 {
00576 if(!ProcessSelected || (*vi).IsS())
00577 {
00578 (*vi).C() = ColorPow((*vi).C(), 1/gamma);
00579 ++counter;
00580 }
00581 }
00582 }
00583 return counter;
00584 }
00585
00586
00587 static Color4b ColorPow(Color4b c, float exponent)
00588 {
00589 return vcg::Color4b(
00590 math::Clamp((int)( ValuePow(float(c[0])/255, exponent)*255), 0, 255),
00591 math::Clamp((int)( ValuePow(float(c[1])/255, exponent)*255), 0, 255),
00592 math::Clamp((int)( ValuePow(float(c[2])/255, exponent)*255), 0, 255),
00593 255);
00594 }
00595
00596 static float ValuePow(float value, float exponent)
00597 {
00598 return powf(value, exponent);
00599 }
00600
00601
00602 enum rgbChMask {ALL_CHANNELS = 7, RED_CHANNEL = 4, GREEN_CHANNEL = 2, BLUE_CHANNEL = 1, NO_CHANNELS = 0 };
00603
00604
00605
00606
00607 static int Levels(UpdateMeshType &m, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask, const bool ProcessSelected=false)
00608 {
00609 int counter=0;
00610 VertexIterator vi;
00611 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00612 {
00613 if(!(*vi).IsD())
00614 {
00615 if(!ProcessSelected || (*vi).IsS())
00616 {
00617 (*vi).C() = ColorLevels((*vi).C(), gamma, in_min, in_max, out_min, out_max, rgbMask);
00618 ++counter;
00619 }
00620 }
00621 }
00622 return counter;
00623 }
00624
00625
00626 static Color4b ColorLevels(Color4b c, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask)
00627 {
00628 unsigned char r = c[0], g = c[1], b = c[2];
00629 if(rgbMask & RED_CHANNEL) r = ValueLevels(c[0], gamma, in_min, in_max, out_min, out_max);
00630 if(rgbMask & GREEN_CHANNEL) g = ValueLevels(c[1], gamma, in_min, in_max, out_min, out_max);
00631 if(rgbMask & BLUE_CHANNEL) b = ValueLevels(c[2], gamma, in_min, in_max, out_min, out_max);
00632 return Color4b(r, g, b, 255);
00633 }
00634
00635
00636 static int ValueLevels(int value, float gamma, float in_min, float in_max, float out_min, float out_max)
00637 {
00638 float fvalue = value/255.0f;
00639
00640 fvalue = math::Clamp<float>(fvalue - in_min, 0.0f, 1.0f) / math::Clamp<float>(in_max - in_min, 1.0f/255.0f, 1.0f);
00641
00642 fvalue = powf(fvalue,1/gamma);
00643
00644 fvalue = fvalue * (out_max - out_min) + out_min;
00645
00646 return math::Clamp<int>((int)(fvalue * 255), 0, 255);
00647 }
00648
00649
00650 static int Colourisation(UpdateMeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
00651 {
00652 int counter=0;
00653 VertexIterator vi;
00654 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00655 {
00656 if(!(*vi).IsD())
00657 {
00658 if(!ProcessSelected || (*vi).IsS())
00659 {
00660 (*vi).C() = ColorApplyDiff((*vi).C(), c, intensity);
00661 ++counter;
00662 }
00663 }
00664 }
00665 return counter;
00666 }
00667
00668
00669 static Color4b ColorApplyDiff(Color4b old_color, Color4b new_color, float intensity)
00670 {
00671 return Color4b( ValueApplyDiff(old_color[0],new_color[0],intensity), ValueApplyDiff(old_color[1],new_color[1],intensity), ValueApplyDiff(old_color[2], new_color[2],intensity), 255);
00672 }
00673
00674 static int ValueApplyDiff(int old_value, int new_value, float intensity)
00675 {
00676 return math::Clamp<int>((int)(old_value + intensity * (new_value - old_value)), 0, 255);
00677 }
00678
00679
00680 enum DesaturationMethods {M_LIGHTNESS = 0, M_LUMINOSITY = 1, M_AVERAGE = 2};
00681
00682
00683 static int Desaturation(UpdateMeshType &m, int method, const bool ProcessSelected=false)
00684 {
00685 int counter=0;
00686 VertexIterator vi;
00687 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00688 {
00689 if(!(*vi).IsD())
00690 {
00691 if(!ProcessSelected || (*vi).IsS())
00692 {
00693 (*vi).C() = ColorDesaturate((*vi).C(), method);
00694 ++counter;
00695 }
00696 }
00697 }
00698 return counter;
00699 }
00700
00701
00702 static Color4b ColorDesaturate(Color4b c, int method)
00703 {
00704 switch(method){
00705 case M_LIGHTNESS:{
00706 int val = (int)ComputeLightness(c);
00707 return Color4b( val, val, val, 255);
00708 }
00709 case M_AVERAGE:{
00710 int val = (int)ComputeAvgLightness(c);
00711 return Color4b( val, val, val, 255);
00712 }
00713 case M_LUMINOSITY:{
00714 int val = (int)ComputeLuminosity(c);
00715 return Color4b( val, val, val, 255);
00716 }
00717 default: assert(0);
00718 }
00719 }
00720
00721
00722 static float ComputeAvgLightness(Color4b c)
00723 {
00724 return float(c[0]+c[1]+c[2])/3.0f;
00725 }
00726
00727
00728 static float ComputeLuminosity(Color4b c)
00729 {
00730 return float(0.2126f*c[0]+0.7152f*c[1]+0.0722f*c[2]);
00731 }
00732
00733
00734
00735 static int Equalize(UpdateMeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
00736 {
00737
00738 Histogramf Hl, Hr, Hg, Hb;
00739 Hl.Clear(); Hr.Clear(); Hg.Clear(); Hb.Clear();
00740 Hl.SetRange(0, 255, 255); Hr.SetRange(0, 255, 255); Hg.SetRange(0, 255, 255); Hb.SetRange(0, 255, 255);
00741
00742 int counter=0;
00743 VertexIterator vi;
00744
00745
00746 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00747 {
00748 if(!(*vi).IsD())
00749 {
00750 if(!ProcessSelected || (*vi).IsS())
00751 {
00752 int v = (int)(ComputeLightness((*vi).C())+0.5);
00753 Hl.Add(v); Hr.Add((*vi).C()[0]); Hg.Add((*vi).C()[1]); Hb.Add((*vi).C()[2]);
00754 }
00755 }
00756 }
00757
00758
00759 int cdf_l[256], cdf_r[256], cdf_g[256], cdf_b[256];
00760 cdf_l[0] = Hl.BinCount(0); cdf_r[0] = Hr.BinCount(0); cdf_g[0] = Hg.BinCount(0); cdf_b[0] = Hb.BinCount(0);
00761 for(int i=1; i<256; i++){
00762 cdf_l[i] = Hl.BinCount(float(i)) + cdf_l[i-1];
00763 cdf_r[i] = Hr.BinCount(float(i)) + cdf_r[i-1];
00764 cdf_g[i] = Hg.BinCount(float(i)) + cdf_g[i-1];
00765 cdf_b[i] = Hb.BinCount(float(i)) + cdf_b[i-1];
00766 }
00767
00768
00769 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00770 {
00771 if(!(*vi).IsD())
00772 {
00773 if(!ProcessSelected || (*vi).IsS())
00774 {
00775 (*vi).C()=ColorEqualize((*vi).C(), cdf_l, cdf_r, cdf_g, cdf_b, rgbMask);
00776 ++counter;
00777 }
00778 }
00779 }
00780 return counter;
00781 }
00782
00783
00784 static Color4b ColorEqualize(Color4b c, int cdf_l[256], int cdf_r[256], int cdf_g[256], int cdf_b[256], unsigned int rgbMask)
00785 {
00786 unsigned char r = c[0], g = c[1], b = c[2];
00787 if(rgbMask == NO_CHANNELS)
00788 {
00789 int v = ValueEqualize(cdf_l[(int)(ComputeLightness(c)+0.5f)], cdf_l[0], cdf_l[255]);
00790 return Color4b(v, v, v, 255);
00791 }
00792 if(rgbMask & RED_CHANNEL) r = ValueEqualize(cdf_r[c[0]], cdf_r[0], cdf_r[255]);
00793 if(rgbMask & GREEN_CHANNEL) g = ValueEqualize(cdf_g[c[1]], cdf_g[0], cdf_g[255]);
00794 if(rgbMask & BLUE_CHANNEL) b = ValueEqualize(cdf_b[c[2]], cdf_b[0], cdf_b[255]);
00795 return Color4b(r, g, b, 255);
00796 }
00797
00798
00799 static int ValueEqualize(int cdfValue, int cdfMin, int cdfMax)
00800 {
00801 return int(float((cdfValue - cdfMin)/float(cdfMax - cdfMin)) * 255.0f);
00802 }
00803
00804
00805
00806 static int WhiteBalance(UpdateMeshType &m, bool automatic, Color4b userColor, const bool ProcessSelected=false)
00807 {
00808 Color4b unbalancedWhite;
00809 float lightness = 0;
00810 int counter=0;
00811 VertexIterator vi;
00812
00813 if(!automatic) unbalancedWhite = userColor;
00814 else
00815 {
00816 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00817 {
00818 if(!(*vi).IsD())
00819 {
00820 if(!ProcessSelected || (*vi).IsS())
00821 {
00822
00823 float v = ComputeLightness((*vi).C());
00824 if( v > lightness){
00825 lightness = v;
00826 unbalancedWhite = (*vi).C();
00827 }
00828 }
00829 }
00830 }
00831 }
00832
00833
00834 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00835 {
00836 if(!(*vi).IsD())
00837 {
00838 if(!ProcessSelected || (*vi).IsS())
00839 {
00840 (*vi).C()=ColorWhiteBalance((*vi).C(),unbalancedWhite);
00841 ++counter;
00842 }
00843 }
00844 }
00845 return counter;
00846 }
00847
00848
00849 static Color4b ColorWhiteBalance(Color4b c, Color4b unbalancedWhite)
00850 {
00851
00852 if(unbalancedWhite[0]==0) unbalancedWhite[0]=1;
00853 if(unbalancedWhite[1]==0) unbalancedWhite[1]=1;
00854 if(unbalancedWhite[2]==0) unbalancedWhite[2]=1;
00855
00856 return Color4b(
00857 math::Clamp<int>((int)(c[0]*(255.0f/unbalancedWhite[0])), 0, 255),
00858 math::Clamp<int>((int)(c[1]*(255.0f/unbalancedWhite[1])), 0, 255),
00859 math::Clamp<int>((int)(c[2]*(255.0f/unbalancedWhite[2])), 0, 255),
00860 255);
00861 }
00862
00863 static void PerlinColor(MeshType& m, Box3f bbox, float freq, Point3i channelOffsets)
00864 {
00865 typedef typename MeshType::ScalarType ScalarType;
00866
00867 Point3<ScalarType> p;
00868 for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
00869 {
00870 if(!(*vi).IsD()){
00871 p = bbox.GlobalToLocal(m.Tr * (*vi).P());
00872 (*vi).C() = Color4b( int(255*math::Perlin::Noise(channelOffsets[0]+p[0]*freq,channelOffsets[0]+p[1]*freq,channelOffsets[0]+p[2]*freq)),
00873 int(255*math::Perlin::Noise(channelOffsets[1]+p[0]*freq,channelOffsets[1]+p[1]*freq,channelOffsets[1]+p[2]*freq)),
00874 int(255*math::Perlin::Noise(channelOffsets[2]+p[0]*freq,channelOffsets[2]+p[1]*freq,channelOffsets[2]+p[2]*freq)),
00875 255 );
00876 }
00877 }
00878 }
00879
00880 static void ColorNoise(MeshType& m, int noiseBits)
00881 {
00882 if(noiseBits>8) noiseBits = 8;
00883 if(noiseBits<1) return;
00884
00885 math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(time(NULL));
00886 for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
00887 {
00888 if(!(*vi).IsD()){
00889 (*vi).C()[0] = math::Clamp<int>((*vi).C()[0] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
00890 (*vi).C()[1] = math::Clamp<int>((*vi).C()[1] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
00891 (*vi).C()[2] = math::Clamp<int>((*vi).C()[2] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
00892 }
00893 }
00894 }
00895
00896 };
00897
00898 }
00899 }
00900 #endif