标签:
彩色的图片处理方式本质上和黑白图片一样,基本上就是先将RGB颜色空间投影到YUV颜色空间,此时每个通道都相当于黑白图,然后对Y(亮度)通道进行灰度图的直方图均衡化,然后合成投影到RGB颜色空间。“实际上,对彩色分量rgb分别做均衡化,会产生奇异的点,图像不和谐。一般采用的是用yuv空间进行亮度的均衡即可。”维基百科的原话。
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 //将图像转换到YUV空间,并计算得到Y通道的直方图count 63 void SkinSegmentHSV(IplImage* src, IplImage* &imgout, int* count) 64 { 65 IplImage* RImg = NULL; 66 IplImage* GImg = NULL; 67 IplImage* BImg = NULL; 68 IplImage* YImg = NULL; 69 IplImage* dst = NULL; 70 71 if (!src || !imgout) { return; } 72 73 CvSize SrcSize = cvGetSize(src); 74 75 RImg = cvCreateImage(SrcSize, 8, 1); 76 GImg = cvCreateImage(SrcSize, 8, 1); 77 BImg = cvCreateImage(SrcSize, 8, 1); 78 YImg = cvCreateImage(SrcSize, 8, 1); 79 dst = cvCreateImage(SrcSize, 8, 3); 80 81 //转换到HSV空间并变成拆分成三个通道 82 cvCvtColor(src, dst, CV_BGR2YCrCb); 83 cvSplit(dst, YImg, GImg, BImg, NULL); 84 85 86 //统计直方图 87 getResult(YImg, count); 88 89 cvCopy(YImg, imgout); 90 91 cvReleaseImage(&YImg); 92 cvReleaseImage(&RImg); 93 cvReleaseImage(&GImg); 94 cvReleaseImage(&BImg); 95 96 } 97 98 //处理过的Y通道和另外两个通道转回rgb 99 void toRGB(IplImage* src, IplImage* mergeImage, IplImage* &YImg) 100 { 101 IplImage* dst = NULL; 102 IplImage* VImg = NULL; 103 IplImage* UImg = NULL; 104 IplImage* temp = NULL; 105 106 CvSize SrcSize = cvGetSize(src); 107 108 dst = cvCreateImage(SrcSize, 8, 3); 109 VImg = cvCreateImage(SrcSize, 8, 1); 110 UImg = cvCreateImage(SrcSize, 8, 1); 111 temp = cvCreateImage(SrcSize, 8, 1); 112 113 //转换到YUV空间并变成拆分成三个通道 114 cvCvtColor(src, dst, CV_BGR2YCrCb); 115 cvSplit(dst, temp, UImg, VImg, NULL); 116 117 for (int x = 0; x<src->height; x++) 118 { 119 for (int y = 0; y<src->width; y++) 120 { 121 CvMat* cur = cvCreateMat(3, 1, CV_32F); 122 cvmSet(cur, 0, 0, ((uchar*)(YImg->imageData + x*YImg->widthStep))[y]); 123 cvmSet(cur, 1, 0, ((uchar*)(UImg->imageData + x*UImg->widthStep))[y]); 124 cvmSet(cur, 2, 0, ((uchar*)(VImg->imageData + x*VImg->widthStep))[y]); 125 126 for (int i = 0; i<3; i++) 127 { 128 double xx = cvmGet(cur, i, 0); 129 ((uchar*)mergeImage->imageData + x*mergeImage->widthStep)[y * 3 + i] = xx; 130 } 131 } 132 } 133 134 cvCvtColor(mergeImage, mergeImage, CV_YCrCb2BGR); 135 cvReleaseImage(&dst); 136 cvReleaseImage(&VImg); 137 cvReleaseImage(&UImg); 138 cvReleaseImage(&temp); 139 140 } 141 142 143 //用得到的映射函数处理原来的灰度图 144 void resetVimg(IplImage* VImg, int* h) 145 { 146 if (!VImg) { return; } 147 int i, j; int value = 0; 148 for (i = 0; i < VImg->height; i++) { 149 for (j = 0; j < VImg->width; j++) { 150 value = cvGetReal2D(VImg, i, j); 151 int v = h[int(value)]; 152 //防止灰度值越界,进行一下处理 153 if (v>255) v = 255; 154 if (v < 0) v = 0; 155 *(VImg->imageData + i*VImg->widthStep + j) = v; 156 } 157 } 158 159 } 160 161 //求累积分布函数 162 void getCDF(int * result, int* cdf){ 163 cdf[0] = result[0]; 164 for (int i = 1; i < 256; i++){ 165 cdf[i] = cdf[i - 1] + result[i]; 166 } 167 } 168 169 //通过累积分布函数cdf得到映射函数h 170 void Equalization(int* cdf, int* h, int m, int n){ 171 int min; 172 for (int i = 0; i < 256; i++){ 173 if (cdf[i] != 0){ 174 min = cdf[i]; 175 break; 176 } 177 } 178 for (int i = 0; i < 256; i++){ 179 h[i] = cvRound((cdf[i] - min)*1.0 / (m*n - min) * 255); 180 } 181 } 182 183 int main() 184 { 185 IplImage* src = NULL; 186 IplImage* originSrcV = NULL; 187 IplImage* ansSrc = NULL; 188 IplImage* mergeImage = NULL; 189 190 191 int result[256]; //直方图 192 int cdf[256]; 193 int h[256]; 194 195 196 197 src = cvLoadImage("lena.jpg", -1); 198 199 CvSize size = cvGetSize(src); 200 201 mergeImage = cvCreateImage(size, 8, 3); 202 ansSrc = cvCreateImage(size, 8, 1); 203 originSrcV = cvCreateImage(size, 8, 1); 204 205 /********* 处理原图像得到V通道的灰度和该图的直方图 ********/ 206 SkinSegmentHSV(src, ansSrc, result); 207 cvNamedWindow("亮度", 1); 208 cvShowImage("亮度", ansSrc); 209 cvCopy(ansSrc, originSrcV); 210 211 // 创建直方图图像 212 int nHistImageWidth = 255; 213 int nHistImageHeight = 200; //直方图图像高度 214 int nScale = 2; 215 IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, result); 216 217 218 /********* 进行均衡化处理并显示出直方图 ********/ 219 getCDF(result, cdf); 220 Equalization(cdf, h, ansSrc->width, ansSrc->height); 221 resetVimg(ansSrc, h); 222 getResult(ansSrc, result); 223 cvNamedWindow("均衡化", 1); 224 cvShowImage("均衡化", ansSrc); 225 cvWaitKey(0); 226 IplImage *pHistImage2 = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, result); 227 toRGB(src, mergeImage, ansSrc); 228 229 230 cvNamedWindow("均衡化前直方图", 1); 231 cvShowImage("均衡化前直方图", pHistImage); 232 cvNamedWindow("均衡化后直方图", 1); 233 cvShowImage("均衡化后直方图", pHistImage2); 234 cvWaitKey(0); 235 cvNamedWindow("src", 1); 236 cvShowImage("src", src); 237 cvNamedWindow("均衡化的彩色图片", 1); 238 cvShowImage("均衡化的彩色图片", mergeImage); 239 cvWaitKey(0); 240 241 cvReleaseImage(&src); 242 cvReleaseImage(&originSrcV); 243 cvReleaseImage(&ansSrc); 244 245 246 return 0; 247 }
彩色图做的直方图均衡化 |
|
原图 |
直方图均衡化的结果 |
标签:
原文地址:http://www.cnblogs.com/coderqich/p/4545010.html