颜色迁移之五——自适应迁移算法

颜色空间为一个三维的线性空间,通常使用红色、绿色和蓝色(RGB)作为颜色空间的基,但这三原色不能直观地度量色调、饱和度和亮度(HSV),为了体现颜色空间中的不同特性,人们总结了很多颜色空间。由Smith等提出的LMS颜色空间的三个分量分别表示长、中、短激发光谱。而人的视网膜中锥状细胞的光感器对光的波长最敏感。在这个意义上,我们把计算机里的RGB图像表示转换成基于人眼更为敏感波长的LMS表示。实际上不同颜色空间是同构的,因此它们之间必然存在变换矩阵,事实上在Reinhard等给出了RGB和LMS之间的颜色变换,经过变换后的LMS值的分布域和RGB 值的分布域一样,还是比较发散,为了使得LMS数据点更加聚敛,Reinhard等对LMS做了对数变换L=logL,M=logM,S=logS来代替LMS的值。胡国飞等在此基础上求出了LMS的相关矩阵

其中rLM,rMS,rLS分别表示L和M,M和S,L和S的相关系数。大量图像样本的实验结果表明相关矩阵通常不是一个三对角矩阵,甚至根本不是对角占优的矩阵,也就是说LMS三个分量间具有严重的相关性。然后利用特征值分析和主元分析方法来得到复合线性变换矩阵,对LMS值采取一系列平移旋转和变比的线性变换,使得所得的图像各像素的颜色分量基本上消除这种相关性。根据矩阵论,很容易地对相关矩阵进行特征值分解,求出特征值λ1,λ2,λ3和特征向量e1,e2,e3,并记特征矩阵为

然后由求出负载因子矩阵,接着就可以求出LMS到lαβ颜色空间的基向量的过渡矩阵(其中为特征值矩阵的逆),这个C就是要求的复合变换矩阵,即。

对每一幅欲处理的图像,都有不同的过渡矩阵C。利用对自适应的处理颜色图像和形状图像所得到的和,分别求出各自的lαβ颜色空间上的值。而不是利用一个固定的C来处理所有的图像。虽然此算法在运算时间上付出一点代价,自适应的方法更符合图像本身的颜色分布。另外,对一幅图像的所有像素进行处理可以增加统计量的精确度,但是出于计算速度和存储资源考虑,也可以间隔采样以减少处理的数据量,而不影响整体效果。

——————————————————————————————————————-——————————————————————

用的一些函数,其他的大部分参考我之前写的Reinhard算法的给出代码

//矩阵求特征值与特征向量
bool JacbiCor(double *pMatrix,int nDim, double *pdblVects, double *pdbEigenValues, double dbEps,int nJt)  
{  
	for(int i = 0; i < nDim; i ++)   
	{     
		pdblVects[i*nDim+i] = 1.0f;   
		for(int j = 0; j < nDim; j ++)   
		{   
			if(i != j)     
				pdblVects[i*nDim+j]=0.0f;   
		}   
	}   

	int nCount = 0;     //迭代次数  
	while(1)  
	{  
		//在pMatrix的非对角线上找到最大元素  
		double dbMax = pMatrix[1];  
		int nRow = 0;  
		int nCol = 1;  
		for (int i = 0; i < nDim; i ++)          //行  
		{  
			for (int j = 0; j < nDim; j ++)      //列  
			{  
				double d = fabs(pMatrix[i*nDim+j]);   

				if((i!=j) && (d> dbMax))   
				{   
					dbMax = d;     
					nRow = i;     
					nCol = j;   
				}   
			}  
		}  

		if(dbMax < dbEps)     //精度符合要求   
			break;    

		if(nCount > nJt)       //迭代次数超过限制  
			break;  

		nCount++;  

		double dbApp = pMatrix[nRow*nDim+nRow];  
		double dbApq = pMatrix[nRow*nDim+nCol];  
		double dbAqq = pMatrix[nCol*nDim+nCol];  

		//计算旋转角度  
		double dbAngle = 0.5*atan2(-2*dbApq,dbAqq-dbApp);  
		double dbSinTheta = sin(dbAngle);  
		double dbCosTheta = cos(dbAngle);  
		double dbSin2Theta = sin(2*dbAngle);  
		double dbCos2Theta = cos(2*dbAngle);  

		pMatrix[nRow*nDim+nRow] = dbApp*dbCosTheta*dbCosTheta +   
			dbAqq*dbSinTheta*dbSinTheta + 2*dbApq*dbCosTheta*dbSinTheta;  
		pMatrix[nCol*nDim+nCol] = dbApp*dbSinTheta*dbSinTheta +   
			dbAqq*dbCosTheta*dbCosTheta - 2*dbApq*dbCosTheta*dbSinTheta;  
		pMatrix[nRow*nDim+nCol] = 0.5*(dbAqq-dbApp)*dbSin2Theta + dbApq*dbCos2Theta;  
		pMatrix[nCol*nDim+nRow] = pMatrix[nRow*nDim+nCol];  

		for(int i = 0; i < nDim; i ++)   
		{   
			if((i!=nCol) && (i!=nRow))   
			{   
				int u = i*nDim + nRow;  //p    
				int w = i*nDim + nCol;  //q  
				dbMax = pMatrix[u];   
				pMatrix[u]= pMatrix[w]*dbSinTheta + dbMax*dbCosTheta;   
				pMatrix[w]= pMatrix[w]*dbCosTheta - dbMax*dbSinTheta;   
			}   
		}   

		for (int j = 0; j < nDim; j ++)  
		{  
			if((j!=nCol) && (j!=nRow))   
			{   
				int u = nRow*nDim + j;  //p  
				int w = nCol*nDim + j;  //q  
				dbMax = pMatrix[u];   
				pMatrix[u]= pMatrix[w]*dbSinTheta + dbMax*dbCosTheta;   
				pMatrix[w]= pMatrix[w]*dbCosTheta - dbMax*dbSinTheta;   
			}   
		}  

		//计算特征向量  
		for(int i = 0; i < nDim; i ++)   
		{   
			int u = i*nDim + nRow;      //p     
			int w = i*nDim + nCol;      //q  
			dbMax = pdblVects[u];   
			pdblVects[u] = pdblVects[w]*dbSinTheta + dbMax*dbCosTheta;   
			pdblVects[w] = pdblVects[w]*dbCosTheta - dbMax*dbSinTheta;   
		}   

	}  

	for(int i = 0; i < nDim; i ++)   
			pdbEigenValues[i] = pMatrix[i*nDim+i];   

	//设定正负号  
	for(int i = 0; i < nDim; i ++)   
	{  
		double dSumVec = 0;  
		for(int j = 0; j < nDim; j ++)  
			dSumVec += pdblVects[j * nDim + i];  
		if(dSumVec<0)  
		{  
			for(int j = 0;j < nDim; j ++)  
				pdblVects[j * nDim + i] *= -1;  
		}  
	}  
	return 1;
}

//矩阵求逆
void InverseMatrix(double A[3][3],double B[3][3],int n)
{
	int i,j,k,m=2*n;
	double mik,temp;
	double a[3][6]={0};

	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			if(i==j)
				B[i][j]=1.0;
			else
				B[i][j]=0.0;
		}
	}        //初始化B=E

	for(i=0;i<n;i++)
		for(j=0;j<n;j++)
			a[i][j]=A[i][j];  //复制A到a,避免改变A的值
	for(i=0;i<n;i++)
		for(j=n;j<m;j++)
			a[i][j]=B[i][j-n];  //复制B到a,增广矩阵

	for(k=1;k<=n-1;k++)
	{
		for(i=k+1;i<=n;i++)
		{
			mik=a[i-1][k-1]/a[k-1][k-1];
			for(j=k+1;j<=m;j++)
			{
				a[i-1][j-1]-=mik*a[k-1][j-1];
			}
		}
	}        //顺序高斯消去法化左下角为零

	for(i=1;i<=n;i++)
	{
		temp=a[i-1][i-1];
		for(j=1;j<=m;j++)
		{
			a[i-1][j-1]/=temp;
		}
	}        //归一化

	for(k=n-1;k>=1;k--)
	{
		for(i=k;i>=1;i--)
		{
			mik=a[i-1][k];
			for(j=k+1;j<=m;j++)
			{
				a[i-1][j-1]-=mik*a[k][j-1];
			}
		}
	}        //逆序高斯消去法化增广矩阵左边为单位矩阵

	for(i=0;i<n;i++)
		for(j=0;j<n;j++)
			B[i][j]=a[i][j+n];  //取出求逆结果

	for(i=0;i<n;i++)
		for(j=0;j<n;j++)
			if(fabs(B[i][j])<0.0001)
				B[i][j]=0.0;
}

——————————————————————————————————————-——————————————————————

参考文献:胡国飞, 傅健, 彭群生. 自适应颜色迁移[J]. 计算机学报, 2004,27(9):1245-1249.

你可能感兴趣的:(算法,迁移)