摘要:
本文参考论文color transfer between images,实现了 图片的色彩转移。
大体思路:
主要思想是把图片的颜色的均值和方差调整成跟另一幅图片的均值和方差差不多。
最简单的思路是在RGB颜色空间上进行均值和方差的调整。但如论文所述,RGB颜色空间三个通道之间存在较大的相关性,难以对每个通道单独作出调整。为此,选择了Lab色彩空间,因为Lab三个通道之间的相关性很弱。
主要流程为:
1,把源图片和目标图片由RGB转换为Lab颜色空间;
2,分别两个计算各个通道的均值和方差,假设m1、m2、d1、d2分别为源图像和目标图像Lab下某一通道的均值和方差;
3,对源图像的每一通道的每个像素点作运算(设p为对应像素值):p=(p-m1)*(d2/d1)+m2;
4,把图像由Lab空间转换成RGB空间
5,对转换回的RGB图像作越界检测矫正处理。
程序运行效果图如下:
原始图片:
参考的颜色图片:
对原始图片进行转移的结果:
程序是在Visual studio 2008+opencv2.1下实现的,具体代码如下:
View Code
#include "cv.h"
#include "highgui.h"
#include<math.h>
#include <stdio.h>
bool colorTransfer(IplImage *img1,IplImage *img2,IplImage *&dst);
bool colorTranssferByLab(IplImage *img1,IplImage *img2,IplImage *&dst);
int main()
{
cvNamedWindow("原始图片");
cvNamedWindow("目标色彩");
cvNamedWindow("颜色转移结果");
IplImage * img1,*img2,*dst;
//第一组
img1=cvLoadImage("p2.jpg");
img2=cvLoadImage("p3.jpg");
cvShowImage("原始图片",img1);
cvShowImage("目标色彩",img2);
dst=cvCloneImage(img1);
colorTransfer(img1,img2,dst);
cvShowImage("颜色转移结果",dst);
cvWaitKey(300000);
//第二组
img1=cvLoadImage("p6.jpg");
img2=cvLoadImage("p3.jpg");
cvShowImage("原始图片",img1);
cvShowImage("目标色彩",img2);
dst=cvCloneImage(img1);
colorTransfer(img1,img2,dst);
cvShowImage("颜色转移结果",dst);
cvWaitKey(30000);
//第三组
img1=cvLoadImage("p6.jpg");
img2=cvLoadImage("p2.jpg");
cvShowImage("原始图片",img1);
cvShowImage("目标色彩",img2);
dst=cvCloneImage(img1);
colorTransfer(img1,img2,dst);
cvShowImage("颜色转移结果",dst);
cvWaitKey(30000);
//第三组
cvDestroyAllWindows();
}
bool colorTransfer(IplImage *img1,IplImage *img2,IplImage *&dst)
{
double sum=0;
double m1[3],m2[3],d1[3],d2[3];
int i,j,k,x,y;
IplImage *src1=cvCloneImage(img1),*src2=cvCloneImage(img2);
int npixs1=src1->width*src1->height;
int npixs2=src2->width*src2->height;
//计算各个通道的均值和方差
for(i=0;i<3;i++)
{
m1[i]=0;
for(x=0;x<src1->height;x++)
{
uchar *ptr=(uchar*)(src1->imageData+x*src1->widthStep);
for(y=0;y<src1->width;y++)
{
m1[i]+=ptr[3*y+i];
}
}
m1[i]/=npixs1;
}
for(i=0;i<3;i++)
{
d1[i]=0;
for(x=0;x<src1->height;x++)
{
uchar *ptr=(uchar*)(src1->imageData+x*src1->widthStep);
for(y=0;y<src1->width;y++)
{
d1[i]+=(ptr[3*y+i]-m1[i])*(ptr[3*y+i]-m1[i]);
}
}
d1[i]/=npixs1;
d1[i]=sqrt(d1[i]);
}
for(i=0;i<3;i++)
{
m2[i]=0;
for(x=0;x<src2->height;x++)
{
uchar *ptr=(uchar*)(src2->imageData+x*src2->widthStep);
for(y=0;y<src2->width;y++)
{
m2[i]+=ptr[3*y+i];
}
}
m2[i]/=npixs2;
}
for(i=0;i<3;i++)
{
d2[i]=0;
for(x=0;x<src2->height;x++)
{
uchar *ptr=(uchar*)(src2->imageData+x*src2->widthStep);
for(y=0;y<src2->width;y++)
{
d2[i]+=(ptr[3*y+i]-m2[i])*(ptr[3*y+i]-m2[i]);
}
}
d2[i]/=npixs2;
d2[i]=sqrt(d2[i]);
}
//对原图像做变换
double rate[3];
for(i=0;i<3;i++)
{
rate[i]=d2[i]/d1[i];
for(x=0;x<src1->height;x++)
{
uchar *ptr=(uchar*)(src1->imageData+x*src1->widthStep);
for(y=0;y<src1->width;y++)
{
double tmp=ptr[3*y+i];
int t=(int)((tmp-m1[i])*rate[i]+m2[i]);
if(t<0) //对越界像素值进行调整
{
t=0;
}
if(t>255)
{
t=255;
}
ptr[3*y+i]=t;
}
}
}
dst=cvCloneImage(src1);
return true;
}
bool colorTranssferByLab(IplImage *img1,IplImage *img2,IplImage *&dst)
{
double sum=0;
double m1[3],m2[3],d1[3],d2[3];
int i,j,k,x,y;
IplImage *src1=cvCloneImage(img1),*src2=cvCloneImage(img2);
cvCvtColor(img1,src1,CV_RGB2Lab);
int npixs1=src1->width*src1->height;
int npixs2=src2->width*src2->height;
//计算各个通道的均值和方差
for(i=0;i<3;i++)
{
m1[i]=0;
for(x=0;x<src1->height;x++)
{
uchar *ptr=(uchar*)(src1->imageData+x*src1->widthStep);
for(y=0;y<src1->width;y++)
{
m1[i]+=ptr[3*y+i];
}
}
m1[i]/=npixs1;
}
for(i=0;i<3;i++)
{
d1[i]=0;
for(x=0;x<src1->height;x++)
{
uchar *ptr=(uchar*)(src1->imageData+x*src1->widthStep);
for(y=0;y<src1->width;y++)
{
d1[i]+=(ptr[3*y+i]-m1[i])*(ptr[3*y+i]-m1[i]);
}
}
d1[i]/=npixs1;
d1[i]=sqrt(d1[i]);
}
for(i=0;i<3;i++)
{
m2[i]=0;
for(x=0;x<src2->height;x++)
{
uchar *ptr=(uchar*)(src2->imageData+x*src2->widthStep);
for(y=0;y<src2->width;y++)
{
m2[i]+=ptr[3*y+i];
}
}
m2[i]/=npixs2;
}
for(i=0;i<3;i++)
{
d2[i]=0;
for(x=0;x<src2->height;x++)
{
uchar *ptr=(uchar*)(src2->imageData+x*src2->widthStep);
for(y=0;y<src2->width;y++)
{
d2[i]+=(ptr[3*y+i]-m2[i])*(ptr[3*y+i]-m2[i]);
}
}
d2[i]/=npixs2;
d2[i]=sqrt(d2[i]);
}
double rate[3];
for(i=0;i<3;i++)
{
rate[i]=d2[i]/d1[i];
}
//计算。。。
for(i=0;i<3;i++)
{
for(x=0;x<src1->height;x++)
{
uchar *ptr=(uchar*)(src1->imageData+x*src1->widthStep);
for(y=0;y<src1->width;y++)
{
double tmp=ptr[3*y+i];
int t=(int)((tmp-m1[i])*rate[i]+m2[i]);
if(t<0)
{
t=0;
}
if(t>255)
{
t=255;
}
ptr[3*y+i]=t;
}
}
}
dst=cvCloneImage(src1);
cvCvtColor(src1,dst,CV_Lab2RGB);
/*for(i=0;i<3;i++)
{
for(x=0;x<dst->height;x++)
{
uchar *ptr=(uchar*)(dst->imageData+x*dst->widthStep);
for(y=0;y<dst->width;y++)
{
int t=ptr[3*y+i];
if(t<0)
{
t=0;
}
if(t>255)
{
t=255;
}
ptr[3*y+i]=t;
}
}
}*/
return true;
}