在matlab7.0中运行DRCN 超分辨率重建

由于下载的代码用了类包装器 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++价值了


猜你喜欢

转载自blog.csdn.net/juebai123/article/details/81025623