这次和前几次一样,也是只介绍算法思路和实现步骤,再给出本人项目中Retinex的代码,Retinex的原理就不做解释。参考的论文是《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images》
本篇参考论文把算法分为两个部分,第一个部分是全局色调映射;第二部分是局部色调映射。全局自适应这部分原理既简单又容易实现,局部自适应这部分原理不简单但是容易实现。因为我们只需要按着步骤来即可。
1、全局色调映射步骤:
本篇论文把过程写的很详细,全局映射按公式(4)即可完成,那里面的参数如何求解呢?按公式(5)即可计算出。这个算法是我实现过程中最省心的。。。。
2、局部色调映射
这部分的原理有点难理解,但是实现还是很容易的,因为他把实现公式又给我们列出来了。
首先求出α,然后实现β,最后带入公式得结果。
-------------------------------------------------------------------------------------------------------------------------------------------------------
其中的Hg(x,y)是什么呢?他也给出了说明:
Hg(x,y)就是引导滤波后的结果,可见这篇算法进行了改进,使用了引导滤波代替了高斯滤波。为什么替换?这篇论文是这么解释的:为了减少光晕伪影。为什么会减少我没有看明白。
接下来是本人项目的实现步骤,共分为五步:
第一步:色彩空间转化
第二步:全局色调映射
Lave = exp(Lsum / (1.0*rows*cols));//计算对数平均值
Mat out_image(rows,cols,CV_32FC1);//定义输出图像
double Ymax=-1e9,Ysum=0,Yave=0,Ymin=1e9;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
//记录XYZ空间下x,y,z的比率
double rateX=xyz[i][j].x/(xyz[i][j].x+xyz[i][j].y+xyz[i][j].z);
double rateY=xyz[i][j].y/(xyz[i][j].x+xyz[i][j].y+xyz[i][j].z);
//对亮度值进行压缩
xyz[i][j].y = log(1 + xyz[i][j].y / Lave) / log(1 + Lmax / Lave);
//还原x,y,z的比率
xyz[i][j].x=xyz[i][j].y/rateY*rateX;
xyz[i][j].z=xyz[i][j].y/rateY*(1-rateX-rateY);
第三步:局部色调映射——引导滤波
resultImage = guidedFilter3(out_image, out_image, 9, 0.01);//对分通道分别进行引导滤波,半径为1、3、5...等奇数
Mat guidedFilter3(Mat srcMat, Mat guidedMat, int radius, double eps)//引导滤波器
{
//转换源图像信息,将输入扩展为64位浮点型,以便以后做乘法
srcMat.convertTo(srcMat, CV_64FC1, 1.0);
guidedMat.convertTo(guidedMat, CV_64FC1, 1.0);
/*imshow("srcMat",srcMat);
imshow("guidedMat",guidedMat);*/
//各种均值计算
Mat mean_p, mean_I, mean_Ip, mean_II;
//生成待滤波图像均值mean_p
boxFilter(srcMat, mean_p, CV_64FC1, Size(radius, radius));
//生成引导图像均值mean_I
boxFilter(guidedMat, mean_I, CV_64FC1, Size(radius, radius));
//生成互相关均值mean_Ip
boxFilter(srcMat.mul(guidedMat), mean_Ip, CV_64FC1, Size(radius, radius));
//生成引导图像自相关均值mean_II
boxFilter(guidedMat.mul(guidedMat), mean_II, CV_64FC1, Size(radius, radius));
//计算相关系数,计算Ip的协方差cov和I的方差var
Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);
Mat var_I = mean_II - mean_I.mul(mean_I);
//计算参数系数a、c
Mat c = cov_Ip / (var_I + eps);
Mat b = mean_p - c.mul(mean_I);
//计算系数a、b的均值
Mat mean_a, mean_b;
boxFilter(c, mean_a, CV_64FC1, Size(radius, radius));
boxFilter(b, mean_b, CV_64FC1, Size(radius, radius));
//生成输出矩阵
Mat dstImage = mean_a.mul(srcMat) + mean_b;
return dstImage;
}
第四步:局部色调映射——计算比例因子带入公式
//获得两个因子,进行色调映射
double aerfa = 1 + 36.0 * xyz[i][j].y/Ymax;
double beta=10*Yave;
double result=resultImage.at<float>(i,j);
xyz[i][j].y=aerfa*log(xyz[i][j].y/(result+a)+beta+1);
第五步:局部色调映射——归一化
//归一化
xyz[i][j].y=(log(xyz[i][j].y+a)-log(Lmin+a))/(log(Lmax+a)-log(Lmin+a));
第六步:色彩空间还原