在《一键上妆的BeautyGAN》一文中介绍了,BeautyGAN 的
实现功能:输入两张人脸图片,一张无妆,一张有妆,模型输出换妆之后的结果,即一张上妆图和一张卸妆图。
并在《https://github.com/Honlan/BeautyGAN》中有训练好的模型下载。这里也来试试。
python 复现结果:
输入图:
结果图:
我们只关注生成器部分:
这个生成器相当于前面 “风格转移(style)”两个合并:
把绿色部分合并成一起,就有两个入口,两个出口,和一个共用的中腹。
C++实现
定义数据池:
struct BeautyGAN模型
{
//输入1 素颜图
层数据 * conv0;
InstanceNorm层数据 * inn0;
层数据 * conv1; //2步长缩小
InstanceNorm层数据 * inn1;
层数据 * conv2; //2步长缩小
InstanceNorm层数据 * inn2;
//输入2 样榜图
层数据 * conv3;
InstanceNorm层数据 * inn3;
层数据 * conv4; //2步长缩小
InstanceNorm层数据 * inn4;
层数据 * conv5; //2步长缩小
InstanceNorm层数据 * inn5;
//合并
//----------共用部分---------------->
//主体
int 公用层数量;//12层
层数据 * conv6_17;
InstanceNorm层数据 * inn6_17;
//插值放大
//----------共用部分----------------<
//输出1
层数据 * conv18;
InstanceNorm层数据 * inn18;
//插值放大
层数据 * conv19;
InstanceNorm层数据 * inn19;
层数据 * conv20;
//生成素颜上妆图
//输出2
层数据 * conv21;
InstanceNorm层数据 * inn21;
//插值放大
层数据 * conv22;
InstanceNorm层数据 * inn22;
层数据 * conv23;
//生成样榜卸妆图
//构造函数
BeautyGAN模型();
};
主函数:
void BeautyGAN(char * savefilename,BeautyGAN模型 & sr,char * makeup)
{
int wid=bmp.width;
int hei=bmp.height;
cout<<"输入图像宽度:"<<wid<<endl;
cout<<" 高度:"<<hei<<endl;
//
卷积层 rgb(wid,hei,3);//即 X_img
rgb.data=new float[wid * hei *3];
//无妆(需上妆)图
//jpg转换为RGB卷积层
bmp2RGB(rgb);
wid=rgb.width;
hei=rgb.height;
//---------------------------------------------->
层数据 * 层;
//两个卷积层 交替前传(源,目标)
//用这个传回
卷积层 * di=(卷积层 *)malloc(sizeof(卷积层));
di->width=1;
di->height=1;
di->depth=1;
di->data=new float[1 ];
卷积层 * si=(卷积层 *)malloc(sizeof(卷积层));
si->width=1;
si->height=1;
si->depth=1;
si->data=new float[1 ];
卷积层 *源,*目标;
源 = si;
目标 = di;
int pad;
//有妆样榜图
loadjpg(makeup);
卷积层 Y_img(bmp.width,bmp.height,3);
Y_img.data=new float[bmp.width*bmp.height *3];
//jpg转换为RGB卷积层
bmp2RGB(Y_img);
cout<<"上妆输入..."<<endl;
//固定大小
wid=256;hei=256;
Resize卷积层(*源,wid,hei,3);
if(rgb.width==wid && rgb.height==hei)
卷积层复制(&rgb,源);
else
resize_卷积层(rgb,*源);
cout<<"卷积 0..."<<endl;
卷积和正则化(sr.conv0,1,sr.inn0);
cout<<"卷积 1..."<<endl;
//wid=wid/2;hei=hei/2;
//卷积和正则化(sr.conv1,2,sr.inn1);
步长为2的卷积和正则化(sr.conv1,sr.inn1);
cout<<"卷积 2..."<<endl;
//wid=wid/2;hei=hei/2;
//卷积和正则化(sr.conv2,2,sr.inn2);
步长为2的卷积和正则化(sr.conv2,sr.inn2);
卷积层 合并(wid,hei,256);
合并.data=new float[wid*hei*256];
cout<<"复制..."<<endl;
卷积层 复制(wid,hei,128);
复制.data=合并.data;//合并.data+wid*hei*128;//
卷积层复制(源,&复制);
cout<<"卸妆输入..."<<endl;
wid=256;hei=256;
Resize卷积层(*源,wid,hei,3);
if(Y_img.width==wid && Y_img.height==hei)
卷积层复制(&Y_img,源);
else
resize_卷积层(Y_img,*源);
cout<<"卷积 3..."<<endl;
卷积和正则化(sr.conv3,1,sr.inn3);
cout<<"卷积 4..."<<endl;
//wid=wid/2;hei=hei/2;
//卷积和正则化(sr.conv4,2,sr.inn4);
步长为2的卷积和正则化(sr.conv4,sr.inn4);
cout<<"卷积 5..."<<endl;
//wid=wid/2;hei=hei/2;
//卷积和正则化(sr.conv5,2,sr.inn5);
步长为2的卷积和正则化(sr.conv5,sr.inn5);
cout<<"合并..."<<endl;
复制.data=合并.data+wid*hei*128;//合并.data;//
卷积层复制(源,&复制);
Resize卷积层(*源,wid,hei,256);
卷积层复制(&合并,源);
cout<<"残差块..."<<endl;
残差块总成(sr,源);//从s_di 传入并返回
cout<<"邻近插值..."<<endl;
wid *= 2;hei *= 2;
Resize卷积层(*目标,wid,hei,256);
最近邻插值(*源,*目标);
std::swap (源,目标);
cout<<"卷积 18..."<<endl;
卷积和正则化(sr.conv18,1,sr.inn18);
cout<<"邻近插值..."<<endl;
wid *= 2;hei *= 2;
Resize卷积层(*目标,wid,hei,64);
最近邻插值(*源,*目标);
std::swap (源,目标);
cout<<"卷积 19..."<<endl;
卷积和正则化(sr.conv19,1,sr.inn19);
cout<<"卷积 20..."<<endl;
卷积前传(sr.conv20,1);
vl_tanh(源);
cout<<"图像转换成jpg格式... "<<endl;
RGB2bmp(*源);
//del卷积层(*目标);
savejpg(savefilename);
cout<<"转换文件已经保存为: "<<savefilename<<endl;
//输出无妆图
wid=输出无妆.width;hei=输出无妆.height;
Resize卷积层(*源,wid,hei,输出无妆.depth);
卷积层复制(&输出无妆,源);
cout<<"卷积 21..."<<endl;
卷积和正则化(sr.conv21,1,sr.inn21);
cout<<"邻近插值..."<<endl;
wid *= 2;hei *= 2;
Resize卷积层(*目标,wid,hei,64);
最近邻插值(*源,*目标);
std::swap (源,目标);
cout<<"卷积 22..."<<endl;
卷积和正则化(sr.conv22,1,sr.inn22);
cout<<"卷积 23..."<<endl;
卷积前传(sr.conv23,1);
vl_tanh(源);
RGB2bmp(*源);
del卷积层(*目标);
savejpg("无妆图.jpg");
cout<<"样板去妆后图已经保存为: "<<"无妆图.jpg"<<endl;
}
来源:https://blog.csdn.net/juebai123/article/details/100922767