00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "film.h"
00025 #include "randomgen.h"
00026 #include "dynload.h"
00027 #include "paramset.h"
00028 #include "tonemap.h"
00029 #include "stats.h"
00030
00031 #define cimg_display_type 0
00032
00033 #ifdef LUX_USE_CONFIG_H
00034 #include "config.h"
00035
00036 #ifdef PNG_FOUND
00037 #define cimg_use_png 1
00038 #endif
00039
00040 #ifdef JPEG_FOUND
00041 #define cimg_use_jpeg 1
00042 #endif
00043
00044 #ifdef TIFF_FOUND
00045 #define cimg_use_tiff 1
00046 #endif
00047
00048
00049 #else //LUX_USE_CONFIG_H
00050 #define cimg_use_png 1
00051 #define cimg_use_tiff 1
00052 #define cimg_use_jpeg 1
00053 #endif //LUX_USE_CONFIG_H
00054
00055 #define cimg_debug 0 // Disable modal window in CImg exceptions.
00056
00057 #define cimg_plugin "greycstoration.h"
00058
00059 #include "cimg.h"
00060 using namespace cimg_library;
00061 #if cimg_OS!=2
00062 #include <pthread.h>
00063 #endif
00064
00065
00066 namespace lux
00067 {
00068
00069 template<class T> T bilinearSampleImage(const vector<T> &pixels,
00070 const int xResolution, const int yResolution,
00071 const float x, const float y)
00072 {
00073 int x1 = Clamp<int>(Floor2Int(x), 0, xResolution-1);
00074 int y1 = Clamp<int>(Floor2Int(y), 0, yResolution-1);
00075 int x2 = Clamp<int>(x1+1, 0, xResolution-1);
00076 int y2 = Clamp<int>(y1+1, 0, yResolution-1);
00077 float tx = Clamp<float>(x - x1, 0, 1);
00078 float ty = Clamp<float>(y - y1, 0, 1);
00079
00080 T c(0.f);
00081 c.AddWeighted((1.f-tx) * (1.f-ty), pixels[y1*xResolution+x1]);
00082 c.AddWeighted(tx * (1.f-ty), pixels[y1*xResolution+x2]);
00083 c.AddWeighted((1.f-tx) * ty, pixels[y2*xResolution+x1]);
00084 c.AddWeighted(tx * ty, pixels[y2*xResolution+x2]);
00085 return c;
00086 }
00087
00088
00089 void horizontalGaussianBlur(const vector<XYZColor> &in, vector<XYZColor> &out,
00090 const int xResolution, const int yResolution, float std_dev)
00091 {
00092 int rad_needed = Ceil2Int(std_dev * 4);
00093
00094 const int lookup_size = rad_needed + 1;
00095
00096 std::vector<float> filter_weights(lookup_size);
00097 for(int x = 0; x < lookup_size; ++x)
00098 filter_weights[x] = expf(- x*x / (std_dev*std_dev));
00099
00100
00101 float sweight = 0.0f;
00102 for(int i = -rad_needed; i <= rad_needed; ++i)
00103 sweight += filter_weights[abs(i)];
00104
00105 sweight = 1.f / sweight;
00106
00107 for(int x = 0; x < lookup_size; ++x) {
00108 filter_weights[x] *= sweight;
00109 if (filter_weights[x] < 1.0e-12f)
00110 rad_needed--;
00111 }
00112
00113 const int pixel_rad = rad_needed;
00114
00115
00116
00117
00118 for(int y = 0; y < yResolution; ++y) {
00119 for(int x = 0; x < xResolution; ++x) {
00120 const int a = y*xResolution + x;
00121
00122 out[a] = XYZColor(0.f);
00123
00124 for(int i = -pixel_rad; i <= pixel_rad; ++i) {
00125 int dx = Clamp(x+i, 0, xResolution-1) - x;
00126 out[a].AddWeighted(filter_weights[abs(i)], in[a+dx]);
00127 }
00128 }
00129 }
00130 }
00131
00132 void rotateImage(const vector<XYZColor> &in, vector<XYZColor> &out,
00133 const int xResolution, const int yResolution, float angle)
00134 {
00135 const int maxRes = max(xResolution, yResolution);
00136
00137 const float s = sinf(-angle);
00138 const float c = cosf(-angle);
00139
00140 const float cx = xResolution * 0.5f;
00141 const float cy = yResolution * 0.5f;
00142
00143 for(int y = 0; y < maxRes; ++y) {
00144 float px = 0 - maxRes * 0.5f;
00145 float py = y - maxRes * 0.5f;
00146
00147 float rx = px * c - py * s + cx;
00148 float ry = px * s + py * c + cy;
00149 for(int x = 0; x < maxRes; ++x) {
00150 out[y*maxRes + x] = bilinearSampleImage<XYZColor>(in, xResolution, yResolution, rx, ry);
00151
00152 rx += c;
00153 ry += s;
00154 }
00155 }
00156 }
00157
00158
00159
00160 void ApplyImagingPipeline(vector<XYZColor> &xyzpixels,
00161 int xResolution, int yResolution,
00162 const GREYCStorationParams &GREYCParams, const ChiuParams &chiuParams,
00163 ColorSystem &colorSpace, Histogram *histogram, bool HistogramEnabled,
00164 bool &haveBloomImage, XYZColor *&bloomImage, bool bloomUpdate,
00165 float bloomRadius, float bloomWeight,
00166 bool VignettingEnabled, float VignetScale,
00167 bool aberrationEnabled, float aberrationAmount,
00168 bool &haveGlareImage, XYZColor *&glareImage, bool glareUpdate,
00169 float glareAmount, float glareRadius, int glareBlades,
00170 const char *toneMapName, const ParamSet *toneMapParams,
00171 float gamma, float dither)
00172 {
00173 const int nPix = xResolution * yResolution;
00174
00175
00176 for (int i = 0; i < nPix; ++i)
00177 xyzpixels[i] = xyzpixels[i].Clamp();
00178
00179
00180
00181 if (bloomRadius > 0.f && bloomWeight > 0.f) {
00182 if(bloomUpdate) {
00183
00184 const int bloomSupport = Float2Int(bloomRadius *
00185 max(xResolution, yResolution));
00186 const int bloomWidth = bloomSupport / 2;
00187
00188 vector<float> bloomFilter(bloomWidth * bloomWidth);
00189 for (int i = 0; i < bloomWidth * bloomWidth; ++i) {
00190 float dist = sqrtf(i) / bloomWidth;
00191 bloomFilter[i] = powf(max(0.f, 1.f - dist), 4.f);
00192 }
00193
00194
00195 if(!haveBloomImage) {
00196 bloomImage = new XYZColor[nPix];
00197 haveBloomImage = true;
00198 }
00199
00200
00201
00202 ProgressReporter prog(yResolution, "Bloom filter");
00203 for (int y = 0; y < yResolution; ++y) {
00204 for (int x = 0; x < xResolution; ++x) {
00205
00206
00207 int x0 = max(0, x - bloomWidth);
00208 int x1 = min(x + bloomWidth, xResolution - 1);
00209 int y0 = max(0, y - bloomWidth);
00210 int y1 = min(y + bloomWidth, yResolution - 1);
00211 int offset = y * xResolution + x;
00212 float sumWt = 0.;
00213 for (int by = y0; by <= y1; ++by) {
00214 for (int bx = x0; bx <= x1; ++bx) {
00215
00216 int dx = x - bx, dy = y - by;
00217 if (dx == 0 && dy == 0)
00218 continue;
00219 int dist2 = dx*dx + dy*dy;
00220 if (dist2 < bloomWidth * bloomWidth) {
00221 int bloomOffset = bx + by * xResolution;
00222 float wt = bloomFilter[dist2];
00223 sumWt += wt;
00224 bloomImage[offset].AddWeighted(wt, xyzpixels[bloomOffset]);
00225 }
00226 }
00227 }
00228 bloomImage[offset] /= sumWt;
00229 }
00230 prog.Update();
00231 }
00232 prog.Done();
00233 }
00234
00235
00236 if(haveBloomImage && bloomImage != NULL)
00237 for (int i = 0; i < nPix; ++i)
00238 xyzpixels[i] = Lerp(bloomWeight, xyzpixels[i], bloomImage[i]);
00239 }
00240
00241 if (glareRadius > 0 && glareAmount > 0) {
00242 if (glareUpdate) {
00243
00244 if(!haveGlareImage) {
00245 glareImage = new XYZColor[nPix];
00246 haveGlareImage = true;
00247 }
00248
00249 int maxRes = max(xResolution, yResolution);
00250 int nPix2 = maxRes*maxRes;
00251
00252 std::vector<XYZColor> rotatedImage(nPix2);
00253 std::vector<XYZColor> blurredImage(nPix2);
00254 for(int i = 0; i < nPix; i++)
00255 glareImage[i] = XYZColor(0.f);
00256
00257 const float radius = maxRes * glareRadius;
00258
00259
00260 for (int i = 0; i < glareBlades; i++) {
00261 float angle = (float)i * 2*M_PI / glareBlades;
00262 rotateImage(xyzpixels, rotatedImage, xResolution, yResolution, angle);
00263 horizontalGaussianBlur(rotatedImage, blurredImage, maxRes, maxRes, radius);
00264 rotateImage(blurredImage, rotatedImage, maxRes, maxRes, -angle);
00265
00266
00267 for(int y=0; y<yResolution; ++y) {
00268 for(int x=0; x<xResolution; ++x) {
00269 int sx = (int)(x + (maxRes - xResolution) * 0.5f);
00270 int sy = (int)(y + (maxRes - yResolution) * 0.5f);
00271
00272 glareImage[y*xResolution+x] += rotatedImage[sy*maxRes + sx];
00273 }
00274 }
00275 }
00276
00277
00278 const float nfactor = 1.f / glareBlades;
00279
00280 for(int i = 0; i < nPix; i++)
00281 glareImage[i] *= nfactor;
00282
00283 rotatedImage.clear();
00284 blurredImage.clear();
00285 }
00286
00287 if (haveGlareImage && glareImage != NULL) {
00288 for(int i = 0; i < nPix; i++)
00289 xyzpixels[i] = Lerp(glareAmount, xyzpixels[i], glareImage[i]);
00290 }
00291 }
00292
00293
00294 if (toneMapName) {
00295 ToneMap *toneMap = MakeToneMap(toneMapName,
00296 toneMapParams ? *toneMapParams : ParamSet());
00297 if (toneMap)
00298 toneMap->Map(xyzpixels, xResolution, yResolution, 100.f);
00299 delete toneMap;
00300 }
00301
00302 vector<RGBColor> &rgbpixels = reinterpret_cast<vector<RGBColor> &>(xyzpixels);
00303 const float invGamma = 1.f / gamma;
00304 for (int i = 0; i < nPix; ++i) {
00305 rgbpixels[i] = colorSpace.ToRGBConstrained(xyzpixels[i]);
00306
00307 rgbpixels[i] = rgbpixels[i].Pow(invGamma);
00308 }
00309
00310
00311
00312
00313
00314 if ((VignettingEnabled && VignetScale != 0.0f) ||
00315 (aberrationEnabled && aberrationAmount > 0.f)) {
00316
00317 RGBColor *outp = &rgbpixels[0];
00318 std::vector<RGBColor> aberrationImage;
00319 if (aberrationEnabled) {
00320 aberrationImage.resize(nPix, RGBColor(0.f));
00321 outp = &aberrationImage[0];
00322 }
00323
00324 const float invxRes = 1.f / xResolution;
00325 const float invyRes = 1.f / yResolution;
00326
00327 for(int y=0; y<yResolution; ++y) {
00328 for(int x=0; x<xResolution; ++x) {
00329 const float nPx = (float)x * invxRes;
00330 const float nPy = (float)y * invyRes;
00331 const float xOffset = nPx - 0.5f;
00332 const float yOffset = nPy - 0.5f;
00333 float tOffset = sqrtf(xOffset*xOffset + yOffset*yOffset);
00334
00335 if (aberrationEnabled && aberrationAmount > 0.f) {
00336 const float rb_x = (0.5f + xOffset * (1.f + tOffset*aberrationAmount)) * xResolution;
00337 const float rb_y = (0.5f + yOffset * (1.f + tOffset*aberrationAmount)) * yResolution;
00338 const float g_x = (0.5f + xOffset * (1.f - tOffset*aberrationAmount)) * xResolution;
00339 const float g_y = (0.5f + yOffset * (1.f - tOffset*aberrationAmount)) * yResolution;
00340
00341 const float redblue[] = {1.f, 0.f, 1.f};
00342 const float green[] = {0.f, 1.f, 0.f};
00343
00344 outp[xResolution*y + x] += RGBColor(redblue) * bilinearSampleImage<RGBColor>(rgbpixels, xResolution, yResolution, rb_x, rb_y);
00345 outp[xResolution*y + x] += RGBColor(green) * bilinearSampleImage<RGBColor>(rgbpixels, xResolution, yResolution, g_x, g_y);
00346 }
00347
00348
00349 if(VignettingEnabled && VignetScale != 0.0f) {
00350
00351 const float invNtOffset = 1.f - (fabsf(tOffset) * 1.42);
00352 float vWeight = Lerp(invNtOffset, 1.f - VignetScale, 1.f);
00353 for(int i=0;i<3;i++)
00354 outp[xResolution*y + x].c[i] *= vWeight;
00355 }
00356 }
00357 }
00358
00359 if (aberrationEnabled) {
00360 for(int i = 0; i < nPix; i++)
00361 rgbpixels[i] = aberrationImage[i];
00362 }
00363
00364 aberrationImage.clear();
00365 }
00366
00367
00368 if (HistogramEnabled) {
00369 if (!histogram)
00370 histogram = new Histogram();
00371 histogram->Calculate(rgbpixels, xResolution, yResolution);
00372 }
00373
00374
00375 if(chiuParams.enabled) {
00376 std::vector<RGBColor> chiuImage(nPix, RGBColor(0.f));
00377
00378
00379
00380 const float radius = max(chiuParams.radius, 1+(chiuParams.includecenter ? 0 : 1e-6));
00381
00382 const int pixel_rad = Ceil2Int(radius);
00383 const int lookup_size = pixel_rad + pixel_rad + 1;
00384
00385
00386 std::vector<float> weights(lookup_size * lookup_size);
00387
00388 for(int y=0; y<lookup_size; ++y) {
00389 for(int x=0; x<lookup_size; ++x) {
00390 if(x == pixel_rad && y == pixel_rad)
00391 weights[lookup_size*y + x] = chiuParams.includecenter ? 1.0f : 0.0f;
00392 else {
00393 const float dx = (float)(x - pixel_rad);
00394 const float dy = (float)(y - pixel_rad);
00395 const float dist = sqrt(dx*dx + dy*dy);
00396 const float weight = powf(max(0.0f, 1.0f - dist / radius), 4.0f);
00397 weights[lookup_size*y + x] = weight;
00398 }
00399 }
00400 }
00401
00402 float sumweight = 0.0f;
00403 for(int y=0; y<lookup_size; ++y)
00404 for(int x=0; x<lookup_size; ++x)
00405 sumweight += weights[lookup_size*y + x];
00406
00407
00408 for(int y=0; y<lookup_size; ++y)
00409 for(int x=0; x<lookup_size; ++x)
00410 weights[lookup_size*y + x] /= sumweight;
00411
00412
00413 for(int y=0; y<yResolution; ++y) {
00414
00415 const int miny = max(0, y - pixel_rad);
00416 const int maxy = min(yResolution, y + pixel_rad + 1);
00417
00418 for(int x=0; x<xResolution; ++x) {
00419
00420 const int minx = max(0, x - pixel_rad);
00421 const int maxx = min(xResolution, x + pixel_rad + 1);
00422
00423
00424 for(int ty=miny; ty<maxy; ++ty) {
00425 for(int tx=minx; tx<maxx; ++tx) {
00426 const int dx=x-tx+pixel_rad;
00427 const int dy=y-ty+pixel_rad;
00428 const float factor = weights[lookup_size*dy + dx];
00429 chiuImage[xResolution*ty + tx].AddWeighted(factor, rgbpixels[xResolution*y + x]);
00430 }
00431 }
00432 }
00433 }
00434
00435 for(int i=0; i<nPix; i++)
00436 rgbpixels[i] = chiuImage[i];
00437
00438
00439 chiuImage.clear();
00440 weights.clear();
00441 }
00442
00443
00444 if(GREYCParams.enabled) {
00445
00446 CImg<float> img(xResolution, yResolution, 1, 3);
00447 for(int y=0; y<yResolution; y++) {
00448 for(int x=0; x<xResolution; x++) {
00449 int index = xResolution * y + x;
00450
00451 for(int j=0; j<3; j++)
00452 img(x, y, 0, j) = rgbpixels[index].c[j] * 255;
00453 }
00454 }
00455
00456 for (unsigned int iter=0; iter<GREYCParams.nb_iter; iter++) {
00457 img.blur_anisotropic(GREYCParams.amplitude,
00458 GREYCParams.sharpness,
00459 GREYCParams.anisotropy,
00460 GREYCParams.alpha,
00461 GREYCParams.sigma,
00462 GREYCParams.dl,
00463 GREYCParams.da,
00464 GREYCParams.gauss_prec,
00465 GREYCParams.interp,
00466 GREYCParams.fast_approx,
00467 1.0f);
00468 }
00469
00470
00471 const float inv_byte = 1.f/255;
00472 for(int y=0; y<yResolution; y++) {
00473 for(int x=0; x<xResolution; x++) {
00474 int index = xResolution * y + x;
00475 for(int j=0; j<3; j++)
00476 rgbpixels[index].c[j] = img(x, y, 0, j) * inv_byte;
00477 }
00478 }
00479 }
00480
00481
00482 if (dither > 0.f)
00483 for (int i = 0; i < nPix; ++i)
00484 rgbpixels[i] += 2.f * dither * (lux::random::floatValueP() - .5f);
00485 }
00486
00487
00488
00489 void Film::getHistogramImage(unsigned char *outPixels, int width, int height, int options){
00490 if (!histogram)
00491 histogram = new Histogram();
00492 histogram->MakeImage(outPixels, width, height, options);
00493 }
00494
00495
00496
00497 Histogram::Histogram(){
00498 m_buckets = NULL;
00499 m_displayGamma = 2.2;
00500
00501
00502 float narrowRangeSize = -log(pow(1.f/2,10*1.f/m_displayGamma));
00503 float scalingFactor = 0.75;
00504 m_lowRange = -(1+scalingFactor)*narrowRangeSize;
00505 m_highRange = scalingFactor*narrowRangeSize;
00506
00507 m_bucketNr = 0;
00508 m_newBucketNr = 300;
00509 CheckBucketNr();
00510 for(int i=0;i<m_bucketNr*4;i++) m_buckets[i]=0;
00511 }
00512
00513 Histogram::~Histogram(){
00514 if(m_buckets != NULL) delete[] m_buckets;
00515 }
00516
00517 void Histogram::CheckBucketNr(){
00518 if(m_newBucketNr>0){
00519 m_bucketNr=m_newBucketNr;
00520 m_newBucketNr=-1;
00521 if(m_buckets != NULL) delete[] m_buckets;
00522 m_buckets = new float[m_bucketNr*4];
00523
00524
00525 m_bucketSize = (m_highRange-m_lowRange)/m_bucketNr;
00526
00527
00528 int bucket, i;
00529 float value, zoneValue = 1.0;
00530 for (i=0;i<11;i++){
00531 value = log(pow(zoneValue,1.f/m_displayGamma));
00532 bucket = (value-m_lowRange)/m_bucketSize;
00533 bucket = Clamp(bucket,0,m_bucketNr-1);
00534 m_zones[i] = bucket;
00535 zoneValue = zoneValue/2;
00536 }
00537 }
00538 }
00539
00540 void Histogram::Calculate(vector<RGBColor> &pixels, unsigned int width, unsigned int height){
00541 if(pixels.empty() || width==0 || height==0) return;
00542 unsigned int i, j;
00543 unsigned int pixelNr=width*height;
00544 float value;
00545 boost::mutex::scoped_lock lock(m_mutex);
00546
00547 CheckBucketNr();
00548
00549
00550 for(i=0;i<(u_int)m_bucketNr*4;i++) m_buckets[i]=0;
00551
00552
00553 int bucket;
00554 for(i=0;i<pixelNr;i++){
00555 for(j=0;j<3;j++){
00556 value = pixels[i].c[j];
00557 if(value>0){
00558 value = log(value);
00559 bucket = (value-m_lowRange)/m_bucketSize;
00560 bucket = Clamp(bucket,0,m_bucketNr-1);
00561 m_buckets[bucket*4+j] += 1;
00562 }
00563 }
00564 value = ( pixels[i].c[0] + pixels[i].c[1] + pixels[i].c[2] )/3;
00565 if(value>0){
00566 value = log(value);
00567 bucket = (value-m_lowRange)/m_bucketSize;
00568 bucket = Clamp(bucket,0,m_bucketNr-1);
00569 m_buckets[bucket*4+3] += 1;
00570 }
00571 }
00572
00573 }
00574
00575 void Histogram::MakeImage(unsigned char *outPixels, unsigned int canvasW, unsigned int canvasH, int options){
00576 #define PIXELIDX(x,y,w) ((y)*(w)*3+(x)*3)
00577 #define GETMAX(x,y) ((x)>(y)?(x):(y))
00578 unsigned int i,x,y,idx;
00579 int bucket;
00580 unsigned char color;
00581 unsigned int borderW = 3;
00582 unsigned int guideW = 3;
00583 unsigned int plotH = canvasH-borderW-(guideW+2)-(borderW-1);
00584 unsigned int plotW = canvasW-2*borderW;
00585 if(canvasW<50 || canvasH<25) return;
00586 boost::mutex::scoped_lock lock(m_mutex);
00587 if(canvasW-2*borderW!=(u_int)m_bucketNr) m_newBucketNr=canvasW-2*borderW;
00588
00589
00590 color=64;
00591 for(x=0;x<plotW;x++)
00592 for(y=0;y<plotH;y++){
00593 idx=PIXELIDX(x+borderW,y+borderW,canvasW);
00594 outPixels[idx]=color;
00595 outPixels[idx+1]=color;
00596 outPixels[idx+2]=color;
00597 }
00598
00599
00600 float *buckets;
00601 if(options&LUX_HISTOGRAM_LOG){
00602 buckets = new float[m_bucketNr*4];
00603 for(i=0;i<(u_int)m_bucketNr*4;i++){
00604 buckets[i]=log(1.f+m_buckets[i]);
00605 }
00606 }else{
00607 buckets=m_buckets;
00608 }
00609
00610
00611 int barHeight, channel=0;
00612 float scale, max, maxExtrL, maxExtrR;
00613 switch( options & ( LUX_HISTOGRAM_RGB | LUX_HISTOGRAM_RED | LUX_HISTOGRAM_GREEN | LUX_HISTOGRAM_BLUE | LUX_HISTOGRAM_VALUE | LUX_HISTOGRAM_RGB_ADD ) ){
00614 case LUX_HISTOGRAM_RGB: {
00615
00616 for(i=1*4,max=0;i<(u_int)(m_bucketNr-1)*4;i++)
00617 if(i%4!=3 && buckets[i]>max) max=buckets[i];
00618 i=0;
00619 maxExtrL = GETMAX(buckets[i*4],GETMAX(buckets[i*4+1],buckets[i*4+2]));
00620 i=m_bucketNr-1;
00621 maxExtrR = GETMAX(buckets[i*4],GETMAX(buckets[i*4+1],buckets[i*4+2]));
00622 if(max>0 || maxExtrL>0 || maxExtrR>0){
00623
00624 for(x=0;x<plotW;x++){
00625 bucket=Clamp((int)(x*m_bucketNr/(plotW-1)), 0, m_bucketNr-1);
00626 if(bucket==0 && maxExtrL>max) scale = (float)plotH/maxExtrL;
00627 else if(bucket==m_bucketNr-1 && maxExtrR>max) scale = (float)plotH/maxExtrR;
00628 else scale = (float)plotH/max;
00629 for(channel=0;channel<3;channel++){
00630 barHeight=plotH-(u_int)(buckets[bucket*4+channel]*scale+0.5);
00631 barHeight=Clamp(barHeight,0,(int)plotH);
00632 for(y=barHeight;y<plotH;y++)
00633 outPixels[PIXELIDX(x+borderW,y+borderW,canvasW)+channel]=255;
00634 }
00635 }
00636 }
00637 } break;
00638 case LUX_HISTOGRAM_VALUE: channel++;
00639 case LUX_HISTOGRAM_BLUE: channel++;
00640 case LUX_HISTOGRAM_GREEN: channel++;
00641 case LUX_HISTOGRAM_RED: {
00642
00643 for(i=1,max=0;i<(u_int)m_bucketNr-1;i++)
00644 if(buckets[i*4+channel]>max) max=buckets[i*4+channel];
00645 i=0;
00646 maxExtrL = buckets[i*4+channel];
00647 i=m_bucketNr-1;
00648 maxExtrR = buckets[i*4+channel];
00649 if(max>0 || maxExtrL>0 || maxExtrR>0){
00650
00651 for(x=0;x<plotW;x++){
00652 bucket=Clamp((int)(x*m_bucketNr/(plotW-1)), 0, m_bucketNr-1);
00653 if(bucket==0 && maxExtrL>max) scale = (float)plotH/maxExtrL;
00654 else if(bucket==m_bucketNr-1 && maxExtrR>max) scale = (float)plotH/maxExtrR;
00655 else scale = (float)plotH/max;
00656 barHeight=plotH-(u_int)(buckets[bucket*4+channel]*scale+0.5);
00657 barHeight=Clamp(barHeight,0,(int)plotH);
00658 for(y=barHeight;y<plotH;y++){
00659 idx=PIXELIDX(x+borderW,y+borderW,canvasW);
00660 outPixels[idx]=255;
00661 outPixels[idx+1]=255;
00662 outPixels[idx+2]=255;
00663 }
00664 }
00665 }
00666 } break;
00667 case LUX_HISTOGRAM_RGB_ADD: {
00668
00669 for(i=1,max=0; i<(u_int)m_bucketNr-1; i++)
00670 if( buckets[i*4]+buckets[i*4+1]+buckets[i*4+2] > max ) max=buckets[i*4]+buckets[i*4+1]+buckets[i*4+2];
00671 i=0;
00672 maxExtrL = buckets[i*4]+buckets[i*4+1]+buckets[i*4+2];
00673 i=m_bucketNr-1;
00674 maxExtrR = buckets[i*4]+buckets[i*4+1]+buckets[i*4+2];
00675 if(max>0 || maxExtrL>0 || maxExtrR>0){
00676
00677 for(x=0;x<plotW;x++){
00678 bucket=Clamp((int)(x*m_bucketNr/(plotW-1)), 0, m_bucketNr-1);
00679 if(bucket==0 && maxExtrL>max) scale = (float)plotH/maxExtrL;
00680 else if(bucket==m_bucketNr-1 && maxExtrR>max) scale = (float)plotH/maxExtrR;
00681 else scale = (float)plotH/max;
00682 barHeight=plotH-(u_int)(buckets[bucket*4]*scale+0.5)-(u_int)(buckets[bucket*4+1]*scale+0.5)-(u_int)(buckets[bucket*4+2]*scale+0.5);
00683 barHeight=Clamp(barHeight,0,(int)plotH);
00684 int newHeight;
00685 for(channel=0;channel<3;channel++){
00686 newHeight=barHeight+(u_int)(buckets[bucket*4+channel]*scale+0.5);
00687 for(y=barHeight;y<(u_int)newHeight;y++)
00688 outPixels[PIXELIDX(x+borderW,y+borderW,canvasW)+channel]=255;
00689 barHeight=newHeight;
00690 }
00691 }
00692 }
00693 } break;
00694 default: break;
00695 }
00696
00697 if(buckets!=m_buckets) delete [] buckets;
00698
00699
00700 for(x=0;x<plotW;x++){
00701 bucket=Clamp((int)(x*m_bucketNr/(plotW-1)), 0, m_bucketNr-1);
00702 for(y=plotH+2;y<plotH+2+guideW;y++){
00703 idx=PIXELIDX(x+borderW,y+borderW,canvasW);
00704 color=Clamp( expf((bucket*m_bucketSize+m_lowRange))*256.f, 0.f, 255.f );
00705 if(options&LUX_HISTOGRAM_RED){
00706 outPixels[idx]=color;
00707 outPixels[idx+1]=0;
00708 outPixels[idx+2]=0;
00709 }else if(options&LUX_HISTOGRAM_GREEN){
00710 outPixels[idx]=0;
00711 outPixels[idx+1]=color;
00712 outPixels[idx+2]=0;
00713 }else if(options&LUX_HISTOGRAM_BLUE){
00714 outPixels[idx]=0;
00715 outPixels[idx+1]=0;
00716 outPixels[idx+2]=color;
00717 }else{
00718 outPixels[idx]=color;
00719 outPixels[idx+1]=color;
00720 outPixels[idx+2]=color;
00721 }
00722 }
00723 }
00724
00725
00726 for(i=0;i<11;i++){
00727 switch(i){
00728 case 0: color=128; break;
00729 case 10: color=128; break;
00730 default: color=0; break;
00731 }
00732 bucket=m_zones[i];
00733 x=Clamp((int)(bucket*plotW/(m_bucketNr-1)), 0, (int)plotW-1);
00734 for(y=plotH+2;y<plotH+2+guideW;y++){
00735 idx=PIXELIDX(x+borderW,y+borderW,canvasW);
00736 outPixels[idx]=color;
00737 outPixels[idx+1]=color;
00738 outPixels[idx+2]=color;
00739 }
00740 }
00741
00742
00743 for(i=0;i<2;i++){
00744 switch(i){
00745 case 0: bucket=m_zones[0]; break;
00746 case 1: bucket=m_zones[10]; break;
00747 }
00748 x=Clamp((int)(bucket*plotW/(m_bucketNr-1)), 0, (int)plotW-1);
00749 for(y=0;y<plotH;y++){
00750 idx=PIXELIDX(x+borderW,y+borderW,canvasW);
00751 if(outPixels[idx]==255 && outPixels[idx+1]==255 && outPixels[idx+2]==255){
00752 outPixels[idx]=128;
00753 outPixels[idx+1]=128;
00754 outPixels[idx+2]=128;
00755 }else{
00756 if(outPixels[idx]==64) outPixels[idx]=128;
00757 if(outPixels[idx+1]==64) outPixels[idx+1]=128;
00758 if(outPixels[idx+2]==64) outPixels[idx+2]=128;
00759 }
00760 }
00761 }
00762
00763 }
00764
00765
00766 }
00767