用C++(OpenCV)自己实现彩色直方图均衡化
2015-05-28 10:32
1111 查看
对于直方图均衡化,我的理解是一个图像原来的像素集中在一个灰度范围里,我们对这种图不敏感,因为其灰度值集中,变化不明显。如果我们把这些像素点的灰度范围扩大,图像就会显得比较清晰。直方图均衡化就是通过一个映射函数,把原图像素点的灰度值映射为一个新的值,使得图像的像素点灰度值在全部灰度范围内比较均匀分布。
直方图均衡化主要有四步:
第一步是统计每个灰度值出现的次数。
第二步是计算累积函数。
第三步是根据映射函数,建立查找表。
第四步是根据查找表计算新的像素值。
OpenCV自带的函数cvEqualizeHist可以实现直方图均衡化,我参考OpenCV该函数的源代码,自己写了一个myEqualizeHist函数来实现。
另外,为了对均衡化的结果进行理性的分析,我还自己写了一个画直方图的函数。
原理是我先统计好每个灰度值的像素点个数,然后调用opencv里的cvRectangle函数,对于每一个灰度值(0-255)都画出一个对应高度的小矩形,矩形的高度就是该灰度值对应的像素点的个数。
代码如下:
![](http://img.blog.csdn.net/20150528103437567?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWGlhbzEzWXUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150528103452752?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWGlhbzEzWXUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150528103502590?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWGlhbzEzWXUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150528103514374?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWGlhbzEzWXUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150528103522864?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWGlhbzEzWXUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150711142838454?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150528103541994?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWGlhbzEzWXUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
直方图均衡化主要有四步:
第一步是统计每个灰度值出现的次数。
第二步是计算累积函数。
第三步是根据映射函数,建立查找表。
第四步是根据查找表计算新的像素值。
OpenCV自带的函数cvEqualizeHist可以实现直方图均衡化,我参考OpenCV该函数的源代码,自己写了一个myEqualizeHist函数来实现。
另外,为了对均衡化的结果进行理性的分析,我还自己写了一个画直方图的函数。
原理是我先统计好每个灰度值的像素点个数,然后调用opencv里的cvRectangle函数,对于每一个灰度值(0-255)都画出一个对应高度的小矩形,矩形的高度就是该灰度值对应的像素点的个数。
代码如下:
#include <highgui.h> #include <cv.h> #include <stdio.h> using namespace cv; using namespace std; IplImage* myDrawHistogram(int* hist_cal) { //找出直方图中最大值,以便进行归一化 int hist_max = 0; for(int i = 0; i < 256; i++) { if(hist_cal[i] > hist_max) hist_max = hist_cal[i]; } //创建一幅空白的图像,用来显示直方图 IplImage* hist_image = cvCreateImage(cvSize(256 * 3, 64 * 3), 8, 1); cvZero(hist_image); for(int i = 0; i < 256; i++) { CvPoint p0 = cvPoint(i * 3, 0); CvPoint p1 = cvPoint((i + 1) * 3, cvRound(((hist_max - hist_cal[i]) * 64) / hist_max * 3)); cvRectangle(hist_image, p0, p1, cvScalar(255, 255, 255), -1, 8, 0); } return hist_image; } int p[256]; int dst_p[256]; void myEqualizeHist(CvArr* srcarr, CvArr* dstarr) { CvMat sstub; CvMat dstub; CvMat *src = cvGetMat(srcarr, &sstub);//convert CvArr to CvMat CvMat *dst = cvGetMat(dstarr, &dstub); CvSize size = cvGetMatSize(src); int x, y; const int hist_size = 256; //int p[hist_size];//p数组长度为图像的灰度等级(一般为256) fill(p, p + hist_size, 0);//初始化为0 //扫描图像的每一个像素点,像素值为k则hist[k]++ for(y = 0; y < size.height; y++) { const uchar* sptr = src->data.ptr + src->step * y; for(x = 0; x < size.width; x++) { p[sptr[x]]++;//相当于[x][y]这个点对应的像素值++ } } int c[hist_size]; c[0] = p[0]; //累积函数 for(int i = 1; i < hist_size; i++) { c[i] = c[i - 1] + p[i]; } uchar lut[hist_size]; //根据映射函数,建立look up table for(int i = 0; i < hist_size; i++) { int val = cvRound(c[i] * (255.f / (size.width * size.height))); lut[i] = CV_CAST_8U(val);//像素值i映射之后值为lut[i] } //根据look up table,改变图像像素值 for(y = 0; y < size.height; y++) { const uchar* sptr = src->data.ptr + src->step * y; uchar* dptr = dst->data.ptr + dst->step * y; for(x = 0; x < size.width; x++) { dptr[x] = lut[sptr[x]]; } } //计算直方图均衡化之后的图像的像素分布 //int dst_p[hist_size]; fill(dst_p, dst_p + hist_size, 0); for(y = 0; y < size.height; y++) { const uchar* dst_sptr = dst->data.ptr + dst->step * y; for(x = 0; x < size.width; x++) { dst_p[dst_sptr[x]]++;//相当于[x][y]这个点对应的像素值++ } } } int main() { IplImage* image = cvLoadImage("D:\\lena.jpg", 1); cvShowImage("原图像", image); 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); myEqualizeHist(redImage, redImage); cvShowImage("对图像进行直方均衡化之前的R直方图", myDrawHistogram(p)); cvShowImage("对图像进行直方均衡化之后的R直方图", myDrawHistogram(dst_p)); myEqualizeHist(greenImage, greenImage); cvShowImage("对图像进行直方均衡化之前的G直方图", myDrawHistogram(p)); cvShowImage("对图像进行直方均衡化之后的G直方图", myDrawHistogram(dst_p)); myEqualizeHist(blueImage, blueImage); cvShowImage("对图像进行直方均衡化之前的B直方图", myDrawHistogram(p)); cvShowImage("对图像进行直方均衡化之后的B直方图", myDrawHistogram(dst_p)); cvMerge(blueImage, greenImage, redImage, NULL, image); cvShowImage("自己实现的直方图均衡化", image); waitKey(0); return 0; }
相关文章推荐
- C++ OpenCV 实现RGB彩色图像转化成灰度图像再转换成二值图像
- 基于C++实现kinect+opencv 获取深度及彩色数据
- 彩色图像的直方图均衡化--基于OpenCV中EqualizeHist_Demo实现
- C++使用opencv实现彩色直方图计算
- 彩色图像直方图均衡化 --- 基于OpenCV中EqualizeHist_Demo实现
- 图像配准 - 三张灰度图合成彩色图 ECC算法 OpenCV C++/Python实现
- opencv3/C++图像滤波实现
- 如何用C++实现自己的Tensorflow
- opencv生成彩色图c++代码实例及运行结果
- opencv 彩色图像亮度、对比度调节 直方图均衡化
- C++自己实现abs
- RGB彩色图像与灰度图像转换 opencv实现 代码及分析
- Matlab/OpenCV自己实现Harris特征点提取和匹配
- opencv读取彩色/灰度图片像素值并存储在本地文件中c++代码实例及运行结果
- OpenCV2.4.4中利用直方图均衡化增强图像对比度(Mat结构实现)
- 【C++版本】OpenCV实现RGB转HSI
- RANSAC之opencv和C++实现
- OpenCV图像增强算法实现(直方图均衡化、拉普拉斯、Log、Gamma)
- 【OpenCV入门指南】第十篇 彩色直方图均衡化
- opencv生成彩色图c++代码实例及运行结果