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 
     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