C++实现超分辨率重建 SRFeat
有个博文介绍了这个 SRFeat ,并且《SRFeat-master》中有模型: SRFeat_full.npz 。
这里也用C++来实现下。
模型流程图:
定义批正则层和残差块:
struct tf_BatchNorm层数据
{
int 数据长度;
float * 偏移;//beta
float * 权重;//gamma
float * 均值;//moving_mean
float * 方差;//moving_variance
};
struct 残差块//
{
层数据 *conv1;
tf_BatchNorm层数据 *BNorm1;
层数据 *conv2;
tf_BatchNorm层数据 *BNorm2;
层数据 *conv3;
};
定义模型:
struct SRFeat模型
{
//头
层数据 * 输入层;//3->128
//主体
int 残差块数量;//16块
残差块 * 块;
//放大层
层数据 * 放大1前层;//128->512
//像素混组层 放大2倍 512->128
层数据 * 放大2前层;//128->512
//像素混组层 放大2倍 512->128
//尾
层数据 * 输出层;//128->3
//构造函数
SRFeat模型();
};
主函数:
void SRFeat(char * savefilename,SRFeat模型 & sr)
{
//
int wid=bmp.width;
int hei=bmp.height;
cout<<"输入图像宽度:"<<wid<<endl;
cout<<" 高度:"<<hei<<endl;
//
卷积层 rgb(wid,hei,3);//即rgb通道
rgb.data=new float[wid * hei *3];
//jpg转换为RGB卷积层
bmp2RGB(rgb);
wid=rgb.width;
hei=rgb.height;
//---------------------------------------------->
层数据 * 层;
tf_BatchNorm层数据 *BN层;
//两个卷积层 交替前传(源,目标)
卷积层 * di=(卷积层 *)malloc(sizeof(卷积层));
di->width=1;
di->height=1;
di->depth=1;
di->data=new float[1 ];
卷积层 *源,*目标;
源 = &rgb;
目标 = di;
int pad;
#define 卷积前传(ConvX)\
\
层=ConvX;/* Conv2 层 */ \
if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)\
Resize卷积层(*目标,wid,hei,层->输出维度);\
pad=层->核宽/2;\
vl_nnconv(源,目标,层 ,1,1,pad,pad,pad,pad);\
\
std::swap (源,目标);\
cout<<"输入层..."<<endl;
卷积前传(sr.输入层);
//load_mat2卷积层("me/c-add.txt",源);
//----------------------------------------------<
卷积层 总和(wid,hei,源->depth);
总和.data=new float[wid * hei * 源->depth ];
//第二部分 16残差层
卷积层 convfea5(wid,hei,源->depth);
convfea5.data=new float[wid * hei * 源->depth ];
卷积层 *源备份=&convfea5;
if(源->depth != 目标->depth || 目标->width != wid || 目标->height != hei)
Resize卷积层(*目标,wid,hei,源->depth);
残差块 * 块0=sr.块;
cout<<sr.残差块数量<<"个残差块... 包括 2 组卷积"<<endl;
for (int k = 0;k<sr.残差块数量;k++)
{
cout<<"\r"<<k;
//备份
卷积层复制(源,源备份);
卷积前传(块0->conv1);
BN层 = 块0->BNorm1;
torch_BatchNorm(源,BN层->权重,BN层->偏移,BN层->均值,BN层->方差);
vl_nnrelu(源,0.2f);
卷积前传(块0->conv2);
BN层 = 块0->BNorm2;
torch_BatchNorm(源,BN层->权重,BN层->偏移,BN层->均值,BN层->方差);
卷积层相加(源备份,源);
if(k==15) //最后一个用不到
{
卷积层相加(源,&总和);
break;
}
else
vl_nnconv(源,目标,块0->conv3 ,1,1);// 不用 swap
卷积层相加(目标,&总和);
块0++;//到下残差块
}
cout<<endl;
del卷积层(*源备份);
卷积层复制(&总和,源);
del卷积层(总和);
//load_mat2卷积层("me/add3_14.txt",源);
//save_卷积层2txt(源,"add-14.txt");
cout<<"放大2倍"<<endl;
卷积前传(sr.放大1前层);
wid=wid*2;hei=hei*2;
Resize卷积层(*目标,wid,hei,128);
depth_to_space(*源,*目标);
vl_nnrelu(目标,0.2f);
std::swap (源,目标);
//load_mat2卷积层("me/pixelshufflerx2-1-lrelu.txt",源);
cout<<"再放大2倍"<<endl;
卷积前传(sr.放大2前层);
wid=wid*2;hei=hei*2;
Resize卷积层(*目标,wid,hei,128);
depth_to_space(*源,*目标);
vl_nnrelu(目标,0.2f);
std::swap (源,目标);
cout<<"输出层..."<<endl;
卷积前传(sr.输出层);
cout<<"生成图 宽,高:"<<源->width<<","<<源->height<<endl;
cout<<"图像转换成jpg格式... "<<endl;
//load_mat2卷积层("me/out.txt",源);
RGB2bmp(*源);
del卷积层(*源);
savejpg(savefilename);
cout<<"转换文件已经保存为: "<<savefilename<<endl;
}
效果图:
小图
SRFeat生成图(4倍,20秒)
ESRGAN生成图(4倍,72秒)
比ESRGAN差一点,速度也快一点,毕竟体量小一点。
超分辨率已经差不多了,暂时就不会有这个内容了。
下载:
win超分辨重建SRFeat
超分辨重建SRFeat(4倍),由《SRFeat-master》中的模型 SRFeat_full.npz 改编而成