opencv 皮肤光泽评判


参考文档 知网上的一篇期刊文章《基于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),它的定义式:

opencv 皮肤光泽评判_第1张图片

其中,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)


效果经测试还成,能够区分出皮肤光泽的好坏,配上方差 或者 我用的相对平均偏差统计方法食用效果更佳

你可能感兴趣的:(opencv)