【fishing-pan:https://blog.csdn.net/u013921430转载请注明出处】
前言
直方图均衡化是最基础的图像处理方法之一,也是本人接触图像处理时最先接触到的算法。算法很简单,但是却不得不说非常的巧妙。本文将从方法的数学基础出发讲解直方图均衡化背后的数学原理,并提供matlab实现代码。
直方图均衡化
图像灰度分布的直方图,顾名思义,就是图像中灰度值数目统计的直方图。直方图均衡化处理是将原图的灰度分布直方图中灰度分布密集的部分扩散成在全局范围内的均匀分布。这样就增加了像素灰度值的动态范围,从而达到增强图像整体对比度的效果。直方图均衡化是一种灰度变换的方法,其对图像进行非线性的拉伸,重新分配像素值。如下图所示;
![](https://i-blog.csdnimg.cn/blog_migrate/ed6b968a9c05b0754d10175a1e8ff90a.png)
图1 左图是均衡化之前的图像灰度分布直方图,右图是理想情况下均衡化之后的灰度分布直方图。
原理
图像变换是需要找到一种合适的变换关系的,直方图均衡化也不例外。为了方便表示,我们假设,图像灰度区间为[0,1];对于区间内的任意像素值,我们需要进行如下变换。
上述式子应该满足两个条件;
1. 在区间[0,1]内, T(r) T ( r ) 单调递增;
2. 应该有 0≤T(r)≤1 0 ≤ T ( r ) ≤ 1 。
同样的,反变换 r=T−1(s) r = T − 1 ( s ) ,也应该服从上面两个条件。条件1 保证了保证原图各灰度级在变换后仍保持从黑 到白(或从白到黑)的排列次序。条件2 保证变换前后灰度值动态范围的一致性。
假设原图r概率密度为 Pr(r) P r ( r ) ,变换后的概率密度为 Ps(s) P s ( s ) 。由于图像灰度总值时不变的,那么就有以下公式;
又由图1中的公式可知
则带入上述式子中,有
所以,我们所要找的变换关系就找到了。
这个式子说明了,变换后的图像的灰度值时根据原图中该点的灰度值的概率分布函数得到的。
离散图像中的变换关系
在离散的图像中,假设图像总共有N个像素点,总共有L个像素级。图像中灰度级为k的像素点的数目为
nk
n
k
。则有如下关系;
则函数 T(r) T ( r ) 可以表示成如下式子;
![](https://i-blog.csdnimg.cn/blog_migrate/30f5bdb046371fa2f5dbde6e55e44fe2.png)
假如有一张八位的图像,图像中一点的灰度为
k
k
,那么在经过变换后,灰度应该为;
代码
下面提供自己编写的代码。
利用Matlab实现的代码
clear all;
clc
I=imread('lena.jpg'); %读入图像;
J=rgb2gray(I); %彩色图转换成灰度图;
figure,imshow(J);
title('原始图');
[m n]=size(J);
pro=zeros(1,256);
sum=zeros(1,256);
for i=1:m
for j=1:n
pro(J(i,j)+1)=pro(J(i,j)+1)+1;
end
end
sum(1)=pro(1);
for g=2:256
sum(g)=pro(g)+sum(g-1);
end
newim=zeros(m,n);
sum=sum.*255/(m*n); %概率分布函数
for i=1:m
for j=1:n
newim(i,j) =uint8(sum(J(i,j)+1));
if newim(i,j)>255
newim(i,j)=255; %重新分布灰度值
end
end
end
figure,imshow(uint8(newim) );
title('自己编写的直方图均衡化处理结果');
figure,histeq(J);
title('Matlab自带的直方图均衡化处理结果');
计算结果
![原始图像](https://i-blog.csdnimg.cn/blog_migrate/14523129eaa2373a6ad5354c6dc49e64.jpeg)
![自编的均衡化结果](https://i-blog.csdnimg.cn/blog_migrate/d575b510b993d3c0a0cbfdd83304a793.jpeg)
![Matlab自带的均衡化函数处理结果](https://i-blog.csdnimg.cn/blog_migrate/93234ff9bfed3b1bd0d590577436b46d.jpeg)
基于OpenCV的代码
/*-------------------------------------------------------------------
OpenCV测试函数。 2018年4月10日,潘正宇
功能:自己编写直方图均衡化
------------------------------------------------------------------*/
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void Histeq(Mat &Scr,Mat &Dst)
{
int Col = Scr.cols;
int Row = Scr.rows;
int Size = Col*Row;
//int *Hist = new int[Size];
Mat pdFunc = Mat::zeros(1, 256, CV_32FC1); //概率密度直方图;
for (int r = 0; r < Row; r++)
{
for (int c = 0; c < Col; c++)
{
pdFunc.at<float>(Scr.at<uchar>(r, c)) = pdFunc.at<float>(Scr.at<uchar>(r, c)) + 1; //统计每个点对应像素值的数目
}
}
Mat PDFunc = Mat::zeros(1, 256, CV_32FC1); //概率分布直方图;
PDFunc.at<float>(0) = pdFunc.at<float>(0);
for (int i = 1; i < 256; i++)
{
PDFunc.at<float>(i) = PDFunc.at<float>(i - 1) + pdFunc.at<float>(i);
int s = PDFunc.at<float>(i);
}
//PDFunc = PDFunc / Size;
for (int r = 0; r < Row; r++)
{
for (int c = 0; c < Col; c++)
{
int s= 255 * PDFunc.at<float>(Scr.at<uchar>(r, c))/Size;
if (s < 0){ s = 0; }
if (s > 255){ s = 255; }
Dst.at<uchar>(r, c) = (uchar)s;
}
}
}
int main()
{
Mat ScrImage = imread("C:\\Users\\most_pan\\Desktop\\lena.jpg",0); //以灰度图的形式读入一张图
imshow("原始图", ScrImage);
Mat DstImage = ScrImage.clone();
Histeq(ScrImage,DstImage);
imshow("直方图均衡的结果", DstImage);
waitKey(0);
return 0;
}
计算结果
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/fb5c50038dd320957d188635a388e9c9.png)
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/cd99e72f5d6c13df34c3dc5024737a57.png)
已完。。