接自上一篇“基础知识”,本文里的色彩空间的转换不再赘述。。。
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值进行显示。
图 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); }
颜色迁移— —Reinhard经典算法,布布扣,bubuko.com
原文:http://blog.csdn.net/sin_geek/article/details/22443537