Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/tmoReinhard05.cpp  view on Meta::CPAN

//     IEEE Transactions on Visualization and Computer Graphics, 11(1), Jan/Feb 2005. 
// [2] Erik Reinhard, 'Parameter estimation for photographic tone reproduction',
//     Journal of Graphics Tools, vol. 7, no. 1, pp. 45–51, 2003.
// ----------------------------------------------------------

/**
Tone mapping operator
@param dib Input / Output RGBF image
@param Y Input luminance image version of dib
@param f Overall intensity in range [-8:8] : default to 0
@param m Contrast in range [0.3:1) : default to 0
@param a Adaptation in range [0:1] : default to 1
@param c Color correction in range [0:1] : default to 0
@return Returns TRUE if successful, returns FALSE otherwise
@see LuminanceFromY
*/
static BOOL 
ToneMappingReinhard05(FIBITMAP *dib, FIBITMAP *Y, float f, float m, float a, float c) {
	float Cav[3];		// channel average
	float Lav = 0;		// average luminance
	float Llav = 0;		// log average luminance
	float minLum = 1;	// min luminance
	float maxLum = 1;	// max luminance

	float L;		// pixel luminance
	float I_g, I_l; // global and local light adaptation
	float I_a;		// interpolated pixel light adaptation
	float k;		// key (low-key means overall dark image, high-key means overall light image)

	// check input parameters 

	if((FreeImage_GetImageType(dib) != FIT_RGBF) || (FreeImage_GetImageType(Y) != FIT_FLOAT)) {
		return FALSE;
	}

	if(f < -8) f = -8; if(f > 8) f = 8;
    if(m < 0)  m = 0;  if(m > 1) m = 1;
    if(a < 0)  a = 0;  if(a > 1) a = 1;
    if(c < 0)  c = 0;  if(c > 1) c = 1;

	const unsigned width  = FreeImage_GetWidth(dib);
	const unsigned height = FreeImage_GetHeight(dib);

	const unsigned dib_pitch  = FreeImage_GetPitch(dib);
	const unsigned y_pitch    = FreeImage_GetPitch(Y);

	int i;
	unsigned x, y;
	BYTE *bits = NULL, *Ybits = NULL;

	// get statistics about the data (but only if its really needed)

	f = exp(-f);
	if((m == 0) || (a != 1) && (c != 1)) {
		// avoid these calculations if its not needed after ...
		LuminanceFromY(Y, &maxLum, &minLum, &Lav, &Llav);
		k = (log(maxLum) - Llav) / (log(maxLum) - log(minLum));
		if(k < 0) {
			// pow(k, 1.4F) is undefined ...
			// there's an ambiguity about the calculation of Llav between Reinhard papers and the various implementations  ...
			// try another world adaptation luminance formula using instead 'worldLum = log(Llav)'
			k = (log(maxLum) - log(Llav)) / (log(maxLum) - log(minLum));
			if(k < 0) m = 0.3F;
		}
	}
	m = (m > 0) ? m : (float)(0.3 + 0.7 * pow(k, 1.4F));

	float max_color = -1e6F;
	float min_color = +1e6F;

	// tone map image

	bits  = (BYTE*)FreeImage_GetBits(dib);
	Ybits = (BYTE*)FreeImage_GetBits(Y);

	if((a == 1) && (c == 0)) {
		// when using default values, use a fastest code

		for(y = 0; y < height; y++) {
			float *Y     = (float*)Ybits;
			float *color = (float*)bits;

			for(x = 0; x < width; x++) {
				I_a = Y[x];	// luminance(x, y)
				for (i = 0; i < 3; i++) {
					*color /= ( *color + pow(f * I_a, m) );
					
					max_color = (*color > max_color) ? *color : max_color;
					min_color = (*color < min_color) ? *color : min_color;

					color++;
				}
			}
			// next line
			bits  += dib_pitch;
			Ybits += y_pitch;
		}
	} else {
		// complete algorithm

		// channel averages

		Cav[0] = Cav[1] = Cav[2] = 0;
		if((a != 1) && (c != 0)) {
			// channel averages are not needed when (a == 1) or (c == 0)
			bits = (BYTE*)FreeImage_GetBits(dib);
			for(y = 0; y < height; y++) {
				float *color = (float*)bits;
				for(x = 0; x < width; x++) {
					for(i = 0; i < 3; i++) {
						Cav[i] += *color;
						color++;
					}
				}
				// next line
				bits += dib_pitch;
			}
			const float image_size = (float)width * height;
			for(i = 0; i < 3; i++) {
				Cav[i] /= image_size;
			}



( run in 1.220 second using v1.01-cache-2.11-cpan-70e19b8f4f1 )