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