在ESRGAN函数内完成主流程:
void ESRGAN(char * savefilename,ESRGAN模型 & sr)
{
//
int wid=jpg.getwidth();
int hei=jpg.getheight();
int wh=wid*hei;
卷积层 rgb(wid,hei,3);//即rgb通道
rgb.data=new float[wid * hei *3];
//jpg转换为RGB卷积层
jpg2RGB(&jpg,&rgb);
RGB2BGR(rgb) ;
//---------------------------------------------->
层数据 * 层;
//两个卷积层 交替前传(源,目标)
//用这个传回
卷积层 * di=(卷积层 *)malloc(sizeof(卷积层));
di->width=1;
di->height=1;
di->depth=1;
di->data=new float[1 ];
卷积层 *源,*目标;
源 = &rgb;
目标 = di;
int pad;
act_TYPE act_type;
#define 一层卷积(ConvX) \
\
层=ConvX;/* Conv2 层 */ \
/*int 层数=2;*/\
if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)\
Resize卷积层(*目标,wid,hei,层->输出维度);\
pad=层->核宽/2;\
vl_nnconv(源,目标,层 ,1,1,pad,pad,pad,pad);\
if(act_type==relu)\
vl_nnrelu(目标);/*激励函数relu*/\
else if(act_type==leakyrelu)\
vl_nnrelu(目标,0.2f);/*激励函数Prelu*/\
\
std::swap (源,目标);\
//特征层
act_type=none;
一层卷积(sr.特征_conv);
save_卷积层2jpg(源,"con1");
//连接池
卷积层 连接池(wid,hei,192); //用于密集残差块
连接池.data=new float[wh * 192 ];
//ShortcutBlock----------------------------------------->
卷积层 副本(wid,hei,64);
副本.data=new float[wh * 64 ];
卷积层复制(源,&副本);
密集残差组 * rb0=sr.rb_blocks.sub;
卷积层 sub副本(wid,hei,64);
sub副本.data=new float[wh * 64 ];
for(int j=0;j<sr.rb_blocks.个数;j++)
{
cout<<j<<endl;
卷积层复制(源,&sub副本);
密集残差块前传(rb0->RDB1,*源,连接池);//
密集残差块前传(rb0->RDB2,*源,连接池);//
密集残差块前传(rb0->RDB3,*源,连接池);//
//out.mul(0.2) + x
卷积层乘以(*源,0.2f);//残差缩放
卷积层相加(&sub副本,源);
rb0++;
}
cout<<"LR_conv"<<endl;
act_type=none;
一层卷积(sr.LR_conv);
//output = x + self.sub(x)
卷积层相加(&副本,源);
save_卷积层2jpg(源,"LR");
//ShortcutBlock-----------------------------------------<
//第一2倍放大
层=sr.up2x_1.conv;
wid*=2;hei*=2;
Resize卷积层(*目标,wid,hei,层->输出维度);
最近邻插值(*源,*目标);
std::swap (源,目标);
act_type=leakyrelu;
一层卷积(sr.up2x_1.conv);
//第二 2倍放大
层=sr.up2x_2.conv;
wid*=2;hei*=2;
Resize卷积层(*目标,wid,hei,层->输出维度);
最近邻插值(*源,*目标);
std::swap (源,目标);
一层卷积(sr.up2x_2.conv);
//输出层
cout<<"输出层..."<<endl;
一层卷积(sr.HR_conv0);
act_type=none;
一层卷积(sr.HR_conv1);
RGB2BGR(*源) ;
//save_卷积层2txt("out.txt",目标);
RGB2jpg(源,&jpg);
//del卷积层(*目标);
savejpg(&jpg,savefilename);
cout<<"转换文件已经保存为: "<<savefilename<<endl;
//
}
其中的密集残差块(PyTorch):
def forward(self, x):
x1 = self.conv1(x)
x2 = self.conv2(torch.cat((x, x1), 1))
x3 = self.conv3(torch.cat((x, x1, x2), 1))
x4 = self.conv4(torch.cat((x, x1, x2, x3), 1))
x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
return x5.mul(0.2) + x
之C++实现:
void 密集残差块前传(密集残差块 & b,卷积层 & s_di,卷积层 & 连接池)//从s_di 传入并返回
{
int wid=s_di.width;
int hei=s_di.height;
int wh=wid*hei;
卷积层 cat目标(wid , hei , 64);//也用于复制
cat目标.data=连接池.data;//指向头,后面向后移
卷积层复制(&s_di,&cat目标);
cat目标.depth=32;//修改为32
cat目标.data+=wh*64;
卷积层 cat(wid , hei , 64);
cat.data=连接池.data;//指向头,后面长度慢慢加32
层数据 * 层;
int pad;
#define cat卷积(ConvX) \
\
层=ConvX;\
pad=层->核宽/2;\
vl_nnconv(&cat,&cat目标,层 ,1,1,pad,pad,pad,pad);\
vl_nnrelu(&cat目标,0.2f);\
\
cat目标.data+=wh*32;/* 向后移32 */\
cat.depth+=32;/*加32长度*/\
cat卷积(b.conv1);
cat卷积(b.conv2);
cat卷积(b.conv3);
cat卷积(b.conv4);
层=b.conv5;
pad=层->核宽/2;
vl_nnconv(&cat,&s_di,层 ,1,1,pad,pad,pad,pad);
//x5.mul(0.2) + x 中的 mul(0.2)
卷积层乘以(s_di,0.2f);//残差缩放
cat目标.depth=64;//
cat目标.data=连接池.data; //头部是原输入
//x5.mul(0.2) + x 中的 + x
卷积层相加(&cat目标,&s_di);
}
记得前面生成过一个SRGAN,来比一比效果:
小图
SRGAN生成
ESRGAN生成
结束。
下载:
win32超分辩重建ESRGAN实用程序
超分辨率重建ESRGAN(4倍)的win32程序,ESRGAN是在[PIRM2018-SR竞赛](区域3)中获得了第一名并获得了最佳感知指数。