/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. #include "FreeImage.h"
  23. #include "Utilities.h"
  24. #include "ToneMapping.h"
  25. // ----------------------------------------------------------
  26. // Global and/or local tone mapping operator
  27. // References:
  28. // [1] Erik Reinhard and Kate Devlin, 'Dynamic Range Reduction Inspired by Photoreceptor Physiology',
  29. // IEEE Transactions on Visualization and Computer Graphics, 11(1), Jan/Feb 2005.
  30. // [2] Erik Reinhard, 'Parameter estimation for photographic tone reproduction',
  31. // Journal of Graphics Tools, vol. 7, no. 1, pp. 45–51, 2003.
  32. // ----------------------------------------------------------
  33. /**
  34. Tone mapping operator
  35. @param dib Input / Output RGBF image
  36. @param Y Input luminance image version of dib
  37. @param f Overall intensity in range [-8:8] : default to 0
  38. @param m Contrast in range [0.3:1) : default to 0
  39. @param a Adaptation in range [0:1] : default to 1
  40. @param c Color correction in range [0:1] : default to 0
  41. @return Returns TRUE if successful, returns FALSE otherwise
  42. @see LuminanceFromY
  43. */
  44. static BOOL
  45. ToneMappingReinhard05(FIBITMAP *dib, FIBITMAP *Y, float f, float m, float a, float c) {
  46. float Cav[3]; // channel average
  47. float Lav = 0; // average luminance
  48. float Llav = 0; // log average luminance
  49. float minLum = 1; // min luminance
  50. float maxLum = 1; // max luminance
  51. float L; // pixel luminance
  52. float I_g, I_l; // global and local light adaptation
  53. float I_a; // interpolated pixel light adaptation
  54. float k; // key (low-key means overall dark image, high-key means overall light image)
  55. // check input parameters
  56. if((FreeImage_GetImageType(dib) != FIT_RGBF) || (FreeImage_GetImageType(Y) != FIT_FLOAT)) {
  57. return FALSE;
  58. }
  59. if(f < -8) f = -8; if(f > 8) f = 8;
  60. if(m < 0) m = 0; if(m > 1) m = 1;
  61. if(a < 0) a = 0; if(a > 1) a = 1;
  62. if(c < 0) c = 0; if(c > 1) c = 1;
  63. const unsigned width = FreeImage_GetWidth(dib);
  64. const unsigned height = FreeImage_GetHeight(dib);
  65. const unsigned dib_pitch = FreeImage_GetPitch(dib);
  66. const unsigned y_pitch = FreeImage_GetPitch(Y);
  67. int i;
  68. unsigned x, y;
  69. BYTE *bits = NULL, *Ybits = NULL;
  70. // get statistics about the data (but only if its really needed)
  71. f = exp(-f);
  72. if((m == 0) || (a != 1) && (c != 1)) {
  73. // avoid these calculations if its not needed after ...
  74. LuminanceFromY(Y, &maxLum, &minLum, &Lav, &Llav);
  75. k = (log(maxLum) - Llav) / (log(maxLum) - log(minLum));
  76. if(k < 0) {
  77. // pow(k, 1.4F) is undefined ...
  78. // there's an ambiguity about the calculation of Llav between Reinhard papers and the various implementations ...
  79. // try another world adaptation luminance formula using instead 'worldLum = log(Llav)'
  80. k = (log(maxLum) - log(Llav)) / (log(maxLum) - log(minLum));
  81. if(k < 0) m = 0.3F;
  82. }
  83. }
  84. m = (m > 0) ? m : (float)(0.3 + 0.7 * pow(k, 1.4F));
  85. float max_color = -1e6F;
  86. float min_color = +1e6F;
  87. // tone map image
  88. bits = (BYTE*)FreeImage_GetBits(dib);
  89. Ybits = (BYTE*)FreeImage_GetBits(Y);
  90. if((a == 1) && (c == 0)) {
  91. // when using default values, use a fastest code
  92. for(y = 0; y < height; y++) {
  93. float *Y = (float*)Ybits;
  94. float *color = (float*)bits;
  95. for(x = 0; x < width; x++) {
  96. I_a = Y[x]; // luminance(x, y)
  97. for (i = 0; i < 3; i++) {
  98. *color /= ( *color + pow(f * I_a, m) );
  99. max_color = (*color > max_color) ? *color : max_color;
  100. min_color = (*color < min_color) ? *color : min_color;
  101. color++;
  102. }
  103. }
  104. // next line
  105. bits += dib_pitch;
  106. Ybits += y_pitch;
  107. }
  108. } else {
  109. // complete algorithm
  110. // channel averages
  111. Cav[0] = Cav[1] = Cav[2] = 0;
  112. if((a != 1) && (c != 0)) {
  113. // channel averages are not needed when (a == 1) or (c == 0)
  114. bits = (BYTE*)FreeImage_GetBits(dib);
  115. for(y = 0; y < height; y++) {
  116. float *color = (float*)bits;
  117. for(x = 0; x < width; x++) {
  118. for(i = 0; i < 3; i++) {
  119. Cav[i] += *color;
  120. color++;
  121. }
  122. }
  123. // next line
  124. bits += dib_pitch;
  125. }
  126. const float image_size = (float)width * height;
  127. for(i = 0; i < 3; i++) {
  128. Cav[i] /= image_size;
  129. }
  130. }
  131. // perform tone mapping
  132. bits = (BYTE*)FreeImage_GetBits(dib);
  133. for(y = 0; y < height; y++) {
  134. const float *Y = (float*)Ybits;
  135. float *color = (float*)bits;
  136. for(x = 0; x < width; x++) {
  137. L = Y[x]; // luminance(x, y)
  138. for (i = 0; i < 3; i++) {
  139. I_l = c * *color + (1-c) * L;
  140. I_g = c * Cav[i] + (1-c) * Lav;
  141. I_a = a * I_l + (1-a) * I_g;
  142. *color /= ( *color + pow(f * I_a, m) );
  143. max_color = (*color > max_color) ? *color : max_color;
  144. min_color = (*color < min_color) ? *color : min_color;
  145. color++;
  146. }
  147. }
  148. // next line
  149. bits += dib_pitch;
  150. Ybits += y_pitch;
  151. }
  152. }
  153. // normalize intensities
  154. if(max_color != min_color) {
  155. bits = (BYTE*)FreeImage_GetBits(dib);
  156. const float range = max_color - min_color;
  157. for(y = 0; y < height; y++) {
  158. float *color = (float*)bits;
  159. for(x = 0; x < width; x++) {
  160. for(i = 0; i < 3; i++) {
  161. *color = (*color - min_color) / range;
  162. color++;
  163. }
  164. }
  165. // next line
  166. bits += dib_pitch;
  167. }
  168. }
  169. return TRUE;
  170. }
  171. // ----------------------------------------------------------
  172. // Main algorithm
  173. // ----------------------------------------------------------
  174. /**
  175. Apply the global/local tone mapping operator to a RGBF image and convert to 24-bit RGB<br>
  176. User parameters control intensity, contrast, and level of adaptation
  177. @param src Input RGBF image
  178. @param intensity Overall intensity in range [-8:8] : default to 0
  179. @param contrast Contrast in range [0.3:1) : default to 0
  180. @param adaptation Adaptation in range [0:1] : default to 1
  181. @param color_correction Color correction in range [0:1] : default to 0
  182. @return Returns a 24-bit RGB image if successful, returns NULL otherwise
  183. */
  184. FIBITMAP* DLL_CALLCONV
  185. FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity, double contrast, double adaptation, double color_correction) {
  186. if(!FreeImage_HasPixels(src)) return NULL;
  187. // working RGBF variable
  188. FIBITMAP *dib = NULL, *Y = NULL;
  189. dib = FreeImage_ConvertToRGBF(src);
  190. if(!dib) return NULL;
  191. // get the Luminance channel
  192. Y = ConvertRGBFToY(dib);
  193. if(!Y) {
  194. FreeImage_Unload(dib);
  195. return NULL;
  196. }
  197. // perform the tone mapping
  198. ToneMappingReinhard05(dib, Y, (float)intensity, (float)contrast, (float)adaptation, (float)color_correction);
  199. // not needed anymore
  200. FreeImage_Unload(Y);
  201. // clamp image highest values to display white, then convert to 24-bit RGB
  202. FIBITMAP *dst = ClampConvertRGBFTo24(dib);
  203. // clean-up and return
  204. FreeImage_Unload(dib);
  205. // copy metadata from src to dst
  206. FreeImage_CloneMetadata(dst, src);
  207. return dst;
  208. }
  209. /**
  210. Apply the global tone mapping operator to a RGBF image and convert to 24-bit RGB<br>
  211. User parameters control intensity and contrast
  212. @param src Input RGBF image
  213. @param intensity Overall intensity in range [-8:8] : default to 0
  214. @param contrast Contrast in range [0.3:1) : default to 0
  215. @return Returns a 24-bit RGB image if successful, returns NULL otherwise
  216. */
  217. FIBITMAP* DLL_CALLCONV
  218. FreeImage_TmoReinhard05(FIBITMAP *src, double intensity, double contrast) {
  219. return FreeImage_TmoReinhard05Ex(src, intensity, contrast, 1, 0);
  220. }