直方图均衡化

直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。

 

直方图均衡化要达到的效果:

 

基本思想:把原始图的直方图变换为均匀分 布的形式,这样就增加了像素灰度值的动态 范围,从而达到增强图像整体对比度的效果

使用的方法是灰度级变换:s = T(r) 

原理:

s=T(r) 0≤r≤1

T(r)满足下列两个条件:

(1)T(r)在区间0≤r≤1中为单值且单调递增

(2)当0≤r≤1时,0≤T(r) ≤1

 

条件(1)保证原图各灰度级在变换后仍保持从黑 到白(或从白到黑)的排列次序

条件(2)保证变换前后灰度值动态范围的一致性

 

Pr(r)是r的概率密度函数,Ps(s)是s的概 率密度函数,Pr(r)和T(r)已知,且T-1(s) 满足上述条件(1),所以有

已知一种重要的变换函数:

关于上限的定积分的导数就是该上限的积分值 (莱布尼茨准则)

对于离散值:

其中r是第k个灰度级,k = 0,1,2,…,L-1.

  nk是图像中灰度级为rk的像素个数.

  n是图像中像素的总数.

已知变换函数的离散形式为:

sk称作直方图均衡化 将输入图像中灰度级为rk(横坐标)的像素映射 到输出图像中灰度级为sk (横坐标)的对应像素得到.

 实现代码:

/******************************************************************************
*    作用:            灰度均衡函数
*    参数:        
*        pixel        原始像素数组
*        tempPixel    保存变换后图像的像素数组
*        width        原始图像宽度
******************************************************************************/
void GrayEqualize(BYTE* pixel, BYTE* tempPixel, UINT width, UINT height)
{

    // 灰度映射表
    BYTE map[256];
    long lCounts[256];

    memset(lCounts, 0, sizeof(long) * 256);

    // 计算各灰度值个数
    for (UINT i = 0; i < width * height; i++)
    {
        int x = pixel[i * 4];
        lCounts[x]++;
    }

    // 保存运算中的临时值
    long lTemp;

    for (int i = 0; i < 256; i++)
    {
        lTemp = 0;
        for (int j = 0; j <= i; j++)
            lTemp += lCounts[j];

        map[i] = (BYTE)(lTemp * 255.0f / width / height);
    }

    // 变换后的值直接在映射表中查找
    for (UINT i = 0; i < width * height; i++)
    {
        int x = pixel[i * 4];

        tempPixel[i*4] = tempPixel[i*4+1] = tempPixel[i*4+2] = pixel[i * 4];
        tempPixel[i*4+3] = 255;
    }
}
View Code

 

 

 

彩色图直方图均衡化: 

 

更清晰:

 

 opencv代码:

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

using namespace cv;
using namespace std;

int main( int argc, const char** argv )
{
       Mat img = imread("MyPic.JPG", CV_LOAD_IMAGE_COLOR); //open and read the image

       if (img.empty()) //if unsuccessful, exit the program
       {
            cout << "Image cannot be loaded..!!" << endl;
            return -1;
       }

       vector<Mat> channels; 
       Mat img_hist_equalized;

       cvtColor(img, img_hist_equalized, CV_BGR2YCrCb); //change the color image from BGR to YCrCb format

       split(img_hist_equalized,channels); //split the image into channels

       equalizeHist(channels[0], channels[0]); //equalize histogram on the 1st channel (Y)

   merge(channels,img_hist_equalized); //merge 3 channels including the modified 1st channel into one image

      cvtColor(img_hist_equalized, img_hist_equalized, CV_YCrCb2BGR); //change the color image from YCrCb to BGR format (to display image properly)

       //create windows
       namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
       namedWindow("Histogram Equalized", CV_WINDOW_AUTOSIZE);

       //show the image
       imshow("Original Image", img);
       imshow("Histogram Equalized", img_hist_equalized);

       waitKey(0); //wait for key press

       destroyAllWindows(); //destroy all open windows

       return 0;
}
View Code

 代码中使用的函数:

 New OpenCV functions

  • cvtColor(img, img_hist_equalized, CV_BGR2YCrCb)
This line converts the color space of BGR in 'img' to YCrCb color space and stores the resulting image in 'img_hist_equalized'.
 
In the above example, I am going to equalize the histogram of color images. In this scenario, I have to equalize the histogram of the intensity component only, not the color components. So, BGR format cannot be used because its all three planes represent color components blue, green and red. So, I have to convert the original BGR color space to YCrCb color space because its 1st plane represents the intensity of the image where as other planes represent the color components.  
 
  • void split(const Mat& m, vector<Mat>& mv )
This function splits each channel of the 'm' multi-channel array into separate channels and stores them in a vector, referenced by 'mv'.
 
Argument list
  • const Mat& m - Input multi-channel array
  •  vector<Mat>& mv - vector that stores the each channel of the input array
 
  • equalizeHist(channels[0], channels[0]);
Here we are only interested in the 1st channel (Y) because it  represents the intensity information whereas other two channels (Cr and Cb) represent color components. So, we equalize the histogram of the 1st channel using OpenCV in-built function, 'equalizeHist(..)' and other two channels remain unchanged.
 
  • void merge(const vector<Mat>& mv, OutputArray dst )
This function does the reverse operation of the split function. It takes the vector of channels and create a single multi-channel array.
Argument list
  • const vector<Mat>& mv - vector that holds several channels. All channels should have same size and same depths
  • OutputArray dst - stores the destination multi-channel array
 
  • cvtColor(img_hist_equalized, img_hist_equalized, CV_YCrCb2BGR)
This line converts the image from YCrCb color space to BGR color space. It is essential to convert to BGR color space because 'imshow(..)' OpenCV function can only show images with that color space. 
 
This is the end of the explanation of new OpenCV functions, found in the above sample code. If you are not familiar with other OpenCV functions, please refer to the previous lessons.
 
 

 参考博客:http://opencv-srf.blogspot.jp/2013/08/histogram-equalization.html

posted on 2016-12-11 20:01  yoyo_sincerely  阅读(51458)  评论(0编辑  收藏  举报