/*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) 2013, OpenCV Foundation, 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 "precomp.hpp" #include "opencv2/photo.hpp" #include "opencv2/imgproc.hpp" #include "hdr_common.hpp" #include namespace cv { class MergeDebevecImpl : public MergeDebevec { public: MergeDebevecImpl() : name("MergeDebevec"), weights(tringleWeights()) { } void process(InputArrayOfArrays src, OutputArray dst, const std::vector& times, InputArray input_response) { std::vector images; src.getMatVector(images); CV_Assert(images.size() == times.size()); checkImageDimensions(images); CV_Assert(images[0].depth() == CV_8U); int channels = images[0].channels(); Size size = images[0].size(); int CV_32FCC = CV_MAKETYPE(CV_32F, channels); dst.create(images[0].size(), CV_32FCC); Mat result = dst.getMat(); Mat response = input_response.getMat(); if(response.empty()) { response = linearResponse(channels); } log(response, response); CV_Assert(response.rows == 256 && response.cols == 1 && response.channels() == channels); Mat exp_values(times); log(exp_values, exp_values); result = Mat::zeros(size, CV_32FCC); std::vector result_split; split(result, result_split); Mat weight_sum = Mat::zeros(size, CV_32F); for(size_t i = 0; i < images.size(); i++) { std::vector splitted; split(images[i], splitted); Mat w = Mat::zeros(size, CV_32F); for(int c = 0; c < channels; c++) { LUT(splitted[c], weights, splitted[c]); w += splitted[c]; } w /= channels; Mat response_img; LUT(images[i], response, response_img); split(response_img, splitted); for(int c = 0; c < channels; c++) { result_split[c] += w.mul(splitted[c] - exp_values.at(i)); } weight_sum += w; } weight_sum = 1.0f / weight_sum; for(int c = 0; c < channels; c++) { result_split[c] = result_split[c].mul(weight_sum); } merge(result_split, result); exp(result, result); } void process(InputArrayOfArrays src, OutputArray dst, const std::vector& times) { process(src, dst, times, Mat()); } protected: String name; Mat weights; Mat linearResponse(int channels) { Mat single_response = Mat(256, 1, CV_32F); for(int i = 1; i < 256; i++) { single_response.at(i) = static_cast(i); } single_response.at(0) = static_cast(1); std::vector splitted(channels); for(int c = 0; c < channels; c++) { splitted[c] = single_response; } Mat result; merge(splitted, result); return result; } }; Ptr createMergeDebevec() { return new MergeDebevecImpl; } class MergeMertensImpl : public MergeMertens { public: MergeMertensImpl(float wcon, float wsat, float wexp) : wcon(wcon), wsat(wsat), wexp(wexp), name("MergeMertens") { } void process(InputArrayOfArrays src, OutputArrayOfArrays dst, const std::vector& times, InputArray response) { process(src, dst); } void process(InputArrayOfArrays src, OutputArray dst) { std::vector images; src.getMatVector(images); checkImageDimensions(images); int channels = images[0].channels(); CV_Assert(channels == 1 || channels == 3); Size size = images[0].size(); int CV_32FCC = CV_MAKETYPE(CV_32F, channels); std::vector weights(images.size()); Mat weight_sum = Mat::zeros(size, CV_32F); for(size_t i = 0; i < images.size(); i++) { Mat img, gray, contrast, saturation, wellexp; std::vector splitted(channels); images[i].convertTo(img, CV_32F, 1.0f/255.0f); if(channels == 3) { cvtColor(img, gray, COLOR_RGB2GRAY); } else { img.copyTo(gray); } split(img, splitted); Laplacian(gray, contrast, CV_32F); contrast = abs(contrast); Mat mean = Mat::zeros(size, CV_32F); for(int c = 0; c < channels; c++) { mean += splitted[c]; } mean /= channels; saturation = Mat::zeros(size, CV_32F); for(int c = 0; c < channels; c++) { Mat deviation = splitted[c] - mean; pow(deviation, 2.0f, deviation); saturation += deviation; } sqrt(saturation, saturation); wellexp = Mat::ones(size, CV_32F); for(int c = 0; c < channels; c++) { Mat exp = splitted[c] - 0.5f; pow(exp, 2.0f, exp); exp = -exp / 0.08f; wellexp = wellexp.mul(exp); } pow(contrast, wcon, contrast); pow(saturation, wsat, saturation); pow(wellexp, wexp, wellexp); weights[i] = contrast; if(channels == 3) { weights[i] = weights[i].mul(saturation); } weights[i] = weights[i].mul(wellexp); weight_sum += weights[i]; } int maxlevel = static_cast(logf(static_cast(min(size.width, size.height))) / logf(2.0f)); std::vector res_pyr(maxlevel + 1); for(size_t i = 0; i < images.size(); i++) { weights[i] /= weight_sum; Mat img; images[i].convertTo(img, CV_32F, 1.0f/255.0f); std::vector img_pyr, weight_pyr; buildPyramid(img, img_pyr, maxlevel); buildPyramid(weights[i], weight_pyr, maxlevel); for(int lvl = 0; lvl < maxlevel; lvl++) { Mat up; pyrUp(img_pyr[lvl + 1], up, img_pyr[lvl].size()); img_pyr[lvl] -= up; } for(int lvl = 0; lvl <= maxlevel; lvl++) { std::vector splitted(channels); split(img_pyr[lvl], splitted); for(int c = 0; c < channels; c++) { splitted[c] = splitted[c].mul(weight_pyr[lvl]); } merge(splitted, img_pyr[lvl]); if(res_pyr[lvl].empty()) { res_pyr[lvl] = img_pyr[lvl]; } else { res_pyr[lvl] += img_pyr[lvl]; } } } for(int lvl = maxlevel; lvl > 0; lvl--) { Mat up; pyrUp(res_pyr[lvl], up, res_pyr[lvl - 1].size()); res_pyr[lvl - 1] += up; } dst.create(size, CV_32FCC); res_pyr[0].copyTo(dst.getMat()); } float getContrastWeight() const { return wcon; } void setContrastWeight(float val) { wcon = val; } float getSaturationWeight() const { return wsat; } void setSaturationWeight(float val) { wsat = val; } float getExposureWeight() const { return wexp; } void setExposureWeight(float val) { wexp = val; } void write(FileStorage& fs) const { fs << "name" << name << "contrast_weight" << wcon << "saturation_weight" << wsat << "exposure_weight" << wexp; } void read(const FileNode& fn) { FileNode n = fn["name"]; CV_Assert(n.isString() && String(n) == name); wcon = fn["contrast_weight"]; wsat = fn["saturation_weight"]; wexp = fn["exposure_weight"]; } protected: String name; float wcon, wsat, wexp; }; Ptr createMergeMertens(float wcon, float wsat, float wexp) { return new MergeMertensImpl(wcon, wsat, wexp); } }