失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 不调用python函数实现直方图均衡化_数字图像处理之直方图均衡化

不调用python函数实现直方图均衡化_数字图像处理之直方图均衡化

时间:2021-08-08 08:06:07

相关推荐

不调用python函数实现直方图均衡化_数字图像处理之直方图均衡化

讲解直方图均衡化之前,先解释一下图像的统计直方图与累加概率。

1. 统计直方图,就是统计图像中每一个像素值的个数。比如对于8位的图像,每一个像素点的像素值取值范围是0~255,那么其统计直方图就是统计0~255中所有像素值在图像中的个数,比如0像素值有几个点、1像素值有几个点、2像素值有几个点......像素255有几个点,如下图所示:

2. 像素的概率,也就是该像素值的统计直方图值(像素数)除以图像的总像素数,假设像素x的统计直方图值为hist(x),图像的总像素数为size,那么该像素的概率为:

像素值x的累加概率,就是所有小于等于x的像素值的像素数,除以图像的总像素数,可按下式计算:

3. 接下来讲解直方图均衡化的原理。通常认为,图像的统计直方图分布越均匀,图像的质量越好,直方图均衡化可以提升图像的对比度和质量。比如有的图像整体较暗,那么说明其直方图中低像素值分布较多,高像素值分布较少,这时可以使用直方图均衡化来平衡其直方图分布,即减少低像素值,增加高像素值。从直观上看,均衡化的效果就是图像的部分区域相对原来变亮了,所以提升了图像的对比度。

直方图均衡化就是一个所有像素值重映射的过程。比如像素值x的直方图均衡化之后的值可按下式计算,其中n为图像的每一个像素点的位宽,对于灰度图通常n=8,P(x)为像素值x的累加概率。

使用C++实现上述算法:

voidmy_equalizeHist(Matsrc,Mat&dst){dst = Mat::zeros(src.size(), CV_8UC1);floathist_tmp[256]={0.0}; for(int i = 0; i < src.rows; i++) {uchar *p = src.ptr(i); for(int j = 0; j < src.cols; j++) {hist_tmp[p[j]] += 1.0; //统计直方图 } } uchar lutt[256] = {0};floatimgsize=1.0/(src.rows*src.cols);hist_tmp[0]=hist_tmp[0]*imgsize;lutt[0]=uchar(hist_tmp[0]*255+0.5); for(inti=1;i256;i++) {hist_tmp[i]=hist_tmp[i-1]+hist_tmp[i]*imgsize;lutt[i]=uchar(hist_tmp[i]*255+0.5);//计算查找表,加0.5是为了四舍五入取整 } dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 0; i < dst.rows; i++) {uchar *p_s = src.ptr(i);uchar*p_d=dst.ptr(i); for(int j = 0; j < dst.cols; j++) {p_d[j]=lutt[p_s[j]];//像素重映射 }}}

运行上述代码,对Lena图像进行直方图均衡化,结果如下,可以看到直方图均衡化之后,图像对比度增强了,统计直方图分布也更加均匀。

原图

直方图均衡化之后图像

原图的统计直方图

直方图均衡化之后的统计直方图

4. 观察上方H(x)的计算公式,P(x)的取值范围是0~1,H(x)与P(x)具有线性关系。为了进一步提升图像对比度,可以对P(x)作一个非线性的S型变换T(P(x)),并保证变换之后T(P(x))的取值范围还在0~1之间。本文分别构造了T1和T2这两个非线性函数用于非线性变换,同时我们可以把原本H(x)与P(x)的线性关系看成函数T0,于是有以下三种变换:

画出以上三种变换函数在0~1区间的曲线如下图所示,可以看到T1和T2的曲线都是S型。

从而H(x)与P(x)有三种映射关系:

增加非线性变换的代码实现与上述代码大同小异:

#define PI 3.14159inlinefloatT1(floatx){return(0.5*(sin(PI*x-PI/2)+1));}inline float T2(float x){float xx=3-x*6;return(1.0/(1+exp(xx)));}void my_equalizeHist(Mat src, Mat &dst){dst = Mat::zeros(src.size(), CV_8UC1); float hist_tmp[256] = {0.0}; for(int i = 0; i < src.rows; i++) {uchar *p = src.ptr(i); for(int j = 0; j < src.cols; j++) {hist_tmp[p[j]] += 1.0; //统计直方图 } } uchar lutt[256] = {0}; float imgsize = 1.0/(src.rows*src.cols); hist_tmp[0] = hist_tmp[0]*imgsize; //lutt[0] = uchar(hist_tmp[0]*255 + 0.5); //T0 //lutt[0] = uchar(T1(hist_tmp[0])*255 + 0.5); //T1lutt[0]=uchar(T2(hist_tmp[0])*255+0.5); //T2 for(int i = 1; i < 256; i++) //计算累加概率 {hist_tmp[i] = hist_tmp[i-1] + hist_tmp[i]*imgsize; //计算查找表,加0.5是为了四舍五入取整 //lutt[i]=uchar(hist_tmp[i]*255+0.5);//T0 //lutt[i] = uchar(T1(hist_tmp[i])*255 + 0.5); //T1 lutt[i] = uchar(T2(hist_tmp[i])*255 + 0.5);//T2 } dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 0; i < dst.rows; i++) {uchar *p_s = src.ptr(i); uchar *p_d = dst.ptr(i); for(int j = 0; j < dst.cols; j++) {p_d [j] = lutt[p_s [j]]; //像素重映射 } }}

分别选择T0、T1和T2变换,运行以上代码,得到的结果如下,可以看到使用T1和T2变换得到结果的对比度相对于T0有所提高。

T0

T1

T2

5. 上述直方图均衡算法还存在一个问题,就是当图像的0像素值占很大比例时,从起始的0像素值的累加概率就很大了,导致后面的1~255像素值的累加概率均变得很大,从而造成直方图均衡化之后的像素值都偏大。比如下图,可以看到直方图均衡化之后图像变白了,严重失真。

原图

直方图均衡化之后的图像

为解决上述问题,我们可以把0像素值排除在外,也即0像素值不做处理,从像素值1开始计算累加概率,同时计算累加概率时使用到的图像总像素数应减去0像素值的像素数。代码如下:

void my_equalizeHist(Mat src, Mat &dst){dst = Mat::zeros(src.size(), CV_8UC1); float hist_tmp[256] = {0.0}; for(int i = 0; i < src.rows; i++) {uchar *p = src.ptr(i); for(int j = 0; j < src.cols; j++) {hist_tmp[p[j]] += 1.0; //统计直方图 } } uchar lutt[256] = {0}; //总像素数减去0像素值的像素数floatimgsize=1.0/(src.rows*src.cols-hist_tmp[0]);hist_tmp[1]=hist_tmp[1]*imgsize; //从像素值1开始计算累加概率 //lutt[1] = uchar(hist_tmp[1]*255 + 0.5); //lutt[1] = uchar(T1(hist_tmp[1])*255 + 0.5); lutt[1] = uchar(T2(hist_tmp[1])*255 + 0.5); dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 2; i < 256; i++) //计算累加概率 {hist_tmp[i] = hist_tmp[i-1] + hist_tmp[i]*imgsize; //lutt[i] = uchar(hist_tmp[i]*255 + 0.5); //lutt[i] = uchar(T1(hist_tmp[i])*255 + 0.5); lutt[i] = uchar(T2(hist_tmp[i])*255 + 0.5); } dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 0; i < dst.rows; i++) {uchar *p_s = src.ptr(i); uchar *p_d = dst.ptr(i); for(int j = 0; j < dst.cols; j++) {p_d [j] = lutt[p_s [j]]; //像素重映射 } }}

运行上述代码,得到结果,可以看到直方图均衡化之后,像素值不会再有整体偏高的问题。

如果觉得《不调用python函数实现直方图均衡化_数字图像处理之直方图均衡化》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。