您的位置:首页 > 编程语言 > C语言/C++

用C++(OpenCV)自己实现彩色直方图均衡化

2015-05-28 10:32 1111 查看
对于直方图均衡化,我的理解是一个图像原来的像素集中在一个灰度范围里,我们对这种图不敏感,因为其灰度值集中,变化不明显。如果我们把这些像素点的灰度范围扩大,图像就会显得比较清晰。直方图均衡化就是通过一个映射函数,把原图像素点的灰度值映射为一个新的值,使得图像的像素点灰度值在全部灰度范围内比较均匀分布。

直方图均衡化主要有四步:

第一步是统计每个灰度值出现的次数。

第二步是计算累积函数。

第三步是根据映射函数,建立查找表。

第四步是根据查找表计算新的像素值。

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;
}
















内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: