纯C++超分辨率重建VDSR --改编
程序员文章站
2023-12-30 19:24:40
...
又找到一个caffe-vdsr-master,其中Test部分是用matconvnet来运行的,鼓捣一下也可以在Matlab 7.0+vc6.0中运行
所以,这一篇用 C++ 翻译 VDSR
VDSR 流程:
可以说:和 SRCNN 差不多,除了卷积核全部是 3x3 头尾一模一样,中间18层代替 SRCNN 的第二层,
残差网络也只是 网络结束后 加上双三次图。哪就开始吧:
先定义一个网络数据池:
struct VDSR模型
{
int 层数; //20
//权重
int 权重_单个_长度; //核长 3x3 =9
float * 权重_数据;
//偏移
int 偏移_单个_长度; //64,(不包括最后层 1)
float * 偏移_数据;
//构造函数
VDSR模型();
};
VDSR模型::VDSR模型()
{
层数=20; //
int size;
//偏移
int 偏移_单个_长度=64; //64,最后层1
size = sizeof(float)*(64 * 19 + 1);//
偏移_数据 = (float*)malloc(size);
//权重
权重_单个_长度=9; //核长 3x3 =9
size = sizeof(float) * (9 * 64 * 2 + 9 * 64 * 64 * 19 );
权重_数据 = (float*)malloc(size);
}
大框架什么的和SRCCN都是相同的,这里直接进入 VDSR函数
先载入数据:
bool loadModel(VDSR模型 *sr)
{
char name[]="VDSR_Official.txt";
std::ifstream fin(name);
//检查文件是否存在
if (!fin)
{
return false;
}
cout<<"正在载入‘VDSR_Official.txt’的数据"<<endl;
//从档案载入
char str[40];
int len;
float * w=sr->权重_数据;
float * b=sr->偏移_数据;
for (int k = 0;k<20;k++)
{
cout<<k<<endl;
//weight = model.weight{k};
//wname=['权重_层' num2str(k) '\n'];
//fprintf(FID,wname );
fin >> str;
cout<<str<<endl;
//[h,w,c,p]=size(weight);
//l=h*w*c*p;
//fprintf(FID,'长度 %d\n',l );%有多少个
fin >> str;
cout<<str<<endl;
fin >> len;//需要载入的个数
cout<<len<<endl;
//for i=1:c
// for j=1:p
// for s=1:h
// for t=1:w
// fprintf(FID, '%f ',weight(s,t,i,j));
// end
// fprintf(FID, '\n');
// end
// end
//end
//float tmp;
for(int i=0;i<len;i++)
{
fin >> *w++;
//fin >> tmp;
//*w=tmp;w++;
//cout<<"tmp:"<<tmp<<endl;
}
//bias = model.bias{k};
//bname=['偏移_层' num2str(k) '\n'];
//fprintf(FID,bname );
fin >> str;
cout<<str<<endl;
//l=length(bias);
//fprintf(FID,'长度 %d\n',l );%有多少个
fin >> str;
cout<<str<<endl;
fin >> len;//需要载入的个数
cout<<len<<endl;
//for i=1:l
// fprintf(FID, '%f ',bias(i));
//end
//fprintf(FID, '\n');
for(int i=0;i<len;i++)
{
fin >> *b++;
//fin >> tmp;
//(*b++)=tmp;
//cout<<"tmp:"<<tmp<<endl;
}
}//end
fin.close ();
return true;
}
其中注解部分就是从matlab 导出数据的代码,就不单独显示了
完整VDSR函数:
IMAGE VDSR(IMAGE *jpg,int up_scale)
{
// 双三次插值
// 先将低分辨率图像使用双三次插值放大至目标尺寸(如放大至2倍、3倍、4倍)
//im_b = imresize(im_gnd, up_scale, 'bicubic');
IMAGE im_h=*jpg;
//双三次2倍(&im_h);
ResizeGrayscaleImage(&im_h,up_scale ) ;
//saveimage("放大.jpg", &im_h);
//// //显示
putimage(im_h.getwidth(), 0, &im_h);
VDSR模型 sr;
// 加载 CNN 模型参数
loadModel(&sr);
int wid=im_h.getwidth();
int hei=im_h.getheight();
//图像转化为卷积矩阵
#define 彩色 1
#if 彩色==1
//彩色
卷积矩阵 im_b(wid,hei);//即Y通道
卷积矩阵 U(wid,hei),V(wid,hei);
//RGB转换为YUV
RGB2YUV(&im_h,&im_b,&U,&V);
#else
//单色
卷积矩阵 im_b=im2卷积矩阵(&im_h);
//save_卷积矩阵 ("im_b.txt",&im_b); //保存权重
#endif
//用于保存调试图像的变量
IMAGE im_tt;
char txt[256];
// 第一层卷积:卷积核尺寸3×3(f1×f1),卷积核数目64(n1),输出64张特征图;
cout<<"第一层卷积..."<<endl;
//conv1_data = zeros(hei, wid, conv1_filters);
vector <卷积矩阵> conv0_data;//[64]结果
clock_t start_t, end_t;//计算时间
double total_t;
start_t = clock();
for (int i = 0 ;i<64;i++)
{
//weights_conv1 = reshape(weights_conv1, conv1_patchsize, conv1_patchsize, conv1_filters);
//准备卷积核
卷积矩阵 filter(3,3);
转换卷积核(&sr,&filter,0,i);
卷积矩阵 res(wid,hei);
// conv1_data(:,:,i) = imfilter(im_b, weights_conv1(:,:,i), 'same', 'replicate');
卷积(&filter,&im_b, &res);
//卷积9x9核(&filter,&im_b, &res);
// conv1_data(:,:,i) = max(conv1_data(:,:,i) + biases_conv1(i), 0);
加上偏移(&res,sr.偏移_数据,i);
conv0_data.push_back(res);
//
////保存64个卷积核
//sprintf(txt, "conv1_filter_%d.txt", i);
//save_卷积矩阵 (txt,&filter);
//保存64个卷积结果矩阵
//sprintf(txt, "conv1_data_%d.txt", i);
//save_卷积矩阵 (txt,&conv_data[i]); //保存权重
////保存64张特征图
//im_tt=卷积矩阵2im(&res);
//sprintf(txt, "conv1_data_0%d.jpg", i);
//saveimage(txt, &im_tt);
end_t = clock();
total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;
if(total_t>1.0){
cout<<i<<"/"<<64<<endl;
start_t = clock();
filter.~卷积矩阵();
res.~卷积矩阵();
}
}//end
vector <卷积矩阵> conv1_data;//[64];//结果
卷积矩阵 空(wid,hei);//
//与conv0_data 一起组成 源 目标 存放池
cout<<"第二至十九层卷积..."<<endl;
for(int k = 1;k<19;k++)
{
cout<<"第"<<k+1<<"层卷积..."<<endl;
// 第二层卷积:卷积核尺寸3×3(f2×f2),卷积核数目64x64(n2),输出64张特征图;
if(k!=1)
{
//交换源 和目标
conv1_data.swap(conv0_data);
}
//清空目标
conv1_data.clear();
for (int i = 0;i<64 ;i++)
{
conv1_data.push_back(空);
}
int ff=0;
start_t = clock();
for (int i = 0;i<64 ;i++)
{
卷积矩阵 conv2(wid,hei);
for (int j = 0 ;j<64;j++)
{
//准备卷积核
卷积矩阵 filter(3,3);
转换卷积核(&sr,&filter,k,i*64+j);
卷积(&filter,&conv0_data[j],&conv2);
加上矩阵(&conv2,&conv1_data[i]);
////保存64个卷积核
//sprintf(txt, "conv%d_filter_%d.txt",k, ff); ff++;
//save_卷积矩阵 (txt,&filter);
}//end
//conv2_data(:,:,i) = max(conv2_data(:,:,i) + biases_conv2(i), 0);
加上偏移(&conv1_data[i],sr.偏移_数据,64+(k-1)*64+i);
////保存64张特征图
//im_tt=卷积矩阵2im(&conv1_data[i]);
//sprintf(txt, "conv2_data_0%d.jpg", i);
//saveimage(txt, &im_tt);
end_t = clock();
total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;
if(total_t>1.0){
cout<<i<<"/"<<64<<endl;
start_t = clock();
}
}//end
}//end
cout<<"第二十层卷积..."<<endl;
// 第三层卷积:卷积核尺寸5×5(f3×f3),卷积核数目1(n3),输出1张特征图即为最终重建高分辨率图像。
//conv3_data = zeros(hei, wid);
卷积矩阵 conv3_data (wid,hei);
start_t = clock();
for(int i = 0;i<64;i++)
{
//conv3_subfilter = reshape(weights_conv3(i,:), conv3_patchsize, conv3_patchsize);
卷积矩阵 conv3_subfilter(3,3);
转换卷积核(&sr,&conv3_subfilter,19,i);
////保存64个卷积核
//sprintf(txt, "conv%d_filter_%d.txt",19, i); ff++;
//save_卷积矩阵 (txt,&conv3_subfilter);
卷积矩阵 conv3_temp (wid,hei);
卷积(&conv3_subfilter,&conv1_data[i],&conv3_temp);
//第三层运算(&conv3_data,&conv3_temp);//特征图迭加
加上矩阵(&conv3_temp,&conv3_data);
//保存32张特征图
//im_tt=卷积矩阵2im(&conv3_temp);
//sprintf(txt, "conv3_temp_0%d.jpg", i);
//saveimage(txt, &im_tt);
//保存32次迭加图
//im_tt=卷积矩阵2im(&conv3_data);
//sprintf(txt, "conv3_data_0%d.jpg", i);
//saveimage(txt, &im_tt);
end_t = clock();
total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;
if(total_t>1.0){
cout<<i<<"/"<<64<<endl;
start_t = clock();
}
}//end
cout<<"卷积完成"<<endl;
//输入图 + 残差图
加上矩阵(&im_b,&conv3_data);
#if 彩色==1
//彩色
//YUV转回RGB
YUV2RGB(&conv3_data,&U,& V,&im_h);
#else
//单色
//卷积矩阵转化为图像
im_h=卷积矩阵2im(&conv3_data);
#endif
return im_h;
}
效果图:
分别为原图,SRCNN重建 和 VDSR重建图
vdsr中已去掉了modcrop,所以图片大了一点
再来一个:
这个相比效果更好
虽然效果好,时间也长,一个只有几秒钟,一个要500多秒。
先这样吧
推荐阅读
-
纯C++超分辨率重建VDSR --改编
-
纯C++超分辨率重建LapSRN --改编--(四)偏置乘法
-
纯C++超分辨率重建SRCNN --改编--(五)卷积边界填充
-
纯C++超分辨率重建SRCNN --改编--(六)彩色
-
纯C++超分辨率重建LapSRN --改编--(二)正向卷积vl_nnconv函数
-
纯C++超分辨率重建LapSRN --改编--(一)数据和框架
-
纯C++超分辨率重建LapSRN --改编--(三)转置卷积vl_nnconvt函数
-
纯C++超分辨率重建SRCNN --改编--在Matlab导出卷积核参数(前奏三)
-
纯C++超分辨率重建FSRCNN --改编--(二)核参数修改 和多参激励vl_nnrelu
-
纯C++超分辨率重建espcn --改编--(三)主函数espcn