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) 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 class AlignMTBImpl : public AlignMTB
     51 {
     52 public:
     53     AlignMTBImpl(int _max_bits, int _exclude_range, bool _cut) :
     54         name("AlignMTB"),
     55         max_bits(_max_bits),
     56         exclude_range(_exclude_range),
     57         cut(_cut)
     58     {
     59     }
     60 
     61     void process(InputArrayOfArrays src, std::vector<Mat>& dst,
     62                  InputArray, InputArray)
     63     {
     64         process(src, dst);
     65     }
     66 
     67     void process(InputArrayOfArrays _src, std::vector<Mat>& dst)
     68     {
     69         std::vector<Mat> src;
     70         _src.getMatVector(src);
     71 
     72         checkImageDimensions(src);
     73         dst.resize(src.size());
     74 
     75         size_t pivot = src.size() / 2;
     76         dst[pivot] = src[pivot];
     77         Mat gray_base;
     78         cvtColor(src[pivot], gray_base, COLOR_RGB2GRAY);
     79         std::vector<Point> shifts;
     80 
     81         for(size_t i = 0; i < src.size(); i++) {
     82             if(i == pivot) {
     83                 shifts.push_back(Point(0, 0));
     84                 continue;
     85             }
     86             Mat gray;
     87             cvtColor(src[i], gray, COLOR_RGB2GRAY);
     88             Point shift = calculateShift(gray_base, gray);
     89             shifts.push_back(shift);
     90             shiftMat(src[i], dst[i], shift);
     91         }
     92         if(cut) {
     93             Point max(0, 0), min(0, 0);
     94             for(size_t i = 0; i < shifts.size(); i++) {
     95                 if(shifts[i].x > max.x) {
     96                     max.x = shifts[i].x;
     97                 }
     98                 if(shifts[i].y > max.y) {
     99                     max.y = shifts[i].y;
    100                 }
    101                 if(shifts[i].x < min.x) {
    102                     min.x = shifts[i].x;
    103                 }
    104                 if(shifts[i].y < min.y) {
    105                     min.y = shifts[i].y;
    106                 }
    107             }
    108             Point size = dst[0].size();
    109             for(size_t i = 0; i < dst.size(); i++) {
    110                 dst[i] = dst[i](Rect(max, min + size));
    111             }
    112         }
    113     }
    114 
    115     Point calculateShift(InputArray _img0, InputArray _img1)
    116     {
    117         Mat img0 = _img0.getMat();
    118         Mat img1 = _img1.getMat();
    119         CV_Assert(img0.channels() == 1 && img0.type() == img1.type());
    120         CV_Assert(img0.size() == img0.size());
    121 
    122         int maxlevel = static_cast<int>(log((double)max(img0.rows, img0.cols)) / log(2.0)) - 1;
    123         maxlevel = min(maxlevel, max_bits - 1);
    124 
    125         std::vector<Mat> pyr0;
    126         std::vector<Mat> pyr1;
    127         buildPyr(img0, pyr0, maxlevel);
    128         buildPyr(img1, pyr1, maxlevel);
    129 
    130         Point shift(0, 0);
    131         for(int level = maxlevel; level >= 0; level--) {
    132 
    133             shift *= 2;
    134             Mat tb1, tb2, eb1, eb2;
    135             computeBitmaps(pyr0[level], tb1, eb1);
    136             computeBitmaps(pyr1[level], tb2, eb2);
    137 
    138             int min_err = (int)pyr0[level].total();
    139             Point new_shift(shift);
    140             for(int i = -1; i <= 1; i++) {
    141                 for(int j = -1; j <= 1; j++) {
    142                     Point test_shift = shift + Point(i, j);
    143                     Mat shifted_tb2, shifted_eb2, diff;
    144                     shiftMat(tb2, shifted_tb2, test_shift);
    145                     shiftMat(eb2, shifted_eb2, test_shift);
    146                     bitwise_xor(tb1, shifted_tb2, diff);
    147                     bitwise_and(diff, eb1, diff);
    148                     bitwise_and(diff, shifted_eb2, diff);
    149                     int err = countNonZero(diff);
    150                     if(err < min_err) {
    151                         new_shift = test_shift;
    152                         min_err = err;
    153                     }
    154                 }
    155             }
    156             shift = new_shift;
    157         }
    158         return shift;
    159     }
    160 
    161     void shiftMat(InputArray _src, OutputArray _dst, const Point shift)
    162     {
    163         Mat src = _src.getMat();
    164         _dst.create(src.size(), src.type());
    165         Mat dst = _dst.getMat();
    166 
    167         Mat res = Mat::zeros(src.size(), src.type());
    168         int width = src.cols - abs(shift.x);
    169         int height = src.rows - abs(shift.y);
    170         Rect dst_rect(max(shift.x, 0), max(shift.y, 0), width, height);
    171         Rect src_rect(max(-shift.x, 0), max(-shift.y, 0), width, height);
    172         src(src_rect).copyTo(res(dst_rect));
    173         res.copyTo(dst);
    174     }
    175 
    176     int getMaxBits() const { return max_bits; }
    177     void setMaxBits(int val) { max_bits = val; }
    178 
    179     int getExcludeRange() const { return exclude_range; }
    180     void setExcludeRange(int val) { exclude_range = val; }
    181 
    182     bool getCut() const { return cut; }
    183     void setCut(bool val) { cut = val; }
    184 
    185     void write(FileStorage& fs) const
    186     {
    187         fs << "name" << name
    188            << "max_bits" << max_bits
    189            << "exclude_range" << exclude_range
    190            << "cut" << static_cast<int>(cut);
    191     }
    192 
    193     void read(const FileNode& fn)
    194     {
    195         FileNode n = fn["name"];
    196         CV_Assert(n.isString() && String(n) == name);
    197         max_bits = fn["max_bits"];
    198         exclude_range = fn["exclude_range"];
    199         int cut_val = fn["cut"];
    200         cut = (cut_val != 0);
    201     }
    202 
    203     void computeBitmaps(InputArray _img, OutputArray _tb, OutputArray _eb)
    204     {
    205         Mat img = _img.getMat();
    206         _tb.create(img.size(), CV_8U);
    207         _eb.create(img.size(), CV_8U);
    208         Mat tb = _tb.getMat(), eb = _eb.getMat();
    209         int median = getMedian(img);
    210         compare(img, median, tb, CMP_GT);
    211         compare(abs(img - median), exclude_range, eb, CMP_GT);
    212     }
    213 
    214 protected:
    215     String name;
    216     int max_bits, exclude_range;
    217     bool cut;
    218 
    219     void downsample(Mat& src, Mat& dst)
    220     {
    221         dst = Mat(src.rows / 2, src.cols / 2, CV_8UC1);
    222 
    223         int offset = src.cols * 2;
    224         uchar *src_ptr = src.ptr();
    225         uchar *dst_ptr = dst.ptr();
    226         for(int y = 0; y < dst.rows; y ++) {
    227             uchar *ptr = src_ptr;
    228             for(int x = 0; x < dst.cols; x++) {
    229                 dst_ptr[0] = ptr[0];
    230                 dst_ptr++;
    231                 ptr += 2;
    232             }
    233             src_ptr += offset;
    234         }
    235     }
    236 
    237     void buildPyr(Mat& img, std::vector<Mat>& pyr, int maxlevel)
    238     {
    239         pyr.resize(maxlevel + 1);
    240         pyr[0] = img.clone();
    241         for(int level = 0; level < maxlevel; level++) {
    242             downsample(pyr[level], pyr[level + 1]);
    243         }
    244     }
    245 
    246     int getMedian(Mat& img)
    247     {
    248         int channels = 0;
    249         Mat hist;
    250         int hist_size = LDR_SIZE;
    251         float range[] = {0, LDR_SIZE} ;
    252         const float* ranges[] = {range};
    253         calcHist(&img, 1, &channels, Mat(), hist, 1, &hist_size, ranges);
    254         float *ptr = hist.ptr<float>();
    255         int median = 0, sum = 0;
    256         int thresh = (int)img.total() / 2;
    257         while(sum < thresh && median < LDR_SIZE) {
    258             sum += static_cast<int>(ptr[median]);
    259             median++;
    260         }
    261         return median;
    262     }
    263 };
    264 
    265 Ptr<AlignMTB> createAlignMTB(int max_bits, int exclude_range, bool cut)
    266 {
    267     return makePtr<AlignMTBImpl>(max_bits, exclude_range, cut);
    268 }
    269 
    270 }
    271