merge.cpp 11.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*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
//
13
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
// 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"

namespace cv
{

class MergeDebevecImpl : public MergeDebevec
{
public:
Fedor Morozov's avatar
Fedor Morozov committed
53 54 55 56 57
    MergeDebevecImpl() :
        name("MergeDebevec"),
        weights(tringleWeights())
    {
    }
58 59

    void process(InputArrayOfArrays src, OutputArray dst, InputArray _times, InputArray input_response)
Fedor Morozov's avatar
Fedor Morozov committed
60 61 62
    {
        std::vector<Mat> images;
        src.getMatVector(images);
63
        Mat times = _times.getMat();
64

65
        CV_Assert(images.size() == times.total());
Fedor Morozov's avatar
Fedor Morozov committed
66
        checkImageDimensions(images);
67 68 69 70 71 72 73 74
        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();
75

Fedor Morozov's avatar
Fedor Morozov committed
76
        Mat response = input_response.getMat();
77 78 79

        if(response.empty()) {
            response = linearResponse(channels);
Fedor Morozov's avatar
Fedor Morozov committed
80
            response.at<Vec3f>(0) = response.at<Vec3f>(1);
Fedor Morozov's avatar
Fedor Morozov committed
81
        }
82
        log(response, response);
83
        CV_Assert(response.rows == LDR_SIZE && response.cols == 1 &&
84 85 86 87
                  response.channels() == channels);

        Mat exp_values(times);
        log(exp_values, exp_values);
88

89 90 91 92
        result = Mat::zeros(size, CV_32FCC);
        std::vector<Mat> result_split;
        split(result, result_split);
        Mat weight_sum = Mat::zeros(size, CV_32F);
93

94 95 96
        for(size_t i = 0; i < images.size(); i++) {
            std::vector<Mat> splitted;
            split(images[i], splitted);
97

98 99 100 101
            Mat w = Mat::zeros(size, CV_32F);
            for(int c = 0; c < channels; c++) {
                LUT(splitted[c], weights, splitted[c]);
                w += splitted[c];
Fedor Morozov's avatar
Fedor Morozov committed
102
            }
103 104 105 106 107 108
            w /= channels;

            Mat response_img;
            LUT(images[i], response, response_img);
            split(response_img, splitted);
            for(int c = 0; c < channels; c++) {
Ilya Lavrenov's avatar
Ilya Lavrenov committed
109
                result_split[c] += w.mul(splitted[c] - exp_values.at<float>((int)i));
Fedor Morozov's avatar
Fedor Morozov committed
110
            }
111 112 113 114 115
            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);
Fedor Morozov's avatar
Fedor Morozov committed
116
        }
117 118
        merge(result_split, result);
        exp(result, result);
Fedor Morozov's avatar
Fedor Morozov committed
119
    }
120

121
    void process(InputArrayOfArrays src, OutputArray dst, InputArray times)
Fedor Morozov's avatar
Fedor Morozov committed
122
    {
123
        process(src, dst, times, Mat());
Fedor Morozov's avatar
Fedor Morozov committed
124
    }
125 126

protected:
Fedor Morozov's avatar
Fedor Morozov committed
127 128
    String name;
    Mat weights;
129 130 131 132
};

Ptr<MergeDebevec> createMergeDebevec()
{
133
    return makePtr<MergeDebevecImpl>();
134 135 136 137 138
}

class MergeMertensImpl : public MergeMertens
{
public:
139 140 141 142 143
    MergeMertensImpl(float _wcon, float _wsat, float _wexp) :
        name("MergeMertens"),
        wcon(_wcon),
        wsat(_wsat),
        wexp(_wexp)
Fedor Morozov's avatar
Fedor Morozov committed
144 145
    {
    }
146 147

    void process(InputArrayOfArrays src, OutputArrayOfArrays dst, InputArray, InputArray)
Fedor Morozov's avatar
Fedor Morozov committed
148 149 150
    {
        process(src, dst);
    }
151

Fedor Morozov's avatar
Fedor Morozov committed
152 153 154 155 156
    void process(InputArrayOfArrays src, OutputArray dst)
    {
        std::vector<Mat> images;
        src.getMatVector(images);
        checkImageDimensions(images);
157

158 159 160 161 162
        int channels = images[0].channels();
        CV_Assert(channels == 1 || channels == 3);
        Size size = images[0].size();
        int CV_32FCC = CV_MAKETYPE(CV_32F, channels);

Fedor Morozov's avatar
Fedor Morozov committed
163
        std::vector<Mat> weights(images.size());
164 165 166
        Mat weight_sum = Mat::zeros(size, CV_32F);

        for(size_t i = 0; i < images.size(); i++) {
Fedor Morozov's avatar
Fedor Morozov committed
167
            Mat img, gray, contrast, saturation, wellexp;
168
            std::vector<Mat> splitted(channels);
169

170 171 172 173 174 175 176
            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);
177

Fedor Morozov's avatar
Fedor Morozov committed
178 179
            Laplacian(gray, contrast, CV_32F);
            contrast = abs(contrast);
180

181 182 183 184 185 186 187 188 189 190
            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);
Fedor Morozov's avatar
Fedor Morozov committed
191 192 193
                saturation += deviation;
            }
            sqrt(saturation, saturation);
194

195 196 197 198 199
            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;
Fedor Morozov's avatar
Fedor Morozov committed
200 201
                wellexp = wellexp.mul(exp);
            }
202

Fedor Morozov's avatar
Fedor Morozov committed
203 204 205
            pow(contrast, wcon, contrast);
            pow(saturation, wsat, saturation);
            pow(wellexp, wexp, wellexp);
206

207 208 209 210
            weights[i] = contrast;
            if(channels == 3) {
                weights[i] = weights[i].mul(saturation);
            }
211
            weights[i] = weights[i].mul(wellexp) + 1e-12f;
212
            weight_sum += weights[i];
Fedor Morozov's avatar
Fedor Morozov committed
213
        }
214
        int maxlevel = static_cast<int>(logf(static_cast<float>(min(size.width, size.height))) / logf(2.0f));
Fedor Morozov's avatar
Fedor Morozov committed
215
        std::vector<Mat> res_pyr(maxlevel + 1);
216

217 218
        for(size_t i = 0; i < images.size(); i++) {
            weights[i] /= weight_sum;
Fedor Morozov's avatar
Fedor Morozov committed
219
            Mat img;
220
            images[i].convertTo(img, CV_32F, 1.0f/255.0f);
221

Fedor Morozov's avatar
Fedor Morozov committed
222 223
            std::vector<Mat> img_pyr, weight_pyr;
            buildPyramid(img, img_pyr, maxlevel);
224 225
            buildPyramid(weights[i], weight_pyr, maxlevel);

Fedor Morozov's avatar
Fedor Morozov committed
226 227 228 229 230 231
            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++) {
232 233 234 235
                std::vector<Mat> splitted(channels);
                split(img_pyr[lvl], splitted);
                for(int c = 0; c < channels; c++) {
                    splitted[c] = splitted[c].mul(weight_pyr[lvl]);
Fedor Morozov's avatar
Fedor Morozov committed
236
                }
237
                merge(splitted, img_pyr[lvl]);
Fedor Morozov's avatar
Fedor Morozov committed
238 239 240 241 242 243 244 245 246 247 248 249
                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;
        }
250
        dst.create(size, CV_32FCC);
Fedor Morozov's avatar
Fedor Morozov committed
251 252
        res_pyr[0].copyTo(dst.getMat());
    }
253

Fedor Morozov's avatar
Fedor Morozov committed
254 255
    float getContrastWeight() const { return wcon; }
    void setContrastWeight(float val) { wcon = val; }
256

Fedor Morozov's avatar
Fedor Morozov committed
257 258
    float getSaturationWeight() const { return wsat; }
    void setSaturationWeight(float val) { wsat = val; }
259

Fedor Morozov's avatar
Fedor Morozov committed
260 261
    float getExposureWeight() const { return wexp; }
    void setExposureWeight(float val) { wexp = val; }
262

Fedor Morozov's avatar
Fedor Morozov committed
263
    void write(FileStorage& fs) const
264 265
    {
        fs << "name" << name
Fedor Morozov's avatar
Fedor Morozov committed
266 267 268
           << "contrast_weight" << wcon
           << "saturation_weight" << wsat
           << "exposure_weight" << wexp;
269 270 271 272 273 274 275
    }

    void read(const FileNode& fn)
    {
        FileNode n = fn["name"];
        CV_Assert(n.isString() && String(n) == name);
        wcon = fn["contrast_weight"];
Fedor Morozov's avatar
Fedor Morozov committed
276 277
        wsat = fn["saturation_weight"];
        wexp = fn["exposure_weight"];
278 279 280
    }

protected:
Fedor Morozov's avatar
Fedor Morozov committed
281 282
    String name;
    float wcon, wsat, wexp;
283 284 285 286
};

Ptr<MergeMertens> createMergeMertens(float wcon, float wsat, float wexp)
{
287
    return makePtr<MergeMertensImpl>(wcon, wsat, wexp);
288 289
}

Fedor Morozov's avatar
Fedor Morozov committed
290 291 292 293 294 295 296 297
class MergeRobertsonImpl : public MergeRobertson
{
public:
    MergeRobertsonImpl() :
        name("MergeRobertson"),
        weight(RobertsonWeights())
    {
    }
298 299

    void process(InputArrayOfArrays src, OutputArray dst, InputArray _times, InputArray input_response)
Fedor Morozov's avatar
Fedor Morozov committed
300 301 302
    {
        std::vector<Mat> images;
        src.getMatVector(images);
303
        Mat times = _times.getMat();
Fedor Morozov's avatar
Fedor Morozov committed
304

305
        CV_Assert(images.size() == times.total());
Fedor Morozov's avatar
Fedor Morozov committed
306 307 308 309 310 311 312 313 314 315 316
        checkImageDimensions(images);
        CV_Assert(images[0].depth() == CV_8U);

        int channels = images[0].channels();
        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()) {
317 318
            float middle = LDR_SIZE / 2.0f;
            response = linearResponse(channels) / middle;
Fedor Morozov's avatar
Fedor Morozov committed
319
        }
320
        CV_Assert(response.rows == LDR_SIZE && response.cols == 1 &&
Fedor Morozov's avatar
Fedor Morozov committed
321
                  response.channels() == channels);
322

Fedor Morozov's avatar
Fedor Morozov committed
323 324 325 326 327 328 329
        result = Mat::zeros(images[0].size(), CV_32FCC);
        Mat wsum = Mat::zeros(images[0].size(), CV_32FCC);
        for(size_t i = 0; i < images.size(); i++) {
            Mat im, w;
            LUT(images[i], weight, w);
            LUT(images[i], response, im);

Ilya Lavrenov's avatar
Ilya Lavrenov committed
330 331
            result += times.at<float>((int)i) * w.mul(im);
            wsum += times.at<float>((int)i) * times.at<float>((int)i) * w;
Fedor Morozov's avatar
Fedor Morozov committed
332 333 334 335
        }
        result = result.mul(1 / wsum);
    }

336
    void process(InputArrayOfArrays src, OutputArray dst, InputArray times)
Fedor Morozov's avatar
Fedor Morozov committed
337 338 339 340 341 342 343 344 345 346 347
    {
        process(src, dst, times, Mat());
    }

protected:
    String name;
    Mat weight;
};

Ptr<MergeRobertson> createMergeRobertson()
{
348
    return makePtr<MergeRobertsonImpl>();
Fedor Morozov's avatar
Fedor Morozov committed
349 350
}

351
}