码迷,mamicode.com
首页 > 其他好文 > 详细

直方图均衡

时间:2015-06-01 22:26:02      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:

灰度直方图:表示图像中具有某种灰度级的像素的个数,反映了图像中某种灰度出现的频率。

直方图均衡:从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。

根据直方图得到累进概率函数,在根据该函数得到映射函数,将原有的灰度图映射到成一个新的灰度图,得到了灰度直方图均衡后的效果。

参考:http://zh.wikipedia.org/wiki/%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1%E5%8C%96

  1 /************************************************
  2   作者:qich
  3   用途:灰度直方图均衡化练习 
  4 ************************************************/ 
  5 #include <opencv2/opencv.hpp> 
  6 #include "cv.h"
  7 #include "cxcore.h"
  8 #include "highgui.h"
  9 #include "cvaux.h"
 10 #include <algorithm>
 11 using namespace cv;
 12 
 13 //画出一个白色的矩形
 14 void FillWhite(IplImage *pImage)
 15 {
 16     cvRectangle(pImage, cvPoint(0, 0), cvPoint(pImage->width, pImage->height), CV_RGB(255, 255, 255), CV_FILLED);
 17 }
 18 
 19 // 根据直方图创建直方图图像
 20 IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, int *pcvHistogram)
 21 {
 22     IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, 1);
 23     //将直方图像的背景染成白色
 24     FillWhite(pHistImage);
 25     float fMaxHistValue = 0;
 26     //统计直方图中的最大直方块
 27     for (int i = 0; i < 256; i++){
 28         if (fMaxHistValue < pcvHistogram[i])
 29             fMaxHistValue = pcvHistogram[i];
 30     }
 31     //分别将每个直方块的值绘制到图中
 32     int i;
 33     for (i = 0; i < nImageWidth; i++)
 34     {
 35         int fHistValue = pcvHistogram[i]; //像素为i的直方块大小
 36         int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight);  //要绘制的高度
 37 
 38         cvRectangle(pHistImage,
 39             cvPoint(i * nScale, nImageHeight - 1),
 40             cvPoint((i + 1) * nScale - 1, nImageHeight - nRealHeight),
 41             cvScalar(i/1.5, 0, 0, 0), //为了方便观测直方图,将每一个柱体的颜色染成其表示的像素的颜色的映射(为了避免白色部分看不清)
 42             CV_FILLED
 43             );
 44     }
 45     return pHistImage;
 46 }
 47 
 48 //得到灰度图的直方图
 49 void getResult(IplImage* VImg, int* result){
 50     //初始化直方图
 51     for (int i = 0; i < 256; i++)
 52         result[i] = 0;
 53     //得到直方图,方法很简单粗暴
 54     for (int i = 0; i < VImg->height; i++)  {
 55         for (int j = 0; j < VImg->width; j++)   {
 56             int value = cvGetReal2D(VImg, i, j);
 57             result[value]++; //直接统计像素值对应的点的个数,像素值取0-255的整数
 58         }
 59     }
 60 }
 61 
 62 //将图像转换到HSV空间,并计算得到V通道的直方图count
 63 void SkinSegmentHSV(IplImage* src, IplImage* &imgout, int* count)
 64 {
 65 
 66     IplImage* HSV = NULL;
 67     IplImage* HImg = NULL;
 68     IplImage* SImg = NULL;
 69     IplImage* VImg = NULL;
 70 
 71     if (!src || !imgout)  { return; }
 72 
 73     CvSize SrcSize = cvGetSize(src);
 74 
 75     HSV = cvCreateImage(SrcSize, 8, 3);
 76     HImg = cvCreateImage(SrcSize, 8, 1);
 77     SImg = cvCreateImage(SrcSize, 8, 1);
 78     VImg = cvCreateImage(SrcSize, 8, 1);
 79 
 80     //转换到HSV空间并变成拆分成三个通道
 81     cvCvtColor(src, HSV, CV_BGR2HSV);
 82     cvSplit(HSV, HImg, SImg, VImg, NULL);
 83 
 84 
 85     //统计直方图
 86     getResult(VImg, count);
 87 
 88     cvCopy(VImg, imgout);
 89 
 90     cvReleaseImage(&HSV);
 91     cvReleaseImage(&VImg);
 92     cvReleaseImage(&HImg);
 93     cvReleaseImage(&SImg);
 94 
 95 }
 96 
 97 
 98 //用得到的映射函数处理原来的灰度图
 99 void resetVimg(IplImage* VImg, int* h)
100 {
101     if (!VImg)  { return; }
102     int i, j;  int value = 0;
103     for (i = 0; i < VImg->height; i++)  {
104         for (j = 0; j < VImg->width; j++)   {
105             value = cvGetReal2D(VImg, i, j);
106             int v = h[int(value)];
107             //防止灰度值越界,进行一下处理
108             if (v>255) v = 255;
109             if (v < 0) v = 0;
110             *(VImg->imageData + i*VImg->widthStep + j) = v;
111         }
112     }
113 
114 }
115 
116 //求累积分布函数
117 void getCDF(int * result, int* cdf){
118     cdf[0] = result[0];
119     for (int i = 1; i < 256; i++){
120         cdf[i] = cdf[i - 1] + result[i];
121     }
122 }
123 
124 //通过累积分布函数cdf得到映射函数h
125 void Equalization(int* cdf, int* h, int m, int n){
126     int min;
127     for (int i = 0; i < 256; i++){
128         if (cdf[i] != 0){
129             min = cdf[i];
130             break;
131         }
132     }
133     for (int i = 0; i < 256; i++){
134         h[i] = cvRound((cdf[i] - min)*1.0 / (m*n - min) * 255);
135     }
136 }
137 
138 int main()
139 {
140     IplImage* src = NULL;
141     IplImage* originSrcV = NULL;
142     IplImage* ansSrc = NULL;
143 
144 
145     int result[256]; //直方图
146     int cdf[256];
147     int h[256];
148 
149     cvNamedWindow("src", 1);
150 
151     src = cvLoadImage("lena.jpg", -1);
152     cvShowImage("src", src);
153     CvSize size = cvGetSize(src);
154 
155     ansSrc = cvCreateImage(size, 8, 1);
156     originSrcV = cvCreateImage(size, 8, 1);
157 
158     /*********    处理原图像得到V通道的灰度和该图的直方图    ********/
159     SkinSegmentHSV(src, ansSrc, result);
160     cvNamedWindow("V通道", 1);
161     cvShowImage("V通道", ansSrc);
162     cvCopy(ansSrc, originSrcV);
163 
164     // 创建直方图图像
165     int nHistImageWidth = 255;
166     int nHistImageHeight = 200;  //直方图图像高度
167     int nScale = 2;
168     IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, result);
169     cvNamedWindow("均衡化前直方图", 1);
170     cvShowImage("均衡化前直方图", pHistImage);
171 
172     /*********       进行均衡化处理并显示出直方图         ********/
173     getCDF(result, cdf);
174     Equalization(cdf, h, ansSrc->width, ansSrc->height);
175     resetVimg(ansSrc, h);
176     getResult(ansSrc, result);
177     cvNamedWindow("均衡化", 1);
178     cvShowImage("均衡化", ansSrc);
179 
180     IplImage *pHistImage2 = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, result);
181     cvNamedWindow("均衡化后直方图", 1);
182     cvShowImage("均衡化后直方图", pHistImage2);
183 
184 
185     /*********       官方均衡化处理并显示出直方图         ********/
186     cvEqualizeHist(originSrcV, ansSrc);
187     cvNamedWindow("均衡化(官方函数)", 1);
188     cvShowImage("均衡化(官方函数)", ansSrc);
189     getResult(ansSrc, result);
190     cvNamedWindow("均衡化后直方图(官方函数)", 1);
191     cvShowImage("均衡化后直方图(官方函数)", pHistImage2);
192 
193     cvWaitKey(0);
194 
195     cvReleaseImage(&src);
196     cvReleaseImage(&originSrcV);
197     cvReleaseImage(&ansSrc);
198 
199 
200     return 0;
201 }

直方图均衡化(灰度图)

 技术分享

原本的灰度直方图,可以看出其灰度值集中在某个区间之内。

 技术分享

自己写的函数进行灰度直方图均衡化之后得到的灰度图。

 技术分享

语言自带的均衡化函数得到的均衡化之后的灰度直方图。对比上图,目测没有区别。

 技术分享

为了增加对比度,我使用了V通道的灰度图,这是原图。

 技术分享

进行均衡化之后显然图片的对比度增强了。

 

 

直方图均衡

标签:

原文地址:http://www.cnblogs.com/coderqich/p/4544984.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!