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

直方图均衡——彩色图片

时间:2015-06-01 22:21:48      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:

     彩色的图片处理方式本质上和黑白图片一样,基本上就是先将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

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