在《一鍵上妝的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;
}