首页 > 其他 > 详细

颜色迁移— —Reinhard经典算法

时间:2014-03-29 05:01:54      阅读:1730      评论:0      收藏:0      [点我收藏+]

接自上一篇“基础知识”,本文里的色彩空间的转换不再赘述。。。        

Reinhard等人根据lαβ颜色空间中各通道互相不关联的特点,提出了一组适用于各颜色分量的色彩迁移公式,较好的实现了彩色图像之间的色彩迁移。基本思想就是根据着色图像的统计分析确定一个线性变换,使得目标图像和源图像在lαβ空间中具有同样的均值和方差。

因此需要计算两幅图像的均值和标准方差。假设l、a、b分别是源图像lαβ通道原有的数据,L、A、B分别是变换后得到新的源图像lαβ通道的值,ml、ma、mb和ml’、ma’、mb’分别是源图像和着色图像的三个颜色通道的均值,nl、na、nb和nl’、na’、nb’表示它们的标准方差。

首先,将源图像原有的数据减掉源图像的均值

L = l – ml

A = a – ma

B = b – mb

再将得到的新数据按比例放缩,其放缩系数是两幅图像标准方差的比值

L’ = (nl’ / nl)* L

A’ = (na’ / na)* A

B’ = (nb’ / nb)* B

将得到的l’、a’、b’分别加上目标图像三个通道的均值,得到最终数据

L = L’ + ml’

A = A’ + ma’

B = B’ + mb’

整理后得到目标图像与源图像之间的像素关系表达

L = (nl’ / nl)* (l – ml) + ml’

A = (na’ / na)* (a – ma) + ma’

B = (nb’ / nb)* (b – mb) + mb’

事实上这组式子表示的就是一个线性方程,以两幅图像的标准方差的比值作为斜率,两幅图像各个通道的均值作为一个点。这个简单的线性变换保证了目标图像和着色图像在lαβ颜色空间中具有相同的均值和方差。将变换后l、α、β的值作为新图像三个通道的值,然后显示的时候再将这三个通道转换为RGB值进行显示。

                                 bubuko.com,布布扣

                                                                                           图 reinhard算法效果图

Reinhard 等人的色彩迁移算法的优点是实现简单,且运行效率很高。但该算法由于是整体色彩迁移,因此它对全局颜色基调单一的图像的有着良好的迁移效果。而对于颜色内容丰富的图像,则效果并不那么明显。一般解决方式是引入人机交互选取样本块的方法,同时还要求用户指定样本块之间的对应关系。这样就给用户增加了许多繁琐的交互。当图像的色彩比较复杂时,用户是无法手工精确地选取样本块的,此时,该算法也将失去作用。

 

BOOL TranRein(LPBYTE lpDIBBits, LONG lmageWidth, LONG lmageHeight,LPBYTE lpDIBBits2, LONG lmageWidth2, LONG lmageHeight2,LPBYTE lpDIBBits3)
{
	int i;
	int j;
	int nindex;
	double al,aa,ab,vl,va,vb,al2,aa2,ab2,vl2,va2,vb2;
	double* lpImageLab = new  double[lmageWidth*lmageHeight*3];
	double* lpImageLab2 = new  double[lmageWidth2*lmageHeight2*3];
	double* lpImageLab3 = new  double[lmageWidth*lmageHeight*3];

	//目标图像转换为lab,并求lab的均值及标准差
	for(j = 0;j <lmageHeight; j++)
	{
		for(i = 0; i <lmageWidth; i++)
		{	
			nindex=((lmageHeight-j-1)*lmageWidth+i);
			RgbToLab(lpDIBBits[nindex*3+2],lpDIBBits[nindex*3+1],lpDIBBits[nindex*3+0],
				lpImageLab[nindex*3+0],lpImageLab[nindex*3+1],lpImageLab[nindex*3+2]);
		}
	}
	AverageVariance(lpImageLab,lmageWidth,lmageHeight,al,aa,ab,vl,va,vb);

	//源图像转换为lab,并求lab的均值及标准差
	for(j = 0;j <lmageHeight2; j++)
	{
		for(i = 0; i <lmageWidth2; i++)
		{	
			nindex=((lmageHeight2-j-1)*lmageWidth2+i);
			RgbToLab(lpDIBBits2[nindex*3+2],lpDIBBits2[nindex*3+1],lpDIBBits2[nindex*3+0],
				lpImageLab2[nindex*3+0],lpImageLab2[nindex*3+1],lpImageLab2[nindex*3+2]);
		}
	}
	AverageVariance(lpImageLab2,lmageWidth2,lmageHeight2,al2,aa2,ab2,vl2,va2,vb2);

	//求结果图像的lab
	for(i = 0;i <lmageWidth*lmageHeight; i++)
	{
		lpImageLab3[i*3+0] = (lpImageLab[i*3+0] - al) * vl2/vl + al2;
		lpImageLab3[i*3+1] = (lpImageLab[i*3+1] - aa) * va2/va + aa2;
		lpImageLab3[i*3+2] = (lpImageLab[i*3+2] - ab) * vb2/vb + ab2;
	}

	//将结果图像的lab转换为RGB
	for(j = 0;j <lmageHeight; j++)
	{
		for(i = 0; i <lmageWidth; i++)
		{	
			nindex=((lmageHeight-j-1)*lmageWidth+i);

			LabToRgb(lpImageLab3[nindex*3+0],lpImageLab3[nindex*3+1],lpImageLab3[nindex*3+2],
				lpDIBBits3[nindex*3+2],lpDIBBits3[nindex*3+1],lpDIBBits3[nindex*3+0]);
		}
	}
	return TRUE;
}

void AverageVariance(double* lpLab,int Width,int Height,double& al,double& aa,double& ab,double& vl,double& va,double& vb)
{
	double suml=0;
	double suma=0;
	double sumb=0;
	double lsuml=0;
	double lsuma=0;
	double lsumb=0;

	//分行求平均,避免和过大而溢出
	for(int j=0;j<Height;j++)
	{		
		for(int i=0;i<Width;i++)
		{
			lsuml+=lpLab[(j*Width+i)*3];
			lsuma+=lpLab[(j*Width+i)*3+1];
			lsumb+=lpLab[(j*Width+i)*3+2];		
		}
		suml += lsuml/Width;
		suma += lsuma/Width;
		sumb += lsumb/Width;
		lsuml=lsuma=lsumb=0;
	}
	al = suml/Height;
	aa = suma/Height;
	ab = sumb/Height;

	suml=suma=sumb=0;
	for(int i=0;i<Width*Height;i++)
	{		
		suml += pow(lpLab[i*3]-al,2);
		suma += pow(lpLab[i*3+1]-aa,2);
		sumb += pow(lpLab[i*3+2]-ab,2);		
	}
	vl = sqrt(suml);
	va = sqrt(suma);
	vb = sqrt(sumb);
}

PS:其中RgbToLab函数与LabToRgb函数在上一篇中。。。。。。。。。。。。。。

 

颜色迁移— —Reinhard经典算法,布布扣,bubuko.com

颜色迁移— —Reinhard经典算法

原文:http://blog.csdn.net/sin_geek/article/details/22443537

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!