/** Apply the global/local tone mapping operator to a RGBF image and convert to 24-bit RGB<br> User parameters control intensity, contrast, and level of adaptation @param src Input RGBF image @param intensity Overall intensity in range [-8:8] : default to 0 @param contrast Contrast in range [0.3:1) : default to 0 @param adaptation Adaptation in range [0:1] : default to 1 @param color_correction Color correction in range [0:1] : default to 0 @return Returns a 24-bit RGB image if successful, returns NULL otherwise */ FIBITMAP* DLL_CALLCONV FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity, double contrast, double adaptation, double color_correction) { if(!FreeImage_HasPixels(src)) return NULL; // working RGBF variable FIBITMAP *dib = NULL, *Y = NULL; dib = FreeImage_ConvertToRGBF(src); if(!dib) return NULL; // get the Luminance channel Y = ConvertRGBFToY(dib); if(!Y) { FreeImage_Unload(dib); return NULL; } // perform the tone mapping ToneMappingReinhard05(dib, Y, (float)intensity, (float)contrast, (float)adaptation, (float)color_correction); // not needed anymore FreeImage_Unload(Y); // clamp image highest values to display white, then convert to 24-bit RGB FIBITMAP *dst = ClampConvertRGBFTo24(dib); // clean-up and return FreeImage_Unload(dib); // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); return dst; }
/** Apply the Adaptive Logarithmic Mapping operator to a HDR image and convert to 24-bit RGB @param src Input RGB16 or RGB[A]F image @param gamma Gamma correction (gamma > 0). 1 means no correction, 2.2 in the original paper. @param exposure Exposure parameter (0 means no correction, 0 in the original paper) @return Returns a 24-bit RGB image if successful, returns NULL otherwise */ FIBITMAP* DLL_CALLCONV FreeImage_TmoDrago03(FIBITMAP *src, double gamma, double exposure) { float maxLum, minLum, avgLum; if(!FreeImage_HasPixels(src)) return NULL; // working RGBF variable FIBITMAP *dib = NULL; dib = FreeImage_ConvertToRGBF(src); if(!dib) return NULL; // default algorithm parameters const float biasParam = 0.85F; const float expoParam = (float)pow(2.0, exposure); //default exposure is 1, 2^0 // convert to Yxy ConvertInPlaceRGBFToYxy(dib); // get the luminance LuminanceFromYxy(dib, &maxLum, &minLum, &avgLum); // perform the tone mapping ToneMappingDrago03(dib, maxLum, avgLum, biasParam, expoParam); // convert back to RGBF ConvertInPlaceYxyToRGBF(dib); if(gamma != 1) { // perform gamma correction REC709GammaCorrection(dib, (float)gamma); } // clamp image highest values to display white, then convert to 24-bit RGB FIBITMAP *dst = ClampConvertRGBFTo24(dib); // clean-up and return FreeImage_Unload(dib); // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); return dst; }
/** Apply the Gradient Domain High Dynamic Range Compression to a RGBF image and convert to 24-bit RGB @param dib Input RGBF / RGB16 image @param color_saturation Color saturation (s parameter in the paper) in [0.4..0.6] @param attenuation Atenuation factor (beta parameter in the paper) in [0.8..0.9] @return Returns a 24-bit RGB image if successful, returns NULL otherwise */ FIBITMAP* DLL_CALLCONV FreeImage_TmoFattal02(FIBITMAP *dib, double color_saturation, double attenuation) { const float alpha = 0.1F; // parameter alpha = 0.1 const float beta = (float)MAX(0.8, MIN(0.9, attenuation)); // parameter beta = [0.8..0.9] const float s = (float)MAX(0.4, MIN(0.6, color_saturation));// exponent s controls color saturation = [0.4..0.6] FIBITMAP *src = NULL; FIBITMAP *Yin = NULL; FIBITMAP *Yout = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; try { // convert to RGBF src = FreeImage_ConvertToRGBF(dib); if(!src) throw(1); // get the luminance channel Yin = ConvertRGBFToY(src); if(!Yin) throw(1); // perform the tone mapping Yout = tmoFattal02(Yin, alpha, beta); if(!Yout) throw(1); // clip low and high values and normalize to [0..1] //NormalizeY(Yout, 0.001F, 0.995F); NormalizeY(Yout, 0, 1); // compress the dynamic range const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); const unsigned rgb_pitch = FreeImage_GetPitch(src); const unsigned y_pitch = FreeImage_GetPitch(Yin); BYTE *bits = (BYTE*)FreeImage_GetBits(src); BYTE *bits_yin = (BYTE*)FreeImage_GetBits(Yin); BYTE *bits_yout = (BYTE*)FreeImage_GetBits(Yout); for(unsigned y = 0; y < height; y++) { float *Lin = (float*)bits_yin; float *Lout = (float*)bits_yout; float *color = (float*)bits; for(unsigned x = 0; x < width; x++) { for(unsigned c = 0; c < 3; c++) { *color = (Lin[x] > 0) ? pow(*color/Lin[x], s) * Lout[x] : 0; color++; } } bits += rgb_pitch; bits_yin += y_pitch; bits_yout += y_pitch; } // not needed anymore FreeImage_Unload(Yin); Yin = NULL; FreeImage_Unload(Yout); Yout = NULL; // clamp image highest values to display white, then convert to 24-bit RGB dst = ClampConvertRGBFTo24(src); // clean-up and return FreeImage_Unload(src); src = NULL; // copy metadata from src to dst FreeImage_CloneMetadata(dst, dib); return dst; } catch(int) { if(src) FreeImage_Unload(src); if(Yin) FreeImage_Unload(Yin); if(Yout) FreeImage_Unload(Yout); return NULL; } }