image_normalization.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 /*
00030  * image_normalization.cpp
00031  *
00032  *  Created on: Jan 19, 2012
00033  *      Author: kkozak
00034  */
00035 
00036 #include <swri_image_util/image_normalization.h>
00037 
00038 namespace swri_image_util
00039 {
00040   void normalize_illumination(cv::Mat NormImage,
00041                               cv::Mat SourceImage,
00042                               cv::Mat& DestImage)
00043   {
00044     // note that Norm image should be of type CV_32FC1 and scaled between 0 and
00045     // 1 (but not exactly equal to 0 anywhere)
00046     cv::Mat tempIm1;
00047     SourceImage.convertTo(tempIm1, CV_32FC1, 1.0, 0.0);
00048     cv::divide(tempIm1, NormImage, tempIm1, 1.0);
00049     cv::Mat firstImage;
00050     cv::Mat secondImage;
00051     tempIm1.convertTo(DestImage, CV_8UC1);
00052   }
00053 
00054   cv::Mat generate_normalization_image(const std::vector<cv::Mat>& image_list)
00055   {
00056     cv::Mat norm_image;
00057     if (image_list.empty())
00058     {
00059       return cv::Mat();
00060     }
00061 
00062     const cv::Mat& rep_im = image_list.front();
00063 
00064     cv::Mat image_sum(cv::Size(rep_im.cols, rep_im.rows), CV_64F);
00065 
00066     for (uint32_t i = 0; i < image_list.size(); i++)
00067     {
00068       cv::Mat temp_im;
00069       image_list[i].convertTo(temp_im, CV_64F, 1.0, 0.0);
00070 
00071       image_sum = image_sum + temp_im;
00072     }
00073 
00074     image_sum = image_sum / static_cast<double>(image_list.size());
00075 
00076     cv::Mat mean_image;
00077     image_sum.convertTo(mean_image, CV_8U);
00078     cv::Mat temp_norm_image;
00079 
00080     cv::medianBlur(mean_image, temp_norm_image, 45);
00081 
00082     cv::Mat temp_norm_image2;
00083     temp_norm_image.convertTo(temp_norm_image2, CV_32F);
00084     double max1 = 0;
00085     for (int32_t i = 0; i < temp_norm_image2.rows; i++)
00086     {
00087       for (int32_t j = 0; j < temp_norm_image2.cols; j++)
00088       {
00089         if (temp_norm_image2.at<float>(i, j) > max1)
00090         {
00091           max1 = temp_norm_image2.at<float>(i, j);
00092         }
00093       }
00094     }
00095 
00096     temp_norm_image2 = temp_norm_image2 * (255.0 / max1);
00097 
00098     cv::Mat temp_norm_image3;
00099     temp_norm_image2.convertTo(temp_norm_image3, CV_8U, 1.0, 0.0);
00100 
00101 
00102     cv::GaussianBlur(temp_norm_image3,
00103                      norm_image,
00104                      cv::Size(25, 25),
00105                      5,
00106                      5);
00107 
00108     return norm_image;
00109   }
00110   
00111   void MaskedBoxFilter(cv::Mat& mat, cv::Mat& mask, int32_t kernel_size)
00112   {
00113     mask.setTo(1, mask);
00114     cv::Mat local_sums;
00115     cv::boxFilter(
00116       mat,
00117       local_sums,
00118       mat.depth(),
00119       cv::Size(kernel_size, kernel_size),
00120       cv::Point(-1, -1),
00121       false);
00122     cv::Mat local_mask_sums;
00123     cv::boxFilter(
00124       mask,
00125       local_mask_sums,
00126       mat.depth(),
00127       cv::Size(kernel_size, kernel_size),
00128       cv::Point(-1, -1),
00129       false);
00130     cv::Mat blurred;
00131     cv::divide(local_sums, local_mask_sums, blurred, 1, mat.type());
00132     blurred.copyTo(mat, local_mask_sums != 0);
00133   }
00134 
00135   void ContrastStretch(
00136     int32_t grid_size, 
00137     const cv::Mat& source_image,
00138     cv::Mat& dest_image,
00139     const cv::Mat& mask,
00140     double max_min,
00141     double min_max)
00142   {   
00143     int x_bin_w = std::floor(static_cast<double>(source_image.cols) / grid_size);
00144     int y_bin_h = std::floor(static_cast<double>(source_image.rows) / grid_size);
00145     
00146     //ROS_ERROR("x_bin_w:%d  y_bin_h:%d", x_bin_w, y_bin_h);
00147     
00148     cv::Mat max_vals(grid_size + 1, grid_size + 1, CV_64F);
00149     cv::Mat min_vals(grid_size + 1, grid_size + 1, CV_64F);
00150     cv::Mat grid_mask = cv::Mat::ones(grid_size + 1, grid_size + 1, CV_8U) * 255;
00151 
00152     bool has_mask = !mask.empty();
00153     for(int i = 0; i < grid_size + 1; i++)
00154     {
00155       for(int j = 0; j < grid_size + 1; j++)
00156       {
00157         double minVal = 0;
00158         double maxVal = 255;
00159         
00160         cv::Rect roi = cv::Rect(j * x_bin_w  - x_bin_w / 2,
00161                        i * y_bin_h - y_bin_h / 2, x_bin_w, y_bin_h);
00162         roi.x = std::max(0, roi.x);
00163         roi.y = std::max(0, roi.y);
00164         roi.width = std::min(source_image.cols - roi.x, roi.width);
00165         roi.height = std::min(source_image.rows - roi.y, roi.height);
00166                        
00167         if (has_mask)
00168         {
00169           if (cv::countNonZero(mask(roi)) > 0)
00170           {
00171             //ROS_ERROR("x:%d  y:%d  w:%d  h:%d", roi.x, roi.y, roi.width, roi.height);
00172             cv::minMaxLoc(source_image(roi), &minVal, &maxVal, 0, 0, mask(roi));
00173           }
00174           else
00175           {
00176             grid_mask.at<uint8_t>(i, j) = 0;
00177           }
00178         }
00179         else
00180         {
00181           cv::minMaxLoc(source_image(roi), &minVal, &maxVal, 0, 0);
00182         }
00183         max_vals.at<double>(i, j) = maxVal;
00184         min_vals.at<double>(i, j) = minVal;
00185       }
00186     }
00187     
00188     MaskedBoxFilter(max_vals, grid_mask, 3);
00189     MaskedBoxFilter(min_vals, grid_mask, 3);
00190 
00191     // Stretch contrast accordingly
00192     for(int i = 0; i < source_image.rows; i++)
00193     {
00194       int ii = i / y_bin_h;
00195       double py = (i - ii * y_bin_h) / static_cast<double>(y_bin_h);
00196 
00197       for(int j = 0; j < source_image.cols; j++)
00198       {
00199         // Find relevant min and max values
00200         int jj = j / x_bin_w;
00201 
00202         // Stretch histogram
00203         double minVal = min_vals.at<double>(ii, jj);
00204         double maxVal = max_vals.at<double>(ii, jj);
00205 
00206         // interp x
00207         double px = (j - jj * x_bin_w) / static_cast<double>(x_bin_w);
00208 
00209         //4-point interpolation
00210         double xM1 = maxVal + px * (max_vals.at<double>(ii, jj+1) - maxVal);
00211         double xM2 = max_vals.at<double>(ii+1, jj) + px * (max_vals.at<double>(ii+1, jj+1) - max_vals.at<double>(ii+1, jj));
00212         double M = xM1 + py * (xM2 - xM1);
00213 
00214         double xm1 = minVal + px*(min_vals.at<double>(ii, jj+1) - minVal);
00215         double xm2 = min_vals.at<double>(ii+1, jj) + px*(min_vals.at<double>(ii+1, jj+1) - min_vals.at<double>(ii+1, jj));
00216         double m = xm1 + py*(xm2 - xm1);
00217         minVal = m;
00218         maxVal = M;
00219 
00220         if(maxVal > 255) maxVal = 255;
00221         if(minVal < 0) minVal = 0;
00222         
00223         // Put a bound on maxVal and minVal
00224         maxVal = std::max(maxVal, min_max);
00225         minVal = std::min(minVal, max_min);
00226 
00227         double val = source_image.at<uint8_t>(i,j);
00228         val = 255.0 * (val - minVal) / (maxVal - minVal);
00229         if(val > 255) val = 255;
00230         if(val < 0) val = 0;
00231         dest_image.at<uint8_t>(i,j) = val;
00232       }
00233     }
00234   }
00235 
00236   void NormalizeResponse(
00237       const cv::Mat& src, 
00238       cv::Mat& dst, 
00239       int winsize, 
00240       int ftzero, 
00241       uchar* buf)
00242   {
00243     if (dst.empty())
00244     {
00245       dst.create(src.size(), CV_8U);
00246     }
00247   
00248     // Source code from OpenCV: modules/calib3d/src/stereobm.cpp
00249     int x, y, wsz2 = winsize / 2;
00250     int* vsum = reinterpret_cast<int*>(cv::alignPtr(buf + (wsz2 + 1) * sizeof(vsum[0]), 32));
00251     int scale_g = winsize * winsize / 8, scale_s = (1024 + scale_g) / (scale_g * 2);
00252     const int OFS = 256 * 5, TABSZ = OFS * 2 + 256;
00253     uchar tab[TABSZ];
00254     const uchar* sptr = src.ptr();
00255     int srcstep = src.step;
00256     cv::Size size = src.size();
00257 
00258     scale_g *= scale_s;
00259 
00260     for (x = 0; x < TABSZ; x++)
00261     {
00262       tab[x] = (uchar)(x - OFS < -ftzero ? 0 : x - OFS > ftzero ? ftzero * 2 : x - OFS + ftzero);
00263     }
00264 
00265     for (x = 0; x < size.width; x++)
00266     {
00267       vsum[x] = (ushort)(sptr[x] * (wsz2 + 2));
00268     }
00269 
00270     for (y = 1; y < wsz2; y++)
00271     {
00272       for (x = 0; x < size.width; x++)
00273       {
00274         vsum[x] = (ushort)(vsum[x] + sptr[srcstep*y + x]);
00275       }
00276     }
00277 
00278     for (y = 0; y < size.height; y++)
00279     {
00280       const uchar* top = sptr + srcstep * MAX(y - wsz2 - 1, 0);
00281       const uchar* bottom = sptr + srcstep * MIN(y + wsz2, size.height - 1);
00282       const uchar* prev = sptr + srcstep * MAX(y - 1, 0);
00283       const uchar* curr = sptr + srcstep * y;
00284       const uchar* next = sptr + srcstep * MIN(y + 1, size.height - 1);
00285       uchar* dptr = dst.ptr<uchar>(y);
00286 
00287       for (x = 0; x < size.width; x++)
00288       {
00289         vsum[x] = (ushort)(vsum[x] + bottom[x] - top[x]);
00290       }
00291 
00292       for (x = 0; x <= wsz2; x++)
00293       {
00294         vsum[-x-1] = vsum[0];
00295         vsum[size.width + x] = vsum[size.width - 1];
00296       }
00297 
00298       int sum = vsum[0] * (wsz2 + 1);
00299       for( x = 1; x <= wsz2; x++ )
00300       {
00301         sum += vsum[x];
00302       }
00303 
00304       int val = ((curr[0] * 5 + curr[1] + prev[0] + next[0]) * scale_g - sum * scale_s) >> 10;
00305       dptr[0] = tab[val + OFS];
00306 
00307       for( x = 1; x < size.width-1; x++ )
00308       {
00309         sum += vsum[x + wsz2] - vsum[x - wsz2 - 1];
00310         val = ((curr[x] * 4 + curr[x - 1] + curr[x + 1] + prev[x] + next[x]) * scale_g - sum * scale_s) >> 10;
00311         dptr[x] = tab[val + OFS];
00312       }
00313 
00314       sum += vsum[x+wsz2] - vsum[x - wsz2 - 1];
00315       val = ((curr[x] * 5 + curr[x - 1] + prev[x] + next[x]) * scale_g - sum * scale_s) >> 10;
00316       dptr[x] = tab[val + OFS];
00317     }
00318   }
00319 
00320   cv::Mat scale_2_8bit(const cv::Mat& image)
00321         {
00322                 if (image.type() == CV_8UC1)
00323                   return image;
00324                 cv::Mat Image8Bit(image.rows, image.cols, CV_8U), Image8BitColor; //Define an 8bit image
00325                 //Convert the image to 32bit float
00326                 cv::Mat ImageFloat;
00327                 image.convertTo(ImageFloat, CV_32F, 1, 0);
00328                 double maxVal; //Define the max value of image
00329                 cv::minMaxLoc(ImageFloat.reshape(1,1), NULL, &maxVal);//Extract the max value of image
00330                 //ReScale the image to 0 to 255
00331                 ImageFloat = ImageFloat*((1 << 8)/pow(2, ceil(log(maxVal)/log(2))));
00332                 ImageFloat.convertTo(Image8Bit,CV_8U, 1, 0);
00333                 return Image8Bit;
00334         }
00335 
00336         cv::Mat scale_2_8bit_color(const cv::Mat& image)
00337         {
00338                 if (image.type() == CV_8UC3)
00339                   return image;
00340                 cv::Mat Image8Bit = scale_2_8bit(image), Image8BitColor;
00341                 cvtColor(Image8Bit, Image8BitColor, CV_GRAY2BGR);
00342                 return Image8BitColor;
00343         }
00344 }


swri_image_util
Author(s): Kris Kozak
autogenerated on Tue Oct 3 2017 03:19:34