现在的位置: 首页 > 综合 > 正文

OpenCV统计应用-直方图等化

2014年02月04日 ⁄ 综合 ⁄ 共 5067字 ⁄ 字号 评论关闭

直方图等化(Histogram Equalization)为一种使用统计方法的影像处理程序设计,它的功能为将统计直方图的色彩分布平均的打散在直方图里,也就是说,让一张图的直方图分布均匀化,同样的也是使用到LUT(Look-up
Table)
的方法

而在设计直方图等化不可或缺的就是需要先知道统计学的机率密度函数(Probability Density Function,PDF)以及累积分配函数(Cumlative Distribution Function,CDF)相关的基本概念,在这边会简单的说明机率密度函数及累积分配函数的概念还有直方图等化的程序设计实作,OpenCV也提供了直接使用直方图等化的函式,cvEqualizeHist(),下面就简单的制作直方图等化的程序设计

RGB结构直方图等化
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1;
    IplImage *Image2;
    IplImage *RedImage;
    IplImage *GreenImage;
    IplImage *BlueImage;

    Image1=cvLoadImage("DarkClouds.jpg",1);
    Image2=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,
3);
    RedImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,
1);
    GreenImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,
1);
    BlueImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,
1);

    cvSplit(Image1,BlueImage,GreenImage,RedImage,0);

    cvEqualizeHist(BlueImage,BlueImage);
    cvEqualizeHist(GreenImage,GreenImage);
    cvEqualizeHist(RedImage,RedImage);

    cvMerge(BlueImage,GreenImage,RedImage,0,Image2);

    cvNamedWindow("DarkClouds",1);
    cvShowImage(
"DarkClouds",Image1);
    cvNamedWindow(
"Equalize DarkClouds",1);
    cvShowImage(
"Equalize DarkClouds",Image2);

    cvWaitKey(0);

}

原始图片:

执行结果:

当然,使用了函式之后就完全不用知道直方图等化在跑什么啦,cvEqualizeHist()只支持单信道uchar型别的图片数据结构,因此,就需要用cvSplit()分割,而这里所做的是将RGB三原色直接做直方图等化,这个直方图等化的结果是彩色的,将个别的RGB直分割后再用cvMerge()合并,通道分割与合并的部份就要参考"数据结构操作与运算-信道的分割,合并与混合"这个地方了.

再来就是比较复杂的直方图等化算法,要知道直方图等化如何计算就要知道以下的步骤

1.数据结构初始化
2.
机率密度函数(PDF)的计算
3.
累积分配函数(CDF)的计算
4.LUT
对应

在机率密度函数的部分,在统计直方图来讲,它的X轴范围会落在0~255,而它的Y轴范围代表着机率,0~255对应的数据代表着它发生的机率,也就是说,这代表着0255数值出现的机率分布,0~255代表着所有的机率的范围,那从0加到255的总和会为1!它所代表的公式如下

PDF机率分布

而累积分配函数就更简单了,它只是将机率密度函数做累积的计算,也就是说,当数值为255的时候它的机率会为1,而且曲线会是由下往上的成长,表达的方式就是将机率密度函数做累加,它的公式如下

CDF机率分布


再来是LUT的部份了,它只是开一个0~255的数组做对应,将累积分配函数的数值乘以255,将它存放在0~255的数组里,这样会出现许多重复的部份,因此,Look-up
table
对应原来的图形的灰阶值,就可以将原本的统计直方图分布打散掉了,而且直方图等化的结果也会发现很多地方数值是空心的,也是因为如此,直方图的分布就会向外推挤了


累积分配直方图乘255存在LUT数组的情况

再来,就是直方图等化的程序了

灰阶直方图等化
#include <stdio.h>
#include <cv.h>
#include <highgui.h>

int HistogramBins =
256;
float HistogramRange1[
2]={0,255};
float *HistogramRange[
1]={&HistogramRange1[0]};

float CumulativeNumber;
float CDFArray[256];
uchar LookupTableData[
256];

void DrawHistogramImage(CvHistogram *Histogram,IplImage *HistogramImage,int HistogramBins);

int main()
{
    IplImage *Image1;
    IplImage *Image2;
    CvHistogram *Histogram1;
    CvHistogram *Histogram2;
    CvMat *LookupTableMatrix;
    IplImage *GrayHistogramImage;
    IplImage *EqualizeHistogramImage;

    Image1=cvLoadImage("DarkClouds.jpg",0);
    Image2=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,
1);
    Histogram1 = cvCreateHist(
1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);
    Histogram2 = cvCreateHist(
1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);

    LookupTableMatrix = cvCreateMat(1,256,CV_8UC1);
    GrayHistogramImage=cvCreateImage(cvSize(
256,250),IPL_DEPTH_8U,3);
    EqualizeHistogramImage=cvCreateImage(cvSize(
256,250),IPL_DEPTH_8U,3);

    GrayHistogramImage->origin=1;
    EqualizeHistogramImage->origin=
1;

    cvCalcHist(&Image1,Histogram1);
    DrawHistogramImage(Histogram1,GrayHistogramImage,HistogramBins);

    //Probability Density Function (PDF)
    cvNormalizeHist(Histogram1,
1);
    
//End

    //Cumulative Distribution Function (CDF)
    CumulativeNumber=
0;
    for(int i=
0;i<HistogramBins;i++)
    {
        CumulativeNumber=CumulativeNumber+cvQueryHistValue_1D(Histogram1,i);
        CDFArray[i]=CumulativeNumber;
    }
    
//End

    //Make Look-up Table
    printf(
"Look-up Table Number:\n");
    for(int i=
0;i<HistogramBins;i++)
    {
        LookupTableData[i]=(uchar)(
255*CDFArray[i]);
        printf(
"%f\n",(255*CDFArray[i]));
    }
    
//End

    cvSetData(LookupTableMatrix,LookupTableData,CV_AUTOSTEP);
    cvLUT(Image1,Image2,LookupTableMatrix);

    cvCalcHist(&Image2,Histogram2);
    DrawHistogramImage(Histogram2,EqualizeHistogramImage,HistogramBins);

    cvNamedWindow("DarkClouds",1);
    cvNamedWindow(
"Equalize DarkClouds",1);
    cvNamedWindow(
"Gray Histogram",1);
    cvNamedWindow(
"Equalize Histogram",1);
    cvShowImage(
"DarkClouds",Image1);
    cvShowImage(
"Equalize DarkClouds",Image2);
    cvShowImage(
"Gray Histogram",GrayHistogramImage);
    cvShowImage(
"Equalize Histogram",EqualizeHistogramImage);

    cvWaitKey(0);

}

void DrawHistogramImage(CvHistogram *Histogram,IplImage *HistogramImage,int HistogramBins)
{
    CvPoint Point1;
    CvPoint Point2;

    for(int i=0;i<HistogramBins;i++)
    {
        Point1=cvPoint(i,(int)(cvQueryHistValue_1D(Histogram,i)/
20));
        Point2=cvPoint(i,
0);
        cvLine(HistogramImage,Point1,Point2,CV_RGB(
127,127,127));

    }
}

执行结果:

前面数据结构初始化的部份,分别制造了两个IplImage图形数据结构,两个CvHistogram直方图数据结构,一个Look-up table对应矩阵结构,两个直方图图形输出的数据结构,并且将它做基本的设定,在用cvCalcHist()放入图形的数据,绘制出灰阶直方图的图形,再来,利用cvNormalizeHist()计算器率密度函数(PDF),机率密度函数有一条规则,所有机率的总和为1,因此,利用cvNormalizeHist()很快的就可以把机率密度函数算出,而在做累积分配直方图,则是用for循环慢慢的累加,制造Look-up
Table
的时候,则是让它乘以255并且给它用uchar型别转换,将转换后的结果存到CvMatrix数据结构里,在用cvLUT()函式做对应,因此均化的灰阶图片就这样被制造出来啦.

cvEqualizeHist()
将单信道8bits uchar型别的图片做直方图等化的算法,输入为单信道uchar型别的IplImage数据结构,输出为直方图等化后单信道uchar型别IplImage数据结构
cvEqualizeHist(
输入单信道uchar型别IplImage数据结构,输出单信道uchar型别数据结构)
 

本文出自:http://bbs.ednchina.com/BLOG_ARTICLE_201549.HTM

抱歉!评论已关闭.