直方图均衡化

目标

在这个教程中你将学到:

  • 什么是图像的直方图和为什么图像的直方图很有用
  • 用OpenCV函数 equalizeHist 对图像进行直方图均衡化

原理

图像的直方图是什么?

  • 直方图是图像中像素强度分布的图形表达方式.
  • 它统计了每一个强度值所具有的像素个数.
../../../../../_images/Histogram_Equalization_Theory_0.jpg

直方图均衡化是什么?

  • 直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法.
  • 说得更清楚一些, 以上面的直方图为例, 你可以看到像素主要集中在中间的一些强度值上. 直方图均衡化要做的就是 拉伸 这个范围. 见下面左图: 绿圈圈出了 少有像素分布其上的 强度值. 对其应用均衡化后, 得到了中间图所示的直方图. 均衡化的图像见下面右图.
../../../../../_images/Histogram_Equalization_Theory_1.jpg

直方图均衡化是怎样做到的?

  • 均衡化指的是把一个分布 (给定的直方图) 映射 到另一个分布 (一个更宽更统一的强度值分布), 所以强度值分布会在整个范围内展开.

  • 要想实现均衡化的效果, 映射函数应该是一个 累积分布函数 (cdf) (更多细节, 参考*学习OpenCV*). 对于直方图 H(i), 它的 累积分布 H^{'}(i) 是:

    H^{'}(i) = \sum_{0 \le j < i} H(j)

    要使用其作为映射函数, 我们必须对最大值为255 (或者用图像的最大强度值) 的累积分布 H^{'}(i) 进行归一化. 同上例, 累积分布函数为:

    ../../../../../_images/Histogram_Equalization_Theory_2.jpg
  • 最后, 我们使用一个简单的映射过程来获得均衡化后像素的强度值:

    equalized( x, y ) = H^{'}( src(x,y) )

例程

  • 咋个例程是用来干嘛的?

    • 加载源图像
    • 把源图像转为灰度图
    • 使用OpenCV函数 EqualizeHist 对直方图均衡化
    • 在窗体中显示源图像和均衡化后图像.
  • 下载例程: 点击 这里

  • 例程一瞥:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;

/**  @function main */
int main( int argc, char** argv )
{
  Mat src, dst;

  char* source_window = "Source image";
  char* equalized_window = "Equalized Image";

  /// 加载源图像
  src = imread( argv[1], 1 );

  if( !src.data )
    { cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
      return -1;}

  /// 转为灰度图
  cvtColor( src, src, CV_BGR2GRAY );

  /// 应用直方图均衡化
  equalizeHist( src, dst );

  /// 显示结果
  namedWindow( source_window, CV_WINDOW_AUTOSIZE );
  namedWindow( equalized_window, CV_WINDOW_AUTOSIZE );

  imshow( source_window, src );
  imshow( equalized_window, dst );

  /// 等待用户按键退出程序
  waitKey(0);

  return 0;
}

说明

  1. 声明原图和目标图以及窗体名称:

    Mat src, dst;
    
    char* source_window = "Source image";
    char* equalized_window = "Equalized Image";
    
  2. 加载源图像:

    src = imread( argv[1], 1 );
    
    if( !src.data )
      { cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
        return -1;}
    
  3. 转为灰度图:

    cvtColor( src, src, CV_BGR2GRAY );
    
  4. 利用函数 equalizeHist 对上面灰度图做直方图均衡化:

    equalizeHist( src, dst );
    

    可以看到, 这个操作的参数只有源图像和目标 (均衡化后) 图像.

  5. 显示这两个图像 (源图像和均衡化后图像) :

    namedWindow( source_window, CV_WINDOW_AUTOSIZE );
    namedWindow( equalized_window, CV_WINDOW_AUTOSIZE );
    
    imshow( source_window, src );
    imshow( equalized_window, dst );
    
  6. 等待用户案件退出程序

    waitKey(0);
    return 0;
    

结果

  1. 为了更好地观察直方图均衡化的效果, 我们使用一张对比度不强的图片作为源图像输入, 如下图:

    ../../../../../_images/Histogram_Equalization_Original_Image.jpg

    它的直方图为:

    ../../../../../_images/Histogram_Equalization_Original_Histogram.jpg

    注意到像素大多集中在直方图中间的强度上.

  2. 使用例程进行均衡化后, 我们得到下面的结果:

    ../../../../../_images/Histogram_Equalization_Equalized_Image.jpg

    这幅图片显然对比度更强. 再验证一下均衡化后图片的直方图:

    ../../../../../_images/Histogram_Equalization_Equalized_Histogram.jpg

    注意到现在像素在整个强度范围内均衡分布.

Note

你们想知道上面的直方图是怎样绘制出来的吗? 请关注接下来的教程!

Table Of Contents

Previous topic

仿射变换

Next topic

直方图计算

This Page