用以前的代碼並不能實現 python、Tensorflow 同樣的效果。
MatConvNet 和 Tensorflow 中的卷積,在步長爲2時,並且圖像長寬是偶數時,並不完全相同
比如步長爲1的一個卷積結果是這樣的:
[[ 2. 0. 2. 4.]
[ 1. 4. 4. 3.]
[ 4. 3. 5. 9.]
[ 3. 4. 6. 2.]]
步長爲2的一個卷積結果可以是:
[[ 2. . 2. .]
[ . . . .]
[ 4. . 5. .]
[ . . . .]]
由於跳步的位置不同也可以是:
[[ . . . .]
[ . 4. . 3.]
[ . . . .]
[ . 4. . 2.]]
這兩個結果顯然是不同的。
由於我的卷積代碼是從 MatConvNet 中抄來的,所以這裏用
<步長爲1的卷積 + 間隔刪除> 來代替 <步長爲2的卷積>
2步長卷積:
/*2步長卷積*/
wid=wid/2;hei=hei/2;
if(ConvX->輸出維度 != 目標->depth || 目標->width != wid || 目標->height != hei)
Resize卷積層(*目標,wid,hei,ConvX->輸出維度);
pad=ConvX->核寬/2;
vl_nnconv(源,目標,ConvX ,2,2,pad,pad,pad,pad);
1步長卷積+間隔刪除:
/* 步長爲1的卷積+隔行刪除 代替 步長爲2的卷積 */
if(ConvX->輸出維度 != 目標->depth || 目標->width != wid || 目標->height != hei)
Resize卷積層(*目標,wid,hei,ConvX->輸出維度);
pad=ConvX->核寬/2;
vl_nnconv(源,目標,ConvX ,1,1,pad,pad,pad,pad);
std::swap (源,目標);
wid=wid/2;hei=hei/2;
Resize卷積層(*目標,wid,hei,ConvX->輸出維度);
隔行列刪(*源,*目標);
間隔刪行列:
void 隔行列刪(卷積層 & si,卷積層 & di)
{
float *s=si.data;
float *d=di.data;
if(si.width==di.width*2 && si.height==di.height*2 && si.depth==di.depth)
{
for(int i=0;i<di.depth;i++)
for(int j=0;j<di.height;j++)
{
s+=si.width;//<---------先跳過一行
for(int k=0;k<di.width;k++)
{
s++;//<---------先跳過一格
*d++ = *s++;
//s++;//<-------後跳過一格
}
//s+=si.width;//<-------後跳過一行
}
}
else
cout<<"隔行列刪 出錯了!";
}
這樣就和《BeautyGAN-master》的效果相同了。
效果圖:
上方都是統一把圖像縮放到256x256,爲了可以處理更大的圖像,並且可以是長方形的,這裏先把圖像剪裁一下:
//取中心區域(4的倍數)
void 剪裁成正方形(卷積層 & di)
{
int wid=di.width;
int hei=di.height;
int w=min(wid,hei);
//取4的倍數
w-=w % 4;
int h=w;//同寬
cout<<"圖像剪裁成:"<< w<<"x"<<w<<endl;
int w邊=(wid-w)/2;
//可能有的1像數
//int x0=wid-w-w邊*2;
int h邊=(hei-h)/2;
//可能有的1像數
int y0=hei-h-h邊*2;
卷積層 t(w,h,di.depth);
t.data=new float[w*h*di.depth];
int wc=di.width;
//複製內容
float *s=di.data;
float *d=t.data;
for(int j=0;j<di.depth;j++)
{
s +=wc*h邊;//跳過上邊
for(int i=0;i<h;i++)
{
cblas_scopy(w,s+w邊 , 1, d, 1);
//下一位置
s+=wc;
d+=w;
}
s +=wc*(h邊+y0);//跳過下邊
}
//刪除原來的,設置新的
delete []di.data; di.data=NULL;
di.data=t.data;
di.width=w;di.height=h;
}
輸入圖:
輸出的8個圖:
下載:
人臉美顏程序
win32人臉圖像美容處理程序,由《BeautyGAN-matser》模型權重轉換而來