zoukankan      html  css  js  c++  java
  • OpenCV 之 直方图处理

    1  图像直方图

    1.1  定义

      统计各个像素值,在整幅图像中出现次数的一个分布函数。

              

    1.2  标准化

      $quad p_r(r_k) = frac{n_k}{MN} qquad k = 0, 1, 2, ..., L -1 $

      $r_{k}$ - 第 k 个像素灰度值;  $n_{k}$ - 像素灰度值为 rk 的像素数目;

      MN - 图像中总的像素个数;  [0, L-1] - 像素灰度值的范围

    1.3  直方图均衡化

    1.3.1  定义 

      直方图均衡化,是将给定图像的直方图改造成均匀分布的直方图,从而扩大像素灰度值的动态范围,达到增强图像对比度的效果。

      $quad s_k = frac{(L - 1)}{MN} sumlimits_{j=0}^k n_j qquad k = 0, 1, 2, ..., L - 1 $

               

               

    1.3.2  实例

      一幅灰度值范围是[0, 7],64行64列的数字图像,其灰度分布如下表所示,求直方图均衡化之后的灰度分布。

      r(k)  n(k)  P(rk)
     r(0) = 0  790   0.19
     r(1) = 1  1023  0.25
     r(2) = 2  850  0.21
     r(3) = 3  656  0.16
     r(4) = 4  329  0.08
     r(5) = 5  245  0.06
     r(6) = 6  122  0.03
     r(7) = 7  81  0.02

      根据上述公式得, s(0)=1.33≈1,s(1)=3.08≈3,s(2)≈5,s(3)≈6,s(4)≈6,s(5)≈7,s(6)≈7,s(7)≈7

      因为 r(k) -> s(k),所以 s(0)=1 对应有790个像素值。因为r(3), r(4) 分别对应 s(3), s(4),且 s(3)=s(4)=6,

      故像素值为6的像素数为 (656+329)个,同理可计算像素值为7的像素数。

      将不同像素值对应的的像素数除以MN(图像的像素总数),便得到均衡化之后的灰度直方图,如下所示:

     

    2  四个参数

      H1 和 H2 为两个待比较的直方图。1) 和 2) 的值越大,二者越匹配;而 3) 和 4) 的值越小,两者越匹配。

    1) Correlation

      

    2) Intersection

       

    3) Chi-square

       

    4) Bhattacharyya distance

       

    3  OpenCV中的函数

    3.1  equalizeHist

    void equalizeHist (
       InputArray src, // 输入图像
       OutputArray dst // 输出图像
    );

      源码:

    void cv::equalizeHist( InputArray _src, OutputArray _dst )
    {
        CV_Assert( _src.type() == CV_8UC1 );
    
        if (_src.empty())
            return;
    
        CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                   ocl_equalizeHist(_src, _dst))
    
        Mat src = _src.getMat();
        _dst.create( src.size(), src.type() );
        Mat dst = _dst.getMat();
    
        Mutex histogramLockInstance;
    
        const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
        int hist[hist_sz] = {0,};
        int lut[hist_sz];
    
        EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);
        EqualizeHistLut_Invoker      lutBody(src, dst, lut);
        cv::Range heightRange(0, src.rows);
    
        if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))
            parallel_for_(heightRange, calcBody);
        else
            calcBody(heightRange);
    
        int i = 0;
        while (!hist[i]) ++i;
    
        int total = (int)src.total();
        if (hist[i] == total)
        {
            dst.setTo(i);
            return;
        }
    
        float scale = (hist_sz - 1.f)/(total - hist[i]);
        int sum = 0;
    
        for (lut[i++] = 0; i < hist_sz; ++i)
        {
            sum += hist[i];
            lut[i] = saturate_cast<uchar>(sum * scale);
        }
    
        if(EqualizeHistLut_Invoker::isWorthParallel(src))
            parallel_for_(heightRange, lutBody);
        else
            lutBody(heightRange);
    }
    View Code

    3.2  calcHist

    void cv::calcHist(     
         const Mat *      images,
        int              nimages,
        const int *      channels,
        InputArray      mask,
        OutputArray      hist,
        int              dims,
        const int *      histSize,
        const float **  ranges,
        bool              uniform = true,
        bool              accumulate = false )     
    View Code

    3.3  compareHist

    double cv::compareHist (     
            InputArray      H1,
            InputArray      H2,
            int                 method
    )  
    View Code

    4  实例

    4.1  直方图计算

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgcodecs/imgcodecs.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    
    using namespace cv;
    
    int main( int, char** argv )
    {
      Mat src, dst;
    
      // 1) Load image
      src = imread("left.png");
      if(src.empty()) {
          return -1;
      }
    
      // 2)  Separate the image in 3 places ( B, G and R )
      std::vector<Mat> bgr_planes;
      split( src, bgr_planes );
    
      // 3)  Establish the number of bins
      int histSize = 256;
    
      // 4)  Set the ranges (for B,G,R)
      float range[] = { 0, 256 } ;
      const float* histRange = { range };
    
      bool uniform = true;
      bool accumulate = false;
    
      Mat b_hist, g_hist, r_hist;
    
      // 5)  Compute the histograms
      calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
      calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
      calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
    
      // 6) Draw the histograms for B, G and R
      int hist_w = 512;
      int hist_h = 400;
      int bin_w = cvRound( (double) hist_w/histSize );
    
      Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
    
      // 7) Normalize the result to [ 0, histImage.rows ]
      normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
      normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
      normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
    
      // 8) Draw for each channel
      for( int i = 1; i < histSize; i++ )
      {
          line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
                           Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
                           Scalar( 255, 0, 0), 2, 8, 0  );
          line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
                           Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
                           Scalar( 0, 255, 0), 2, 8, 0  );
          line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
                           Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
                           Scalar( 0, 0, 255), 2, 8, 0  );
      }
    
      // 9) Display
      imshow("calcHist Demo", histImage );
    
      waitKey(0);
    }

    4.2  直方图均衡化

    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    
    using namespace cv;
    using namespace std;
    
    int main( int, char** argv )
    {
      Mat src, dst;
    
      const char* source_window = "Source image";
      const char* equalized_window = "Equalized Image";
    
      // Load image
      src = imread( argv[1], 1 );
    
      if( src.empty() )
        { cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
          return -1;
        }
    
      // Convert to grayscale
      cvtColor( src, src, COLOR_BGR2GRAY );
    
      // Apply Histogram Equalization
      equalizeHist( src, dst );
    
      // Display results
      namedWindow( source_window, WINDOW_AUTOSIZE );
      namedWindow( equalized_window, WINDOW_AUTOSIZE );
    
      imshow( source_window, src );
      imshow( equalized_window, dst );
    
      // Wait until user exits the program
      waitKey(0);
    
      return 0;
    
    }
    View Code

    4.3  直方图比较

    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    
    using namespace std;
    using namespace cv;
    
    /**
     * @function main
     */
    int main( int argc, char** argv )
    {
        Mat src_base, hsv_base;
        Mat src_test1, hsv_test1;
        Mat src_test2, hsv_test2;
        Mat hsv_half_down;
    
        /// Load three images with different environment settings
        if( argc < 4 )
        {
            printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>
    ");
            return -1;
        }
    
        src_base = imread( argv[1], 1 );
        src_test1 = imread( argv[2], 1 );
        src_test2 = imread( argv[3], 1 );
    
        /// Convert to HSV
        cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
        cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
        cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV );
    
        hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
    
        /// Using 50 bins for hue and 60 for saturation
        int h_bins = 50; int s_bins = 60;
        int histSize[] = { h_bins, s_bins };
    
        // hue varies from 0 to 179, saturation from 0 to 255
        float h_ranges[] = { 0, 180 };
        float s_ranges[] = { 0, 256 };
    
        const float* ranges[] = { h_ranges, s_ranges };
    
        // Use the o-th and 1-st channels
        int channels[] = { 0, 1 };
    
    
        /// Histograms
        MatND hist_base;
        MatND hist_half_down;
        MatND hist_test1;
        MatND hist_test2;
    
        /// Calculate the histograms for the HSV images
        calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );
        normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() );
    
        calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false );
        normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() );
    
        calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );
        normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() );
    
        calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false );
        normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() );
    
        /// Apply the histogram comparison methods
        for( int i = 0; i < 4; i++ )
        {
            int compare_method = i;
            double base_base = compareHist( hist_base, hist_base, compare_method );
            double base_half = compareHist( hist_base, hist_half_down, compare_method );
            double base_test1 = compareHist( hist_base, hist_test1, compare_method );
            double base_test2 = compareHist( hist_base, hist_test2, compare_method );
    
            printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f 
    ", i, base_base, base_half , base_test1, base_test2 );
        }
    
        printf( "Done 
    " );
    
        return 0;
    }
    View Code

    参考资料

      <Digital Image Processing> 3rd

      OpenCV Tutorials / Image Processing (imgproc module) / Histogram Calculation

  • 相关阅读:
    trident介绍
    Effective TensorFlow Chapter 4: TensorFlow中的广播Broadcast机制【转】
    tslib移植笔记(1)【转】
    jz2440-linux3.4.2-kernel移植【学习笔记】【原创】
    Linxu内核版本号后面多出字符串或者+号【学习笔记】
    向linux内核版本号添加字符/为何有时会自动添加"+"号或者"xxx-dirty"【转】
    chrome浏览器新建标签打开页面【学习笔记】
    jz2440-uboot-201204版本移植【学习笔记】【原创】
    Ubuntu 14.04 下安装 TFTP 艰辛之路【转】
    更改UBoot实现通过loady命令下载代码【转】
  • 原文地址:https://www.cnblogs.com/xinxue/p/5290660.html
Copyright © 2011-2022 走看看