Home | History | Annotate | Download | only in src
      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) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 #include "precomp.hpp"
     44 #include "opencv2/photo.hpp"
     45 #include "opencv2/imgproc.hpp"
     46 //#include "opencv2/highgui.hpp"
     47 #include "hdr_common.hpp"
     48 
     49 namespace cv
     50 {
     51 
     52 class CalibrateDebevecImpl : public CalibrateDebevec
     53 {
     54 public:
     55     CalibrateDebevecImpl(int _samples, float _lambda, bool _random) :
     56         name("CalibrateDebevec"),
     57         samples(_samples),
     58         lambda(_lambda),
     59         random(_random),
     60         w(tringleWeights())
     61     {
     62     }
     63 
     64     void process(InputArrayOfArrays src, OutputArray dst, InputArray _times)
     65     {
     66         std::vector<Mat> images;
     67         src.getMatVector(images);
     68         Mat times = _times.getMat();
     69 
     70         CV_Assert(images.size() == times.total());
     71         checkImageDimensions(images);
     72         CV_Assert(images[0].depth() == CV_8U);
     73 
     74         int channels = images[0].channels();
     75         int CV_32FCC = CV_MAKETYPE(CV_32F, channels);
     76 
     77         dst.create(LDR_SIZE, 1, CV_32FCC);
     78         Mat result = dst.getMat();
     79 
     80         std::vector<Point> sample_points;
     81         if(random) {
     82             for(int i = 0; i < samples; i++) {
     83                 sample_points.push_back(Point(rand() % images[0].cols, rand() % images[0].rows));
     84             }
     85         } else {
     86             int x_points = static_cast<int>(sqrt(static_cast<double>(samples) * images[0].cols / images[0].rows));
     87             int y_points = samples / x_points;
     88             int step_x = images[0].cols / x_points;
     89             int step_y = images[0].rows / y_points;
     90 
     91             for(int i = 0, x = step_x / 2; i < x_points; i++, x += step_x) {
     92                 for(int j = 0, y = step_y / 2; j < y_points; j++, y += step_y) {
     93                     if( 0 <= x && x < images[0].cols &&
     94                         0 <= y && y < images[0].rows )
     95                         sample_points.push_back(Point(x, y));
     96                 }
     97             }
     98         }
     99 
    100         std::vector<Mat> result_split(channels);
    101         for(int channel = 0; channel < channels; channel++) {
    102             Mat A = Mat::zeros((int)sample_points.size() * (int)images.size() + LDR_SIZE + 1, LDR_SIZE + (int)sample_points.size(), CV_32F);
    103             Mat B = Mat::zeros(A.rows, 1, CV_32F);
    104 
    105             int eq = 0;
    106             for(size_t i = 0; i < sample_points.size(); i++) {
    107                 for(size_t j = 0; j < images.size(); j++) {
    108 
    109                     int val = images[j].ptr()[3*(sample_points[i].y * images[j].cols + sample_points[i].x) + channel];
    110                     A.at<float>(eq, val) = w.at<float>(val);
    111                     A.at<float>(eq, LDR_SIZE + (int)i) = -w.at<float>(val);
    112                     B.at<float>(eq, 0) = w.at<float>(val) * log(times.at<float>((int)j));
    113                     eq++;
    114                 }
    115             }
    116             A.at<float>(eq, LDR_SIZE / 2) = 1;
    117             eq++;
    118 
    119             for(int i = 0; i < 254; i++) {
    120                 A.at<float>(eq, i) = lambda * w.at<float>(i + 1);
    121                 A.at<float>(eq, i + 1) = -2 * lambda * w.at<float>(i + 1);
    122                 A.at<float>(eq, i + 2) = lambda * w.at<float>(i + 1);
    123                 eq++;
    124             }
    125             Mat solution;
    126             solve(A, B, solution, DECOMP_SVD);
    127             solution.rowRange(0, LDR_SIZE).copyTo(result_split[channel]);
    128         }
    129         merge(result_split, result);
    130         exp(result, result);
    131     }
    132 
    133     int getSamples() const { return samples; }
    134     void setSamples(int val) { samples = val; }
    135 
    136     float getLambda() const { return lambda; }
    137     void setLambda(float val) { lambda = val; }
    138 
    139     bool getRandom() const { return random; }
    140     void setRandom(bool val) { random = val; }
    141 
    142     void write(FileStorage& fs) const
    143     {
    144         fs << "name" << name
    145            << "samples" << samples
    146            << "lambda" << lambda
    147            << "random" << static_cast<int>(random);
    148     }
    149 
    150     void read(const FileNode& fn)
    151     {
    152         FileNode n = fn["name"];
    153         CV_Assert(n.isString() && String(n) == name);
    154         samples = fn["samples"];
    155         lambda = fn["lambda"];
    156         int random_val = fn["random"];
    157         random = (random_val != 0);
    158     }
    159 
    160 protected:
    161     String name;
    162     int samples;
    163     float lambda;
    164     bool random;
    165     Mat w;
    166 };
    167 
    168 Ptr<CalibrateDebevec> createCalibrateDebevec(int samples, float lambda, bool random)
    169 {
    170     return makePtr<CalibrateDebevecImpl>(samples, lambda, random);
    171 }
    172 
    173 class CalibrateRobertsonImpl : public CalibrateRobertson
    174 {
    175 public:
    176     CalibrateRobertsonImpl(int _max_iter, float _threshold) :
    177         name("CalibrateRobertson"),
    178         max_iter(_max_iter),
    179         threshold(_threshold),
    180         weight(RobertsonWeights())
    181     {
    182     }
    183 
    184     void process(InputArrayOfArrays src, OutputArray dst, InputArray _times)
    185     {
    186         std::vector<Mat> images;
    187         src.getMatVector(images);
    188         Mat times = _times.getMat();
    189 
    190         CV_Assert(images.size() == times.total());
    191         checkImageDimensions(images);
    192         CV_Assert(images[0].depth() == CV_8U);
    193 
    194         int channels = images[0].channels();
    195         int CV_32FCC = CV_MAKETYPE(CV_32F, channels);
    196 
    197         dst.create(LDR_SIZE, 1, CV_32FCC);
    198         Mat response = dst.getMat();
    199         response = linearResponse(3) / (LDR_SIZE / 2.0f);
    200 
    201         Mat card = Mat::zeros(LDR_SIZE, 1, CV_32FCC);
    202         for(size_t i = 0; i < images.size(); i++) {
    203            uchar *ptr = images[i].ptr();
    204            for(size_t pos = 0; pos < images[i].total(); pos++) {
    205                for(int c = 0; c < channels; c++, ptr++) {
    206                    card.at<Vec3f>(*ptr)[c] += 1;
    207                }
    208            }
    209         }
    210         card = 1.0 / card;
    211 
    212         Ptr<MergeRobertson> merge = createMergeRobertson();
    213         for(int iter = 0; iter < max_iter; iter++) {
    214 
    215             radiance = Mat::zeros(images[0].size(), CV_32FCC);
    216             merge->process(images, radiance, times, response);
    217 
    218             Mat new_response = Mat::zeros(LDR_SIZE, 1, CV_32FC3);
    219             for(size_t i = 0; i < images.size(); i++) {
    220                 uchar *ptr = images[i].ptr();
    221                 float* rad_ptr = radiance.ptr<float>();
    222                 for(size_t pos = 0; pos < images[i].total(); pos++) {
    223                     for(int c = 0; c < channels; c++, ptr++, rad_ptr++) {
    224                         new_response.at<Vec3f>(*ptr)[c] += times.at<float>((int)i) * *rad_ptr;
    225                     }
    226                 }
    227             }
    228             new_response = new_response.mul(card);
    229             for(int c = 0; c < 3; c++) {
    230                 float middle = new_response.at<Vec3f>(LDR_SIZE / 2)[c];
    231                 for(int i = 0; i < LDR_SIZE; i++) {
    232                     new_response.at<Vec3f>(i)[c] /= middle;
    233                 }
    234             }
    235             float diff = static_cast<float>(sum(sum(abs(new_response - response)))[0] / channels);
    236             new_response.copyTo(response);
    237             if(diff < threshold) {
    238                 break;
    239             }
    240         }
    241     }
    242 
    243     int getMaxIter() const { return max_iter; }
    244     void setMaxIter(int val) { max_iter = val; }
    245 
    246     float getThreshold() const { return threshold; }
    247     void setThreshold(float val) { threshold = val; }
    248 
    249     Mat getRadiance() const { return radiance; }
    250 
    251     void write(FileStorage& fs) const
    252     {
    253         fs << "name" << name
    254            << "max_iter" << max_iter
    255            << "threshold" << threshold;
    256     }
    257 
    258     void read(const FileNode& fn)
    259     {
    260         FileNode n = fn["name"];
    261         CV_Assert(n.isString() && String(n) == name);
    262         max_iter = fn["max_iter"];
    263         threshold = fn["threshold"];
    264     }
    265 
    266 protected:
    267     String name;
    268     int max_iter;
    269     float threshold;
    270     Mat weight, radiance;
    271 };
    272 
    273 Ptr<CalibrateRobertson> createCalibrateRobertson(int max_iter, float threshold)
    274 {
    275     return makePtr<CalibrateRobertsonImpl>(max_iter, threshold);
    276 }
    277 
    278 }
    279