Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/tmoColorConvert.cpp view on Meta::CPAN
float max_lum = -1e20F, min_lum = 1e20F;
double sumLum = 0, sumLogLum = 0;
BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
for(unsigned y = 0; y < height; y++) {
const float *pixel = (float*)bits;
for(unsigned x = 0; x < width; x++) {
const float Y = pixel[x];
max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene
min_lum = ((Y > 0) && (min_lum < Y)) ? min_lum : Y; // min Luminance in the scene
sumLum += Y; // average luminance
sumLogLum += log(2.3e-5F + Y); // contrast constant in Tumblin paper
}
// next line
bits += pitch;
}
// maximum luminance
*maxLum = max_lum;
// minimum luminance
*minLum = min_lum;
// average luminance
*Lav = (float)(sumLum / (width * height));
// average log luminance, a.k.a. world adaptation luminance
*Llav = (float)exp(sumLogLum / (width * height));
return TRUE;
}
// --------------------------------------------------------------------------
static void findMaxMinPercentile(FIBITMAP *Y, float minPrct, float *minLum, float maxPrct, float *maxLum) {
int x, y;
int width = FreeImage_GetWidth(Y);
int height = FreeImage_GetHeight(Y);
int pitch = FreeImage_GetPitch(Y);
std::vector<float> vY(width * height);
BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
for(y = 0; y < height; y++) {
float *pixel = (float*)bits;
for(x = 0; x < width; x++) {
if(pixel[x] != 0) {
vY.push_back(pixel[x]);
}
}
bits += pitch;
}
std::sort(vY.begin(), vY.end());
*minLum = vY.at( int(minPrct * vY.size()) );
*maxLum = vY.at( int(maxPrct * vY.size()) );
}
/**
Clipping function<br>
Remove any extremely bright and/or extremely dark pixels
and normalize between 0 and 1.
@param Y Input/Output image
@param minPrct Minimum percentile
@param maxPrct Maximum percentile
*/
void
NormalizeY(FIBITMAP *Y, float minPrct, float maxPrct) {
int x, y;
float maxLum, minLum;
if(minPrct > maxPrct) {
// swap values
float t = minPrct; minPrct = maxPrct; maxPrct = t;
}
if(minPrct < 0) minPrct = 0;
if(maxPrct > 1) maxPrct = 1;
int width = FreeImage_GetWidth(Y);
int height = FreeImage_GetHeight(Y);
int pitch = FreeImage_GetPitch(Y);
// find max & min luminance values
if((minPrct > 0) || (maxPrct < 1)) {
maxLum = 0, minLum = 0;
findMaxMinPercentile(Y, minPrct, &minLum, maxPrct, &maxLum);
} else {
maxLum = -1e20F, minLum = 1e20F;
BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
for(y = 0; y < height; y++) {
const float *pixel = (float*)bits;
for(x = 0; x < width; x++) {
const float value = pixel[x];
maxLum = (maxLum < value) ? value : maxLum; // max Luminance in the scene
minLum = (minLum < value) ? minLum : value; // min Luminance in the scene
}
// next line
bits += pitch;
}
}
if(maxLum == minLum) return;
// normalize to range 0..1
const float divider = maxLum - minLum;
BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
for(y = 0; y < height; y++) {
float *pixel = (float*)bits;
for(x = 0; x < width; x++) {
pixel[x] = (pixel[x] - minLum) / divider;
if(pixel[x] <= 0) pixel[x] = EPSILON;
if(pixel[x] > 1) pixel[x] = 1;
}
// next line
bits += pitch;
}
}
( run in 2.025 seconds using v1.01-cache-2.11-cpan-adec679a428 )