我们假设:
数组p1[255/N]存放每个0-(255/N)块像素值的个数;
数组p[255/N]存放归一化直方图,即每个0-(255/N)在[ 0 1 ]区间所占的比例,是像素值在某个范围内的概率;
数组Sum[255/N]存放均衡化结果,离散灰度级的累加和;
K = 255/N, Num = image->width*image->height
0- k p1[1]
1- k p1[2]
2- k p1[3]
3- k p1[4]
4- k p1[5]
......
归一化直方图:
p[1] = p1[1]/Num
p[2] = p1[2]/Num
p[3] = p1[3]/Num
……
直方图均衡:(提高亮度的一种方法)
均衡化变换:
Sum[1] = p[1]
Sum[2] = Sum[1] + p[2]
Sum[3] = Sum[2] + p[3]
……
对于各个0-(255/N)范围内的亮度,factor = 0.5 or other values
0- k Sum[1]*255 + factor
1- k Sum[2]*255 + factor
2- k Sum[3]*255 + factor
3- k Sum[4]*255 + factor
……
CSDN博客:http://blog.csdn.net/soarnic/archive/2008/09/26/2985116.aspx
有相应的基于OpenCV的VC描述,将灰度级拉伸:
int ImageStretchByHistogram( IplImage* src, IplImage* dst )
{
//p[]存放图像各个灰度级的出现概率;
//p1[]存放各个灰度级之前的概率和,用于直方图变换;
//num[]存放图象各个灰度级出现的次数;
assert( src->width == dst->width);
float p[256],p1[256],num[256];//1-256 相当于0-255
//清空三个数组
memset( p, 0, sizeof(p));
memset( p1, 0, sizeof(p1));
memset( num, 0 ,sizeof(num));
int height = src->height;
int width = src->width;
long wmulh = height*width;
//求图像各个灰度级出现的次数,to do use openmp
for (int x=0; x<width; x++)
{
for (int y=0; y<height; y++)
{
//imageData是指向char的指针,所以要转换,单通道单字节的图像像素值的访问
unsigned char v = ((uchar*)(src->imageData + src->widthStep*y))[x];
num[v]++;
}
}
//求存放图像各个灰度级的出现概率,归一化
for (int i=0; i<256; i++)
{
p[i] = num[i]/wmulh;
}
//求存放各个灰度级之前的概率和
for (int i=0; i<256; i++)
{
for(int k=0; k<i; k++)
p1[i] += p[k];
}
//直方图变换
for (int x=0; x<width; x++)
{
for (int y=0; y<height; y++)
{
uchar v = ((uchar*)(src->imageData + src->widthStep*y))[x];
((uchar*)(dst->imageData + dst->widthStep*y))[x] = p1[v]*255 +0.5;
}
}
return 0;
}
使用OpenCV自身直方图均衡化函数
cvEqualizeHist( GrayImage, dstGrayImage);//突出图像的微小灰度区别细节