diff --git a/modules/photo/src/tonemap.cpp b/modules/photo/src/tonemap.cpp new file mode 100644 index 0000000000..0c40898753 --- /dev/null +++ b/modules/photo/src/tonemap.cpp @@ -0,0 +1,190 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" + +namespace cv +{ + static float getParam(std::vector<float>& params, size_t i, float defval) + { + if(params.size() > i) { + return params[i]; + } else { + return defval; + } + + } + static void DragoMap(Mat& src_img, Mat &dst_img, std::vector<float>& params) + { + float bias_value = getParam(params, 1, 0.85f); + Mat gray_img; + cvtColor(src_img, gray_img, COLOR_RGB2GRAY); + Mat log_img; + log(gray_img, log_img); + float mean = exp((float)sum(log_img)[0] / log_img.total()); + gray_img /= mean; + log_img.release(); + + double max; + minMaxLoc(gray_img, NULL, &max); + + Mat map; + log(gray_img + 1.0f, map); + Mat div; + pow(gray_img / (float)max, log(bias_value) / log(0.5f), div); + log(2.0f + 8.0f * div, div); + map = map.mul(1.0f / div); + map = map.mul(1.0f / gray_img); + div.release(); + gray_img.release(); + + std::vector<Mat> channels(3); + split(src_img, channels); + for(int i = 0; i < 3; i++) { + channels[i] = channels[i].mul(map); + } + map.release(); + merge(channels, dst_img); + } + + static void ReinhardDevlinMap(Mat& src_img, Mat &dst_img, std::vector<float>& params) + { + float intensity = getParam(params, 1, 0.0f); + float color_adapt = getParam(params, 2, 0.0f); + float light_adapt = getParam(params, 3, 1.0f); + + Mat gray_img; + cvtColor(src_img, gray_img, COLOR_RGB2GRAY); + Mat log_img; + log(gray_img, log_img); + + float log_mean = (float)sum(log_img)[0] / log_img.total(); + double log_min, log_max; + minMaxLoc(log_img, &log_min, &log_max); + log_img.release(); + + double key = (float)((log_max - log_mean) / (log_max - log_min)); + float map_key = 0.3f + 0.7f * pow((float)key, 1.4f); + intensity = exp(-intensity); + Scalar chan_mean = mean(src_img); + float gray_mean = (float)mean(gray_img)[0]; + + std::vector<Mat> channels(3); + split(src_img, channels); + + for(int i = 0; i < 3; i++) { + float global = color_adapt * (float)chan_mean[i] + (1.0f - color_adapt) * gray_mean; + Mat adapt = color_adapt * channels[i] + (1.0f - color_adapt) * gray_img; + adapt = light_adapt * adapt + (1.0f - light_adapt) * global; + pow(intensity * adapt, map_key, adapt); + channels[i] = channels[i].mul(1.0f / (adapt + channels[i])); + } + gray_img.release(); + merge(channels, dst_img); + } + + static void DurandMap(Mat& src_img, Mat& dst_img, std::vector<float>& params) + { + float contrast = getParam(params, 1, 4.0f); + float sigma_color = getParam(params, 2, 2.0f); + float sigma_space = getParam(params, 3, 2.0f); + + Mat gray_img; + cvtColor(src_img, gray_img, COLOR_RGB2GRAY); + Mat log_img; + log(gray_img, log_img); + Mat map_img; + bilateralFilter(log_img, map_img, -1, sigma_color, sigma_space); + + double min, max; + minMaxLoc(map_img, &min, &max); + float scale = contrast / (float)(max - min); + + exp(map_img * (scale - 1.0f) + log_img, map_img); + log_img.release(); + map_img = map_img.mul(1.0f / gray_img); + gray_img.release(); + + std::vector<Mat> channels(3); + split(src_img, channels); + for(int i = 0; i < 3; i++) { + channels[i] = channels[i].mul(map_img); + } + merge(channels, dst_img); + } + + void tonemap(InputArray _src, OutputArray _dst, tonemap_algorithms algorithm, + std::vector<float>& params) + { + typedef void (*tonemap_func)(Mat&, Mat&, std::vector<float>&); + const unsigned param_count[TONEMAP_COUNT] = {0, 1, 3, 3}; + tonemap_func functions[TONEMAP_COUNT] = { + NULL, DragoMap, ReinhardDevlinMap, DurandMap}; + + Mat src = _src.getMat(); + if(src.empty()) { + CV_Error(Error::StsBadArg, "Empty input image"); + } + if(algorithm < 0 || algorithm >= TONEMAP_COUNT) { + CV_Error(Error::StsBadArg, "Wrong algorithm index"); + } + + _dst.create(src.size(), CV_32FC3); + Mat dst = _dst.getMat(); + src.copyTo(dst); + + double min, max; + minMaxLoc(dst, &min, &max); + if(max - min < 1e-10f) { + return; + } + dst = (dst - min) / (max - min); + if(functions[algorithm]) { + functions[algorithm](dst, dst, params); + } + minMaxLoc(dst, &min, &max); + dst = (dst - min) / (max - min); + float gamma = getParam(params, 0, 1.0f); + pow(dst, 1.0f / gamma, dst); + } +} \ No newline at end of file