直方图的简单应用(显示,均衡化)

首先,我们先了解什么是直方图:

http://baike.baidu.com/view/1164383.htm

 

 

其实我们从小就有接触直方图这东西了,好像以前数学考试很多题目都是通过直方分布图来求各种分布情况和概率

其实,在OPENCV,直方图也是一个分解图像的各方面的概率,如RGB,HSV等,让我们更好利用这些概率去处理一些东西

总之几个词吧:形象,方便

灰度直方图的定义

灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数(或该灰度级像素出现的频率):其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数(频率)。
一维直方图的结构表示为

高维直方图可以理解为图像在每个维度上灰度级分布的直方图。


我们以前会把直方图更多地想象成一幅“图”,继而理解图中横坐标,纵坐标的意义。而在OpenCV中,应该更多把直方图看做数据结构来理解。

下面我们直接来讲应用了:

创建直方图 cvCreateHist()

  1. CvHistogram* cvCreateHist(
  2. int dims, //直方图维数
  3. int* sizes,//直方图维数尺寸
  4. int type, //直方图的表示格式
  5. float** ranges=NULL,//图中方块范围的数组
  6. int uniform=1 //归一化标识
  7. );
CvHistogram* cvCreateHist(   
    int dims, //直方图维数   
    int* sizes,//直方图维数尺寸  
    int type, //直方图的表示格式  
        float** ranges=NULL, //图中方块范围的数组  
    int uniform=1 //归一化标识  
    );  

通过cvCreateHist()我们创建一个直方图数据结构。

计算图像直方图的函数CalcHist():

  1. void cvCalcHist(
  2. IplImage** image, //输入图像(也可用CvMat**)
  3. CvHistogram* hist, //直方图指针
  4. int accumulate=0, //累计标识。如果设置,则直方图在开始时不被清零。
  5. const CvArr* mask=NULL//操作 mask, 确定输入图像的哪个象素被计数
  6. );
void cvCalcHist(   
    IplImage** image, //输入图像(也可用CvMat**)  
    CvHistogram* hist, //直方图指针  
                 int accumulate=0, //累计标识。如果设置,则直方图在开始时不被清零。  
    const CvArr* mask=NULL //操作 mask, 确定输入图像的哪个象素被计数  
    );  
第一个参数 输入图像跟我们上面创建的直方图维数相关,一维要一个图像,二维要输入两个图像

通过这个CalcHist()函数将我们的图像和上面新建的直方图打上联系


具体参数如何赋值如何用,我们看一下下面的例子:

一、显示一维图像的直方图

既然这里的直方图是数据结构,那我们如何才能显示出我们以前常见的RGB分布直方图的“图”呢?

一般在构建直方图数据结构有这么三个连续步骤:

  1. cvCreateHist() //创建直方图
  2. cvCalcHist()//直方图,图像计算
  3. cvNormalizeHist()//归一化
cvCreateHist() //创建直方图
cvCalcHist()//直方图,图像计算
cvNormalizeHist()//归一化


我们可以通过GUI自己构造一个这样的显示灰度级直方图子函数myShowHist():

  1. //自定义显示直方图函数 窗口名 源图像
  2. void myShowHist(constchar* name,IplImage * src)
  3. {
  4. char window[100]; //新窗口
  5. IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
  6. cvCvtColor(src,gray_plane,CV_BGR2GRAY);
  7. int hist_size = 256; //直方图尺寸
  8. int hist_height = 256;
  9. // float range[] = {0,255}; //灰度级的范围
  10. // float* ranges[]={range};
  11. //创建一维直方图,统计图像在[0 255]像素的均匀分布
  12. // CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);//参数完整版
  13. CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY);//省略默认版
  14. //计算灰度图像的一维直方图
  15. cvCalcHist(&gray_plane,gray_hist,0,0);
  16. //归一化直方图
  17. cvNormalizeHist(gray_hist,1.0);
  18. //扩展倍数
  19. int scale = 2;
  20. //创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数(*scale)
  21. IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);
  22. cvZero(hist_image);
  23. //统计直方图中的最大直方块(按回比例除乘)
  24. float max_value = 0;
  25. cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);
  26. //分别将每个直方块的值绘制到图中
  27. for(int i=0;i<hist_size;i++)
  28. {
  29. float bin_val = cvQueryHistValue_1D(gray_hist,i);//像素i的概率
  30. int intensity = cvRound(bin_val*hist_height/max_value);//要绘制的高度
  31. cvRectangle(hist_image,
  32. cvPoint(i*scale,hist_height-1),
  33. cvPoint((i+1)*scale - 1, hist_height - intensity),
  34. CV_RGB(255,255,255));
  35. }
  36. cvNamedWindow( name, 1 );
  37. cvShowImage(name,src);
  38. sprintf(window, "%s_histogram", name);//新窗口
  39. cvShowImage( window, hist_image );
  40. }
  41. int main(int argc,char** argv )
  42. {
  43. IplImage * src= cvLoadImage("baboon.jpg");
  44. myShowHist("Source",src);
  45. cvWaitKey(0);
  46. return 0;
  47. }
//自定义显示直方图函数       窗口名          源图像
void myShowHist(const char* name,IplImage * src)
{
     char window[100]; //新窗口
    IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
    cvCvtColor(src,gray_plane,CV_BGR2GRAY);

    int hist_size = 256;    //直方图尺寸
    int hist_height = 256;
//    float range[] = {0,255};  //灰度级的范围
//    float* ranges[]={range};
    //创建一维直方图,统计图像在[0 255]像素的均匀分布
//    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);//参数完整版
    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY);//省略默认版
    //计算灰度图像的一维直方图
    cvCalcHist(&gray_plane,gray_hist,0,0);
    //归一化直方图
    cvNormalizeHist(gray_hist,1.0);

    //扩展倍数
    int scale = 2;
    //创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数(*scale)
    IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);
    cvZero(hist_image);
    //统计直方图中的最大直方块(按回比例除乘)
    float max_value = 0;
    cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);

    //分别将每个直方块的值绘制到图中
    for(int i=0;i<hist_size;i++)
    {
        float bin_val = cvQueryHistValue_1D(gray_hist,i); //像素i的概率
        int intensity = cvRound(bin_val*hist_height/max_value);  //要绘制的高度
        cvRectangle(hist_image,
            cvPoint(i*scale,hist_height-1),
            cvPoint((i+1)*scale - 1, hist_height - intensity),
            CV_RGB(255,255,255));
    }
    cvNamedWindow( name, 1 );
    cvShowImage(name,src);
    sprintf(window, "%s_histogram", name); //新窗口
    cvShowImage( window, hist_image );
}

int main(int argc, char** argv )
{
    IplImage * src= cvLoadImage("baboon.jpg");
    myShowHist("Source",src);
    cvWaitKey(0);
    return 0;
}


效果如下:



以下我们就可以用这个写好的子函数方便处理很多东西了O(∩_∩)O哈哈~

二、直方图均衡化

直方图均衡化(Histogram Equalization)是直方图最典型的应用,是图像点运算的一种。

直方图均衡化是通过灰度变换将一幅图像转换为另一幅具有均衡直方图,即在每个灰度级上都具有接近相同的像素点数过程。

如下图是理想的单纯高斯分布映射的示意图:


OpenCV中的cvEqualizeHist()

  1. void cvEqualizeHist( const CvArr* src, CvArr* dst );
void cvEqualizeHist( const CvArr* src, CvArr* dst );  

参数很明确简单,但是要注意下面:
此函数只能处理单通道的灰色图像,对于彩色图像,我们可以把每个信道先Split出来,分别均衡化,再Merge为彩色图像


代码参考如下:

  1. int main(int argc,char** argv )
  2. {
  3. IplImage * image= cvLoadImage("baboon.jpg");
  4. myShowHist("Source",image);
  5. IplImage* eqlimage=cvCreateImage(cvGetSize(image),image->depth,3);
  6. //分别均衡化每个信道
  7. IplImage* redImage=cvCreateImage(cvGetSize(image),image->depth,1);
  8. IplImage* greenImage=cvCreateImage(cvGetSize(image),image->depth,1);
  9. IplImage* blueImage=cvCreateImage(cvGetSize(image),image->depth,1);
  10. cvSplit(image,blueImage,greenImage,redImage,NULL);<SPAN style="WHITE-SPACE: pre"> </SPAN>//分解3通道
  11. <SPAN style="WHITE-SPACE: pre"> </SPAN>
  12. cvEqualizeHist(redImage,redImage);
  13. cvEqualizeHist(greenImage,greenImage);
  14. cvEqualizeHist(blueImage,blueImage);
  15. //均衡化后的图像
  16. cvMerge(blueImage,greenImage,redImage,NULL,eqlimage);//合并
  17. myShowHist("Equalized",eqlimage);
  18. cvWaitKey(0);
  19. return 0;
  20. }
int main(int argc, char** argv )
{
    IplImage * image= cvLoadImage("baboon.jpg");

    myShowHist("Source",image);

    IplImage* eqlimage=cvCreateImage(cvGetSize(image),image->depth,3);
    //分别均衡化每个信道
    IplImage* redImage=cvCreateImage(cvGetSize(image),image->depth,1);
    IplImage* greenImage=cvCreateImage(cvGetSize(image),image->depth,1);
    IplImage* blueImage=cvCreateImage(cvGetSize(image),image->depth,1);
    cvSplit(image,blueImage,greenImage,redImage,NULL);	//分解3通道
    	
    cvEqualizeHist(redImage,redImage);
    cvEqualizeHist(greenImage,greenImage);
    cvEqualizeHist(blueImage,blueImage);

    //均衡化后的图像
    cvMerge(blueImage,greenImage,redImage,NULL,eqlimage);//合并
    myShowHist("Equalized",eqlimage);

    cvWaitKey(0);
    return 0;
}

现象如下:

均衡前:



均衡后:




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值