[openCV]直方图均衡

1.图像的直方图

图像的直方图,代表了图像的灰度值的分布状况。从直方图上,我们可以很明确的知道,图像的偏暗程度和饱和程度。如果一幅数字图像中,假设作为水平轴的灰度值 rk 出现了 nk 次,那么对应于垂直轴的归一化后的函数如下所示。

pk=nkMN

这样的图像,被称为直方图。为了直观感受一下直方图的作用,我使用相机调节曝光补偿,拍摄了以下3枚图像。
这里写图片描述
从图像的上方的直方图就可以看出来,图像的偏暗程度与饱和程度。并且,可以将左图像与中央图像称为动态范围较窄的图像。相反的,对于右边图像,其动态范围较宽,图像得到了很好的显示。

2.直方图均衡

直方图均衡,可以用于调节动态范围较窄的图像,增强图像对比度。然而,灰度拉升或者其他的灰度变换同样可以达到这个目的。所以,直方图均衡的本质目的是,将图像的累积分布函数(Probability Density Function)调节为45°曲线。为此,直方图均衡的目的是明确的,而不是像灰度拉升这种操作那么暧昧。
具体的直方图均衡的原理,可以参照的之前的博文。
[数字图像处理]灰度变换——直方图处理

2.1代码实现

下面是openCV的代码,由于写得比较早,可能不是那么整洁。

//-------------------------------------------------------
// 内容:OpenCV 环境的配置
//       图像的读取
//       直方图的绘制与直方图均衡的实现
//       直方图的累积分布函数(PDF)的计算
//                                    2015.4.17   
//                                    by zhou fan
// ------------------------------------------------------

#include "stdafx.h"

#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  

#define   RGB_image    1
#define  Gray_image    0
#define other_image   -1


using namespace cv;  
using namespace std;  


int main(int argc, char** argv[])
{
    //IplImage * ori= cvLoadImage("..\\Data\\Fig0320(4)(bottom_left).tif",Gray_image);
    IplImage * ori= cvLoadImage("..\\Data\\EV.JPG",Gray_image);

    cvNamedWindow("Original",1);        //new window,
    cvShowImage("Original",ori);        //show

    int hist_xMax = 256;      //size
    int hist_yMax = 256;  
    float range[] = {0,255};  //统计范围  
    float* ranges[]={range};  

    //创建直方图  
    CvHistogram* hist = cvCreateHist(1,&hist_xMax,CV_HIST_ARRAY,ranges,1);  
    //统计概率
    cvCalcHist(&ori,hist,
               0,            //累積タイプではない
               0);
    //归一化
    cvNormalizeHist(hist,1.0);  

    //histogram  and PDF show
    {
        Mat HistImage(hist_xMax,hist_yMax,CV_8UC3,Scalar(255,255,255));
        IplImage hist_show = HistImage;

        Mat HistPDFImage(hist_xMax,hist_yMax,CV_8UC3,Scalar(255,255,255));
        IplImage hist_PDF_show = HistPDFImage;

        float HistPDF[256] = {0};


        float max_value = 0;  
        float yMax_Limt = 0.1;
        cvGetMinMaxHistValue(hist,0,&max_value,0,0); 

        for(int x=0;x<hist_xMax;x++)  
        {  
            float yHistVal = cvGetReal1D((hist)->bins,x);   //取得1D数据的值
            int yVal = cvRound(yHistVal*hist_yMax/yMax_Limt);  //要绘制的高度  

            HistPDF[x] = (float)((x == 0)? cvGetReal1D((hist)->bins,x):
                                           cvGetReal1D((hist)->bins,x) + HistPDF[x-1]); 

            cvLine(&hist_show,   
                   cvPoint(x,hist_yMax),  
                   cvPoint(x,hist_yMax - yVal),  
                   CV_RGB(0,0,0)); 

            cvLine(&hist_PDF_show,   
                   cvPoint(x-1,hist_yMax - cvRound(HistPDF[x-1]*hist_yMax)),  
                   cvPoint(  x,hist_yMax - cvRound(HistPDF[x]*hist_yMax)),  
                   CV_RGB(0,0,0)); 

            //cout << yHistVal << "         "<<(HistPDF[x])<<"\n" ;
        }  


        //想要窗口内的图片随着窗口一起扩大的话,需要使用样式 WINDOW_NORMAL
        //cvNamedWindow("Histogram",WINDOW_NORMAL);

        cvNamedWindow("Histogram",1);             //new window,
        cvShowImage("Histogram",&hist_show);        //show

        cvNamedWindow("PDF",1);             //new window,
        cvShowImage("PDF",&hist_PDF_show);        //show
    }

    //直方图均衡
    cvEqualizeHist(ori,ori);

    cvNamedWindow("Result",1);        //new window,
    cvShowImage("Result",ori);      //show

    //计算均衡后的直方图
    cvCalcHist(&ori,hist,
               0,            //非累积
               0);
    //归一化
    cvNormalizeHist(hist,1.0);  

    //histogram  and PDF show
    {
        Mat HistImage(hist_xMax,hist_yMax,CV_8UC3,Scalar(255,255,255));
        IplImage hist_show = HistImage;

        Mat HistPDFImage(hist_xMax,hist_yMax,CV_8UC3,Scalar(255,255,255));
        IplImage hist_PDF_show = HistPDFImage;

        float HistPDF[256] = {0};


        float max_value = 0;  
        float yMax_Limt = 0.1;
        cvGetMinMaxHistValue(hist,0,&max_value,0,0); 

        for(int x=0;x<hist_xMax;x++)  
        {  
            float yHistVal = cvGetReal1D((hist)->bins,x);   //取得1D数据的值
            int yVal = cvRound(yHistVal*hist_yMax/yMax_Limt);  //要绘制的高度  

            HistPDF[x] = (float)((x == 0)? cvGetReal1D((hist)->bins,x):
                                           cvGetReal1D((hist)->bins,x) + HistPDF[x-1]); 

            cvLine(&hist_show,   
                   cvPoint(x,hist_yMax),  
                   cvPoint(x,hist_yMax - yVal),  
                   CV_RGB(0,0,0)); 

            cvLine(&hist_PDF_show,   
                   cvPoint(x-1,hist_yMax - cvRound(HistPDF[x-1]*hist_yMax)),  
                   cvPoint(  x,hist_yMax - cvRound(HistPDF[x]*hist_yMax)),  
                   CV_RGB(0,0,0)); 

            //cout << yHistVal << "         "<<(HistPDF[x])<<"\n" ;
        }  

        cvNamedWindow("Histogram_Result",1);             //new window,
        cvShowImage("Histogram_Result",&hist_show);        //show

        cvNamedWindow("PDF_Result",1);             //new window,
        cvShowImage("PDF_Result",&hist_PDF_show);        //show
    }


    cvWaitKey(0);  

    return (int)0;
}

2.1执行结果

执行直方图均衡前的直方图与PDF
这里写图片描述
结果的直方图与PDF
这里写图片描述

执行直方图均衡前的直方图与PDF
这里写图片描述
结果的直方图与PDF
这里写图片描述

原文发于博客:http://blog.csdn.net/thnh169/

猜你喜欢

转载自blog.csdn.net/thnh169/article/details/45867829
今日推荐