接自上一篇“基础知识”,本文里的色彩空间的转换不再赘述。。。
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