PageRenderTime 39ms CodeModel.GetById 1ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 1ms

/src/FreeImage/Source/FreeImage/tmoReinhard05.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 260 lines | 135 code | 40 blank | 85 comment | 47 complexity | 0a5b5e51878cb5145c8bea0d68fa4da9 MD5 | raw file
  1// ==========================================================
  2// Tone mapping operator (Reinhard, 2005)
  3//
  4// Design and implementation by
  5// - Hervé Drolon (drolon@infonie.fr)
  6// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
  7//
  8// This file is part of FreeImage 3
  9//
 10// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 11// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 12// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 13// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 14// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 15// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 16// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 17// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 18// THIS DISCLAIMER.
 19//
 20// Use at your own risk!
 21// ==========================================================
 22
 23#include "FreeImage.h"
 24#include "Utilities.h"
 25#include "ToneMapping.h"
 26
 27// ----------------------------------------------------------
 28// Global and/or local tone mapping operator
 29// References: 
 30// [1] Erik Reinhard and Kate Devlin, 'Dynamic Range Reduction Inspired by Photoreceptor Physiology', 
 31//     IEEE Transactions on Visualization and Computer Graphics, 11(1), Jan/Feb 2005. 
 32// [2] Erik Reinhard, 'Parameter estimation for photographic tone reproduction',
 33//     Journal of Graphics Tools, vol. 7, no. 1, pp. 45–51, 2003.
 34// ----------------------------------------------------------
 35
 36/**
 37Tone mapping operator
 38@param dib Input / Output RGBF image
 39@param Y Input luminance image version of dib
 40@param f Overall intensity in range [-8:8] : default to 0
 41@param m Contrast in range [0.3:1) : default to 0
 42@param a Adaptation in range [0:1] : default to 1
 43@param c Color correction in range [0:1] : default to 0
 44@return Returns TRUE if successful, returns FALSE otherwise
 45@see LuminanceFromY
 46*/
 47static BOOL 
 48ToneMappingReinhard05(FIBITMAP *dib, FIBITMAP *Y, float f, float m, float a, float c) {
 49	float Cav[3];		// channel average
 50	float Lav = 0;		// average luminance
 51	float Llav = 0;		// log average luminance
 52	float minLum = 1;	// min luminance
 53	float maxLum = 1;	// max luminance
 54
 55	float L;		// pixel luminance
 56	float I_g, I_l; // global and local light adaptation
 57	float I_a;		// interpolated pixel light adaptation
 58	float k;		// key (low-key means overall dark image, high-key means overall light image)
 59
 60	// check input parameters 
 61
 62	if((FreeImage_GetImageType(dib) != FIT_RGBF) || (FreeImage_GetImageType(Y) != FIT_FLOAT)) {
 63		return FALSE;
 64	}
 65
 66	if(f < -8) f = -8; if(f > 8) f = 8;
 67    if(m < 0)  m = 0;  if(m > 1) m = 1;
 68    if(a < 0)  a = 0;  if(a > 1) a = 1;
 69    if(c < 0)  c = 0;  if(c > 1) c = 1;
 70
 71	const unsigned width  = FreeImage_GetWidth(dib);
 72	const unsigned height = FreeImage_GetHeight(dib);
 73
 74	const unsigned dib_pitch  = FreeImage_GetPitch(dib);
 75	const unsigned y_pitch    = FreeImage_GetPitch(Y);
 76
 77	int i;
 78	unsigned x, y;
 79	BYTE *bits = NULL, *Ybits = NULL;
 80
 81	// get statistics about the data (but only if its really needed)
 82
 83	f = exp(-f);
 84	if((m == 0) || (a != 1) && (c != 1)) {
 85		// avoid these calculations if its not needed after ...
 86		LuminanceFromY(Y, &maxLum, &minLum, &Lav, &Llav);
 87		k = (log(maxLum) - Llav) / (log(maxLum) - log(minLum));
 88		if(k < 0) {
 89			// pow(k, 1.4F) is undefined ...
 90			// there's an ambiguity about the calculation of Llav between Reinhard papers and the various implementations  ...
 91			// try another world adaptation luminance formula using instead 'worldLum = log(Llav)'
 92			k = (log(maxLum) - log(Llav)) / (log(maxLum) - log(minLum));
 93			if(k < 0) m = 0.3F;
 94		}
 95	}
 96	m = (m > 0) ? m : (float)(0.3 + 0.7 * pow(k, 1.4F));
 97
 98	float max_color = -1e6F;
 99	float min_color = +1e6F;
100
101	// tone map image
102
103	bits  = (BYTE*)FreeImage_GetBits(dib);
104	Ybits = (BYTE*)FreeImage_GetBits(Y);
105
106	if((a == 1) && (c == 0)) {
107		// when using default values, use a fastest code
108
109		for(y = 0; y < height; y++) {
110			float *Y     = (float*)Ybits;
111			float *color = (float*)bits;
112
113			for(x = 0; x < width; x++) {
114				I_a = Y[x];	// luminance(x, y)
115				for (i = 0; i < 3; i++) {
116					*color /= ( *color + pow(f * I_a, m) );
117					
118					max_color = (*color > max_color) ? *color : max_color;
119					min_color = (*color < min_color) ? *color : min_color;
120
121					color++;
122				}
123			}
124			// next line
125			bits  += dib_pitch;
126			Ybits += y_pitch;
127		}
128	} else {
129		// complete algorithm
130
131		// channel averages
132
133		Cav[0] = Cav[1] = Cav[2] = 0;
134		if((a != 1) && (c != 0)) {
135			// channel averages are not needed when (a == 1) or (c == 0)
136			bits = (BYTE*)FreeImage_GetBits(dib);
137			for(y = 0; y < height; y++) {
138				float *color = (float*)bits;
139				for(x = 0; x < width; x++) {
140					for(i = 0; i < 3; i++) {
141						Cav[i] += *color;
142						color++;
143					}
144				}
145				// next line
146				bits += dib_pitch;
147			}
148			const float image_size = (float)width * height;
149			for(i = 0; i < 3; i++) {
150				Cav[i] /= image_size;
151			}
152		}
153
154		// perform tone mapping
155
156		bits = (BYTE*)FreeImage_GetBits(dib);
157		for(y = 0; y < height; y++) {
158			const float *Y     = (float*)Ybits;
159			float *color = (float*)bits;
160
161			for(x = 0; x < width; x++) {
162				L = Y[x];	// luminance(x, y)
163				for (i = 0; i < 3; i++) {
164					I_l = c * *color + (1-c) * L;
165					I_g = c * Cav[i] + (1-c) * Lav;
166					I_a = a * I_l + (1-a) * I_g;
167					*color /= ( *color + pow(f * I_a, m) );
168					
169					max_color = (*color > max_color) ? *color : max_color;
170					min_color = (*color < min_color) ? *color : min_color;
171
172					color++;
173				}
174			}
175			// next line
176			bits  += dib_pitch;
177			Ybits += y_pitch;
178		}
179	}
180
181	// normalize intensities
182
183	if(max_color != min_color) {
184		bits = (BYTE*)FreeImage_GetBits(dib);
185		const float range = max_color - min_color;
186		for(y = 0; y < height; y++) {
187			float *color = (float*)bits;
188			for(x = 0; x < width; x++) {
189				for(i = 0; i < 3; i++) {
190					*color = (*color - min_color) / range;
191					color++;
192				}
193			}
194			// next line
195			bits += dib_pitch;
196		}
197	}
198
199	return TRUE;
200}
201
202// ----------------------------------------------------------
203//  Main algorithm
204// ----------------------------------------------------------
205
206/**
207Apply the global/local tone mapping operator to a RGBF image and convert to 24-bit RGB<br>
208User parameters control intensity, contrast, and level of adaptation
209@param src Input RGBF image
210@param intensity Overall intensity in range [-8:8] : default to 0
211@param contrast Contrast in range [0.3:1) : default to 0
212@param adaptation Adaptation in range [0:1] : default to 1
213@param color_correction Color correction in range [0:1] : default to 0
214@return Returns a 24-bit RGB image if successful, returns NULL otherwise
215*/
216FIBITMAP* DLL_CALLCONV 
217FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity, double contrast, double adaptation, double color_correction) {
218	if(!FreeImage_HasPixels(src)) return NULL;
219
220	// working RGBF variable
221	FIBITMAP *dib = NULL, *Y = NULL;
222
223	dib = FreeImage_ConvertToRGBF(src);
224	if(!dib) return NULL;
225
226	// get the Luminance channel
227	Y = ConvertRGBFToY(dib);
228	if(!Y) {
229		FreeImage_Unload(dib);
230		return NULL;
231	}
232
233	// perform the tone mapping
234	ToneMappingReinhard05(dib, Y, (float)intensity, (float)contrast, (float)adaptation, (float)color_correction);
235	// not needed anymore
236	FreeImage_Unload(Y);
237	// clamp image highest values to display white, then convert to 24-bit RGB
238	FIBITMAP *dst = ClampConvertRGBFTo24(dib);
239
240	// clean-up and return
241	FreeImage_Unload(dib);
242
243	// copy metadata from src to dst
244	FreeImage_CloneMetadata(dst, src);
245
246	return dst;
247}
248
249/**
250Apply the global tone mapping operator to a RGBF image and convert to 24-bit RGB<br>
251User parameters control intensity and contrast
252@param src Input RGBF image
253@param intensity Overall intensity in range [-8:8] : default to 0
254@param contrast Contrast in range [0.3:1) : default to 0
255@return Returns a 24-bit RGB image if successful, returns NULL otherwise
256*/
257FIBITMAP* DLL_CALLCONV 
258FreeImage_TmoReinhard05(FIBITMAP *src, double intensity, double contrast) {
259	return FreeImage_TmoReinhard05Ex(src, intensity, contrast, 1, 0);
260}