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 45 namespace cv { 46 namespace detail { 47 48 Ptr<ExposureCompensator> ExposureCompensator::createDefault(int type) 49 { 50 if (type == NO) 51 return makePtr<NoExposureCompensator>(); 52 if (type == GAIN) 53 return makePtr<GainCompensator>(); 54 if (type == GAIN_BLOCKS) 55 return makePtr<BlocksGainCompensator>(); 56 CV_Error(Error::StsBadArg, "unsupported exposure compensation method"); 57 return Ptr<ExposureCompensator>(); 58 } 59 60 61 void ExposureCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images, 62 const std::vector<UMat> &masks) 63 { 64 std::vector<std::pair<UMat,uchar> > level_masks; 65 for (size_t i = 0; i < masks.size(); ++i) 66 level_masks.push_back(std::make_pair(masks[i], 255)); 67 feed(corners, images, level_masks); 68 } 69 70 71 void GainCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images, 72 const std::vector<std::pair<UMat,uchar> > &masks) 73 { 74 LOGLN("Exposure compensation..."); 75 #if ENABLE_LOG 76 int64 t = getTickCount(); 77 #endif 78 79 CV_Assert(corners.size() == images.size() && images.size() == masks.size()); 80 81 const int num_images = static_cast<int>(images.size()); 82 Mat_<int> N(num_images, num_images); N.setTo(0); 83 Mat_<double> I(num_images, num_images); I.setTo(0); 84 85 //Rect dst_roi = resultRoi(corners, images); 86 Mat subimg1, subimg2; 87 Mat_<uchar> submask1, submask2, intersect; 88 89 for (int i = 0; i < num_images; ++i) 90 { 91 for (int j = i; j < num_images; ++j) 92 { 93 Rect roi; 94 if (overlapRoi(corners[i], corners[j], images[i].size(), images[j].size(), roi)) 95 { 96 subimg1 = images[i](Rect(roi.tl() - corners[i], roi.br() - corners[i])).getMat(ACCESS_READ); 97 subimg2 = images[j](Rect(roi.tl() - corners[j], roi.br() - corners[j])).getMat(ACCESS_READ); 98 99 submask1 = masks[i].first(Rect(roi.tl() - corners[i], roi.br() - corners[i])).getMat(ACCESS_READ); 100 submask2 = masks[j].first(Rect(roi.tl() - corners[j], roi.br() - corners[j])).getMat(ACCESS_READ); 101 intersect = (submask1 == masks[i].second) & (submask2 == masks[j].second); 102 103 N(i, j) = N(j, i) = std::max(1, countNonZero(intersect)); 104 105 double Isum1 = 0, Isum2 = 0; 106 for (int y = 0; y < roi.height; ++y) 107 { 108 const Point3_<uchar>* r1 = subimg1.ptr<Point3_<uchar> >(y); 109 const Point3_<uchar>* r2 = subimg2.ptr<Point3_<uchar> >(y); 110 for (int x = 0; x < roi.width; ++x) 111 { 112 if (intersect(y, x)) 113 { 114 Isum1 += std::sqrt(static_cast<double>(sqr(r1[x].x) + sqr(r1[x].y) + sqr(r1[x].z))); 115 Isum2 += std::sqrt(static_cast<double>(sqr(r2[x].x) + sqr(r2[x].y) + sqr(r2[x].z))); 116 } 117 } 118 } 119 I(i, j) = Isum1 / N(i, j); 120 I(j, i) = Isum2 / N(i, j); 121 } 122 } 123 } 124 125 double alpha = 0.01; 126 double beta = 100; 127 128 Mat_<double> A(num_images, num_images); A.setTo(0); 129 Mat_<double> b(num_images, 1); b.setTo(0); 130 for (int i = 0; i < num_images; ++i) 131 { 132 for (int j = 0; j < num_images; ++j) 133 { 134 b(i, 0) += beta * N(i, j); 135 A(i, i) += beta * N(i, j); 136 if (j == i) continue; 137 A(i, i) += 2 * alpha * I(i, j) * I(i, j) * N(i, j); 138 A(i, j) -= 2 * alpha * I(i, j) * I(j, i) * N(i, j); 139 } 140 } 141 142 solve(A, b, gains_); 143 144 LOGLN("Exposure compensation, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); 145 } 146 147 148 void GainCompensator::apply(int index, Point /*corner*/, InputOutputArray image, InputArray /*mask*/) 149 { 150 multiply(image, gains_(index, 0), image); 151 } 152 153 154 std::vector<double> GainCompensator::gains() const 155 { 156 std::vector<double> gains_vec(gains_.rows); 157 for (int i = 0; i < gains_.rows; ++i) 158 gains_vec[i] = gains_(i, 0); 159 return gains_vec; 160 } 161 162 163 void BlocksGainCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images, 164 const std::vector<std::pair<UMat,uchar> > &masks) 165 { 166 CV_Assert(corners.size() == images.size() && images.size() == masks.size()); 167 168 const int num_images = static_cast<int>(images.size()); 169 170 std::vector<Size> bl_per_imgs(num_images); 171 std::vector<Point> block_corners; 172 std::vector<UMat> block_images; 173 std::vector<std::pair<UMat,uchar> > block_masks; 174 175 // Construct blocks for gain compensator 176 for (int img_idx = 0; img_idx < num_images; ++img_idx) 177 { 178 Size bl_per_img((images[img_idx].cols + bl_width_ - 1) / bl_width_, 179 (images[img_idx].rows + bl_height_ - 1) / bl_height_); 180 int bl_width = (images[img_idx].cols + bl_per_img.width - 1) / bl_per_img.width; 181 int bl_height = (images[img_idx].rows + bl_per_img.height - 1) / bl_per_img.height; 182 bl_per_imgs[img_idx] = bl_per_img; 183 for (int by = 0; by < bl_per_img.height; ++by) 184 { 185 for (int bx = 0; bx < bl_per_img.width; ++bx) 186 { 187 Point bl_tl(bx * bl_width, by * bl_height); 188 Point bl_br(std::min(bl_tl.x + bl_width, images[img_idx].cols), 189 std::min(bl_tl.y + bl_height, images[img_idx].rows)); 190 191 block_corners.push_back(corners[img_idx] + bl_tl); 192 block_images.push_back(images[img_idx](Rect(bl_tl, bl_br))); 193 block_masks.push_back(std::make_pair(masks[img_idx].first(Rect(bl_tl, bl_br)), 194 masks[img_idx].second)); 195 } 196 } 197 } 198 199 GainCompensator compensator; 200 compensator.feed(block_corners, block_images, block_masks); 201 std::vector<double> gains = compensator.gains(); 202 gain_maps_.resize(num_images); 203 204 Mat_<float> ker(1, 3); 205 ker(0,0) = 0.25; ker(0,1) = 0.5; ker(0,2) = 0.25; 206 207 int bl_idx = 0; 208 for (int img_idx = 0; img_idx < num_images; ++img_idx) 209 { 210 Size bl_per_img = bl_per_imgs[img_idx]; 211 gain_maps_[img_idx].create(bl_per_img, CV_32F); 212 213 { 214 Mat_<float> gain_map = gain_maps_[img_idx].getMat(ACCESS_WRITE); 215 for (int by = 0; by < bl_per_img.height; ++by) 216 for (int bx = 0; bx < bl_per_img.width; ++bx, ++bl_idx) 217 gain_map(by, bx) = static_cast<float>(gains[bl_idx]); 218 } 219 220 sepFilter2D(gain_maps_[img_idx], gain_maps_[img_idx], CV_32F, ker, ker); 221 sepFilter2D(gain_maps_[img_idx], gain_maps_[img_idx], CV_32F, ker, ker); 222 } 223 } 224 225 226 void BlocksGainCompensator::apply(int index, Point /*corner*/, InputOutputArray _image, InputArray /*mask*/) 227 { 228 CV_Assert(_image.type() == CV_8UC3); 229 230 UMat u_gain_map; 231 if (gain_maps_[index].size() == _image.size()) 232 u_gain_map = gain_maps_[index]; 233 else 234 resize(gain_maps_[index], u_gain_map, _image.size(), 0, 0, INTER_LINEAR); 235 236 Mat_<float> gain_map = u_gain_map.getMat(ACCESS_READ); 237 Mat image = _image.getMat(); 238 for (int y = 0; y < image.rows; ++y) 239 { 240 const float* gain_row = gain_map.ptr<float>(y); 241 Point3_<uchar>* row = image.ptr<Point3_<uchar> >(y); 242 for (int x = 0; x < image.cols; ++x) 243 { 244 row[x].x = saturate_cast<uchar>(row[x].x * gain_row[x]); 245 row[x].y = saturate_cast<uchar>(row[x].y * gain_row[x]); 246 row[x].z = saturate_cast<uchar>(row[x].z * gain_row[x]); 247 } 248 } 249 } 250 251 } // namespace detail 252 } // namespace cv 253