参考文档 知网上的一篇期刊文章《基于Retinex图像增强算法的面部皮肤光泽度评价研究 焦志鑫》
抄一段介绍:Retinex 是一种常用的图像增强方法 由 Land 于 1963 年提出。Retinex 的基础理论是物体的颜色由物 体对长波( 红色) 、中波( 绿色) 和短波( 蓝色) 光线的 反射能力来决定,而不是由反射光强度的绝对值来决 定,物体的色彩不受光照非均匀性的影响,具有一致 性,即 Retinex 是以色感一致性( 颜色恒常性) 为基础 的。利用 Retinex 算法可以处理雾天退化图像,进而有 效地去除雾的退化作用,提高图像的对比度和清晰度。更多的理论知识可以参考http://blog.csdn.net/carson2005/article/details/9502053,计算机视觉小菜鸟的专栏的《Retinex算法详解》。
几个重要结论:在Retinex算法中定义一副图像S(x,y)可以用反射图像R(x,y)点乘入射图像L(x,y)构成:
定义一种输出图像r(x,y),它的定义式:
其中,F(x,y)为中心环绕函数:
C为高斯环绕尺度,经验值70~90,lamba为尺度,它要求:
说白了就是已知S(x,y),要 求R(x,y),所以就是先确定lamda值,后计算F(x,y),再计算得r(x,y)最终得出R(x,y)
计算出了R(x,y),并没有结束,得到了是每一个点上的值,按照论文里的说明,需要对R(x,y)计算像素均值作为皮肤光泽度评判指标。
贴下关键代码,我是把RGB通道分离,针对3个频段都做一遍,然后算下每个通道的均值,在返回。
/*---单尺度Retinex算法---*/
/*
Rxy = pow(10,(log10(Sxy)-log10(Fxy*Sxy))//是卷积不是乘
利用Rxy值的离散程度来检测图片的光泽程度
完成通道分离,积分,计算lambda,计算Fxy
对三通道分别做SSR_Cal,求和
*/
int SSR(Mat& img)
{
/*---初始参数:高斯环绕尺度C,经验值70~90;三通道初始化---*/
double c = 80;
double sum = 0.0;
double lambda;
int i ,j;
Mat rImg,gImg,bImg;
vector channels;
split(img,channels);
bImg = channels.at(0);
gImg = channels.at(1);
rImg = channels.at(2);
for(i = 0;i < rImg.rows;i++)
{
for(j = 0;j < rImg.cols;j++)
{
sum += exp((-1)*((i*i + j *j)/(c*c)));
}
}
lambda = 1.0/sum;
//printf("%lf,%lf\n",sum,lambda);
/*---计算Fxy---*/
double **fx = NULL;
fx = (double **)malloc(rImg.rows * sizeof(double *));
for(i = 0;i < rImg.rows;i++)
{
fx[i] = (double *)malloc(rImg.cols * sizeof(double));
}
for(i = 0;i < rImg.rows;i++)
{
for(j = 0;j < rImg.cols;j++)
{
fx[i][j] = lambda * exp((-1)*((i * i + j * j)/(c * c)));
}
}
//printf("\n%d,%d,%d",SSR_Cal(rImg,fx),SSR_Cal(gImg,fx),SSR_Cal(bImg,fx));
//printf("\n%d",SSR_Cal(rImg,fx)+SSR_Cal(gImg,fx)+SSR_Cal(bImg,fx));
return SSR_Cal(rImg,fx)+SSR_Cal(gImg,fx)+SSR_Cal(bImg,fx);
}
/*---单尺度Retinex后续计算,以及统计学方法:相对平均偏差---*/
/*
后续计算:卷积,做log10,求pow(10,(log10(Sxy[i][j]) - VecB[i][j])),得到Rxy
(∑fabs(Rxy-average))/average
*/
int SSR_Cal(Mat& src,double** Fxy)
{
int N1 = src.rows ,N2 = src.rows;
int M1 = src.cols ,M2 = src.cols;
/*---Sxy初始化---*/
double ** Sxy = NULL;
double ** answer = NULL;
Sxy = (double **)malloc(src.rows * sizeof(double*));
answer = (double **)malloc(src.rows * sizeof(double*));
for(int i = 0;i (i);
for(int j = 0;j < src.cols;j++)
{
Sxy[i][j] = data[j];
//printf("%lf ",Sxy[i][j]);
}
//printf("\n");
}
double **VecB = NULL;
VecB = (double **)malloc((src.rows * 2 -1) * sizeof(double *));
for(int i = 0;i < src.rows * 2 -1;i++)
{
VecB[i] = (double *)malloc((src.cols * 2 - 1) * sizeof(double));
}
/*---做卷积然后做log10---*/
for(int i = 0;i < N1+N2-1;i++)
{
for(int j = 0;j < M1+M2-1;j++)
{
double temp = 0.0;
for(int m = 0;m < N1;m++)
{
for(int n = 0;n < M1;n++)
{
if((i-m)>=0&&(i-m)=0&&(j-n)
效果经测试还成,能够区分出皮肤光泽的好坏,配上方差 或者 我用的相对平均偏差统计方法食用效果更佳