标签:
灰度直方图:表示图像中具有某种灰度级的像素的个数,反映了图像中某种灰度出现的频率。
直方图均衡:从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。
根据直方图得到累进概率函数,在根据该函数得到映射函数,将原有的灰度图映射到成一个新的灰度图,得到了灰度直方图均衡后的效果。
参考: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