原理详解:
假设输入图像为I,高为H、宽为W,I(r,c)代表I的第r行第c列的灰度值,将I中出现的最小灰度级记为Imin,最大灰度级记为Imax,即I(r,c)ϵ[Imin,Imax]\epsilon[Imin,Imax]ϵ[Imin,Imax],为使输出图像O的灰度级范围为[Omin,Omax],I(r,c)和O(r,c)做以下映射关系:
O(r,c)=Omax−OminImax−Imin\frac{Omax-Omin}{Imax-Imin}Imax−IminOmax−Omin(I(r,c)-Imin)+Omin
其中0≤\leq≤r≤\leq≤H,0≤\leq≤c≤\leq≤W, O(r,c)代表O的第r行第c列的灰度值。这个过程就是常称的直方图正规化。因为0≤\leq≤I(r,c)−IminImax−Imin\frac{I(r,c)-Imin}{Imax-Imin}Imax−IminI(r,c)−Imin≤\leq≤1,所以O(r,c)1, 所以O(r,c)1,所以O(r,c)ϵ\epsilonϵ[Omin,Omax],一般令Omin=0,Omax=255。显然,直方图正规化是一种自动选取a和b的值的线性变换方法,其中:
a=Omax−OminImax−Imin\frac{Omax-Omin}{Imax-Imin}Imax−IminOmax−Omin,b=Omin-Omax−OminImax−Imin\frac{Omax-Omin}{Imax-Imin}Imax−IminOmax−Omin*Imin
在直方图正规化中最核心的步骤之一是计算原图中出现的最小灰度级和最大灰度级,OpenCV提供的函数:
void minMaxLoc(InputArray src, double* minVal, double* maxVal=0,Point* minLoc=0,Point* maxLoc=0,InputArray mask =noArray())
src 输入矩阵
minVal 最小值,double类型指针
maxVal 最大值,double类型指针
minLoc 最小值的位置索引,Point类型指针
maxLoc 最大值的位置索引,Point类型指针
利用minMaxLoc函数不仅可以计算出矩阵中的最大值和最小值,而且可以求出最大值的位置和最小值的位置,当然在使用过程中 如果只想得到最大值和最小值,则将其他的变量值设为NULL即可。例如:
minMaxLoc(src,&minVal,&maxValue,NULL,NULL)
只计算出最大值和最小值。
对于直方图正规化的c++实现,首先利用minMaxLoc函数计算出原图中的最大值和最小值,然后使用函数convertScaleAbs或者成员函数convertTo完成直方图正规化中的线性变换步骤:
//输入图像矩阵
Mat I = imread("E://image1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//找到I的最大值和最小值
double Imax,Imin;
minMaxLoc(I,&Imin,&Imax,NULL,NULL);
//设置Omin 和Omax
double Omin=0,Omax=255;
//计算a和b
double a =(Omax-Omin)/(Imax-Imin);
double b =Omin-a*Imin;
//线性变换
Mat 0;
convertScaleAbs(I,O,a,b);
//显示原图和直方图正规化的效果
imshow("I",I);
imshow("O",O);
对于图像直方图正规化的操作,OpenCV提供的函数normalize实现了类似的功能。
void normalize(InputArray src, OutputArray dst, double alpha=1,double beta =0, int norm_type = NORM_L2,int dtype=-1,InputArray mask = noArray())
在介绍这个函数的作用之前,首先需要了解矩阵范数的概念。矩阵src范数一般有三种形式:
(1)1-范数----------------计算矩阵中值的绝对值的和:
∣∣src∣∣1||src||_1∣∣src∣∣1=∑r=1M\sum\limits_{r=1}^M