本文主要是介绍基于Retinex的人脸关照不变量的提取,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
为了解决人脸的关照问题,现在的研究方法主要有一下3类:
一、基于不变特征的方法、关照变化建模的方法和人脸图像关照归一化的方法。基于不变特征的方法是利用人脸的关照不变特征进行人脸识别,一般指利用朗博关照模型从图像中消除关照的影响。
二、光照建模的方法,主要是指在一个在一个子空间中表示不同关照引起的变化,并估计参数模型,但是此类方法计算量大,不能应用与实时的人脸识别系统中。
三、人脸图像归一化的方法,是指利用基本的图像处理技术对光照图像进行预处理。如:直方图均衡化和伽马校正等方法。
Retinex理论是Land提出的从信号分析角度出发,直接从单张图像中提取光照不变量。
步骤:
首先从原始图像中估计光照图像,然后在对数域里从原图中减去光照图像得到增强后的图像
Retinex方法主要包括两部分:关照的估计和归一化。
光照模型和对数变换:
根据Retinex理论:图像由入射分量和反射分量构成:
其中,表示图像的亮度分量,是缓慢变化的低频信号;表示物体的反射性质,是图像的光照不变量,是图像的高频信息;
- //INFaceTool.h
- #include<opencv2\opencv.hpp>
- using namespace cv;
- Mat normalize8(Mat &X,int model=1);
- // The function applies the adaptive single scale retinex algorithm to an image.
- void adative_sigle_scale_retinex(Mat &img,Mat &L,Mat &Gradient,Mat&LocalInhomogenity,int T=10);
- //This is an auxialry function for computing the iterative convolution
- Mat convolute(Mat &X,Mat&y,Mat&N);
- //INFaceTool.cpp
- #include<opencv2\opencv.hpp>
- #include<core\core.hpp>
- #include"INFaceTool.h"
- using namespace cv;
- //The function adjusts the dynamic range of the grey scale image to the interval [0,255] or [0,1]
- Mat normalize8(Mat&X,int model)
- {
- double max_v_x;
- double min_v_x;
- Mat Y(X.rows,X.cols,CV_64F);
- Mat Ones=Mat::ones(X.rows,X.cols,CV_64F);
- minMaxLoc(X,&min_v_x,&max_v_x,NULL,NULL);
- if(model==1)
- {
- Y=((X-min_v_x*Ones)/(max_v_x*Ones-min_v_x*Ones))*255;
- int nl=Y.rows;
- int nc=Y.cols;
- if(Y.isContinuous())
- {
- nc=nc*nl;
- nl=1;
- }
- for(int j=0;j<nl;j++)
- {
- double*data=Y.ptr<double>(j);
- for(int i=0;i<nc;i++)
- {
- //std::cout<<"data"<<data[i];
- data[i]=ceil(data[i]);
- }
- }
- return Y;
- }
- else
- {
- Y=(X-min_v_x*Ones)/(max_v_x*Ones-min_v_x*Ones);
- return Y;
- }
- }
- void adative_sigle_scale_retinex(Mat &img,Mat &L,Mat &Gradient,Mat&LocalInhomogenity,int T)
- {
- Mat X=img.clone();
- if(X.channels()==3)
- {
- cvtColor(X,X,CV_RGB2GRAY);
- }
- X.convertTo(X,CV_64F);
- X=normalize8(X);
- // Compute spatial gradient in x and y directions
- int a=X.rows;
- int b=X.cols;
- Mat X1=Mat::zeros(a,b+2,CV_64F);
- Mat X1r=X1(Rect(2,0,b,a)); X.copyTo(X1r);
- Mat X2=Mat::zeros(a,b+2,CV_64F);
- Mat X2r=X2(Rect(0,0,b,a));X.copyTo(X2r);
- Mat Gx=X1(Rect(1,0,b,a))-X2(Rect(1,0,b,a));
- X1=Mat::zeros(a+2,b,CV_64F);
- X1r=X1(Rect(0,2,b,a));X.copyTo(X1r);
- X2=Mat::zeros(a+2,b,CV_64F);
- X2r=X2(Rect(0,0,b,a));X.copyTo(X2r);
- Mat Gy=X1(Rect(0,1,b,a))-X2(Rect(0,1,b,a));
- pow(Gx,2,Gx);
- pow(Gy,2,Gy);
- Mat I;
- pow((Gx+Gy),0.5,I);
- //Compute local inhomogenity
- Mat tao=Mat::zeros(a,b,CV_64F);
- Mat Xtmp=Mat::zeros(a+2,b+2,CV_64F);
- Mat Xtmpr=Xtmp(Rect(1,1,b,a));X.copyTo(Xtmpr);
- float suma=0;
- for(int i=1;i<a+1;i++)
- {
- for(int j=1;j<b+1;j++)
- {
- suma=0;
- for(int k=-1;k<2;k++)
- { for(int h=-1;h<2;h++)
- {
- suma=suma+abs(X.at<double>(i-1,j-1)-Xtmp.at<double>(i+k,j+h));
- }
- }
- suma=suma/9;
- tao.at<double>(i-1,j-1)=suma;
- }
- }
- double tao_min,tao_max;
- minMaxLoc(tao,&tao_min,&tao_max,NULL,NULL);
- Mat tao_slash=(tao-tao_min)/(tao_max-tao_min);
- int nl=tao_slash.rows;
- int nc=tao_slash.cols;
- if(tao_slash.isContinuous())
- {
- nc=nc*nl;
- nl=1;
- }
- for(int j=0;j<nl;j++)
- {
- double*data=tao_slash.ptr<double>(j);
- for(int i=0;i<nc;i++)
- {
- //std::cout<<"data"<<data[i];
- data[i]=sin(CV_PI/2*data[i]);
- }
- }
- Scalar m1=mean(I);
- Scalar m2=mean(tao_slash);
- double meanI=m1.val[0];
- double meanH=m2.val[0];
- //Set needed parameters if they are not provided as inputs
- double S=10*exp(-(meanI)/10);
- double h=0.1*exp(-(meanH)/0.1);
- //Determine weight functions
- Mat sqrt_tao_slash;
- Mat sqrt_I;
- pow(tao_slash/h,0.5,sqrt_tao_slash);
- pow(I/S,0.5,sqrt_I);
- Mat alpha=1/(1+sqrt_tao_slash);
- Mat beta=1/(1+sqrt_I);
- Mat weight=alpha.mul(beta);
- //precompute Ns
- Mat w=Mat::zeros(a+2,b+2,CV_64F);
- Mat wr=w(Rect(1,1,b,a));
- weight.copyTo(wr);
- Mat N=Mat::zeros(a,b,CV_64F);
- for(int i=1;i<a+1;i++)
- {
- for(int j=1;j<b+1;j++)
- { suma=0;
- for(int k=-1;k<2;k++)
- {
- for(h=-1;h<2;h++)
- {
- suma=suma+(w.at<double>(i+k,j+h));
- }
- }
- N.at<double>(i-1,j-1)=suma;
- }
- }
- // Start iterative convolution
- Mat L_old;
- X.copyTo(L_old);
- Mat L_new,L_new_s;
- L_new=Mat::zeros(a,b,CV_64F);
- L_new_s=Mat::zeros(a,b,CV_64F);
- for(int i=0;i<T;i++)
- {
- L_new_s=convolute(L_old,weight,N);
- L_new=max(L_new_s,L_old);
- L_new.reshape(0,a);
- L_new.copyTo(L_old);
- }
- //Produce ilumination invariant representation of input image
- nc=X.cols;
- nl=X.rows;
- if(X.isContinuous())
- {
- nc=nc*nl;
- nl=1;
- }
- // R=Mat::zeros(a,b,CV_64F);
- L=Mat::zeros(a,b,CV_64F);;
- for(int j=0;j<nl;j++)
- { //double*dataR=R.ptr<double>(j);
- double*dataX=X.ptr<double>(j);
- double*dataL=L.ptr<double>(j);
- double*dataL_new=L_new.ptr<double>(j);
- for(int i=0;i<nc;i++)
- {
- //dataR[i]=log(dataX[i]+1)-log(dataL_new[i]+1);
- dataL[i]=log(dataL_new[i]+1);
- }
- }
- L=normalize8(L);
- // R=normalize8(R);
- L.convertTo(L,CV_8U);
- //R.convertTo(R,CV_8U);
- I.convertTo(I,CV_8U);
- I.copyTo(Gradient);
- tao_slash.copyTo(tao_slash);
- //tao_slash.copyTo(LocalInhomogenity);
- }
- //This is an auxialry function for computing the iterative convolution
- Mat convolute(Mat &X,Mat&y,Mat&N)
- {
- int a=X.rows;
- int b=X.cols;
- Mat X1=Mat::zeros(a+2,b+2,CV_64F);
- Mat X1r=X1(Rect(1,1,b,a));X.copyTo(X1r);
- Mat w=Mat::zeros(a+2,b+2,CV_64F);
- Mat wr=w(Rect(1,1,b,a));y.copyTo(wr);
- Mat Y=Mat::zeros(a,b,CV_64F);
- double tt;
- for(int i=1;i<a;i++)
- {
- for(int j=1;j<b;j++)
- {
- tt=sum(X1(Rect(j-1,i-1,3,3)).mul(w(Rect(j-1,i-1,3,3)))).val[0];
- Y.at<double>(i-1,j-1)=tt/N.at<double>(i-1,j-1);
- }
- }
- return Y;
- }
这篇关于基于Retinex的人脸关照不变量的提取的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!