~paparazzi-uav/paparazzi/v5.0-manual

« back to all changes in this revision

Viewing changes to sw/ext/opencv_bebop/opencv/modules/photo/src/tonemap.cpp

  • Committer: Paparazzi buildbot
  • Date: 2016-05-18 15:00:29 UTC
  • Revision ID: felix.ruess+docbot@gmail.com-20160518150029-e8lgzi5kvb4p7un9
Manual import commit 4b8bbb730080dac23cf816b98908dacfabe2a8ec from v5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*M///////////////////////////////////////////////////////////////////////////////////////
 
2
//
 
3
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 
4
//
 
5
//  By downloading, copying, installing or using the software you agree to this license.
 
6
//  If you do not agree to this license, do not download, install,
 
7
//  copy or use the software.
 
8
//
 
9
//
 
10
//                           License Agreement
 
11
//                For Open Source Computer Vision Library
 
12
//
 
13
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
 
14
// Third party copyrights are property of their respective owners.
 
15
//
 
16
// Redistribution and use in source and binary forms, with or without modification,
 
17
// are permitted provided that the following conditions are met:
 
18
//
 
19
//   * Redistribution's of source code must retain the above copyright notice,
 
20
//     this list of conditions and the following disclaimer.
 
21
//
 
22
//   * Redistribution's in binary form must reproduce the above copyright notice,
 
23
//     this list of conditions and the following disclaimer in the documentation
 
24
//     and/or other materials provided with the distribution.
 
25
//
 
26
//   * The name of the copyright holders may not be used to endorse or promote products
 
27
//     derived from this software without specific prior written permission.
 
28
//
 
29
// This software is provided by the copyright holders and contributors "as is" and
 
30
// any express or implied warranties, including, but not limited to, the implied
 
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
 
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
 
33
// indirect, incidental, special, exemplary, or consequential damages
 
34
// (including, but not limited to, procurement of substitute goods or services;
 
35
// loss of use, data, or profits; or business interruption) however caused
 
36
// and on any theory of liability, whether in contract, strict liability,
 
37
// or tort (including negligence or otherwise) arising in any way out of
 
38
// the use of this software, even if advised of the possibility of such damage.
 
39
//
 
40
//M*/
 
41
 
 
42
#include "precomp.hpp"
 
43
#include "opencv2/photo.hpp"
 
44
#include "opencv2/imgproc.hpp"
 
45
#include "hdr_common.hpp"
 
46
 
 
47
namespace cv
 
48
{
 
49
 
 
50
inline void log_(const Mat& src, Mat& dst)
 
51
{
 
52
    max(src, Scalar::all(1e-4), dst);
 
53
    log(dst, dst);
 
54
}
 
55
 
 
56
class TonemapImpl : public Tonemap
 
57
{
 
58
public:
 
59
    TonemapImpl(float _gamma) : name("Tonemap"), gamma(_gamma)
 
60
    {
 
61
    }
 
62
 
 
63
    void process(InputArray _src, OutputArray _dst)
 
64
    {
 
65
        Mat src = _src.getMat();
 
66
        CV_Assert(!src.empty());
 
67
        _dst.create(src.size(), CV_32FC3);
 
68
        Mat dst = _dst.getMat();
 
69
 
 
70
        double min, max;
 
71
        minMaxLoc(src, &min, &max);
 
72
        if(max - min > DBL_EPSILON) {
 
73
            dst = (src - min) / (max - min);
 
74
        } else {
 
75
            src.copyTo(dst);
 
76
        }
 
77
 
 
78
        pow(dst, 1.0f / gamma, dst);
 
79
    }
 
80
 
 
81
    float getGamma() const { return gamma; }
 
82
    void setGamma(float val) { gamma = val; }
 
83
 
 
84
    void write(FileStorage& fs) const
 
85
    {
 
86
        fs << "name" << name
 
87
           << "gamma" << gamma;
 
88
    }
 
89
 
 
90
    void read(const FileNode& fn)
 
91
    {
 
92
        FileNode n = fn["name"];
 
93
        CV_Assert(n.isString() && String(n) == name);
 
94
        gamma = fn["gamma"];
 
95
    }
 
96
 
 
97
protected:
 
98
    String name;
 
99
    float gamma;
 
100
};
 
101
 
 
102
Ptr<Tonemap> createTonemap(float gamma)
 
103
{
 
104
    return makePtr<TonemapImpl>(gamma);
 
105
}
 
106
 
 
107
class TonemapDragoImpl : public TonemapDrago
 
108
{
 
109
public:
 
110
    TonemapDragoImpl(float _gamma, float _saturation, float _bias) :
 
111
        name("TonemapDrago"),
 
112
        gamma(_gamma),
 
113
        saturation(_saturation),
 
114
        bias(_bias)
 
115
    {
 
116
    }
 
117
 
 
118
    void process(InputArray _src, OutputArray _dst)
 
119
    {
 
120
        Mat src = _src.getMat();
 
121
        CV_Assert(!src.empty());
 
122
        _dst.create(src.size(), CV_32FC3);
 
123
        Mat img = _dst.getMat();
 
124
 
 
125
        Ptr<Tonemap> linear = createTonemap(1.0f);
 
126
        linear->process(src, img);
 
127
 
 
128
        Mat gray_img;
 
129
        cvtColor(img, gray_img, COLOR_RGB2GRAY);
 
130
        Mat log_img;
 
131
        log_(gray_img, log_img);
 
132
        float mean = expf(static_cast<float>(sum(log_img)[0]) / log_img.total());
 
133
        gray_img /= mean;
 
134
        log_img.release();
 
135
 
 
136
        double max;
 
137
        minMaxLoc(gray_img, NULL, &max);
 
138
 
 
139
        Mat map;
 
140
        log(gray_img + 1.0f, map);
 
141
        Mat div;
 
142
        pow(gray_img / static_cast<float>(max), logf(bias) / logf(0.5f), div);
 
143
        log(2.0f + 8.0f * div, div);
 
144
        map = map.mul(1.0f / div);
 
145
        div.release();
 
146
 
 
147
        mapLuminance(img, img, gray_img, map, saturation);
 
148
 
 
149
        linear->setGamma(gamma);
 
150
        linear->process(img, img);
 
151
    }
 
152
 
 
153
    float getGamma() const { return gamma; }
 
154
    void setGamma(float val) { gamma = val; }
 
155
 
 
156
    float getSaturation() const { return saturation; }
 
157
    void setSaturation(float val) { saturation = val; }
 
158
 
 
159
    float getBias() const { return bias; }
 
160
    void setBias(float val) { bias = val; }
 
161
 
 
162
    void write(FileStorage& fs) const
 
163
    {
 
164
        fs << "name" << name
 
165
           << "gamma" << gamma
 
166
           << "bias" << bias
 
167
           << "saturation" << saturation;
 
168
    }
 
169
 
 
170
    void read(const FileNode& fn)
 
171
    {
 
172
        FileNode n = fn["name"];
 
173
        CV_Assert(n.isString() && String(n) == name);
 
174
        gamma = fn["gamma"];
 
175
        bias = fn["bias"];
 
176
        saturation = fn["saturation"];
 
177
    }
 
178
 
 
179
protected:
 
180
    String name;
 
181
    float gamma, saturation, bias;
 
182
};
 
183
 
 
184
Ptr<TonemapDrago> createTonemapDrago(float gamma, float saturation, float bias)
 
185
{
 
186
    return makePtr<TonemapDragoImpl>(gamma, saturation, bias);
 
187
}
 
188
 
 
189
class TonemapDurandImpl : public TonemapDurand
 
190
{
 
191
public:
 
192
    TonemapDurandImpl(float _gamma, float _contrast, float _saturation, float _sigma_color, float _sigma_space) :
 
193
        name("TonemapDurand"),
 
194
        gamma(_gamma),
 
195
        contrast(_contrast),
 
196
        saturation(_saturation),
 
197
        sigma_color(_sigma_color),
 
198
        sigma_space(_sigma_space)
 
199
    {
 
200
    }
 
201
 
 
202
    void process(InputArray _src, OutputArray _dst)
 
203
    {
 
204
        Mat src = _src.getMat();
 
205
        CV_Assert(!src.empty());
 
206
        _dst.create(src.size(), CV_32FC3);
 
207
        Mat img = _dst.getMat();
 
208
        Ptr<Tonemap> linear = createTonemap(1.0f);
 
209
        linear->process(src, img);
 
210
 
 
211
        Mat gray_img;
 
212
        cvtColor(img, gray_img, COLOR_RGB2GRAY);
 
213
        Mat log_img;
 
214
        log_(gray_img, log_img);
 
215
        Mat map_img;
 
216
        bilateralFilter(log_img, map_img, -1, sigma_color, sigma_space);
 
217
 
 
218
        double min, max;
 
219
        minMaxLoc(map_img, &min, &max);
 
220
        float scale = contrast / static_cast<float>(max - min);
 
221
        exp(map_img * (scale - 1.0f) + log_img, map_img);
 
222
        log_img.release();
 
223
 
 
224
        mapLuminance(img, img, gray_img, map_img, saturation);
 
225
        pow(img, 1.0f / gamma, img);
 
226
    }
 
227
 
 
228
    float getGamma() const { return gamma; }
 
229
    void setGamma(float val) { gamma = val; }
 
230
 
 
231
    float getSaturation() const { return saturation; }
 
232
    void setSaturation(float val) { saturation = val; }
 
233
 
 
234
    float getContrast() const { return contrast; }
 
235
    void setContrast(float val) { contrast = val; }
 
236
 
 
237
    float getSigmaColor() const { return sigma_color; }
 
238
    void setSigmaColor(float val) { sigma_color = val; }
 
239
 
 
240
    float getSigmaSpace() const { return sigma_space; }
 
241
    void setSigmaSpace(float val) { sigma_space = val; }
 
242
 
 
243
    void write(FileStorage& fs) const
 
244
    {
 
245
        fs << "name" << name
 
246
           << "gamma" << gamma
 
247
           << "contrast" << contrast
 
248
           << "sigma_color" << sigma_color
 
249
           << "sigma_space" << sigma_space
 
250
           << "saturation" << saturation;
 
251
    }
 
252
 
 
253
    void read(const FileNode& fn)
 
254
    {
 
255
        FileNode n = fn["name"];
 
256
        CV_Assert(n.isString() && String(n) == name);
 
257
        gamma = fn["gamma"];
 
258
        contrast = fn["contrast"];
 
259
        sigma_color = fn["sigma_color"];
 
260
        sigma_space = fn["sigma_space"];
 
261
        saturation = fn["saturation"];
 
262
    }
 
263
 
 
264
protected:
 
265
    String name;
 
266
    float gamma, contrast, saturation, sigma_color, sigma_space;
 
267
};
 
268
 
 
269
Ptr<TonemapDurand> createTonemapDurand(float gamma, float contrast, float saturation, float sigma_color, float sigma_space)
 
270
{
 
271
    return makePtr<TonemapDurandImpl>(gamma, contrast, saturation, sigma_color, sigma_space);
 
272
}
 
273
 
 
274
class TonemapReinhardImpl : public TonemapReinhard
 
275
{
 
276
public:
 
277
    TonemapReinhardImpl(float _gamma, float _intensity, float _light_adapt, float _color_adapt) :
 
278
        name("TonemapReinhard"),
 
279
        gamma(_gamma),
 
280
        intensity(_intensity),
 
281
        light_adapt(_light_adapt),
 
282
        color_adapt(_color_adapt)
 
283
    {
 
284
    }
 
285
 
 
286
    void process(InputArray _src, OutputArray _dst)
 
287
    {
 
288
        Mat src = _src.getMat();
 
289
        CV_Assert(!src.empty());
 
290
        _dst.create(src.size(), CV_32FC3);
 
291
        Mat img = _dst.getMat();
 
292
        Ptr<Tonemap> linear = createTonemap(1.0f);
 
293
        linear->process(src, img);
 
294
 
 
295
        Mat gray_img;
 
296
        cvtColor(img, gray_img, COLOR_RGB2GRAY);
 
297
        Mat log_img;
 
298
        log_(gray_img, log_img);
 
299
 
 
300
        float log_mean = static_cast<float>(sum(log_img)[0] / log_img.total());
 
301
        double log_min, log_max;
 
302
        minMaxLoc(log_img, &log_min, &log_max);
 
303
        log_img.release();
 
304
 
 
305
        double key = static_cast<float>((log_max - log_mean) / (log_max - log_min));
 
306
        float map_key = 0.3f + 0.7f * pow(static_cast<float>(key), 1.4f);
 
307
        intensity = exp(-intensity);
 
308
        Scalar chan_mean = mean(img);
 
309
        float gray_mean = static_cast<float>(mean(gray_img)[0]);
 
310
 
 
311
        std::vector<Mat> channels(3);
 
312
        split(img, channels);
 
313
 
 
314
        for(int i = 0; i < 3; i++) {
 
315
            float global = color_adapt * static_cast<float>(chan_mean[i]) + (1.0f - color_adapt) * gray_mean;
 
316
            Mat adapt = color_adapt * channels[i] + (1.0f - color_adapt) * gray_img;
 
317
            adapt = light_adapt * adapt + (1.0f - light_adapt) * global;
 
318
            pow(intensity * adapt, map_key, adapt);
 
319
            channels[i] = channels[i].mul(1.0f / (adapt + channels[i]));
 
320
        }
 
321
        gray_img.release();
 
322
        merge(channels, img);
 
323
 
 
324
        linear->setGamma(gamma);
 
325
        linear->process(img, img);
 
326
    }
 
327
 
 
328
    float getGamma() const { return gamma; }
 
329
    void setGamma(float val) { gamma = val; }
 
330
 
 
331
    float getIntensity() const { return intensity; }
 
332
    void setIntensity(float val) { intensity = val; }
 
333
 
 
334
    float getLightAdaptation() const { return light_adapt; }
 
335
    void setLightAdaptation(float val) { light_adapt = val; }
 
336
 
 
337
    float getColorAdaptation() const { return color_adapt; }
 
338
    void setColorAdaptation(float val) { color_adapt = val; }
 
339
 
 
340
    void write(FileStorage& fs) const
 
341
    {
 
342
        fs << "name" << name
 
343
           << "gamma" << gamma
 
344
           << "intensity" << intensity
 
345
           << "light_adapt" << light_adapt
 
346
           << "color_adapt" << color_adapt;
 
347
    }
 
348
 
 
349
    void read(const FileNode& fn)
 
350
    {
 
351
        FileNode n = fn["name"];
 
352
        CV_Assert(n.isString() && String(n) == name);
 
353
        gamma = fn["gamma"];
 
354
        intensity = fn["intensity"];
 
355
        light_adapt = fn["light_adapt"];
 
356
        color_adapt = fn["color_adapt"];
 
357
    }
 
358
 
 
359
protected:
 
360
    String name;
 
361
    float gamma, intensity, light_adapt, color_adapt;
 
362
};
 
363
 
 
364
Ptr<TonemapReinhard> createTonemapReinhard(float gamma, float contrast, float sigma_color, float sigma_space)
 
365
{
 
366
    return makePtr<TonemapReinhardImpl>(gamma, contrast, sigma_color, sigma_space);
 
367
}
 
368
 
 
369
class TonemapMantiukImpl : public TonemapMantiuk
 
370
{
 
371
public:
 
372
    TonemapMantiukImpl(float _gamma, float _scale, float _saturation) :
 
373
        name("TonemapMantiuk"),
 
374
        gamma(_gamma),
 
375
        scale(_scale),
 
376
        saturation(_saturation)
 
377
    {
 
378
    }
 
379
 
 
380
    void process(InputArray _src, OutputArray _dst)
 
381
    {
 
382
        Mat src = _src.getMat();
 
383
        CV_Assert(!src.empty());
 
384
        _dst.create(src.size(), CV_32FC3);
 
385
        Mat img = _dst.getMat();
 
386
        Ptr<Tonemap> linear = createTonemap(1.0f);
 
387
        linear->process(src, img);
 
388
 
 
389
        Mat gray_img;
 
390
        cvtColor(img, gray_img, COLOR_RGB2GRAY);
 
391
        Mat log_img;
 
392
        log_(gray_img, log_img);
 
393
 
 
394
        std::vector<Mat> x_contrast, y_contrast;
 
395
        getContrast(log_img, x_contrast, y_contrast);
 
396
 
 
397
        for(size_t i = 0; i < x_contrast.size(); i++) {
 
398
            mapContrast(x_contrast[i]);
 
399
            mapContrast(y_contrast[i]);
 
400
        }
 
401
 
 
402
        Mat right(src.size(), CV_32F);
 
403
        calculateSum(x_contrast, y_contrast, right);
 
404
 
 
405
        Mat p, r, product, x = log_img;
 
406
        calculateProduct(x, r);
 
407
        r = right - r;
 
408
        r.copyTo(p);
 
409
 
 
410
        const float target_error = 1e-3f;
 
411
        float target_norm = static_cast<float>(right.dot(right)) * powf(target_error, 2.0f);
 
412
        int max_iterations = 100;
 
413
        float rr = static_cast<float>(r.dot(r));
 
414
 
 
415
        for(int i = 0; i < max_iterations; i++)
 
416
        {
 
417
            calculateProduct(p, product);
 
418
            float alpha = rr / static_cast<float>(p.dot(product));
 
419
 
 
420
            r -= alpha * product;
 
421
            x += alpha * p;
 
422
 
 
423
            float new_rr = static_cast<float>(r.dot(r));
 
424
            p = r + (new_rr / rr) * p;
 
425
            rr = new_rr;
 
426
 
 
427
            if(rr < target_norm) {
 
428
                break;
 
429
            }
 
430
        }
 
431
        exp(x, x);
 
432
        mapLuminance(img, img, gray_img, x, saturation);
 
433
 
 
434
        linear = createTonemap(gamma);
 
435
        linear->process(img, img);
 
436
    }
 
437
 
 
438
    float getGamma() const { return gamma; }
 
439
    void setGamma(float val) { gamma = val; }
 
440
 
 
441
    float getScale() const { return scale; }
 
442
    void setScale(float val) { scale = val; }
 
443
 
 
444
    float getSaturation() const { return saturation; }
 
445
    void setSaturation(float val) { saturation = val; }
 
446
 
 
447
    void write(FileStorage& fs) const
 
448
    {
 
449
        fs << "name" << name
 
450
           << "gamma" << gamma
 
451
           << "scale" << scale
 
452
           << "saturation" << saturation;
 
453
    }
 
454
 
 
455
    void read(const FileNode& fn)
 
456
    {
 
457
        FileNode n = fn["name"];
 
458
        CV_Assert(n.isString() && String(n) == name);
 
459
        gamma = fn["gamma"];
 
460
        scale = fn["scale"];
 
461
        saturation = fn["saturation"];
 
462
    }
 
463
 
 
464
protected:
 
465
    String name;
 
466
    float gamma, scale, saturation;
 
467
 
 
468
    void signedPow(Mat src, float power, Mat& dst)
 
469
    {
 
470
        Mat sign = (src > 0);
 
471
        sign.convertTo(sign, CV_32F, 1.0f/255.0f);
 
472
        sign = sign * 2.0f - 1.0f;
 
473
        pow(abs(src), power, dst);
 
474
        dst = dst.mul(sign);
 
475
    }
 
476
 
 
477
    void mapContrast(Mat& contrast)
 
478
    {
 
479
        const float response_power = 0.4185f;
 
480
        signedPow(contrast, response_power, contrast);
 
481
        contrast *= scale;
 
482
        signedPow(contrast, 1.0f / response_power, contrast);
 
483
    }
 
484
 
 
485
    void getGradient(Mat src, Mat& dst, int pos)
 
486
    {
 
487
        dst = Mat::zeros(src.size(), CV_32F);
 
488
        Mat a, b;
 
489
        Mat grad = src.colRange(1, src.cols) - src.colRange(0, src.cols - 1);
 
490
        grad.copyTo(dst.colRange(pos, src.cols + pos - 1));
 
491
        if(pos == 1) {
 
492
            src.col(0).copyTo(dst.col(0));
 
493
        }
 
494
    }
 
495
 
 
496
    void getContrast(Mat src, std::vector<Mat>& x_contrast, std::vector<Mat>& y_contrast)
 
497
    {
 
498
        int levels = static_cast<int>(logf(static_cast<float>(min(src.rows, src.cols))) / logf(2.0f));
 
499
        x_contrast.resize(levels);
 
500
        y_contrast.resize(levels);
 
501
 
 
502
        Mat layer;
 
503
        src.copyTo(layer);
 
504
        for(int i = 0; i < levels; i++) {
 
505
            getGradient(layer, x_contrast[i], 0);
 
506
            getGradient(layer.t(), y_contrast[i], 0);
 
507
            resize(layer, layer, Size(layer.cols / 2, layer.rows / 2));
 
508
        }
 
509
    }
 
510
 
 
511
    void calculateSum(std::vector<Mat>& x_contrast, std::vector<Mat>& y_contrast, Mat& sum)
 
512
    {
 
513
        if (x_contrast.empty())
 
514
            return;
 
515
        const int last = (int)x_contrast.size() - 1;
 
516
        sum = Mat::zeros(x_contrast[last].size(), CV_32F);
 
517
        for(int i = last; i >= 0; i--)
 
518
        {
 
519
            Mat grad_x, grad_y;
 
520
            getGradient(x_contrast[i], grad_x, 1);
 
521
            getGradient(y_contrast[i], grad_y, 1);
 
522
            resize(sum, sum, x_contrast[i].size());
 
523
            sum += grad_x + grad_y.t();
 
524
        }
 
525
    }
 
526
 
 
527
    void calculateProduct(Mat src, Mat& dst)
 
528
    {
 
529
        std::vector<Mat> x_contrast, y_contrast;
 
530
        getContrast(src, x_contrast, y_contrast);
 
531
        calculateSum(x_contrast, y_contrast, dst);
 
532
    }
 
533
};
 
534
 
 
535
Ptr<TonemapMantiuk> createTonemapMantiuk(float gamma, float scale, float saturation)
 
536
{
 
537
    return makePtr<TonemapMantiukImpl>(gamma, scale, saturation);
 
538
}
 
539
 
 
540
}