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