由于下载的代码用了类包装器 dagnn ,这个是针对matlab7的后续版本的,已经没法使用,只能按照它的意思重新写了。
先外框架:
% DRCN 超分辨率重建
clc;clear all;
name='6a.jpg';
SF = 2; % 测试比例因子。 可以是2,3或4
%设置引用的 matconvnet中的函数路径
run('snu_matconvnet/matlab/vl_setupnn.m');
addpath('util/');
%模型数据名
model=['sf',num2str(SF),'/DRCN_sf',num2str(SF),'.mat'];
if isempty(model)
error('no model');
else
PathModel = ['DRCN model/',model];
end
% 载入
load(PathModel);
clear stats;clear max_psnr;
%读入图
im = imread(name);
im = imresize(im, SF, 'bicubic');%先放大到目标大小
if size(im,3) > 1
im = rgb2ycbcr(im);% 3通道则只对Y通道重建(先转化)
else
im = im;
end
imlow = single(im)/255;
if size(im,3)>1
imlowy = imlow(:,:,1);
imlowy = max(16.0/255, min(235.0/255, imlowy));% 分离出
imlowcb = imlow(:,:,2);
imlowcr = imlow(:,:,3);
else
imlowy = imlow;
end
impred = myDRCN(net, imlowy);% 重建
%imwrite(uint8(impred*255), 'DRCN 重建单色.jpg');
if size(im,3) > 1
impredColor = cat(3,impred,imlowcb,imlowcr);%连回
imwrite(ycbcr2rgb(uint8(impredColor*255)), ['DRCN ',num2str(SF),'倍重建.jpg']);
else
impredColor = impred;
imwrite(uint8(impredColor*255), 'DRCN 重建单色.jpg');
end
核心函数:
% DRCN 超分辨率重建 - 各层代码
function impred = myDRCN(net, imlow)
l=length(net.layers);%总层数
j=0; %卷积层计数,可以无
[h,w,tmp]=size(imlow);%图像大小
prediction=zeros(h,w,17);% 17张中间残差图
prediction_num=0; % 残差图计数,可以不用
for i=1:l % 循环直到所有层结束
disp(['第 ',num2str(i),' 层']);
% disp(net.layers(i).name);
% disp(net.layers(i).type);
% disp(net.layers(i).inputs);
% disp(net.layers(i).outputs);
% disp(net.layers(i).params);
% disp(net.layers(i).block);
if strTong(net.layers(i).type,'dagnn.Conv') % 字符串是否相同
j=j+1
disp('卷积层');
%得到权重(也就是卷积核)和偏移
disp('参数是:');
disp(net.layers(i).params);
fft=net.layers(i).params{1};
for k=1:length(net.params)
if strTong(net.params(k).name,fft)
weight=net.params(k).value;
break;
end
end
if net.layers(i).block.hasBias==false
bias=[]; % 无偏移
else
fft=net.layers(i).params{2};
for k=1:length(net.params)
if strTong(net.params(k).name,fft)
bias=net.params(k).value;
break;
end
end
end
%得到输入
disp('输入是:');
disp(net.layers(i).inputs);
disp('输出是:');
disp(net.layers(i).outputs);
if strTong(net.layers(i).inputs{1},'input') %第一层
convfea = myconv(imlow,weight,bias,'Pad',1);%一图得出256特征图
else %一以后
% 字符串是否包含
if strBao(net.layers(i).outputs{:}, 'prediction') %残差
if strTong(net.layers(i).outputs{:}, 'prediction') %总残差
prediction=single(prediction);
prediction = myconv(prediction,weight,bias);%17合成1个
else %中间残差
prediction_num=prediction_num+1;% 应该有17个
prediction(:,:,prediction_num)= myconv(convfea,weight,bias,'Pad',1);
end
else
convfea = myconv(convfea,weight,bias,'Pad',1);%中间层 256特征图合成1图 再重新生成深一层256特征图
end
end
end
if strTong(net.layers(i).type,'dagnn.ReLU' )
disp('激励层');
disp('输入是:');
disp(net.layers(i).inputs);
disp('参数是:');
disp(net.layers(i).params);
disp('输出是:');
disp(net.layers(i).outputs);
convfea = vl_nnrelu(convfea);
end
% for k=1:size(convfea,3) %保存中间图
% %保存256张特征图
% im_tt=uint8(convfea(:,:,k) * 255);
% imwrite(im_tt, ['data/conv' num2str(i) '_data_0' num2str(k) '.jpg']);
% end
end
%输入和残差相加 为输出
impred=imlow+prediction;
%加边并卷积后还原
function [X] = myconv(X, F, B, option1, value1)
if nargin==3
X = vl_nnconv(X, F, B);
else
%消除四边一条线和左上角白点,否则会随着层数的增加,会越来越大
BoundarySize=1;
X = padarray(X, [BoundarySize,BoundarySize], 'replicate','both');
X = vl_nnconv(X, F, B, option1, value1);
X = X(BoundarySize+1:end-BoundarySize,BoundarySize+1:end-BoundarySize,:);
end
相同和包含函数:
%字符串相同
function TrueFalse = strTong(str1, str2)
TrueFalse=0;
l1=length(str1);
l2=length(str2);
if l1==l2
if str1==str2
TrueFalse=1;
end
end
%字符串包含
%在str1中 是否 包含有 str2
function TrueFalse = strBao(str1, str2)
TrueFalse=0;
l1=length(str1);
l2=length(str2);
if l1==l2
if str1==str2
TrueFalse=1;
end
else
if l1>l2
str3=str1(1:l2);
if str3==str2
TrueFalse=1;
end
end
end
其它 vl_nnrelu 可以直接运行
vl_nnconv可以先用下面这个,由于是256 通道 非常慢,可以用很小的图,比如10x10
%VL_NNCONV CNN 卷积。
% Y = VL_NNCONV(X, F, B)计算图像堆x的卷积,F是卷积核,B是偏置。X=H*W*D*N,
% (H,W)是图像的高和宽,D是图像深度(特征频道的数目,例彩色就是3),
% N是堆中图像的数目。F=FW*FH*FD*K ,(FH,FW)是卷积核的大小,FD是卷积核的深度,
% 须与D一致,或能整除D,K是卷积核的数目。
% Y = VL_NNCONV(X, F, B) 计算图像X与滤波器组F的卷积并偏置B。
% 如果B是空矩阵,则不添加偏置。如果F是空矩阵,则函数不过滤图像,
% 但仍添加偏移并应用下采样和填充,如下所述。
%
% X 是维度 H x W x C x N 的阵列,其中( H,W )是图像堆栈的高度和宽度,
% C是特征通道的数量,N是批处理中的图像数量。
%
% F 是尺寸为FW×FH×FC×K的阵列,其中 (FH,FW) 是滤波器高度和宽度,
% K是滤波器组中的滤波器数量。 FC 是每个滤波器中的特征信道数,
% 必须与 X 中的特征信道数 C 匹配。 Alternatively, FC can
% *divide* the C; in this case, filters are assumed to form G=C/FC
% *groups* of equal size (where G must divide K). {或者,FC可以*除C;
% 在这种情况下,假定滤波器形成大小相等的G = C / FC *组* (其中G必须除以K )。}
% 每组滤波器在输入阵列 X 的特征信道的连续子集上工作。
%
% [DX, DF, DB] = VL_NNCONV(X, F, B, DY) 计算投影到 P 上的算子的导数。
% DX、DF、DB和DY分别具有与X、F、B和Y相同的尺寸。特别地,如果B是空矩阵,
% 则DB也是空的。
%
% VL_NNCONV() 实现了一种特殊的*完全连接*模式:当过滤器的支持与输入图像的
% 支持完全匹配时,代码使用优化的途径以加快计算速度。
%
% VL_NNCONV(..., 'option', value, ...) 接受以下
% 选项:
%
% `Stride`:: 1
% 输出步幅或下采样因子。如果该值是标量,则相同的步幅应用于垂直和水平方向;
% 否则,通过 [STRIDEY STRIDEX] 允许为每个方向指定不同的下采样因子。
%
% `Pad`:: 0
% 输入填充量。在计算卷积之前,输入图像用零填充该数量的像素。通过[上 下 左 右][TOP BOTTOM LEFT RIGHT]
% 允许分别为顶侧、底侧、左侧和右侧指定不同的填充量。
% 传递单个标量将相同的填充应用于所有边框。
%
% 过滤器尺寸必须不大于填充图像,即
%
% 1 <= FH <= H + 2*(PADTOP+PADBOTTOM),
% 1 <= FW <= W + 2*(PADLEFT+PADRIGHT).
%
% 输出a是N幅图像尺寸YH×YW×K×N的阵列,具有K个特征值和大小:
%
% YH = floor((H + (PADTOP+PADBOTTOM) - FH)/STRIDEY) + 1,
% YW = floor((W + (PADLEFT+PADRIGHT) - FW)/STRIDEX) + 1.
%
% 参数可以是单精度或双个精度的以及CPU或GPU阵列;但是,
% 它们必须具有相同的类型(除非为空)。
function Y = vl_nnconv(X, F, B, option1, value1, option2, value2, ...
ops,cudnn)
% vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ...
% 'pad', l.pad, ...
% 'stride', l.stride, ...
% l.opts{:}, ...
% cudnn{:}) ;
F=double(F);
[np,tmp]=size(B);
if np>1
[FW,FH,FC,K]=size(F);
if (FC==1 && K~=1)||(FC~=1 && K==1)
Kp=max(FC,K);
%第一层 生成64特征图
[h,w,c]=size(X);
Y=zeros(h,w,Kp);
for i=1:Kp
if K~=1;ff=F(:,:,1,i);end;
if FC~=1;ff=F(:,:,i);end;
Y(:,:,i) =B(i)+ imfilter(X,ff, 'same', 'replicate');
end
else
[h,w,c, N]=size(X);
if K==1
else
%中间层2-19 :先把64个特征图合在一起,再重新找出64种特征图。
Y=zeros(h,w,K);
%K
for j=1:FC
for i=1:K
xx=X(:,:,i);
% ff=F(:,:,j,i);
ff=F(:,:,i,j);
Y(:,:,j) =Y(:,:,j)+imfilter(xx,ff, 'same', 'replicate');%convn
end
Y(:,:,j) =Y(:,:,j) + B(j);
end
end
end
else
%最后一层,64 图合成 1 图
[h,w, N]=size(X);
Y=zeros(h,w);
for i=1:N
xx=X(:,:,i);
ff=F(:,:,i);
Y =Y+imfilter(xx,ff, 'same', 'replicate');
end
Y=Y + B(1);
end
如果要加快运行速度,就要编译matconvnet 中的vl_nnconv
找不到<blas.h>中的 sgemm 矩阵乘法 可以先用下面的:
for(i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
for(int q=0;q<k;q++)
{
c[j*m+i]+=a[q*m+i]*b[j*k+q];
}
}
}
虽然只实现 sgemm 中的部分功能,但在这里已经够用了(另外网上有个C语言版sgemm,放在这里好象不能用,不知为什么?)
然后得到一个 vl_nnconv.dll 这样虽然快了一点,但是还是很慢的
效果图:
原图
2倍重建图
这个是等了很久才出来的,3,4倍就更慢了,就没有运行了
这样就没有改成C++价值了