├── Demo_bicubic_degradation_SRMD.m ├── Demo_bicubic_degradation_SRMDNF.m ├── Demo_degradation_direct_SRMD.m ├── Demo_degradation_direct_SRMDNF.m ├── Demo_denoising_and_deblurring_color_SRMD.m ├── Demo_denoising_and_deblurring_gray_SRMD.m ├── Demo_genearal_degradation_SRMD.m ├── Demo_genearal_degradation_SRMDNF.m ├── Demo_real_application_SRMD.m ├── Demo_real_application_denoising_and_deblurring_color.m ├── Demo_real_application_denoising_and_deblurring_gray.m ├── README.md ├── Test_Track_3_SRMD_non_blind.m ├── TrainingCodes ├── Demo_Get_PCA_matrix.m ├── Demo_Test_SRMD_x3.m ├── Demo_Train_SRMD_x3.m ├── degradation_model.m ├── generatepatches.m ├── kernels │ ├── Demo_Get_PCA_matrix.m │ ├── Demo_show_PCA_matrix.m │ ├── Demo_show_kernels.m │ ├── PCA_P.mat │ └── anisotropic_Gaussian.m ├── model_init_SRMD_x3.m ├── model_train.m ├── testsets │ └── Set5 │ │ ├── baby_GT.bmp │ │ ├── bird_GT.bmp │ │ ├── butterfly_GT.bmp │ │ ├── head_GT.bmp │ │ └── woman_GT.bmp ├── utilities │ ├── Cal_PSNRSSIM.m │ ├── Merge_Bnorm_Demo.m │ ├── data_augmentation.m │ ├── modcrop.m │ ├── shave.m │ ├── simplenn_matlab.m │ ├── vl_simplenn_mergebnorm.m │ ├── vl_srmd.m │ ├── vl_srmd_concise.m │ └── vl_srmd_matlab.m ├── vl_nnSubP.m ├── vl_nnloss.m └── vl_simplenn.m ├── figs ├── 0991x4d.png ├── 0991x4d_srmd.png ├── architecture.png ├── bicubic1.png ├── bicubic2.png ├── butterfly_GT30_VDSR.png ├── butterfly_GTSRMD_x3.png ├── butterfly_GT_x2_.png ├── butterfly_GT_x2_2274.png ├── butterfly_GT_x3_.png ├── butterfly_GT_x3_2675.png ├── butterfly_GT_x4_.png ├── butterfly_GT_x4_2771.png ├── realSR1.png ├── realSR2.png ├── track3.png ├── woman_GT30_VDSR.png └── woman_GTSRMD_x3.png ├── models ├── Demo_show_kernels.m ├── SRMDNFx2.mat ├── SRMDNFx3.mat ├── SRMDNFx4.mat ├── SRMD_non_blind.mat ├── SRMDx1_color.mat ├── SRMDx1_gray.mat ├── SRMDx2.mat ├── SRMDx3.mat └── SRMDx4.mat ├── results ├── Hilbert_SRMD_x1_itrG_5_nlevel_10 │ └── Hilbert_x1.png └── chip_SRMD_Real_x4_itrG_17_nlevel_10 │ └── chip_x4.png ├── testsets ├── Audrey_Hepburn │ └── Audrey_Hepburn.jpg ├── BSD68 │ ├── test001.png │ ├── test002.png │ ├── test003.png │ ├── test004.png │ ├── test005.png │ ├── test006.png │ ├── test007.png │ ├── test008.png │ ├── test009.png │ ├── test010.png │ ├── test011.png │ ├── test012.png │ ├── test013.png │ ├── test014.png │ ├── test015.png │ ├── test016.png │ ├── test017.png │ ├── test018.png │ ├── test019.png │ ├── test020.png │ ├── test021.png │ ├── test022.png │ ├── test023.png │ ├── test024.png │ ├── test025.png │ ├── test026.png │ ├── test027.png │ ├── test028.png │ ├── test029.png │ ├── test030.png │ ├── test031.png │ ├── test032.png │ ├── test033.png │ ├── test034.png │ ├── test035.png │ ├── test036.png │ ├── test037.png │ ├── test038.png │ ├── test039.png │ ├── test040.png │ ├── test041.png │ ├── test042.png │ ├── test043.png │ ├── test044.png │ ├── test045.png │ ├── test046.png │ ├── test047.png │ ├── test048.png │ ├── test049.png │ ├── test050.png │ ├── test051.png │ ├── test052.png │ ├── test053.png │ ├── test054.png │ ├── test055.png │ ├── test056.png │ ├── test057.png │ ├── test058.png │ ├── test059.png │ ├── test060.png │ ├── test061.png │ ├── test062.png │ ├── test063.png │ ├── test064.png │ ├── test065.png │ ├── test066.png │ ├── test067.png │ └── test068.png ├── Hilbert │ └── Hilbert.jpg ├── Nami │ └── Nami.jpg ├── Set14 │ ├── baboon.bmp │ ├── barbara.bmp │ ├── bridge.bmp │ ├── coastguard.bmp │ ├── comic.bmp │ ├── face.bmp │ ├── flowers.bmp │ ├── foreman.bmp │ ├── lenna.bmp │ ├── man.bmp │ ├── monarch.bmp │ ├── pepper.bmp │ ├── ppt3.bmp │ └── zebra.bmp ├── Set5 │ ├── baby_GT.bmp │ ├── bird_GT.bmp │ ├── butterfly_GT.bmp │ ├── head_GT.bmp │ └── woman_GT.bmp ├── cat │ └── cat.png ├── chip │ └── chip.png ├── flowers │ └── Flowers.png ├── flowersL │ └── Flowers.png ├── frog │ └── Frog.png ├── stars │ └── Stars.png └── starsL │ └── Stars.png └── utilities ├── Cal_PSNRSSIM.m ├── center_crop.m ├── data_augmentation.m ├── im_crop.m ├── im_pad.m ├── modcrop.m ├── shave.m ├── vl_nnSubP.m ├── vl_simplenn_mergebnorm.m ├── vl_srmd.m ├── vl_srmd_concise.m └── vl_srmd_matlab.m /Demo_bicubic_degradation_SRMD.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMD for the widely-used . 3 | % For bicubic degradation, the basic setting is: 4 | % 1. the blur kernel is delta kernel; "kernel = fspecial('gaussian',15,0.2)". 5 | % 2. the noise level is zero; "nlevel = 0". 6 | % 3. the downsampler is fixed to bicubic downsampler. 7 | % For direct downsampler, you can either train a new model with 8 | % direct downsamper or use the estimated kernel k_b under bicubic 9 | % downsampler. The former is preferred. 10 | % 4. there are three SRMD models, "SRMDx2.mat" for scale factor 2, "SRMDx3.mat" 11 | % for scale factor 3, and "SRMDx4.mat" for scale factor 4. 12 | %========================================================================== 13 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 14 | % solve x^ = arg min_x 1/(2 sigma^2) ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 15 | % via x^ = CNN(y,k,sigma;\Theta) or HR^ = CNN(LR,kernel,noiselevel;\Theta). 16 | % 17 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 18 | % level (sigma; nlevel). 19 | % 20 | % For more information, please refer to the following paper. 21 | % @article{zhang2017learningsrmd, 22 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 23 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 24 | % year={2017}, 25 | % } 26 | % 27 | % If you have any question, please feel free to contact with . 28 | % 29 | % This code is for research purpose only. 30 | % 31 | % by Kai Zhang (Nov, 2017) 32 | %========================================================================== 33 | % clear; clc; 34 | format compact; 35 | 36 | addpath('utilities'); 37 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 38 | 39 | %% select testing dataset, use GPU or not, ... 40 | setTest = imageSets([1,2,3,4]); % select the datasets for each tasks 41 | showResult = 0; % save restored images 42 | pauseTime = 0; 43 | useGPU = 1; % 1 or 0, true or false 44 | method = 'SRMD'; 45 | folderTest = 'testsets'; 46 | folderResult = 'results'; 47 | if ~exist(folderResult,'file') 48 | mkdir(folderResult); 49 | end 50 | 51 | %% scale factor (2, 3, 4) 52 | 53 | sf = 4; 54 | 55 | %% load model with scale factor sf 56 | folderModel = 'models'; 57 | load(fullfile(folderModel,['SRMDx',int2str(sf),'.mat'])); 58 | %net.layers = net.layers(1:end-1); 59 | net = vl_simplenn_tidy(net); 60 | if useGPU 61 | net = vl_simplenn_move(net, 'gpu') ; 62 | end 63 | 64 | %% degradation parameter (kernel & noise level) setting 65 | global degpar; 66 | nlevel = 0; % noise level is zero. 67 | kernel = fspecial('gaussian',15, 0.2); % kernel is delta kernel. Note: the kernel size is fixed to 15X15. 68 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 69 | tag = ['_',method,'_x',num2str(sf),'_bicubic']; 70 | 71 | for n_set = 1 : numel(setTest) 72 | 73 | %% search images 74 | setTestCur = cell2mat(setTest(n_set)); 75 | disp('--------------------------------------------'); 76 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 77 | disp('--------------------------------------------'); 78 | folderTestCur = fullfile(folderTest,setTestCur); 79 | ext = {'*.jpg','*.png','*.bmp'}; 80 | filepaths = []; 81 | for i = 1 : length(ext) 82 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 83 | end 84 | 85 | %% prepare results 86 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 87 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 88 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 89 | if ~exist(folderResultCur,'file') 90 | mkdir(folderResultCur); 91 | end 92 | 93 | %% perform SISR 94 | for i = 1 : length(filepaths) 95 | 96 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 97 | C = size(HR,3); 98 | if C == 1 99 | HR = cat(3,HR,HR,HR); 100 | end 101 | [~,imageName,ext] = fileparts(filepaths(i).name); 102 | HR = modcrop(HR, sf); 103 | label_RGB = HR; 104 | 105 | %% bicubic degradation 106 | %blury_HR = imfilter(im2double(HR),double(kernel),'replicate'); % blur 107 | LR = imresize(im2double(HR),1/sf,'bicubic'); % bicubic downsampling 108 | input = im2single(LR); 109 | %input = im2single(im2uint8(LR)); % another widely-used setting 110 | 111 | %tic 112 | if useGPU 113 | input = gpuArray(input); 114 | end 115 | 116 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 117 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 118 | %res = vl_srmd_matlab(net, input); % you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 119 | 120 | output_RGB = gather(res(end).x); 121 | %toc; 122 | 123 | if C == 1 124 | label = mean(im2double(HR),3); 125 | output = mean(output_RGB,3); 126 | else 127 | label = rgb2ycbcr(im2double(HR)); 128 | output = rgb2ycbcr(double(output_RGB)); 129 | label = label(:,:,1); 130 | output = output(:,:,1); 131 | end 132 | 133 | %% calculate PSNR and SSIM 134 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 135 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 136 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 137 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 138 | if showResult 139 | imshow(cat(2,label_RGB,imresize(im2uint8(LR),sf),im2uint8(output_RGB))); 140 | drawnow; 141 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 142 | pause(pauseTime) 143 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 144 | end 145 | 146 | end 147 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 148 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 149 | 150 | %% save PSNR and SSIM results 151 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 152 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 153 | 154 | end 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /Demo_bicubic_degradation_SRMDNF.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMDNF for the widely-used . 3 | % For bicubic degradation, the basic setting is: 4 | % 1. the blur kernel is delta kernel; "kernel = fspecial('gaussian',15,0.2)". 5 | % 2. the downsampler is fixed to bicubic downsampler. You can either 6 | % train a new model with direct downsamper or use the estimated 7 | % kernel k_b under direct downsampler. 8 | % 3. there are three SRMDNF models, "SRMDNFx2.mat" for scale factor 2, "SRMDNFx3.mat" 9 | % for scale factor 3, and "SRMDNFx4.mat" for scale factor 4. 10 | %========================================================================== 11 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 12 | % solve x^ = arg min_x 1/2 ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 13 | % via x^ = CNN(y,k;\Theta) or HR^ = CNN(LR,kernel;\Theta). 14 | % 15 | % There involves two important factors, i.e., blur kernel (k; kernel), in SRMDNF. 16 | % 17 | % For more information, please refer to the following paper. 18 | % @article{zhang2017learningsrmd, 19 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 20 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 21 | % year={2017}, 22 | % } 23 | % 24 | % If you have any question, please feel free to contact with . 25 | % 26 | % This code is for research purpose only. 27 | % 28 | % by Kai Zhang (Nov, 2017) 29 | %========================================================================== 30 | % clear; clc; 31 | format compact; 32 | 33 | addpath('utilities'); 34 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 35 | 36 | %% select testing dataset, use GPU or not, ... 37 | setTest = imageSets([1,2,3,4]); % select the datasets for each tasks 38 | showResult = 0; % save restored images 39 | pauseTime = 0; 40 | useGPU = 1; % 1 or 0, true or false 41 | method = 'SRMDNF'; 42 | folderTest = 'testsets'; 43 | folderResult = 'results'; 44 | if ~exist(folderResult,'file') 45 | mkdir(folderResult); 46 | end 47 | 48 | %% scale factor (2, 3, 4) 49 | sf = 4; 50 | 51 | %% load model with scale factor sf 52 | folderModel = 'models'; 53 | load(fullfile(folderModel,['SRMDNFx',int2str(sf),'.mat'])); 54 | %net.layers = net.layers(1:end-1); 55 | net = vl_simplenn_tidy(net); 56 | if useGPU 57 | net = vl_simplenn_move(net, 'gpu') ; 58 | end 59 | 60 | %% degradation parameter (kernel & noise level) setting 61 | global degpar; 62 | kernel = fspecial('gaussian',15, 0.2); % kernel is delta kernel. Note: the kernel size is fixed to 15X15. 63 | degpar = single(net.meta.P*kernel(:)); 64 | tag = ['_',method,'_x',num2str(sf),'_bicubic']; 65 | 66 | for n_set = 1 : numel(setTest) 67 | 68 | %% search images 69 | setTestCur = cell2mat(setTest(n_set)); 70 | disp('--------------------------------------------'); 71 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 72 | disp('--------------------------------------------'); 73 | folderTestCur = fullfile(folderTest,setTestCur); 74 | ext = {'*.jpg','*.png','*.bmp'}; 75 | filepaths = []; 76 | for i = 1 : length(ext) 77 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 78 | end 79 | 80 | %% prepare results 81 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 82 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 83 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 84 | if ~exist(folderResultCur,'file') 85 | mkdir(folderResultCur); 86 | end 87 | 88 | %% perform SISR 89 | for i = 1 : length(filepaths) 90 | 91 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 92 | C = size(HR,3); 93 | if C == 1 94 | HR = cat(3,HR,HR,HR); 95 | end 96 | [~,imageName,ext] = fileparts(filepaths(i).name); 97 | HR = modcrop(HR, sf); 98 | label_RGB = HR; 99 | %% bicubic degradation 100 | %blury_HR = imfilter(im2double(HR),double(kernel),'replicate'); % blur 101 | LR = imresize(im2double(HR),1/sf,'bicubic'); % bicubic downsampling 102 | input = im2single(LR); 103 | %input = im2single(im2uint8(LR)); % another widely-used setting 104 | %tic 105 | if useGPU 106 | input = gpuArray(input); 107 | end 108 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 109 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 110 | %res = vl_srmd_matlab(net, input); % you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 111 | 112 | output_RGB = gather(res(end).x); 113 | 114 | %toc; 115 | if C == 1 116 | label = mean(im2double(HR),3); 117 | output = mean(output_RGB,3); 118 | else 119 | label = rgb2ycbcr(im2double(HR)); 120 | output = rgb2ycbcr(double(output_RGB)); 121 | label = label(:,:,1); 122 | output = output(:,:,1); 123 | end 124 | 125 | %% calculate PSNR and SSIM 126 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 127 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 128 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 129 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 130 | if showResult 131 | imshow(cat(2,label_RGB,imresize(im2uint8(LR),sf),im2uint8(output_RGB))); 132 | drawnow; 133 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 134 | pause(pauseTime) 135 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 136 | end 137 | 138 | end 139 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 140 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 141 | 142 | %% save PSNR and SSIM results 143 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 144 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 145 | 146 | end 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /Demo_degradation_direct_SRMD.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMDNF for the widely-used degradation with 7x7 3 | % Gaussian kernel of width 1.6 and direct downsampler of scale factor 3. 4 | % For this degradation, the basic setting is: 5 | % 1. the image blur kernel is; "kernel = fspecial('gaussian',7,1.6)". 6 | % 2. the noise level is zero; "nlevel = 0". 7 | % 3. the downsampler is direct downsampler. The scale factor is fixed to 3. 8 | % You can either train a new model with direct downsamper or use the estimated 9 | % kernel k_b under direct downsampler. 10 | % 4. there are three SRMD models, "SRMDx2.mat" for scale factor 2, "SRMDx3.mat" 11 | % for scale factor 3, and "SRMDx4.mat" for scale factor 4. 12 | %========================================================================== 13 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 14 | % solve x^ = arg min_x 1/(2 sigma^2) ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 15 | % via x^ = CNN(y,k,sigma;\Theta) or HR^ = CNN(LR,kernel,noiselevel;\Theta). 16 | % 17 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 18 | % level (sigma; nlevel). 19 | % 20 | % For more information, please refer to the following paper. 21 | % @article{zhang2017learningsrmd, 22 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 23 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 24 | % year={2017}, 25 | % } 26 | % 27 | % If you have any question, please feel free to contact with . 28 | % 29 | % This code is for research purpose only. 30 | % 31 | % by Kai Zhang (Nov, 2017) 32 | %========================================================================== 33 | % clear; clc; 34 | format compact; 35 | 36 | addpath('utilities'); 37 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 38 | 39 | %% select testing dataset, use GPU or not, ... 40 | setTest = imageSets([1,2,3,4]); % select the datasets for each tasks 41 | showResult = 0; % save restored images 42 | pauseTime = 0; 43 | useGPU = 1; % 1 or 0, true or false 44 | method = 'SRMD'; 45 | folderTest = 'testsets'; 46 | folderResult = 'results'; 47 | if ~exist(folderResult,'file') 48 | mkdir(folderResult); 49 | end 50 | 51 | %% scale factor (3 only) 52 | 53 | sf = 3; % Here, do not set sf to 2 or 4. 54 | 55 | %% load model with scale factor sf 56 | folderModel = 'models'; 57 | load(fullfile(folderModel,['SRMDx',int2str(sf),'.mat'])); 58 | %net.layers = net.layers(1:end-1); 59 | net = vl_simplenn_tidy(net); 60 | if useGPU 61 | net = vl_simplenn_move(net, 'gpu') ; 62 | end 63 | 64 | %% degradation parameter (kernel & noise level) setting 65 | global degpar; 66 | image_kernel = fspecial('gaussian',7, 1.6); % 7x7 Gaussian kernel k_d with width 1.6 67 | nlevel = 0; % noise level is zero. 68 | kernel = net.meta.directKernel(:,:,:,5); % corrresponding k_b under bicubic downsampler 69 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 70 | tag = ['_',method,'_x',num2str(sf),'_directG_7_16']; 71 | 72 | 73 | for n_set = 1 : numel(setTest) 74 | 75 | %% search images 76 | setTestCur = cell2mat(setTest(n_set)); 77 | disp('--------------------------------------------'); 78 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 79 | disp('--------------------------------------------'); 80 | folderTestCur = fullfile(folderTest,setTestCur); 81 | ext = {'*.jpg','*.png','*.bmp'}; 82 | filepaths = []; 83 | for i = 1 : length(ext) 84 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 85 | end 86 | 87 | %% prepare results 88 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 89 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 90 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 91 | if ~exist(folderResultCur,'file') 92 | mkdir(folderResultCur); 93 | end 94 | 95 | %% perform SISR 96 | for i = 1 : length(filepaths) 97 | 98 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 99 | C = size(HR,3); 100 | if C == 1 101 | HR = cat(3,HR,HR,HR); 102 | end 103 | [~,imageName,ext] = fileparts(filepaths(i).name); 104 | HR = modcrop(HR, sf); 105 | label_RGB = HR; 106 | 107 | %% bicubic degradation 108 | blury_HR = imfilter(im2double(HR),double(image_kernel),'replicate'); % blur 109 | LR = imresize(im2double(blury_HR),1/sf,'nearest'); % bicubic downsampling 110 | randn('seed',0); 111 | LR_noisy = LR + nlevel/255.*randn(size(LR)); % add random noise (AWGN) 112 | input = single(LR_noisy); 113 | 114 | %input = im2single(im2uint8(LR)); % another widely-used setting 115 | %tic 116 | if useGPU 117 | input = gpuArray(input); 118 | end 119 | 120 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 121 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 122 | %res = vl_srmd_matlab(net, input); % you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 123 | 124 | output_RGB = gather(res(end).x); 125 | %toc; 126 | 127 | if C == 1 128 | label = mean(im2double(HR),3); 129 | output = mean(output_RGB,3); 130 | else 131 | label = rgb2ycbcr(im2double(HR)); 132 | output = rgb2ycbcr(double(output_RGB)); 133 | label = label(:,:,1); 134 | output = output(:,:,1); 135 | end 136 | 137 | %% calculate PSNR and SSIM 138 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 139 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 140 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 141 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 142 | if showResult 143 | imshow(cat(2,label_RGB,imresize(im2uint8(LR),sf),im2uint8(output_RGB))); 144 | drawnow; 145 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 146 | pause(pauseTime) 147 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 148 | end 149 | 150 | end 151 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 152 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 153 | 154 | %% save PSNR and SSIM results 155 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 156 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 157 | 158 | end 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /Demo_degradation_direct_SRMDNF.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMDNF for the widely-used degradation with 7x7 3 | % Gaussian kernel of width 1.6 and direct downsampler of scale factor 3. 4 | % For this degradation, the basic setting is: 5 | % 1. the image blur kernel is; "kernel = fspecial('gaussian',7,1.6)". 6 | % 2. the downsampler is direct downsampler. The scale factor is fixed to 3. 7 | % You can either train a new model with direct downsamper or use the estimated 8 | % kernel k_b under direct downsampler. 9 | % 3. there are three SRMDNF models, "SRMDNFx2.mat" for scale factor 2, "SRMDNFx3.mat" 10 | % for scale factor 3, and "SRMDNFx4.mat" for scale factor 4. 11 | %========================================================================== 12 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 13 | % solve x^ = arg min_x 1/2 ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 14 | % via x^ = CNN(y,k;\Theta) or HR^ = CNN(LR,kernel;\Theta). 15 | % 16 | % There involves two important factors, i.e., blur kernel (k; kernel), in SRMDNF. 17 | % 18 | % For more information, please refer to the following paper. 19 | % @article{zhang2017learningsrmd, 20 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 21 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 22 | % year={2017}, 23 | % } 24 | % 25 | % If you have any question, please feel free to contact with . 26 | % 27 | % This code is for research purpose only. 28 | % 29 | % by Kai Zhang (Nov, 2017) 30 | %========================================================================== 31 | % clear; clc; 32 | format compact; 33 | 34 | addpath('utilities'); 35 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 36 | 37 | %% select testing dataset, use GPU or not, ... 38 | setTest = imageSets([1,2,3,4]); % select the datasets for each tasks 39 | showResult = 0; % save restored images 40 | pauseTime = 0; 41 | useGPU = 1; % 1 or 0, true or false 42 | method = 'SRMDNF'; 43 | folderTest = 'testsets'; 44 | folderResult = 'results'; 45 | if ~exist(folderResult,'file') 46 | mkdir(folderResult); 47 | end 48 | 49 | %% scale factor (3 only) 50 | sf = 3; % Here, do not set sf to 2 or 4. 51 | 52 | %% load model with scale factor sf 53 | folderModel = 'models'; 54 | load(fullfile(folderModel,['SRMDNFx',int2str(sf),'.mat'])); 55 | %net.layers = net.layers(1:end-1); 56 | net = vl_simplenn_tidy(net); 57 | if useGPU 58 | net = vl_simplenn_move(net, 'gpu') ; 59 | end 60 | 61 | %% degradation parameter (kernel & noise level) setting 62 | global degpar; 63 | image_kernel = fspecial('gaussian',7, 1.6); % 7x7 Gaussian kernel k_d with width 1.6 64 | kernel = net.meta.directKernel(:,:,:,5); % corrresponding k_b under bicubic downsampler 65 | degpar = single(net.meta.P*kernel(:)); 66 | tag = ['_',method,'_x',num2str(sf),'_directG_7_16']; 67 | 68 | 69 | 70 | for n_set = 1 : numel(setTest) 71 | 72 | %% search images 73 | setTestCur = cell2mat(setTest(n_set)); 74 | disp('--------------------------------------------'); 75 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 76 | disp('--------------------------------------------'); 77 | folderTestCur = fullfile(folderTest,setTestCur); 78 | ext = {'*.jpg','*.png','*.bmp'}; 79 | filepaths = []; 80 | for i = 1 : length(ext) 81 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 82 | end 83 | 84 | %% prepare results 85 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 86 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 87 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 88 | if ~exist(folderResultCur,'file') 89 | mkdir(folderResultCur); 90 | end 91 | 92 | %% perform SISR 93 | for i = 1 : length(filepaths) 94 | 95 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 96 | C = size(HR,3); 97 | if C == 1 98 | HR = cat(3,HR,HR,HR); 99 | end 100 | [~,imageName,ext] = fileparts(filepaths(i).name); 101 | HR = modcrop(HR, sf); 102 | label_RGB = HR; 103 | %% bicubic degradation 104 | blury_HR = imfilter(im2double(HR),double(image_kernel),'replicate'); % blur 105 | LR = imresize(im2double(blury_HR),1/sf,'nearest'); % bicubic downsampling 106 | input = im2single(LR); 107 | %input = im2single(im2uint8(LR)); % another widely-used setting 108 | 109 | if useGPU 110 | input = gpuArray(input); 111 | end 112 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 113 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 114 | %res = vl_srmd_matlab(net, input); % you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 115 | 116 | output_RGB = gather(res(end).x); 117 | 118 | if C == 1 119 | label = mean(im2double(HR),3); 120 | output = mean(output_RGB,3); 121 | else 122 | label = rgb2ycbcr(im2double(HR)); 123 | output = rgb2ycbcr(double(output_RGB)); 124 | label = label(:,:,1); 125 | output = output(:,:,1); 126 | end 127 | 128 | %% calculate PSNR and SSIM 129 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 130 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 131 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 132 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 133 | if showResult 134 | imshow(cat(2,label_RGB,imresize(im2uint8(LR),sf),im2uint8(output_RGB))); 135 | drawnow; 136 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 137 | pause(pauseTime) 138 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 139 | end 140 | 141 | end 142 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 143 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 144 | 145 | %% save PSNR and SSIM results 146 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 147 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 148 | 149 | end 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /Demo_denoising_and_deblurring_color_SRMD.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of a special case of SRMD (scale factor = 1) for . 3 | % There are two models, "SRMDx1_gray.mat" for grayscale image, "SRMDx1_color.mat" 4 | % for color image. The models can do: 5 | % 1. Deblurring. (The kernel is assumed to be Gaussian-like) there are two types of kernels: 6 | % including isotropic Gaussian (width range: [0.1, 3]), 7 | % anisotropic Gaussian ([0.5, 8]). 8 | % 2. Denoising. the noise level range is [0, 75]. 9 | % For denoising only, set "kerneltype = 1; kernelwidth = 0.1." (i.e., delta kernel) 10 | % 11 | %========================================================================== 12 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR (with special case of sf=1), i.e., 13 | % solve x^ = arg min_x 1/(2 sigma^2) ||kx - y||^2 + lamda \Phi(x) 14 | % via x^ = CNN(y,k,sigma;\Theta) or x^ = CNN(y,kernel,noiselevel;\Theta). 15 | % 16 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 17 | % level (sigma; nlevel). 18 | % 19 | % For more information, please refer to the following paper. 20 | % @article{zhang2017learningsrmd, 21 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 22 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 23 | % year={2017}, 24 | % } 25 | % 26 | % If you have any question, please feel free to contact with . 27 | % 28 | % This code is for research purpose only. 29 | % 30 | % by Kai Zhang (Nov, 2017) 31 | %========================================================================== 32 | 33 | % clear; clc; 34 | format compact; 35 | 36 | addpath('utilities'); 37 | imageSets = {'CBSD68','BSD100'}; % testing dataset 38 | 39 | %% select testing dataset, use GPU or not, ... 40 | setTest = imageSets([1]); % 41 | showResult = 0; % 1, show results; 2, save restored images 42 | pauseTime = 0; 43 | useGPU = 1; % 1 or 0, true or false 44 | method = 'SRMD'; 45 | folderTest = 'testsets'; 46 | folderResult = 'results'; 47 | if ~exist(folderResult,'file') 48 | mkdir(folderResult); 49 | end 50 | 51 | %% scale factor (it is fixed to 1) 52 | 53 | sf = 1; %{1} 54 | 55 | %% load model with scale factor sf 56 | folderModel = 'models'; 57 | load(fullfile(folderModel,['SRMDx',int2str(sf),'_color.mat'])); 58 | %net.layers = net.layers(1:end-1); 59 | net = vl_simplenn_tidy(net); 60 | if useGPU 61 | net = vl_simplenn_move(net, 'gpu') ; 62 | end 63 | 64 | %% degradation parameter (noise level and kernel) setting 65 | %############################# noise level ################################ 66 | % noise level, from a range of [0, 75] 67 | 68 | nlevel = 25; % [0, 75] 69 | 70 | kerneltype = 1; % {1, 2} 71 | 72 | %############################### kernel ################################### 73 | % there are tree types of kernels, including isotropic Gaussian, 74 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 75 | % under direct downsampler (x2 and x3 only). 76 | 77 | if kerneltype == 1 78 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 79 | kernelwidth = 0.1; % from a range of [0.1, 3]. set kernelwidth from (0.001, 0.2) to generate delta kernel (no blur) 80 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 81 | tag = ['_',method,'_x',num2str(sf),'_itrG_',int2str(kernelwidth*10),'_nlevel_',int2str(nlevel)]; 82 | 83 | elseif kerneltype == 2 84 | % type 2, anisotropic Gaussian 85 | nk = randi(size(net.meta.AtrpGaussianKernel,4)); % randomly select one 86 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 87 | tag = ['_',method,'_x',num2str(sf),'_atrG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 88 | 89 | end 90 | 91 | %########################################################################## 92 | 93 | % surf(kernel) % show kernel 94 | % view(45,55); 95 | % title('Assumed kernel'); 96 | % xlim([1 15]); 97 | % ylim([1 15]); 98 | % pause(2) 99 | % close; 100 | 101 | %% for degradation maps 102 | global degpar; 103 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 104 | 105 | 106 | for n_set = 1 : numel(setTest) 107 | 108 | %% search images 109 | setTestCur = cell2mat(setTest(n_set)); 110 | disp('--------------------------------------------'); 111 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 112 | disp('--------------------------------------------'); 113 | folderTestCur = fullfile(folderTest,setTestCur); 114 | ext = {'*.jpg','*.png','*.bmp'}; 115 | filepaths = []; 116 | for i = 1 : length(ext) 117 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 118 | end 119 | 120 | %% prepare results 121 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 122 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 123 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 124 | if ~exist(folderResultCur,'file') 125 | mkdir(folderResultCur); 126 | end 127 | 128 | %% perform denoising or/and deblurring (only support Gaussian-like kernel) 129 | for i = 1 : length(filepaths) 130 | 131 | label = imread(fullfile(folderTestCur,filepaths(i).name)); 132 | %label = modcrop(label, 2); 133 | [h,w,C] = size(label); 134 | if C == 1 135 | label = cat(3,label,label,label); 136 | end 137 | 138 | [~,imageName,ext] = fileparts(filepaths(i).name); 139 | 140 | blurry_label = imfilter(label,double(kernel),'replicate'); % blur 141 | randn('seed',0); 142 | noisy_blurry_label = im2single(blurry_label) + nlevel/255.*randn(size(blurry_label)); % add random noise (AWGN) 143 | input = single(noisy_blurry_label); 144 | 145 | input = im_pad(input); 146 | %tic 147 | if useGPU 148 | input = gpuArray(input); 149 | end 150 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 151 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 152 | %res = vl_srmd_matlab(net, input); % When use this, you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 153 | 154 | output = im2uint8(gather(res(end).x)); 155 | 156 | output = im_crop(output,h,w); 157 | %input = im_crop(input,h,w); 158 | %toc; 159 | % output2 = im2uint8(0.9*im2single(output) + 0.1*gather(input)); 160 | 161 | %% calculate PSNR and SSIM 162 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label,output,0,0); %%% single 163 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 164 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 165 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 166 | if showResult 167 | imshow(cat(2,label,im2uint8(noisy_blurry_label),output)); 168 | drawnow; 169 | title(['Denoising and sharpening ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 170 | pause%(pauseTime) 171 | imwrite(output,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 172 | end 173 | 174 | end 175 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 176 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 177 | 178 | %% save PSNR and SSIM results 179 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 180 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 181 | 182 | end 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Demo_denoising_and_deblurring_gray_SRMD.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of a special case of SRMD (scale factor = 1) for . 3 | % There are two models, "SRMDx1_gray.mat" for grayscale image, "SRMDx1_color.mat" 4 | % for color image. The models can do: 5 | % 1. Deblurring. (The kernel is assumed to be Gaussian-like) there are two types of kernels: 6 | % including isotropic Gaussian (width range: [0.1, 3]), 7 | % anisotropic Gaussian ([0.5, 8]). 8 | % 2. Denoising. the noise level range is [0, 75]. 9 | % For denoising only, set "kerneltype = 1; kernelwidth = 0.1." (i.e., delta kernel) 10 | % 11 | %========================================================================== 12 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR (with special case of sf=1), i.e., 13 | % solve x^ = arg min_x 1/(2 sigma^2) ||kx - y||^2 + lamda \Phi(x) 14 | % via x^ = CNN(y,k,sigma;\Theta) or x^ = CNN(y,kernel,noiselevel;\Theta). 15 | % 16 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 17 | % level (sigma; nlevel). 18 | % 19 | % For more information, please refer to the following paper. 20 | % @article{zhang2017learningsrmd, 21 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 22 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 23 | % year={2017}, 24 | % } 25 | % 26 | % If you have any question, please feel free to contact with . 27 | % 28 | % This code is for research purpose only. 29 | % 30 | % by Kai Zhang (Nov, 2017) 31 | %========================================================================== 32 | 33 | % clear; clc; 34 | format compact; 35 | 36 | addpath('utilities'); 37 | imageSets = {'BSD68','BSD100','Urban100'}; % testing dataset 38 | 39 | %% select testing dataset, use GPU or not, ... 40 | setTest = imageSets([1]); % 41 | showResult = 0; % 1, show results; 2, save restored images 42 | pauseTime = 0; 43 | useGPU = 1; % 1 or 0, true or false 44 | method = 'SRMD'; 45 | folderTest = 'testsets'; 46 | folderResult = 'results'; 47 | if ~exist(folderResult,'file') 48 | mkdir(folderResult); 49 | end 50 | 51 | %% scale factor (it is fixed to 1) 52 | 53 | sf = 1; %{1} 54 | 55 | %% load model with scale factor sf 56 | folderModel = 'models'; 57 | load(fullfile(folderModel,['SRMDx',int2str(sf),'_gray.mat'])); 58 | %net.layers = net.layers(1:end-1); 59 | net = vl_simplenn_tidy(net); 60 | if useGPU 61 | net = vl_simplenn_move(net, 'gpu') ; 62 | end 63 | 64 | %% degradation parameter (noise level and kernel) setting 65 | %############################# noise level ################################ 66 | % noise level, from a range of [0, 75] 67 | 68 | nlevel = 25; % [0, 75] 69 | 70 | kerneltype = 1; % {1, 2} 71 | 72 | %############################### kernel ################################### 73 | % there are tree types of kernels, including isotropic Gaussian, 74 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 75 | % under direct downsampler (x2 and x3 only). 76 | 77 | if kerneltype == 1 78 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 79 | kernelwidth = 0.1; % from a range of [0.1, 3]. set kernelwidth from (0.001, 0.2) to generate delta kernel (no blur) 80 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 81 | tag = ['_',method,'_x',num2str(sf),'_itrG_',int2str(kernelwidth*10),'_nlevel_',int2str(nlevel)]; 82 | 83 | elseif kerneltype == 2 84 | % type 2, anisotropic Gaussian 85 | nk = randi(size(net.meta.AtrpGaussianKernel,4)); % randomly select one 86 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 87 | tag = ['_',method,'_x',num2str(sf),'_atrG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 88 | 89 | end 90 | 91 | %########################################################################## 92 | 93 | % surf(kernel) % show kernel 94 | % view(45,55); 95 | % title('Assumed kernel'); 96 | % xlim([1 15]); 97 | % ylim([1 15]); 98 | % pause(2) 99 | % close; 100 | 101 | %% for degradation maps 102 | global degpar; 103 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 104 | 105 | 106 | for n_set = 1 : numel(setTest) 107 | 108 | %% search images 109 | setTestCur = cell2mat(setTest(n_set)); 110 | disp('--------------------------------------------'); 111 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 112 | disp('--------------------------------------------'); 113 | folderTestCur = fullfile(folderTest,setTestCur); 114 | ext = {'*.jpg','*.png','*.bmp'}; 115 | filepaths = []; 116 | for i = 1 : length(ext) 117 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 118 | end 119 | 120 | %% prepare results 121 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 122 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 123 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 124 | if ~exist(folderResultCur,'file') 125 | mkdir(folderResultCur); 126 | end 127 | 128 | %% perform denoising or/and deblurring (only support Gaussian-like kernel) 129 | for i = 1 : length(filepaths) 130 | 131 | label = imread(fullfile(folderTestCur,filepaths(i).name)); 132 | %label = modcrop(label, 2); 133 | [h,w,C] = size(label); 134 | if C == 3 135 | label = rgb2gray(label); 136 | end 137 | 138 | [~,imageName,ext] = fileparts(filepaths(i).name); 139 | 140 | blurry_label = imfilter(label,double(kernel),'replicate'); % blur 141 | randn('seed',0); 142 | noisy_blurry_label = im2single(blurry_label) + nlevel/255.*randn(size(blurry_label)); % add random noise (AWGN) 143 | input = single(noisy_blurry_label); 144 | 145 | input = im_pad(input); 146 | %tic 147 | if useGPU 148 | input = gpuArray(input); 149 | end 150 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 151 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 152 | %res = vl_srmd_matlab(net, input); % When use this, you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 153 | 154 | 155 | output = im2uint8(gather(res(end).x)); 156 | 157 | output = im_crop(output,h,w); 158 | input = im_crop(gather(input),h,w); 159 | %toc; 160 | % output = im2uint8(0.9*im2single(output) + 0.1*gather(input)); 161 | 162 | %% calculate PSNR and SSIM 163 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label,output,0,0); %%% single 164 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 165 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 166 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 167 | if showResult 168 | imshow(cat(2,label,im2uint8(noisy_blurry_label),output)); 169 | drawnow; 170 | title(['Denoising and sharpening ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 171 | pause(pauseTime) 172 | imwrite(output,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 173 | end 174 | 175 | end 176 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 177 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 178 | 179 | %% save PSNR and SSIM results 180 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 181 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 182 | 183 | end 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /Demo_genearal_degradation_SRMD.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMD for the of SISR. 3 | % For general degradation, the basic setting is: 4 | % 1. there are tree types of kernels, including isotropic Gaussian, 5 | % anisotropic Gaussian, and estimated kernel k_b for isotropic 6 | % Gaussian k_d under direct downsampler (x2 and x3 only). 7 | % 2. the noise level range is [0, 75]. 8 | % 3. the downsampler is fixed to bicubic downsampler. 9 | % For direct downsampler, you can either train a new model with 10 | % direct downsamper or use the estimated kernel k_b under direct 11 | % downsampler. The former is preferred. 12 | % 4. there are three models, "SRMDx2.mat" for scale factor 2, "SRMDx3.mat" 13 | % for scale factor 3, and "SRMDx4.mat" for scale factor 4. 14 | %========================================================================== 15 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 16 | % solve x^ = arg min_x 1/(2 sigma^2) ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 17 | % via x^ = CNN(y,k,sigma;\Theta) or HR^ = CNN(LR,kernel,noiselevel;\Theta). 18 | % 19 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 20 | % level (sigma; nlevel). 21 | % 22 | % For more information, please refer to the following paper. 23 | % @article{zhang2017learningsrmd, 24 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 25 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 26 | % year={2017}, 27 | % } 28 | % 29 | % If you have any question, please feel free to contact with . 30 | % 31 | % This code is for research purpose only. 32 | % 33 | % by Kai Zhang (Nov, 2017) 34 | %========================================================================== 35 | 36 | % clear; clc; 37 | format compact; 38 | 39 | addpath('utilities'); 40 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 41 | 42 | %% select testing dataset, use GPU or not, ... 43 | setTest = imageSets([1]); % 44 | showResult = 1; % 1, show ground-truth, bicubicly interpolated LR image, and restored HR images by SRMD; 2, save restored images 45 | pauseTime = 1; 46 | useGPU = 1; % 1 or 0, true or false 47 | method = 'SRMD'; 48 | folderTest = 'testsets'; 49 | folderResult = 'results'; 50 | if ~exist(folderResult,'file') 51 | mkdir(folderResult); 52 | end 53 | 54 | %% scale factor (2, 3, 4) 55 | 56 | sf = 2; %{2, 3, 4} 57 | 58 | %% load model with scale factor sf 59 | folderModel = 'models'; 60 | load(fullfile(folderModel,['SRMDx',int2str(sf),'.mat'])); 61 | %net.layers = net.layers(1:end-1); 62 | net = vl_simplenn_tidy(net); 63 | if useGPU 64 | net = vl_simplenn_move(net, 'gpu') ; 65 | end 66 | 67 | %% degradation parameter (noise level and kernel) setting 68 | %############################# noise level ################################ 69 | % noise level, from a range of [0, 75] 70 | 71 | nlevel = 15; % [0, 75] 72 | 73 | kerneltype = 1; % {1, 2, 3} 74 | 75 | %############################### kernel ################################### 76 | % there are tree types of kernels, including isotropic Gaussian, 77 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 78 | % under direct downsampler (x2 and x3 only). 79 | 80 | if kerneltype == 1 81 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 82 | kernelwidth = 2.6; % from a range of [0.2, 2] for sf = 2, [0.2, 3] for sf = 3, and [0.2, 4] for sf = 4. 83 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 84 | tag = ['_',method,'_x',num2str(sf),'_itrG_',int2str(kernelwidth*10),'_nlevel_',int2str(nlevel)]; 85 | 86 | elseif kerneltype == 2 87 | % type 2, anisotropic Gaussian 88 | nk = randi(size(net.meta.AtrpGaussianKernel,4)); % randomly select one 89 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 90 | tag = ['_',method,'_x',num2str(sf),'_atrG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 91 | 92 | elseif kerneltype == 3 && ( sf==2 || sf==3 ) 93 | % type 3, estimated kernel k_b (x2 and x3 only) 94 | nk = randi(size(net.meta.directKernel,4)); % randomly select one 95 | kernel = net.meta.directKernel(:,:,:,nk); 96 | tag = ['_',method,'_x',num2str(sf),'_dirG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 97 | end 98 | 99 | %########################################################################## 100 | 101 | surf(kernel) % show kernel 102 | view(45,55); 103 | title('Assumed kernel'); 104 | xlim([1 15]); 105 | ylim([1 15]); 106 | pause(2) 107 | close; 108 | 109 | %% for degradation maps 110 | global degpar; 111 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 112 | 113 | 114 | for n_set = 1 : numel(setTest) 115 | 116 | %% search images 117 | setTestCur = cell2mat(setTest(n_set)); 118 | disp('--------------------------------------------'); 119 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 120 | disp('--------------------------------------------'); 121 | folderTestCur = fullfile(folderTest,setTestCur); 122 | ext = {'*.jpg','*.png','*.bmp'}; 123 | filepaths = []; 124 | for i = 1 : length(ext) 125 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 126 | end 127 | 128 | %% prepare results 129 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 130 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 131 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 132 | if ~exist(folderResultCur,'file') 133 | mkdir(folderResultCur); 134 | end 135 | 136 | %% perform SISR 137 | for i = 1 : length(filepaths) 138 | 139 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 140 | C = size(HR,3); 141 | if C == 1 142 | HR = cat(3,HR,HR,HR); 143 | end 144 | [~,imageName,ext] = fileparts(filepaths(i).name); 145 | HR = modcrop(HR, sf); 146 | label_RGB = HR; 147 | blury_HR = imfilter(im2double(HR),double(kernel),'replicate'); % blur 148 | LR = imresize(blury_HR,1/sf,'bicubic'); % bicubic downsampling 149 | randn('seed',0); 150 | LR_noisy = LR + nlevel/255.*randn(size(LR)); % add random noise (AWGN) 151 | input = single(LR_noisy); 152 | %tic 153 | if useGPU 154 | input = gpuArray(input); 155 | end 156 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 157 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 158 | %res = vl_srmd_matlab(net, input); % When use this, you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 159 | 160 | output_RGB = gather(res(end).x); 161 | 162 | %toc; 163 | if C == 1 164 | label = mean(im2double(HR),3); 165 | output = mean(output_RGB,3); 166 | else 167 | label = rgb2ycbcr(im2double(HR)); 168 | output = rgb2ycbcr(double(output_RGB)); 169 | label = label(:,:,1); 170 | output = output(:,:,1); 171 | end 172 | 173 | %% calculate PSNR and SSIM 174 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 175 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 176 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 177 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 178 | if showResult 179 | imshow(cat(2,label_RGB,imresize(im2uint8(LR_noisy),sf),im2uint8(output_RGB))); 180 | drawnow; 181 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 182 | pause(pauseTime) 183 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 184 | end 185 | 186 | end 187 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 188 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 189 | 190 | %% save PSNR and SSIM results 191 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 192 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 193 | 194 | end 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /Demo_genearal_degradation_SRMDNF.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMDNF for the of SISR. 3 | % For general degradation, the basic setting is: 4 | % 1. there are tree types of kernels, including isotropic Gaussian, 5 | % anisotropic Gaussian, and estimated kernel k_b for isotropic 6 | % Gaussian k_d under direct downsampler (x2 and x3 only). 7 | % 3. the downsampler is fixed to bicubic downsampler. 8 | % For direct downsampler, you can either train a new model with 9 | % direct downsamper or use the estimated kernel k_b under direct 10 | % downsampler. The former is preferred. 11 | % 3. there are three models, "SRMDNFx2.mat" for scale factor 2, "SRMDNFx3.mat" 12 | % for scale factor 3, and "SRMDNFx4.mat" for scale factor 4. 13 | %========================================================================== 14 | % The basic idea of SRMDNF is to learn a CNN to infer the MAP of general SISR, i.e., 15 | % solve x^ = arg min_x 1/2 ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 16 | % via x^ = CNN(y,k;\Theta) or HR^ = CNN(LR,kernel;\Theta). 17 | % 18 | % There involves one important factor, i.e., blur kernel (k; kernel), in SRMDNF. 19 | % 20 | % For more information, please refer to the following paper. 21 | % @article{zhang2017learningsrmd, 22 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 23 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 24 | % year={2017}, 25 | % } 26 | % 27 | % If you have any question, please feel free to contact with . 28 | % 29 | % This code is for research purpose only. 30 | % 31 | % by Kai Zhang (Nov, 2017) 32 | %========================================================================== 33 | 34 | % clear; clc; 35 | format compact; 36 | 37 | addpath('utilities'); 38 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 39 | 40 | %% select testing dataset, use GPU or not, ... 41 | setTest = imageSets([1]); % 42 | showResult = 1; % 1, show ground-truth, bicubicly interpolated LR image, and restored HR images by SRMD; 2, save restored images 43 | pauseTime = 1; 44 | useGPU = 1; % 1 or 0, true or false 45 | method = 'SRMDNF'; 46 | folderTest = 'testsets'; 47 | folderResult = 'results'; 48 | if ~exist(folderResult,'file') 49 | mkdir(folderResult); 50 | end 51 | 52 | %% scale factor (2, 3, 4) 53 | 54 | sf = 2; 55 | 56 | %% load model with scale factor sf 57 | folderModel = 'models'; 58 | load(fullfile(folderModel,['SRMDNFx',int2str(sf),'.mat'])); 59 | %net.layers = net.layers(1:end-1); 60 | net = vl_simplenn_tidy(net); 61 | if useGPU 62 | net = vl_simplenn_move(net, 'gpu') ; 63 | end 64 | 65 | %% degradation parameter (kernel) setting 66 | global degpar; 67 | 68 | kerneltype = 1; 69 | 70 | %################################kernel#################################### 71 | % there are tree types of kernels, including isotropic Gaussian, 72 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 73 | % under direct downsampler (x2 and x3 only). 74 | if kerneltype == 1 75 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 76 | kernelwidth = 2.6; % from a range of [0.2, 2] for sf = 2, [0.2, 3] for sf = 3, and [0.2, 4] for sf = 4. 77 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 78 | tag = ['_',method,'_x',num2str(sf),'_itrG_',int2str(kernelwidth*10)]; 79 | 80 | elseif kerneltype == 2 81 | % type 2, anisotropic Gaussian 82 | nk = randi(size(net.meta.AtrpGaussianKernel,4)); % randomly select one 83 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 84 | tag = ['_',method,'_x',num2str(sf),'_atrG_',int2str(nk)]; 85 | 86 | elseif kerneltype == 3 && ( sf==2 || sf==3 ) 87 | % type 3, estimated kernel k_b (x2 and x3 only) 88 | nk = randi(size(net.meta.directKernel,4)); % randomly select one 89 | kernel = net.meta.directKernel(:,:,:,nk); 90 | tag = ['_',method,'_x',num2str(sf),'_dirG_',int2str(nk)]; 91 | 92 | end 93 | %########################################################################## 94 | 95 | surf(kernel) % show kernel 96 | view(45,55); 97 | title('Assumed kernel'); 98 | xlim([1 15]); 99 | ylim([1 15]); 100 | pause(2) 101 | close; 102 | 103 | %% for degradation maps 104 | degpar = single(net.meta.P*kernel(:)); 105 | 106 | 107 | for n_set = 1 : numel(setTest) 108 | 109 | %% search images 110 | setTestCur = cell2mat(setTest(n_set)); 111 | disp('--------------------------------------------'); 112 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 113 | disp('--------------------------------------------'); 114 | folderTestCur = fullfile(folderTest,setTestCur); 115 | ext = {'*.jpg','*.png','*.bmp'}; 116 | filepaths = []; 117 | for i = 1 : length(ext) 118 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 119 | end 120 | 121 | %% prepare results 122 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 123 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 124 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 125 | if ~exist(folderResultCur,'file') 126 | mkdir(folderResultCur); 127 | end 128 | 129 | %% perform SISR 130 | for i = 1 : length(filepaths) 131 | 132 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 133 | C = size(HR,3); 134 | if C == 1 135 | HR = cat(3,HR,HR,HR); 136 | end 137 | [~,imageName,ext] = fileparts(filepaths(i).name); 138 | HR = modcrop(HR, sf); 139 | label_RGB = HR; 140 | blury_HR = imfilter(im2double(HR),double(kernel),'replicate'); % blur 141 | LR = imresize(blury_HR,1/sf,'bicubic'); % bicubic downsampling 142 | input = single(LR); 143 | 144 | if useGPU 145 | input = gpuArray(input); 146 | end 147 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 148 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 149 | %res = vl_srmd_matlab(net, input); % When use this, you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 150 | 151 | output_RGB = gather(res(end).x); 152 | 153 | if C == 1 154 | label = mean(im2double(HR),3); 155 | output = mean(output_RGB,3); 156 | else 157 | label = rgb2ycbcr(im2double(HR)); 158 | output = rgb2ycbcr(double(output_RGB)); 159 | label = label(:,:,1); 160 | output = output(:,:,1); 161 | end 162 | 163 | %% calculate PSNR and SSIM 164 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 165 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 166 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 167 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 168 | if showResult 169 | imshow(cat(2,label_RGB,imresize(im2uint8(LR),sf),im2uint8(output_RGB))); 170 | drawnow; 171 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 172 | pause(pauseTime) 173 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 174 | end 175 | 176 | end 177 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 178 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 179 | 180 | %% save PSNR and SSIM results 181 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 182 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 183 | 184 | end 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /Demo_real_application_SRMD.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMD (x2, x3, x4) for real image SR. 3 | % For general degradation, the basic setting is: 4 | % 1. there are tree types of kernels, including isotropic Gaussian, 5 | % anisotropic Gaussian, and estimated kernel k_b for isotropic 6 | % Gaussian k_d under direct downsampler (x2 and x3 only). 7 | % It is preferred to estimate the kernel first, or you can sample 8 | % several kernels to produce multiple results and select the best one. 9 | % 2. the noise level range is [0, 75]. 10 | % 3. the downsampler is fixed to bicubic downsampler. 11 | % For direct downsampler, you can either train a new model with 12 | % direct downsamper or use the estimated kernel k_b under direct 13 | % downsampler. The former is preferred. 14 | % 4. there are three models, "SRMDx2.mat" for scale factor 2, "SRMDx3.mat" 15 | % for scale factor 3, and "SRMDx4.mat" for scale factor 4. 16 | %========================================================================== 17 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 18 | % solve x^ = arg min_x 1/(2 sigma^2) ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 19 | % via x^ = CNN(y,k,sigma;\Theta) or HR^ = CNN(LR,kernel,noiselevel;\Theta). 20 | % 21 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 22 | % level (sigma; nlevel). 23 | % 24 | % For more information, please refer to the following paper. 25 | % @article{zhang2017learningsrmd, 26 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 27 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 28 | % year={2017}, 29 | % } 30 | % 31 | % If you have any question, please feel free to contact with . 32 | % 33 | % This code is for research purpose only. 34 | % 35 | % by Kai Zhang (Nov, 2017) 36 | %========================================================================== 37 | 38 | % clear; clc; 39 | format compact; 40 | 41 | addpath('utilities'); 42 | imageSets = {'chip','cat','flowers','stars','Set5','Set14','BSD100','Urban100'}; % testing dataset 43 | 44 | 45 | %%======= ======= ======= degradation parameter settings ======= ======= ======= 46 | 47 | % For real image 'chip', some examples of degradation setting are given as follows. 48 | % sf = 2; nlevel = 5~10; kerneltype = 1; kernelwidth = 0.8; 49 | % sf = 2; nlevel = 5~10; kerneltype = 3; nk = 5; 50 | % sf = 3; nlevel = 5~10; kerneltype = 1; kernelwidth = 1.2; 51 | % sf = 3; nlevel = 5~10; kerneltype = 3; nk = 5; 52 | % sf = 4; nlevel = 5~10; kerneltype = 1; kernelwidth = 1.7; 53 | 54 | % For real image 'cat', some examples of degradation setting are given as follows. 55 | % sf = 2; nlevel = 20; kerneltype = 1; kernelwidth = 1.6; 56 | % sf = 2; nlevel = 20; kerneltype = 3; nk = 12; 57 | % sf = 3; nlevel = 20; kerneltype = 1; kernelwidth = 2.4; 58 | % sf = 3; nlevel = 20; kerneltype = 3; nk = 9; 59 | % sf = 4; nlevel = 20; kerneltype = 1; kernelwidth = 3.2; 60 | 61 | % For real image 'flowers', some examples of degradation setting are given as follows. 62 | % sf = 2; nlevel = 60; kerneltype = 1; kernelwidth = 1.2; 63 | % sf = 2; nlevel = 60; kerneltype = 3; nk = 4; 64 | % sf = 3; nlevel = 60; kerneltype = 1; kernelwidth = 2.4; 65 | % sf = 3; nlevel = 60; kerneltype = 3; nk = 6; 66 | % sf = 4; nlevel = 60; kerneltype = 1; kernelwidth = 3; 67 | 68 | % For real image 'stars', some examples of degradation setting are given as follows. 69 | % sf = 2; nlevel = 20; kerneltype = 1; kernelwidth = 0.8; 70 | % sf = 2; nlevel = 20; kerneltype = 3; nk = 4; 71 | % sf = 3; nlevel = 20; kerneltype = 1; kernelwidth = 1.2; 72 | % sf = 3; nlevel = 20; kerneltype = 3; nk = 4; 73 | % sf = 4; nlevel = 20; kerneltype = 1; kernelwidth = 1.6; 74 | 75 | % For real image sets 'Set5','Set14','BSD100','Urban100', some examples of degradation are: 76 | % sf = 2; nlevel = 10; kerneltype = 1; kernelwidth = 0.4; 77 | % sf = 3; nlevel = 10; kerneltype = 1; kernelwidth = 0.8; 78 | % sf = 4; nlevel = 10; kerneltype = 1; kernelwidth = 1.2; 79 | 80 | %%======= ======= ======= ======= ======= ======= ======= ======= ======= ======= 81 | 82 | 83 | %% select testing dataset, use GPU or not, ... 84 | setTest = imageSets([1]); % 85 | showResult = 1; % 1, show images; 2, save restored images 86 | pauseTime = 1; 87 | useGPU = 1; % 1 or 0, true or false 88 | method = 'SRMD'; 89 | folderTest = 'testsets'; 90 | folderResult = 'results'; 91 | if ~exist(folderResult,'file') 92 | mkdir(folderResult); 93 | end 94 | 95 | %% scale factor (2, 3, 4) 96 | 97 | sf = 4; %{2, 3, 4} 98 | 99 | %% load model with scale factor sf 100 | folderModel = 'models'; 101 | load(fullfile(folderModel,['SRMDx',int2str(sf),'.mat'])); 102 | %net.layers = net.layers(1:end-1); 103 | net = vl_simplenn_tidy(net); 104 | if useGPU 105 | net = vl_simplenn_move(net, 'gpu') ; 106 | end 107 | 108 | %% degradation parameter (noise level and kernel) setting 109 | %############################# noise level ################################ 110 | % noise level, from a range of [0, 75] 111 | 112 | nlevel = 10; % [0, 75] 113 | 114 | kerneltype = 1; % {1, 2, 3} 115 | 116 | %############################### kernel ################################### 117 | % there are tree types of kernels, including isotropic Gaussian, 118 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 119 | % under direct downsampler (x2 and x3 only). 120 | 121 | if kerneltype == 1 122 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 123 | kernelwidth = 1.7; % from a range of [0.2, 2] for sf = 2, [0.2, 3] for sf = 3, and [0.2, 4] for sf = 4. 124 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 125 | tag = ['_',method,'_Real_x',num2str(sf),'_itrG_',int2str(kernelwidth*10),'_nlevel_',int2str(nlevel)]; 126 | 127 | elseif kerneltype == 2 128 | % type 2, anisotropic Gaussian 129 | nk = 1; % randi(size(net.meta.AtrpGaussianKernel,4)); % select one 130 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 131 | tag = ['_',method,'_Real_x',num2str(sf),'_atrG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 132 | 133 | elseif kerneltype == 3 && ( sf==2 || sf==3 ) 134 | % type 3, estimated kernel k_b (x2 and x3 only) 135 | nk = 5; %randi(size(net.meta.directKernel,4)); % select one 136 | kernel = net.meta.directKernel(:,:,:,nk); 137 | tag = ['_',method,'_Real_x',num2str(sf),'_dirG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 138 | end 139 | 140 | %########################################################################## 141 | 142 | surf(kernel) % show kernel 143 | view(45,55); 144 | title('Assumed kernel'); 145 | xlim([1 15]); 146 | ylim([1 15]); 147 | pause(2) 148 | close; 149 | 150 | %% for degradation maps 151 | global degpar; 152 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 153 | 154 | 155 | for n_set = 1 : numel(setTest) 156 | 157 | %% search images 158 | setTestCur = cell2mat(setTest(n_set)); 159 | disp('--------------------------------------------'); 160 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 161 | disp('--------------------------------------------'); 162 | folderTestCur = fullfile(folderTest,setTestCur); 163 | ext = {'*.jpg','*.png','*.bmp'}; 164 | filepaths = []; 165 | for i = 1 : length(ext) 166 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 167 | end 168 | 169 | %% prepare results 170 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 171 | if ~exist(folderResultCur,'file') 172 | mkdir(folderResultCur); 173 | end 174 | 175 | %% perform SISR 176 | for i = 1 : length(filepaths) 177 | 178 | LR = imread(fullfile(folderTestCur,filepaths(i).name)); 179 | C = size(LR,3); 180 | if C == 1 181 | LR = cat(3,LR,LR,LR); 182 | end 183 | [~,imageName,ext] = fileparts(filepaths(i).name); 184 | input = im2single(LR); 185 | %tic 186 | if useGPU 187 | input = gpuArray(input); 188 | end 189 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 190 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 191 | %res = vl_srmd_matlab(net, input); % you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 192 | 193 | output_RGB = gather(res(end).x); 194 | 195 | %toc; 196 | 197 | disp([setTestCur,' ',int2str(i),' ',' ',filepaths(i).name]); 198 | 199 | if showResult 200 | imshow(cat(2,imresize(im2uint8(LR),sf),im2uint8(output_RGB))); 201 | drawnow; 202 | title(['SRMD ',filepaths(i).name],'FontSize',12) 203 | pause(pauseTime) 204 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'.png']));% save results 205 | 206 | end 207 | end 208 | end 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /Demo_real_application_denoising_and_deblurring_color.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of a special case of SRMD (scale factor = 1) for real image . 3 | % There are two models, "SRMDx1_gray.mat" for grayscale image, "SRMDx1_color.mat" 4 | % for color image. The models can do: 5 | % 1. Deblurring. (The kernel is assumed to be Gaussian-like!!! For other kernels, you should re-train the model!) 6 | % there are two types of kernels, 7 | % including isotropic Gaussian (width range: [0.1, 3]), 8 | % anisotropic Gaussian ([0.5, 8]). 9 | % 2. Denoising. the noise level range is [0, 75]. 10 | % For denoising only, set "kerneltype = 1; kernelwidth = 0.1." (i.e., delta kernel) 11 | % 12 | %========================================================================== 13 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR (with special case of sf=1), i.e., 14 | % solve x^ = arg min_x 1/(2 sigma^2) ||kx - y||^2 + lamda \Phi(x) 15 | % via x^ = CNN(y,k,sigma;\Theta) or x^ = CNN(y,kernel,noiselevel;\Theta). 16 | % 17 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 18 | % level (sigma; nlevel). 19 | % 20 | % For more information, please refer to the following paper. 21 | % @article{zhang2017learningsrmd, 22 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 23 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 24 | % year={2017}, 25 | % } 26 | % 27 | % If you have any question, please feel free to contact with . 28 | % 29 | % This code is for research purpose only. 30 | % 31 | % by Kai Zhang (Nov, 2017) 32 | %========================================================================== 33 | 34 | % clear; clc; 35 | format compact; 36 | 37 | addpath('utilities'); 38 | imageSets = {'hanzi','starsL','Audrey_Hepburn','flowersL','frog','Nami','Set5','Set14'}; % testing dataset 39 | 40 | %%======= ======= ======= degradation parameter settings ======= ======= ======= 41 | % For real image 'starsL', some examples of degradation setting are given as follows. 42 | % sf = 1; nlevel = 20; kerneltype = 1; kernelwidth = 0.1; % denoising 43 | 44 | % For real image 'Audrey_Hepburn', some examples of degradation setting are given as follows. 45 | % sf = 1; nlevel = 10; kerneltype = 1; kernelwidth = 0.1; % denoising 46 | 47 | % For real image 'flowersL', some examples of degradation setting are given as follows. 48 | % sf = 1; nlevel = 65; kerneltype = 1; kernelwidth = 0.1; % denoising 49 | 50 | % For real image 'frog', some examples of degradation setting are given as follows. 51 | % sf = 1; nlevel = 15; kerneltype = 1; kernelwidth = 0.1; % denoising 52 | 53 | % For real image 'Nami', some examples of degradation setting are given as follows. 54 | % sf = 1; nlevel = 10; kerneltype = 1; kernelwidth = 1; % denoising and deblurring 55 | 56 | %%======= ======= ======= ======= ======= ======= ======= ======= ======= ======= 57 | 58 | 59 | %% select testing dataset, use GPU or not, ... 60 | setTest = imageSets([5]); % 61 | showResult = 1; % 1; show results; 2; save restored images 62 | pauseTime = 1; 63 | useGPU = 1; % 1 or 0, true or false 64 | method = 'SRMD'; 65 | folderTest = 'testsets'; 66 | folderResult = 'results'; 67 | if ~exist(folderResult,'file') 68 | mkdir(folderResult); 69 | end 70 | 71 | %% scale factor (it is fixed to 1) 72 | 73 | sf = 1; %{1} 74 | 75 | %% load model with scale factor sf 76 | folderModel = 'models'; 77 | load(fullfile(folderModel,['SRMDx',int2str(sf),'_color.mat'])); 78 | %net.layers = net.layers(1:end-1); 79 | net = vl_simplenn_tidy(net); 80 | if useGPU 81 | net = vl_simplenn_move(net, 'gpu') ; 82 | end 83 | 84 | %% degradation parameter (noise level and kernel) setting 85 | %############################# noise level ################################ 86 | % noise level, from a range of [0, 75] 87 | 88 | nlevel = 15; % [0, 75] 89 | 90 | kerneltype = 1; % {1, 2} 91 | 92 | %############################### kernel ################################### 93 | % there are tree types of kernels, including isotropic Gaussian, 94 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 95 | % under direct downsampler (x2 and x3 only). 96 | 97 | if kerneltype == 1 98 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 99 | kernelwidth = 0.1; % from a range of [0.1, 3]. set kernelwidth from (0.001, 0.2) to generate delta kernel (no blur) 100 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 101 | tag = ['_',method,'_x',num2str(sf),'_itrG_',int2str(kernelwidth*10),'_nlevel_',int2str(nlevel)]; 102 | 103 | elseif kerneltype == 2 104 | % type 2, anisotropic Gaussian 105 | nk = randi(size(net.meta.AtrpGaussianKernel,4)); % randomly select one 106 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 107 | tag = ['_',method,'_x',num2str(sf),'_atrG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 108 | 109 | end 110 | 111 | 112 | %########################################################################## 113 | 114 | surf(kernel) % show kernel 115 | view(45,55); 116 | title('Assumed kernel'); 117 | xlim([1 15]); 118 | ylim([1 15]); 119 | pause(2) 120 | close; 121 | 122 | %% for degradation maps 123 | global degpar; 124 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 125 | 126 | 127 | for n_set = 1 : numel(setTest) 128 | 129 | %% search images 130 | setTestCur = cell2mat(setTest(n_set)); 131 | disp('--------------------------------------------'); 132 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 133 | disp('--------------------------------------------'); 134 | folderTestCur = fullfile(folderTest,setTestCur); 135 | ext = {'*.jpg','*.png','*.bmp'}; 136 | filepaths = []; 137 | for i = 1 : length(ext) 138 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 139 | end 140 | 141 | %% prepare results 142 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 143 | if ~exist(folderResultCur,'file') 144 | mkdir(folderResultCur); 145 | end 146 | 147 | %% perform denoising or/and deblurring (only support Gaussian-like kernel) 148 | for i = 1 : length(filepaths) 149 | 150 | label = imread(fullfile(folderTestCur,filepaths(i).name)); 151 | %label = modcrop(label, 2); 152 | [h,w,C] = size(label); 153 | if C == 1 154 | label = cat(3,label,label,label); 155 | end 156 | 157 | input = label; 158 | [~,imageName,ext] = fileparts(filepaths(i).name); 159 | 160 | input = im_pad(input); 161 | %tic 162 | if useGPU 163 | input = gpuArray(im2single(input)); 164 | end 165 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 166 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 167 | %res = vl_srmd_matlab(net, input); % When use this, you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 168 | 169 | output = im2uint8(gather(res(end).x)); 170 | 171 | output = im_crop(output,h,w); 172 | input = im_crop(input,h,w); 173 | %toc; 174 | % a = 0.1;%0.15-nlevel/700; 175 | % output2 = (1-a)*output + a*label; % add noise and structure back to make the output more visually plausible. or GAN? 176 | disp([setTestCur,' ',int2str(i),' ',filepaths(i).name]); 177 | 178 | if showResult 179 | imshow(cat(2,label,output)); 180 | drawnow; 181 | title(['Denoising and Gaussian deblurring ',filepaths(i).name],'FontSize',12) 182 | pause(pauseTime) 183 | imwrite(output,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'.png']));% save results 184 | 185 | end 186 | 187 | end 188 | 189 | end 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /Demo_real_application_denoising_and_deblurring_gray.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of a special case of SRMD (scale factor = 1) for real image . 3 | % There are two models, "SRMDx1_gray.mat" for grayscale image, "SRMDx1_color.mat" 4 | % for color image. The models can do: 5 | % 1. Deblurring. (The kernel is assumed to be Gaussian-like!!! For other kernels, you should re-train the model!) 6 | % there are two types of kernels, 7 | % including isotropic Gaussian (width range: [0.1, 3]), 8 | % anisotropic Gaussian ([0.5, 8]). 9 | % 2. Denoising. the noise level range is [0, 75]. 10 | % For denoising only, set "kerneltype = 1; kernelwidth = 0.1." (i.e., delta kernel) 11 | % 12 | %========================================================================== 13 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR (with special case of sf=1), i.e., 14 | % solve x^ = arg min_x 1/(2 sigma^2) ||kx - y||^2 + lamda \Phi(x) 15 | % via x^ = CNN(y,k,sigma;\Theta) or x^ = CNN(y,kernel,noiselevel;\Theta). 16 | % 17 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 18 | % level (sigma; nlevel). 19 | % 20 | % For more information, please refer to the following paper. 21 | % @article{zhang2017learningsrmd, 22 | % title={Learning a Single Convolutional Super-Resolution Network for Multiple Degradations}, 23 | % author={Kai, Zhang and Wangmeng, Zuo and Lei, Zhang}, 24 | % year={2017}, 25 | % } 26 | % 27 | % If you have any question, please feel free to contact with . 28 | % 29 | % This code is for research purpose only. 30 | % 31 | % by Kai Zhang (Nov, 2017) 32 | %========================================================================== 33 | 34 | % clear; clc; 35 | format compact; 36 | 37 | addpath('utilities'); 38 | imageSets = {'Hilbert','Set5','Set14','BSD68','BSD100','Urban100'}; % testing dataset 39 | 40 | 41 | %%======= ======= ======= degradation parameter settings ======= ======= ======= 42 | 43 | % For real image 'Hilbert', some examples of degradation setting are given as follows. 44 | % sf = 1; nlevel = 8; kerneltype = 1; kernelwidth = 0.2; % denoising only 45 | % sf = 1; nlevel = 10; kerneltype = 1; kernelwidth = 0.5; % denoising and sharpening(deblurring) 46 | 47 | %%======= ======= ======= ======= ======= ======= ======= ======= ======= ======= 48 | 49 | 50 | %% select testing dataset, use GPU or not, ... 51 | setTest = imageSets([1]); % 52 | showResult = 1; % 1, show results; 2, save restored images 53 | pauseTime = 1; 54 | useGPU = 1; % 1 or 0, true or false 55 | method = 'SRMD'; 56 | folderTest = 'testsets'; 57 | folderResult = 'results'; 58 | if ~exist(folderResult,'file') 59 | mkdir(folderResult); 60 | end 61 | 62 | %% scale factor (it is fixed to 1) 63 | 64 | sf = 1; %{1} 65 | 66 | %% load model with scale factor sf 67 | folderModel = 'models'; 68 | load(fullfile(folderModel,['SRMDx',int2str(sf),'_gray.mat'])); 69 | %net.layers = net.layers(1:end-1); 70 | net = vl_simplenn_tidy(net); 71 | if useGPU 72 | net = vl_simplenn_move(net, 'gpu') ; 73 | end 74 | 75 | %% degradation parameter (noise level and kernel) setting 76 | %############################# noise level ################################ 77 | % noise level, from a range of [0, 75] 78 | 79 | nlevel = 10; % [0, 75] 80 | 81 | kerneltype = 1; % {1} 82 | 83 | %############################### kernel ################################### 84 | % there are tree types of kernels, including isotropic Gaussian, 85 | % anisotropic Gaussian, and estimated kernel k_b for isotropic Gaussian k_d 86 | % under direct downsampler (x2 and x3 only). 87 | 88 | if kerneltype == 1 89 | % type 1, isotropic Gaussian---although it is a special case of anisotropic Gaussian. 90 | kernelwidth = 0.5; % from a range of [0.1, 3]. set kernelwidth from (0.001, 0.2) to generate delta kernel (no blur) 91 | kernel = fspecial('gaussian',15, kernelwidth); % Note: the kernel size is fixed to 15X15. 92 | tag = ['_',method,'_x',num2str(sf),'_itrG_',int2str(kernelwidth*10),'_nlevel_',int2str(nlevel)]; 93 | 94 | elseif kerneltype == 2 95 | % type 2, anisotropic Gaussian 96 | nk = 1;%randi(size(net.meta.AtrpGaussianKernel,4)); % randomly select one 97 | kernel = net.meta.AtrpGaussianKernel(:,:,:,nk); 98 | tag = ['_',method,'_x',num2str(sf),'_atrG_',int2str(nk),'_nlevel_',int2str(nlevel)]; 99 | 100 | end 101 | 102 | %########################################################################## 103 | 104 | surf(kernel) % show kernel 105 | view(45,55); 106 | title('Assumed kernel'); 107 | xlim([1 15]); 108 | ylim([1 15]); 109 | pause(2) 110 | close; 111 | 112 | %% for degradation maps 113 | global degpar; 114 | degpar = single([net.meta.P*kernel(:); nlevel(:)/255]); 115 | 116 | 117 | for n_set = 1 : numel(setTest) 118 | 119 | %% search images 120 | setTestCur = cell2mat(setTest(n_set)); 121 | disp('--------------------------------------------'); 122 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 123 | disp('--------------------------------------------'); 124 | folderTestCur = fullfile(folderTest,setTestCur); 125 | ext = {'*.jpg','*.png','*.bmp'}; 126 | filepaths = []; 127 | for i = 1 : length(ext) 128 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 129 | end 130 | 131 | %% prepare results 132 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 133 | if ~exist(folderResultCur,'file') 134 | mkdir(folderResultCur); 135 | end 136 | 137 | %% perform denoising or/and deblurring (only support Gaussian-like kernel) 138 | for i = 1 : length(filepaths) 139 | 140 | input = imread(fullfile(folderTestCur,filepaths(i).name)); 141 | %label = modcrop(label, 2); 142 | [h,w,C] = size(input); 143 | input = im_pad(input); 144 | if C == 3 145 | input = rgb2gray(input); % input = rgb2ycbcr(input); input = input(:,:,1); % another option 146 | end 147 | 148 | [~,imageName,ext] = fileparts(filepaths(i).name); 149 | input1 = im2single(input); 150 | %tic 151 | if useGPU 152 | input1 = gpuArray(input1); 153 | end 154 | res = vl_srmd(net, input1,[],[],'conserveMemory',true,'mode','test','cudnn',true); 155 | %res = vl_srmd_concise(net, input1); % a concise version of "vl_srmd". 156 | %res = vl_srmd_matlab(net, input1); % You should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 157 | 158 | output = im2uint8(gather(res(end).x)); 159 | 160 | %toc; 161 | output = im_crop(output,h,w); 162 | input = im_crop(input,h,w); 163 | %output2 = 0.8*output + 0.2*input; % add noise and structure back to make the output more visually plausible. or GAN? 164 | 165 | disp([setTestCur,' ',int2str(i),' ',filepaths(i).name]); 166 | if showResult 167 | imshow(cat(2,input,output)); 168 | drawnow; 169 | title(['Denoising and deblurring ',filepaths(i).name],'FontSize',12) 170 | pause(pauseTime) 171 | imwrite(output,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'.png']));% save results 172 | 173 | end 174 | end 175 | end 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning a Single Convolutional Super-Resolution Network for Multiple Degradations 2 | 3 | ![visitors](https://visitor-badge.glitch.me/badge?page_id=cszn/SRMD) 4 | 5 | # [PyTorch training and testing code](https://github.com/cszn/KAIR) - 18/12/2019 6 | `I recommend to use the PyTorch code for training and testing. The model parameters of MatConvnet and PyTorch are same.` 7 | - [main_train_srmd.py](https://github.com/cszn/KAIR/blob/master/main_train_srmd.py) 8 | - [main_test_srmd.py](https://github.com/cszn/KAIR/blob/master/main_test_srmd.py) 9 | 10 | # Abstract 11 | Recent years have witnessed the unprecedented success of deep convolutional neural networks (CNNs) in single image super-resolution (SISR). However, existing CNN-based SISR methods mostly assume that a low-resolution (LR) image is bicubicly downsampled from a high-resolution (HR) image, thus inevitably giving rise to poor performance when the true degradation does not follow this assumption. Moreover, they lack scalability in learning a single model to deal with multiple degradations. To address these issues, we propose a dimensionality stretching strategy that enables a single convolutional super-resolution network to take two key factors of the SISR degradation process, i.e., blur kernel and noise level, as input. Consequently, the proposed super-resolver can handle multiple and even spatially variant degradations, which significantly improves the practicability. Extensive experimental results on synthetic and real LR images show that the proposed convolutional super-resolution network not only can produce favorable results on multiple degradations but also is computationally efficient, providing a highly effective and scalable solution to practical SISR applications. 12 | 13 | # Training Codes 14 | 15 | [SRMD_MatConvNet](https://github.com/cszn/SRMD/tree/master/TrainingCodes) 16 | 17 | # Network Architecture 18 | ![architecture](https://github.com/cszn/SRMD/blob/master/figs/architecture.png) 19 | In contrast to other CNN-based SISR methods which only take the LR image as input and lack scalability to handle other degradations, 20 | the proposed network takes the concatenated LR image and degradation maps as input, thus allowing a single model to manipulate multiple 21 | and even spatially variant degradations. 22 | 23 | # NTIRE 2018 Challenge on Image Super-Resolution [知乎](https://zhuanlan.zhihu.com/p/39930043) 24 | 25 | ## Track 3: Realistic Difficult Adverse Conditions 26 | 27 | [Test_Track_3_SRMD_non_blind.m](Test_Track_3_SRMD_non_blind.m) is the testing code for Track 3 of NTIRE 2018 challenge on image super-resolution. 28 | 29 | ### PSNR/SSIM Result of SRMD 30 | 31 | ![track3](figs/track3.png) 32 | 33 | ### Visual Result of SRMD 34 | 35 | The image size of the LR image is 510x405, the scale factor is 4. 36 | 37 | 38 | 39 | 40 | # SISR Results 41 | 42 | ## Bicubic Degradation 43 | ![bicubic1](https://github.com/cszn/SRMD/blob/master/figs/bicubic1.png) 44 | 45 | ![bicubic2](https://github.com/cszn/SRMD/blob/master/figs/bicubic2.png) 46 | 47 | ## General Degradation 48 | The left is the LR image with isotropic Gaussian blur and noise level 50, the right is the super-resolved image by SRMD with scale factor 2. 49 | 50 | 51 | 52 | The left is the LR image with isotropic Gaussian blur and noise level 5, the right is the super-resolved image by SRMD with scale factor 3. 53 | 54 | 55 | 56 | The left is the LR image with anisotropic Gaussian blur, the right is the super-resolved image by SRMD with scale factor 4. 57 | 58 | 59 | 60 | ## Real Image SR 61 | ![realSR1](https://github.com/cszn/SRMD/blob/master/figs/realSR1.png) 62 | 63 | ![realSR2](https://github.com/cszn/SRMD/blob/master/figs/realSR2.png) 64 | 65 | 66 | # SRMD models 67 | 68 | - Bicubic Degradation 69 | 70 | [Demo_bicubic_degradation_SRMD.m](Demo_bicubic_degradation_SRMD.m) is the testing demo of SRMD for the widely-used bicubic degradation. 71 | [Demo_bicubic_degradation_SRMDNF.m](Demo_bicubic_degradation_SRMDNF.m) is the testing demo of SRMDNF for the widely-used bicubic degradation. 72 | 73 | 74 | 75 | - General Degradation 76 | 77 | [Demo_genearal_degradation_SRMD.m](Demo_genearal_degradation_SRMD.m) is the testing demo of SRMD for the general degradation. 78 | [Demo_genearal_degradation_SRMDNF.m](Demo_genearal_degradation_SRMDNF.m) is the testing demo of SRMDNF for the general degradation. 79 | 80 | 81 | - Real Application 82 | 83 | [Demo_real_application_SRMD.m](Demo_real_application_SRMD.m) is the testing demo of SRMD for real image SR. 84 | 85 | 86 | - Others 87 | 88 | [Demo_degradation_direct_SRMD.m](Demo_degradation_direct_SRMD.m) is the testing demo of SRMD for another widely-used degradation with direct downsampler. 89 | 90 | [Demo_degradation_direct_SRMDNF.m](Demo_degradation_direct_SRMDNF.m) is the testing demo of SRMD for another widely-used degradation with direct downsampler. 91 | 92 | A special case of SRMD when scale factor is 1. 93 | 94 | [Demo_denoising_and_deblurring_gray_SRMD.m](Demo_denoising_and_deblurring_gray_SRMD.m) is the testing demo of SRMD for grayscale image denoising and deblurring. 95 | 96 | [Demo_denoising_and_deblurring_color_SRMD.m](Demo_denoising_and_deblurring_color_SRMD.m) is the testing demo of SRMD for for color image denoising and deblurring. 97 | 98 | [Demo_real_application_denoising_and_deblurring_gray.m](Demo_real_application_denoising_and_deblurring_gray.m) is the testing demo of SRMD for real grayscale image denoising and deblurring. 99 | 100 | [Demo_real_application_denoising_and_deblurring_color.m](Demo_real_application_denoising_and_deblurring_color.m) is the testing demo of SRMD for real color image denoising and deblurring. 101 | 102 | 103 | # Requirements and Dependencies 104 | - MATLAB R2015b 105 | - [Cuda](https://developer.nvidia.com/cuda-toolkit-archive)-8.0 & [cuDNN](https://developer.nvidia.com/cudnn) v-5.1 106 | - [MatConvNet](http://www.vlfeat.org/matconvnet/) 107 | 108 | or 109 | 110 | - MATLAB R2015b 111 | ``` 112 | Use `res = vl_srmd_matlab(net, input)` instead. 113 | ``` 114 | 115 | # Citation 116 | 117 | ``` 118 | @inproceedings{zhang2018learning, 119 | title={Learning a single convolutional super-resolution network for multiple degradations}, 120 | author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei}, 121 | booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, 122 | pages={3262-3271}, 123 | year={2018} 124 | } 125 | ``` 126 | -------------------------------------------------------------------------------- /Test_Track_3_SRMD_non_blind.m: -------------------------------------------------------------------------------- 1 | % http://www.vision.ee.ethz.ch/en/ntire18/ 2 | % paper: http://openaccess.thecvf.com/content_cvpr_2018_workshops/papers/w13/Timofte_NTIRE_2018_Challenge_CVPR_2018_paper.pdf 3 | 4 | % 1) non-blind SRMD can handle Track 2, 3 and 4 in a single model. 5 | % 2) non-blind SRMD can produce good results with accurate blur kernel of LR images. 6 | % Since non-blind SRMD also takes the blur kernel (degradation maps) as input, we use the information of LR image in Track 1 to facilitate the blur kernel estimation. 7 | 8 | % In this code, the dimention-reduced blur kernels are precalculated and 9 | % are stored in `kernel_reduced_3`of the `SRMD_non_blind.mat`. 10 | 11 | % Note: we use a single `SRMD_non_blind.mat` model in `Test_Track_3_SRMD_non_blind.m` and `Test_Track_4_SRMD_non_blind.m`. 12 | 13 | gpu = 1; 14 | 15 | %% load model 16 | load(fullfile('model','SRMD_non_blind.mat')); 17 | 18 | if gpu 19 | net = vl_simplenn_move(net, 'gpu') ; 20 | end 21 | 22 | %% LR images 23 | folderLR = 'H:\matlabH\DIV2K_test_LR_difficult'; 24 | 25 | folderResultCur= 'Results_Track_3_non_blind'; 26 | if ~isdir(folderResultCur) 27 | mkdir(folderResultCur) 28 | end 29 | 30 | global kncf; 31 | 32 | for i = 1:100 33 | 34 | Iname = num2str(i+900,'%04d'); 35 | LR = im2single(imread(fullfile(folderLR,[Iname,'x4d.png']))); 36 | 37 | kncf = kernel_reduced_3(:,i); % reduced blur kernel after PCA projection 38 | 39 | tic; 40 | if gpu 41 | input = gpuArray(single(LR)); 42 | end 43 | res = vl_simplenn(net, input,[],[],'conserveMemory',true,'mode','test'); 44 | im = res(end).x; 45 | if gpu 46 | im = gather(im); 47 | end 48 | toc; 49 | imshow(cat(2,imresize(LR,4),im)); 50 | imwrite(im, fullfile(folderResultCur,[Iname,'x4d.png'])); 51 | pause(0.001) 52 | 53 | end 54 | -------------------------------------------------------------------------------- /TrainingCodes/Demo_Get_PCA_matrix.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | % ksize - e.g., 15, kernel size 5 | % theta - [0, pi], rotation angle range 6 | % l1 - [0.1,10], scaling of eigenvalues 7 | % l2 - [0.1,l1], scaling of eigenvalues 8 | 9 | addpath('kernels'); 10 | format compact 11 | ksize = 15; % kernel size 12 | num_samples = 10000; % number of sampled kernels 13 | dim_PCA = 15; 14 | 15 | for i = 1:num_samples 16 | if mod(i,1000)==0 17 | disp(i); 18 | end 19 | theta = pi*rand(1); 20 | l1 = 0.1+9.9*rand(1); 21 | l2 = 0.1+(l1-0.1)*rand(1); 22 | % l2 = l1; % you will get isotropic Gaussian kernel 23 | 24 | kernel = anisotropic_Gaussian(ksize,theta,l1,l2); 25 | vec_kernels(:,i) = kernel(:); 26 | 27 | end 28 | 29 | % PCA dimensionality reduction 30 | C = double(vec_kernels * vec_kernels'); 31 | [V, D] = eig(C); 32 | 33 | % perform PCA on features matrix 34 | D = diag(D); 35 | D = cumsum(D) / sum(D); 36 | 37 | %k = find(D >= 2e-3, 1); % ignore 0.2% energy 38 | k = ksize^2 - dim_PCA + 1; 39 | 40 | % choose the largest eigenvectors' projection 41 | V_pca = V(:, k:end); 42 | features_pca = V_pca' * vec_kernels; 43 | P = single(V_pca'); 44 | 45 | save PCA_P P 46 | -------------------------------------------------------------------------------- /TrainingCodes/Demo_Test_SRMD_x3.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | % This is the testing code of SRMD for the of SISR. 3 | 4 | %========================================================================== 5 | % The basic idea of SRMD is to learn a CNN to infer the MAP of general SISR, i.e., 6 | % solve x^ = arg min_x 1/(2 sigma^2) ||(kx)\downarrow_s - y||^2 + lamda \Phi(x) 7 | % via x^ = CNN(y,k,sigma;\Theta) or HR^ = CNN(LR,kernel,noiselevel;\Theta). 8 | % 9 | % There involves two important factors, i.e., blur kernel (k; kernel) and noise 10 | % level (sigma; nlevel). 11 | % 12 | % For more information, please refer to the following paper. 13 | % 14 | % @inproceedings{zhang2018learning, 15 | % title={Learning a single convolutional super-resolution network for multiple degradations}, 16 | % author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei}, 17 | % booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, 18 | % pages={3262-3271}, 19 | % year={2018} 20 | % } 21 | % 22 | % If you have any question, please feel free to contact with . 23 | % 24 | % This code is for research purpose only. 25 | % 26 | % by Kai Zhang (Nov, 2017) 27 | %========================================================================== 28 | 29 | % clear; clc; 30 | format compact; 31 | 32 | addpath('utilities'); 33 | addpath('kernels'); 34 | imageSets = {'Set5','Set14','BSD100','Urban100'}; % testing dataset 35 | 36 | %% select testing dataset, use GPU or not, ... 37 | setTest = imageSets([1]); % 38 | showResult = 1; % 1, show ground-truth, bicubicly interpolated LR image, and restored HR images by SRMD; 2, save restored images 39 | pauseTime = 1; 40 | useGPU = 1; % 1 or 0, true or false 41 | method = 'SRMD'; 42 | folderTest = 'testsets'; 43 | folderResult = 'results'; 44 | if ~exist(folderResult,'file') 45 | mkdir(folderResult); 46 | end 47 | 48 | %% scale factor (2, 3, 4) 49 | 50 | sf = 3; %{2, 3, 4} 51 | 52 | %% load model with scale factor sf 53 | folderModel = fullfile('data',['SRMD_x',num2str(sf)]); 54 | load(fullfile(folderModel,['SRMD_x',num2str(sf),'-epoch-1.mat'])); % load the trained model 55 | 56 | net.layers = net.layers(1:end-1); 57 | net = vl_simplenn_tidy(net); 58 | if useGPU 59 | net = vl_simplenn_move(net, 'gpu') ; 60 | end 61 | 62 | %% degradation parameter (noise level and kernel) setting 63 | %############################# noise level ################################ 64 | % noise level, from a range of [0, 75] 65 | 66 | nlevel = 15; % [0, 75] 67 | 68 | kerneltype = 1; % {1, 2, 3} 69 | 70 | %############################### kernel ################################### 71 | 72 | ksize = 15; 73 | theta = pi*rand(1); 74 | l1 = 0.1+9.9*rand(1); 75 | l2 = 0.1+(l1-0.1)*rand(1); 76 | kernel = anisotropic_Gaussian(ksize,theta,l1,l2); 77 | tag = ['_',method,'_x',num2str(sf)]; 78 | 79 | %########################################################################## 80 | 81 | surf(kernel) % show kernel 82 | view(45,55); 83 | title('Assumed kernel'); 84 | xlim([1 15]); 85 | ylim([1 15]); 86 | pause(2) 87 | close; 88 | 89 | %% for degradation maps 90 | load('PCA_P.mat') 91 | global degpar; 92 | degpar = single([P*kernel(:); nlevel(:)/255]); 93 | 94 | 95 | for n_set = 1 : numel(setTest) 96 | 97 | %% search images 98 | setTestCur = cell2mat(setTest(n_set)); 99 | disp('--------------------------------------------'); 100 | disp([' ----',setTestCur,'-----Super-Resolution-----']); 101 | disp('--------------------------------------------'); 102 | folderTestCur = fullfile(folderTest,setTestCur); 103 | ext = {'*.jpg','*.png','*.bmp'}; 104 | filepaths = []; 105 | for i = 1 : length(ext) 106 | filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i}))); 107 | end 108 | 109 | %% prepare results 110 | eval(['PSNR_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 111 | eval(['SSIM_',setTestCur,'_x',num2str(sf),' = zeros(length(filepaths),1);']); 112 | folderResultCur = fullfile(folderResult, [setTestCur,tag]); 113 | if ~exist(folderResultCur,'file') 114 | mkdir(folderResultCur); 115 | end 116 | 117 | %% perform SISR 118 | for i = 1 : length(filepaths) 119 | 120 | HR = imread(fullfile(folderTestCur,filepaths(i).name)); 121 | C = size(HR,3); 122 | if C == 1 123 | HR = cat(3,HR,HR,HR); 124 | end 125 | [~,imageName,ext] = fileparts(filepaths(i).name); 126 | HR = modcrop(HR, sf); 127 | label_RGB = HR; 128 | blury_HR = imfilter(im2double(HR),double(kernel),'replicate'); % blur 129 | LR = imresize(blury_HR,1/sf,'bicubic'); % bicubic downsampling 130 | randn('seed',0); 131 | LR_noisy = LR + nlevel/255.*randn(size(LR)); % add random noise (AWGN) 132 | input = single(LR_noisy); 133 | %tic 134 | if useGPU 135 | input = gpuArray(input); 136 | end 137 | res = vl_srmd(net, input,[],[],'conserveMemory',true,'mode','test','cudnn',true); 138 | %res = vl_srmd_concise(net, input); % a concise version of "vl_srmd". 139 | %res = vl_srmd_matlab(net, input); % When use this, you should also set "useGPU = 0;" and comment "net = vl_simplenn_tidy(net);" 140 | 141 | output_RGB = gather(res(end).x); 142 | 143 | %toc; 144 | if C == 1 145 | label = mean(im2double(HR),3); 146 | output = mean(output_RGB,3); 147 | else 148 | label = rgb2ycbcr(im2double(HR)); 149 | output = rgb2ycbcr(double(output_RGB)); 150 | label = label(:,:,1); 151 | output = output(:,:,1); 152 | end 153 | 154 | %% calculate PSNR and SSIM 155 | [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(label*255,output*255,sf,sf); %%% single 156 | disp([setTestCur,' ',int2str(i),' ',num2str(PSNR_Cur,'%2.2f'),'dB',' ',filepaths(i).name]); 157 | eval(['PSNR_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = PSNR_Cur;']); 158 | eval(['SSIM_',setTestCur,'_x',num2str(sf),'(',num2str(i),') = SSIM_Cur;']); 159 | if showResult 160 | imshow(cat(2,label_RGB,imresize(im2uint8(LR_noisy),sf),im2uint8(output_RGB))); 161 | drawnow; 162 | title(['SISR ',filepaths(i).name,' ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12) 163 | pause(pauseTime) 164 | imwrite(output_RGB,fullfile(folderResultCur,[imageName,'_x',int2str(sf),'_',int2str(PSNR_Cur*100),'.png']));% save results 165 | end 166 | 167 | end 168 | disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',setTestCur,'_x',num2str(sf)])),'%2.2f'),'dB']); 169 | disp(['Average SSIM is ',num2str(mean(eval(['SSIM_',setTestCur,'_x',num2str(sf)])),'%2.4f')]); 170 | 171 | %% save PSNR and SSIM results 172 | save(fullfile(folderResultCur,['PSNR_',setTestCur,'_x',num2str(sf),'.mat']),['PSNR_',setTestCur,'_x',num2str(sf)]); 173 | save(fullfile(folderResultCur,['SSIM_',setTestCur,'_x',num2str(sf),'.mat']),['SSIM_',setTestCur,'_x',num2str(sf)]); 174 | 175 | end 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /TrainingCodes/Demo_Train_SRMD_x3.m: -------------------------------------------------------------------------------- 1 | % This is the training demo of SRMD for scale factor 3. 2 | % 3 | % To run the code, you should install Matconvnet (http://www.vlfeat.org/matconvnet/) first. 4 | % 5 | % For more information, please refer to the following paper. 6 | % 7 | % @inproceedings{zhang2018learning, 8 | % title={Learning a single convolutional super-resolution network for multiple degradations}, 9 | % author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei}, 10 | % booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, 11 | % pages={3262-3271}, 12 | % year={2018} 13 | % } 14 | % 15 | % If you have any question, please feel free to contact with me. 16 | % Kai Zhang (e-mail: cskaizhang@gmail.com) 17 | 18 | %% xxxxxxxxxxxxxxx Note! xxxxxxxxxxxxxxx 19 | % 20 | % run 'Demo_Get_PCA_matrix.m' first to calculate the PCA matrix of vectorized 21 | % blur kernels. 22 | % 23 | % ** You should set the training images folders from "generatepatches.m" first. Then you can run "Demo_Train_SRMD_x3.m" directly. 24 | % ** 25 | % ** folders = {'path_of_your_training_dataset'};% set this from "generatepatches.m" first! 26 | % ** stride = 40*scale; % control the number of image patches, from "generatepatches.m" 27 | % ** nimages = round(length(filepaths)); % control the number of image patches, from "generatepatches.m" 28 | % ** 29 | %% xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 30 | 31 | format compact; 32 | addpath('utilities'); 33 | addpath('kernels'); 34 | 35 | global P; 36 | load('PCA_P.mat') 37 | 38 | %------------------------------------------------------------------------- 39 | % Configuration 40 | %------------------------------------------------------------------------- 41 | 42 | opts.modelName = 'SRMD_x3'; % model name 43 | opts.learningRate = [logspace(-4,-4,100),logspace(-4,-4,100)/3,logspace(-4,-4,100)/(3^2),logspace(-4,-4,100)/(3^3),logspace(-4,-4,100)/(3^4)];% you can change the learning rate 44 | opts.batchSize = 64; % default 45 | opts.gpus = [1]; % this code can only support one GPU! 46 | opts.numSubBatches = 2; 47 | opts.weightDecay = 0.0005; 48 | opts.expDir = fullfile('data', opts.modelName); 49 | 50 | %------------------------------------------------------------------------- 51 | % Initialize model 52 | %------------------------------------------------------------------------- 53 | 54 | net = feval(['model_init_',opts.modelName]); 55 | 56 | %------------------------------------------------------------------------- 57 | % Train 58 | %------------------------------------------------------------------------- 59 | 60 | [net, info] = model_train(net, ... 61 | 'expDir', opts.expDir, ... 62 | 'learningRate',opts.learningRate, ... 63 | 'numSubBatches',opts.numSubBatches, ... 64 | 'weightDecay',opts.weightDecay, ... 65 | 'batchSize', opts.batchSize, ... 66 | 'modelname', opts.modelName, ... 67 | 'gpus',opts.gpus) ; 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /TrainingCodes/degradation_model.m: -------------------------------------------------------------------------------- 1 | function [LR, HR, kernel, sigma] = degradation_model(HR, scale) 2 | 3 | 4 | % kernel 5 | ksize = 15; 6 | theta = pi*rand(1); 7 | l1 = 0.1+9.9*rand(1); 8 | l2 = 0.1+(l1-0.1)*rand(1); 9 | kernel = anisotropic_Gaussian(ksize,theta,l1,l2); % double 10 | kernel = single(kernel); 11 | 12 | % noise level 13 | sigma_max = 75; 14 | sigma = single(sigma_max*rand(1)/255); % single 15 | 16 | % HR image 17 | HR = modcrop(HR, scale); % double 18 | 19 | % xxxxxxxxxxxxxx degradation model xxxxxxxxxxxxxxxxxxxxxx 20 | % you can change to your own degradation model 21 | 22 | blurry_HR = imfilter(HR,double(kernel),'replicate'); 23 | downsampled_HR = imresize(blurry_HR, 1/scale,'bicubic'); 24 | downsampled_HR = im2single(im2uint8(downsampled_HR)); 25 | 26 | noise = single(randn(size(downsampled_HR),'single')*sigma); 27 | LR = downsampled_HR + noise; 28 | 29 | kernel = single(kernel); 30 | % xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 31 | 32 | end 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /TrainingCodes/generatepatches.m: -------------------------------------------------------------------------------- 1 | function [imdb] = generatepatches 2 | 3 | folder = 'path_of_your_training_dataset'; 4 | scale = 3; 5 | 6 | size_label = 32*scale; % size of the HR patch 7 | stride = 40*scale; % 1) control the total number of patches 8 | stride_low = stride/scale; 9 | batchSize = 256; 10 | nchannels = 3; 11 | kernelsize = 15; 12 | 13 | size_input = size_label; 14 | padding = abs(size_input - size_label)/2; 15 | 16 | ext = {'*.jpg','*.png','*.bmp'}; 17 | filepaths = []; 18 | for i = 1 : length(ext) 19 | filepaths = cat(1,filepaths, dir(fullfile(folder, ext{i}))); 20 | end 21 | 22 | rdis = randperm(length(filepaths)); 23 | nimages = round(length(filepaths)); % 2) control the total number of patches 24 | scalesc = min(1,0.5 + 0.05*randi(15,[1,nimages])); 25 | nn = randi(8,[1,nimages]); 26 | 27 | count = 0; 28 | for i = 1 : nimages 29 | im = imread(fullfile(folder,filepaths(rdis(i)).name)); 30 | im = data_augmentation(im, nn(i)); 31 | disp([i,nimages,round(count/256)]) 32 | im = imresize(im,scalesc(i),'bicubic'); 33 | 34 | im = modcrop(im, scale); 35 | 36 | LR = ones([size(im,1)/scale,size(im,2)/scale]); 37 | [hei,wid,~] = size(im); 38 | for x = 1 : stride : (hei-size_input+1) 39 | for y = 1 : stride : (wid-size_input+1) 40 | x_l = stride_low*(x-1)/stride + 1; 41 | y_l = stride_low*(y-1)/stride + 1; 42 | if x_l+size_input/scale-1 > size(LR,1) || y_l+size_input/scale-1 > size(LR,2) 43 | continue; 44 | end 45 | count=count+1; 46 | end 47 | end 48 | end 49 | 50 | 51 | numPatches = ceil(count/batchSize)*batchSize; 52 | diffPatches = numPatches - count; 53 | disp([numPatches,numPatches/batchSize,diffPatches]); 54 | 55 | disp('---------------PAUSE------------'); 56 | %pause 57 | 58 | count = 0; 59 | imdb.LRlabels = zeros(size_label/scale, size_label/scale, nchannels, numPatches,'single'); 60 | imdb.HRlabels = zeros(size_label, size_label, nchannels, numPatches,'single'); 61 | imdb.kernels = zeros(kernelsize, kernelsize, numPatches,'single'); 62 | imdb.sigmas = zeros(1,numPatches,'single'); 63 | 64 | for i = 1 : nimages 65 | im = imread(fullfile(folder,filepaths(rdis(i)).name)); 66 | im = data_augmentation(im, nn(i)); 67 | disp([i,nimages,round(count/256)]) 68 | im = imresize(im,scalesc(i),'bicubic'); 69 | 70 | im = im2double(im); 71 | 72 | [LR, HR, kernel, sigma] = degradation_model(im, scale); 73 | 74 | [hei,wid,~] = size(HR); 75 | 76 | for x = 1 : stride : (hei-size_input+1) 77 | for y = 1 : stride : (wid-size_input+1) 78 | x_l = stride_low*(x-1)/stride + 1; 79 | y_l = stride_low*(y-1)/stride + 1; 80 | if x_l+size_input/scale-1 > size(LR,1) || y_l+size_input/scale-1 > size(LR,2) 81 | continue; 82 | end 83 | subim_LR = LR(x_l : x_l+size_input/scale-1, y_l : y_l+size_input/scale-1,1:nchannels); 84 | subim_HR = HR(x+padding : x+padding+size_label-1, y+padding : y+padding+size_label-1,1:nchannels); 85 | count=count+1; 86 | imdb.HRlabels(:, :, :, count) = subim_HR; 87 | imdb.LRlabels(:, :, :, count) = subim_LR; 88 | imdb.kernels(:,:,count) = single(kernel); 89 | imdb.sigmas(count) = single(sigma); 90 | 91 | if count<=diffPatches 92 | imdb.LRlabels(:, :, :, end-count+1) = LR(x_l : x_l+size_input/scale-1, y_l : y_l+size_input/scale-1,1:nchannels); 93 | imdb.HRlabels(:, :, :, end-count+1) = HR(x+padding : x+padding+size_label-1, y+padding : y+padding+size_label-1,1:nchannels); 94 | imdb.kernels(:,:,end-count+1) = single(kernel); 95 | imdb.sigmas(end-count+1) = single(sigma); 96 | end 97 | end 98 | end 99 | end 100 | 101 | imdb.set = uint8(ones(1,size(imdb.LRlabels,4))); 102 | 103 | 104 | -------------------------------------------------------------------------------- /TrainingCodes/kernels/Demo_Get_PCA_matrix.m: -------------------------------------------------------------------------------- 1 | 2 | % ksize - e.g., 15, kernel size 3 | % theta - [0, pi], rotation angle range 4 | % l1 - [0.1,10], scaling of eigenvalues 5 | % l2 - [0.1,l1], scaling of eigenvalues 6 | 7 | ksize = 15; % kernel size 8 | num_samples = 10000; % number of sampled kernels 9 | dim_PCA = 15; 10 | 11 | for i = 1:num_samples 12 | 13 | theta = pi*rand(1); 14 | l1 = 0.1+9.9*rand(1); 15 | l2 = 0.1+(l1-0.1)*rand(1); 16 | 17 | kernel = anisotropic_Gaussian(ksize,theta,l1,l2); 18 | vec_kernels(:,i) = kernel(:); 19 | 20 | end 21 | 22 | % PCA dimensionality reduction 23 | C = double(vec_kernels * vec_kernels'); 24 | [V, D] = eig(C); 25 | 26 | % perform PCA on features matrix 27 | D = diag(D); 28 | D = cumsum(D) / sum(D); 29 | 30 | %k = find(D >= 2e-3, 1); % ignore 0.2% energy 31 | k = ksize^2 - dim_PCA + 1; 32 | 33 | % choose the largest eigenvectors' projection 34 | V_pca = V(:, k:end); 35 | features_pca = V_pca' * vec_kernels; 36 | P = single(V_pca'); 37 | 38 | save PCA_P P 39 | -------------------------------------------------------------------------------- /TrainingCodes/kernels/Demo_show_PCA_matrix.m: -------------------------------------------------------------------------------- 1 | % run Demo_Get_PCA_matrix.m first 2 | 3 | ksize = 15; 4 | 5 | load PCA_P.mat; 6 | 7 | % show the PCA basis 8 | 9 | for i = 1:size(P,1) 10 | 11 | kernel = reshape(P(i,:),ksize,ksize); 12 | 13 | subplot 121 14 | imagesc(kernel); 15 | title([int2str(i)]) 16 | axis square; 17 | 18 | subplot 122 19 | surf(kernel); 20 | title([int2str(i)]) 21 | view(45,55) 22 | xlim([1 15]); 23 | ylim([1 15]); 24 | axis square; 25 | pause(2) 26 | end 27 | 28 | -------------------------------------------------------------------------------- /TrainingCodes/kernels/Demo_show_kernels.m: -------------------------------------------------------------------------------- 1 | 2 | % load SRMDNFx2.mat; 3 | 4 | %% show the Gaussian kernels 5 | % ksize - e.g., 15, kernel size 6 | % theta - [0, pi], rotation angle range 7 | % l1 - [0.1,10], scaling of eigenvalues 8 | % l2 - [0.1,l1], scaling of eigenvalues 9 | 10 | ksize = 15; 11 | 12 | 13 | for i = 1:1000 14 | 15 | theta = pi*rand(1); 16 | l1 = 0.1+9.9*rand(1); 17 | l2 = 0.1+(l1-0.1)*rand(1); 18 | 19 | kernel = anisotropic_Gaussian(ksize,theta,l1,l2); 20 | 21 | subplot 121 22 | imagesc(kernel); 23 | title([int2str(i)]) 24 | axis square; 25 | 26 | subplot 122 27 | surf(kernel); 28 | title([int2str(i)]) 29 | view(45,55) 30 | xlim([1 15]); 31 | ylim([1 15]); 32 | axis square; 33 | pause(0.1) 34 | end 35 | 36 | 37 | % %% show the PCA basis 38 | % 39 | % 40 | % for i = 1:size(net.meta.P,1) 41 | % 42 | % kernel = reshape(net.meta.P(i,:),15,15); 43 | % 44 | % subplot 121 45 | % imagesc(kernel); 46 | % title([int2str(i),' / ',int2str(size(net.meta.P,1))]) 47 | % axis square; 48 | % 49 | % subplot 122 50 | % surf(kernel); 51 | % title([int2str(i),' / ',int2str(size(net.meta.P,1))]) 52 | % view(45,55) 53 | % xlim([1 15]); 54 | % ylim([1 15]); 55 | % axis square; 56 | % pause(2) 57 | % end 58 | 59 | -------------------------------------------------------------------------------- /TrainingCodes/kernels/PCA_P.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/TrainingCodes/kernels/PCA_P.mat -------------------------------------------------------------------------------- /TrainingCodes/kernels/anisotropic_Gaussian.m: -------------------------------------------------------------------------------- 1 | function [k] = anisotropic_Gaussian(ksize,theta,l1,l2) 2 | % generate an anisotropic Gaussian kernel. 3 | % 4 | % Input: 5 | % ksize - e.g., 15, kernel size 6 | % theta - [0, pi], rotation angle range 7 | % l1 - [0.1,10], scaling of eigenvalues 8 | % l2 - [0.1,l1], scaling of eigenvalues 9 | 10 | % If l1 = l2, you will get an isotropic Gaussian kernel. 11 | 12 | % Output: 13 | % k - kernel 14 | 15 | v = [cos(theta), -sin(theta); sin(theta), cos(theta)] * [1; 0]; 16 | V = [v(1), v(2); v(2), -v(1)]; 17 | D = [l1, 0; 0, l2]; 18 | Sigma = V * D * V^(-1); 19 | gm = gmdistribution([0, 0], Sigma); 20 | k = gm_blur_kernel(gm, ksize); 21 | 22 | 23 | function [k] = gm_blur_kernel(gm, size) 24 | center = size / 2.0 + 0.5; 25 | k = zeros(size, size); 26 | for y = 1 : size 27 | for x = 1 : size 28 | cy = y - center; 29 | cx = x - center; 30 | k(y, x) = pdf(gm, [cx, cy]); 31 | end 32 | end 33 | 34 | k = k ./ sum(k(:)); 35 | 36 | 37 | -------------------------------------------------------------------------------- /TrainingCodes/model_init_SRMD_x3.m: -------------------------------------------------------------------------------- 1 | 2 | function net = model_init_SRMD_x3 3 | 4 | sf = 3; 5 | 6 | lr11 = [1 1]; 7 | lr10 = [1 0]; 8 | weightDecay = [1 1]; 9 | nCh = 128; % number of channels 10 | C = 3; % C = 3 for color image, C = 1 for gray-scale image 11 | dim_PCA = 15; 12 | 13 | useBnorm = 1; % if useBnorm = 0, you should also use adam. 14 | 15 | % Define network 16 | net.layers = {} ; 17 | 18 | %net.layers{end+1} = struct('type', 'SubP','scale',1/2) ; 19 | 20 | net.layers{end+1} = struct('type', 'concat') ; 21 | 22 | net.layers{end+1} = struct('type', 'conv', ... 23 | 'weights', {{orthrize(sqrt(2/(9*nCh))*randn(3,3,C+dim_PCA+1,nCh,'single')), zeros(nCh,1,'single')}}, ... 24 | 'stride', 1, ... 25 | 'pad', 1, ... 26 | 'dilate',1, ... 27 | 'learningRate',lr11, ... 28 | 'weightDecay',weightDecay, ... 29 | 'opts',{{}}) ; 30 | net.layers{end+1} = struct('type', 'relu','leak',0) ; 31 | 32 | for i = 1:1:10 33 | 34 | if useBnorm ~= 0 35 | net.layers{end+1} = struct('type', 'conv', ... 36 | 'weights', {{orthrize(sqrt(2/(9*nCh))*randn(3,3,nCh,nCh,'single')), zeros(nCh,1,'single')}}, ... 37 | 'stride', 1, ... 38 | 'learningRate',lr10, ... 39 | 'dilate',1, ... 40 | 'weightDecay',weightDecay, ... 41 | 'pad', 1, 'opts', {{}}) ; 42 | net.layers{end+1} = struct('type', 'bnorm', ... 43 | 'weights', {{clipping(sqrt(2/(9*nCh))*randn(nCh,1,'single'),0.01), zeros(nCh,1,'single'),[zeros(nCh,1,'single'), 0.01*ones(nCh,1,'single')]}}, ... 44 | 'learningRate', [1 1 1], ... 45 | 'weightDecay', [0 0]) ; 46 | else 47 | net.layers{end+1} = struct('type', 'conv', ... 48 | 'weights', {{orthrize(sqrt(2/(9*nCh))*randn(3,3,nCh,nCh,'single')), zeros(nCh,1,'single')}}, ... 49 | 'stride', 1, ... 50 | 'learningRate',lr11, ... 51 | 'dilate',1, ... 52 | 'weightDecay',weightDecay, ... 53 | 'pad', 1, 'opts', {{}}) ; 54 | end 55 | net.layers{end+1} = struct('type', 'relu','leak',0) ; 56 | 57 | end 58 | 59 | net.layers{end+1} = struct('type', 'conv', ... 60 | 'weights', {{orthrize(sqrt(2/(9*nCh))*randn(3,3,nCh,sf^2*C,'single')), zeros(sf^2*C,1,'single')}}, ... 61 | 'stride', 1, ... 62 | 'learningRate',lr10, ... 63 | 'dilate',1, ... 64 | 'weightDecay',weightDecay, ... 65 | 'pad', 1, 'opts', {{}}) ; 66 | net.layers{end+1} = struct('type', 'SubP','scale',sf) ; 67 | 68 | net.layers{end+1} = struct('type', 'loss') ; % make sure the new 'vl_nnloss.m' is in the same folder. 69 | 70 | % Fill in default values 71 | net = vl_simplenn_tidy(net); 72 | 73 | end 74 | 75 | 76 | function W = orthrize(a) 77 | 78 | s_ = size(a); 79 | a = reshape(a,[size(a,1)*size(a,2)*size(a,3),size(a,4),1,1]); 80 | [u,d,v] = svd(a, 'econ'); 81 | if(size(a,1) < size(a, 2)) 82 | u = v'; 83 | end 84 | %W = sqrt(2).*reshape(u, s_); 85 | W = reshape(u, s_); 86 | 87 | end 88 | 89 | 90 | function A = clipping2(A,b) 91 | 92 | A(Ab(2)) = b(2); 94 | 95 | end 96 | 97 | 98 | 99 | function A = clipping(A,b) 100 | 101 | A(A>=0&A-b) = -b; 103 | 104 | end 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /TrainingCodes/model_train.m: -------------------------------------------------------------------------------- 1 | function [net, state] = model_train(net, varargin) 2 | 3 | 4 | % simple code 5 | 6 | % The function automatically restarts after each training epoch by 7 | % checkpointing. 8 | % 9 | % The function supports training on CPU or on one or more GPUs 10 | % (specify the list of GPU IDs in the `gpus` option). 11 | 12 | % Copyright (C) 2014-16 Andrea Vedaldi. 13 | % All rights reserved. 14 | % 15 | % This file is part of the VLFeat library and is made available under 16 | % the terms of the BSD license (see the COPYING file). 17 | 18 | %------------------------------------------------------------------------- 19 | % solver: Adam 20 | %------------------------------------------------------------------------- 21 | 22 | opts.beta1 = 0.9; 23 | opts.beta2 = 0.999; 24 | opts.alpha = 0.01; 25 | opts.epsilon = 1e-8; 26 | opts.weightDecay = 0.0001; 27 | 28 | %------------------------------------------------------------------------- 29 | % setting for simplenn 30 | %------------------------------------------------------------------------- 31 | 32 | opts.conserveMemory = true; 33 | opts.mode = 'normal'; 34 | opts.cudnn = true ; 35 | opts.backPropDepth = +inf ; 36 | opts.skipForward = false; 37 | opts.numSubBatches = 1; 38 | 39 | %------------------------------------------------------------------------- 40 | % setting for model 41 | %------------------------------------------------------------------------- 42 | 43 | opts.batchSize = 128 ; 44 | opts.gpus = []; 45 | opts.numEpochs = 300 ; 46 | opts.learningRate = 0.0001*ones(1,100,'single'); 47 | opts.modelName = 'model'; 48 | opts.expDir = fullfile('data',opts.modelName) ; 49 | 50 | %------------------------------------------------------------------------- 51 | % update settings 52 | %------------------------------------------------------------------------- 53 | 54 | opts = vl_argparse(opts, varargin); 55 | opts.numEpochs = numel(opts.learningRate); 56 | 57 | if ~exist(opts.expDir, 'dir'), mkdir(opts.expDir) ; end 58 | 59 | %------------------------------------------------------------------------- 60 | % Initialization 61 | %------------------------------------------------------------------------- 62 | 63 | net = vl_simplenn_tidy(net); %%% fill in some eventually missing values 64 | net.layers{end-1}.precious = 1; 65 | vl_simplenn_display(net, 'batchSize', opts.batchSize) ; 66 | 67 | state.getBatch = getBatch ; 68 | 69 | %------------------------------------------------------------------------- 70 | % Train and Test 71 | %------------------------------------------------------------------------- 72 | 73 | modelPath = @(ep) fullfile(opts.expDir, sprintf([opts.modelName,'-epoch-%d.mat'], ep)); 74 | 75 | start = findLastCheckpoint(opts.expDir,opts.modelName) ; 76 | if start >= 1 77 | fprintf('%s: resuming by loading epoch %d', mfilename, start) ; 78 | load(modelPath(start), 'net') ; 79 | % net = vl_simplenn_tidy(net) ; 80 | end 81 | 82 | imdb = []; 83 | 84 | for epoch = start+1 : opts.numEpochs 85 | 86 | % Train for one epoch. 87 | state.epoch = epoch ; 88 | state.learningRate = opts.learningRate(min(epoch, numel(opts.learningRate))); 89 | if numel(opts.gpus) == 1 90 | net = vl_simplenn_move(net, 'gpu') ; 91 | end 92 | 93 | %------------------------------------------------------------------------- 94 | % generate training data 95 | %------------------------------------------------------------------------- 96 | 97 | if mod(epoch,5)~=1 && isfield(imdb,'set') ~= 0 98 | 99 | else 100 | clear imdb; 101 | [imdb] = generatepatches; 102 | end 103 | opts.train = find(imdb.set==1); 104 | 105 | state.train = opts.train(randperm(numel(opts.train))) ; % shuffle 106 | [net, state] = process_epoch(net, state, imdb, opts, 'train'); 107 | %net.layers{end}.class =[]; 108 | net = vl_simplenn_move(net, 'cpu'); 109 | % save current model 110 | save(modelPath(epoch), 'net') 111 | 112 | end 113 | 114 | 115 | function [net, state] = process_epoch(net, state, imdb, opts, mode) 116 | if strcmp(mode,'train') 117 | % solver: Adam 118 | for i = 1:numel(net.layers) 119 | if isfield(net.layers{i}, 'weights') 120 | for j = 1:numel(net.layers{i}.weights) 121 | state.layers{i}.t{j} = 0; 122 | state.layers{i}.m{j} = 0; 123 | state.layers{i}.v{j} = 0; 124 | end 125 | end 126 | end 127 | end 128 | 129 | subset = state.(mode) ; 130 | num = 0 ; 131 | res = []; 132 | for t=1:opts.batchSize:numel(subset) 133 | for s=1:opts.numSubBatches 134 | 135 | % get this image batch 136 | batchStart = t + (s-1); 137 | batchEnd = min(t+opts.batchSize-1, numel(subset)); 138 | batch = subset(batchStart : opts.numSubBatches : batchEnd) ; 139 | num = num + numel(batch) ; 140 | if numel(batch) == 0, continue ; end 141 | 142 | [inputs,labels] = state.getBatch(imdb, batch) ; 143 | 144 | if numel(opts.gpus) >= 1 145 | inputs = gpuArray(inputs); 146 | labels = gpuArray(labels); 147 | end 148 | 149 | if strcmp(mode, 'train') 150 | dzdy = single(1); 151 | evalMode = 'normal';% forward and backward 152 | else 153 | dzdy = [] ; 154 | evalMode = 'test'; % forward only 155 | end 156 | 157 | net.layers{end}.class = labels ; 158 | res = vl_simplenn(net, inputs, dzdy, res, ... 159 | 'accumulate', s ~= 1, ... 160 | 'mode', evalMode, ... 161 | 'conserveMemory', opts.conserveMemory, ... 162 | 'backPropDepth', opts.backPropDepth, ... 163 | 'cudnn', opts.cudnn) ; 164 | end 165 | 166 | if strcmp(mode, 'train') 167 | [state, net] = params_updates(state, net, res, opts, opts.batchSize) ; 168 | end 169 | 170 | lossL2 = gather(res(end).x) ; 171 | 172 | %--------add your code here------------------------ 173 | 174 | %-------------------------------------------------- 175 | 176 | fprintf('%s: epoch %02d : %3d/%3d: loss: %4.4f \n', mode, state.epoch, ... 177 | fix((t-1)/opts.batchSize)+1, ceil(numel(subset)/opts.batchSize),lossL2) ; 178 | % fprintf('loss: %4.4f \n', lossL2) ; 179 | 180 | end 181 | 182 | 183 | function [state, net] = params_updates(state, net, res, opts, batchSize) 184 | 185 | % solver: Adam 186 | for l=numel(net.layers):-1:1 187 | for j=1:numel(res(l).dzdw) 188 | 189 | if j == 3 && strcmp(net.layers{l}.type, 'bnorm') 190 | 191 | % special case for learning bnorm moments 192 | thisLR = net.layers{l}.learningRate(j); 193 | net.layers{l}.weights{j} = vl_taccum(... 194 | 1 - thisLR, ... 195 | net.layers{l}.weights{j}, ... 196 | thisLR / batchSize, ... 197 | res(l).dzdw{j}) ; 198 | 199 | else 200 | 201 | % if j == 1 && strcmp(net.layers{l}.type, 'bnorm') 202 | % c = net.layers{l}.weights{j}; 203 | % net.layers{l}.weights{j} = clipping(c,mean(abs(c))/2); 204 | % end 205 | 206 | thisLR = state.learningRate * net.layers{l}.learningRate(j); 207 | state.layers{l}.t{j} = state.layers{l}.t{j} + 1; 208 | t = state.layers{l}.t{j}; 209 | alpha = thisLR; 210 | lr = alpha * sqrt(1 - opts.beta2^t) / (1 - opts.beta1^t); 211 | 212 | state.layers{l}.m{j} = state.layers{l}.m{j} + (1 - opts.beta1) .* (res(l).dzdw{j} - state.layers{l}.m{j}); 213 | state.layers{l}.v{j} = state.layers{l}.v{j} + (1 - opts.beta2) .* (res(l).dzdw{j} .* res(l).dzdw{j} - state.layers{l}.v{j}); 214 | 215 | % weight decay 216 | net.layers{l}.weights{j} = net.layers{l}.weights{j} - thisLR * opts.weightDecay * net.layers{l}.weightDecay(j) * net.layers{l}.weights{j}; 217 | 218 | % update weights 219 | net.layers{l}.weights{j} = net.layers{l}.weights{j} - lr * state.layers{l}.m{j} ./ (sqrt(state.layers{l}.v{j}) + opts.epsilon) ; 220 | 221 | 222 | % %--------add your own code to update the parameters here------- 223 | % 224 | % if rand > 0.99 225 | % A = net.layers{l}.weights{j}; 226 | % if numel(A)>=3*3*64 227 | % A = reshape(A,[size(A,1)*size(A,2)*size(A,3),size(A,4),1,1]); 228 | % if size(A,1)> size(A,2) 229 | % [U,S,V] = svd(A,0); 230 | % else 231 | % [U,S,V] = svd(A,'econ'); 232 | % end 233 | % S1 =smallClipping2(diag(S),1.1,0.9); 234 | % A = U*diag(S1)*V'; 235 | % A = reshape(A,size(net.layers{l}.weights{j})); 236 | % net.layers{l}.weights{j} = A; 237 | % end 238 | % end 239 | % 240 | % %-------------------------------------------------------------- 241 | 242 | end 243 | end 244 | end 245 | %end 246 | 247 | 248 | function epoch = findLastCheckpoint(modelDir,modelName) 249 | list = dir(fullfile(modelDir, [modelName,'-epoch-*.mat'])) ; 250 | tokens = regexp({list.name}, [modelName,'-epoch-([\d]+).mat'], 'tokens') ; 251 | epoch = cellfun(@(x) sscanf(x{1}{1}, '%d'), tokens) ; 252 | epoch = max([epoch 0]) ; 253 | 254 | 255 | function A = smallClipping(A, theta) 256 | A(A>theta) = A(A>theta) -0.000001; 257 | A(A<-theta) = A(A<-theta)+0.000001; 258 | 259 | 260 | function A = smallClipping2(A, theta1,theta2) 261 | A(A>theta1) = A(A>theta1)-0.00001; 262 | A(A degradation maps 286 | global P; % PCA projection matrix 287 | 288 | inputs = imdb.LRlabels(:,:,:,batch); 289 | labels = imdb.HRlabels(:,:,:,batch); 290 | kernel = imdb.kernels(:,:,batch); 291 | 292 | % n = randi(8); 293 | % inputs = data_augmentation(inputs,n); 294 | % labels = data_augmentation(labels,n); 295 | % kernel = data_augmentation(kernel,n); 296 | 297 | kk = P*reshape(kernel,size(P,2),size(kernel,3)); 298 | ss = imdb.sigmas(batch); 299 | degvectors = [kk;ss]; 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | -------------------------------------------------------------------------------- /TrainingCodes/testsets/Set5/baby_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/TrainingCodes/testsets/Set5/baby_GT.bmp -------------------------------------------------------------------------------- /TrainingCodes/testsets/Set5/bird_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/TrainingCodes/testsets/Set5/bird_GT.bmp -------------------------------------------------------------------------------- /TrainingCodes/testsets/Set5/butterfly_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/TrainingCodes/testsets/Set5/butterfly_GT.bmp -------------------------------------------------------------------------------- /TrainingCodes/testsets/Set5/head_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/TrainingCodes/testsets/Set5/head_GT.bmp -------------------------------------------------------------------------------- /TrainingCodes/testsets/Set5/woman_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/TrainingCodes/testsets/Set5/woman_GT.bmp -------------------------------------------------------------------------------- /TrainingCodes/utilities/Cal_PSNRSSIM.m: -------------------------------------------------------------------------------- 1 | function [psnr_cur, ssim_cur] = Cal_PSNRSSIM(A,B,row,col) 2 | 3 | 4 | [n,m,ch]=size(B); 5 | A = A(row+1:n-row,col+1:m-col,:); 6 | B = B(row+1:n-row,col+1:m-col,:); 7 | A=double(A); % Ground-truth 8 | B=double(B); % 9 | 10 | e=A(:)-B(:); 11 | mse=mean(e.^2); 12 | psnr_cur=10*log10(255^2/mse); 13 | 14 | if ch==1 15 | [ssim_cur, ~] = ssim_index(A, B); 16 | else 17 | ssim_cur = (ssim_index(A(:,:,1), B(:,:,1)) + ssim_index(A(:,:,2), B(:,:,2)) + ssim_index(A(:,:,3), B(:,:,3)))/3; 18 | end 19 | 20 | 21 | function [mssim, ssim_map] = ssim_index(img1, img2, K, window, L) 22 | 23 | %======================================================================== 24 | %SSIM Index, Version 1.0 25 | %Copyright(c) 2003 Zhou Wang 26 | %All Rights Reserved. 27 | % 28 | %The author is with Howard Hughes Medical Institute, and Laboratory 29 | %for Computational Vision at Center for Neural Science and Courant 30 | %Institute of Mathematical Sciences, New York University. 31 | % 32 | %---------------------------------------------------------------------- 33 | %Permission to use, copy, or modify this software and its documentation 34 | %for educational and research purposes only and without fee is hereby 35 | %granted, provided that this copyright notice and the original authors' 36 | %names appear on all copies and supporting documentation. This program 37 | %shall not be used, rewritten, or adapted as the basis of a commercial 38 | %software or hardware product without first obtaining permission of the 39 | %authors. The authors make no representations about the suitability of 40 | %this software for any purpose. It is provided "as is" without express 41 | %or implied warranty. 42 | %---------------------------------------------------------------------- 43 | % 44 | %This is an implementation of the algorithm for calculating the 45 | %Structural SIMilarity (SSIM) index between two images. Please refer 46 | %to the following paper: 47 | % 48 | %Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image 49 | %quality assessment: From error measurement to structural similarity" 50 | %IEEE Transactios on Image Processing, vol. 13, no. 1, Jan. 2004. 51 | % 52 | %Kindly report any suggestions or corrections to zhouwang@ieee.org 53 | % 54 | %---------------------------------------------------------------------- 55 | % 56 | %Input : (1) img1: the first image being compared 57 | % (2) img2: the second image being compared 58 | % (3) K: constants in the SSIM index formula (see the above 59 | % reference). defualt value: K = [0.01 0.03] 60 | % (4) window: local window for statistics (see the above 61 | % reference). default widnow is Gaussian given by 62 | % window = fspecial('gaussian', 11, 1.5); 63 | % (5) L: dynamic range of the images. default: L = 255 64 | % 65 | %Output: (1) mssim: the mean SSIM index value between 2 images. 66 | % If one of the images being compared is regarded as 67 | % perfect quality, then mssim can be considered as the 68 | % quality measure of the other image. 69 | % If img1 = img2, then mssim = 1. 70 | % (2) ssim_map: the SSIM index map of the test image. The map 71 | % has a smaller size than the input images. The actual size: 72 | % size(img1) - size(window) + 1. 73 | % 74 | %Default Usage: 75 | % Given 2 test images img1 and img2, whose dynamic range is 0-255 76 | % 77 | % [mssim ssim_map] = ssim_index(img1, img2); 78 | % 79 | %Advanced Usage: 80 | % User defined parameters. For example 81 | % 82 | % K = [0.05 0.05]; 83 | % window = ones(8); 84 | % L = 100; 85 | % [mssim ssim_map] = ssim_index(img1, img2, K, window, L); 86 | % 87 | %See the results: 88 | % 89 | % mssim %Gives the mssim value 90 | % imshow(max(0, ssim_map).^4) %Shows the SSIM index map 91 | % 92 | %======================================================================== 93 | 94 | 95 | if (nargin < 2 || nargin > 5) 96 | ssim_index = -Inf; 97 | ssim_map = -Inf; 98 | return; 99 | end 100 | 101 | if (size(img1) ~= size(img2)) 102 | ssim_index = -Inf; 103 | ssim_map = -Inf; 104 | return; 105 | end 106 | 107 | [M N] = size(img1); 108 | 109 | if (nargin == 2) 110 | if ((M < 11) || (N < 11)) 111 | ssim_index = -Inf; 112 | ssim_map = -Inf; 113 | return 114 | end 115 | window = fspecial('gaussian', 11, 1.5); % 116 | K(1) = 0.01; % default settings 117 | K(2) = 0.03; % 118 | L = 255; % 119 | end 120 | 121 | if (nargin == 3) 122 | if ((M < 11) || (N < 11)) 123 | ssim_index = -Inf; 124 | ssim_map = -Inf; 125 | return 126 | end 127 | window = fspecial('gaussian', 11, 1.5); 128 | L = 255; 129 | if (length(K) == 2) 130 | if (K(1) < 0 || K(2) < 0) 131 | ssim_index = -Inf; 132 | ssim_map = -Inf; 133 | return; 134 | end 135 | else 136 | ssim_index = -Inf; 137 | ssim_map = -Inf; 138 | return; 139 | end 140 | end 141 | 142 | if (nargin == 4) 143 | [H W] = size(window); 144 | if ((H*W) < 4 || (H > M) || (W > N)) 145 | ssim_index = -Inf; 146 | ssim_map = -Inf; 147 | return 148 | end 149 | L = 255; 150 | if (length(K) == 2) 151 | if (K(1) < 0 || K(2) < 0) 152 | ssim_index = -Inf; 153 | ssim_map = -Inf; 154 | return; 155 | end 156 | else 157 | ssim_index = -Inf; 158 | ssim_map = -Inf; 159 | return; 160 | end 161 | end 162 | 163 | if (nargin == 5) 164 | [H W] = size(window); 165 | if ((H*W) < 4 || (H > M) || (W > N)) 166 | ssim_index = -Inf; 167 | ssim_map = -Inf; 168 | return 169 | end 170 | if (length(K) == 2) 171 | if (K(1) < 0 || K(2) < 0) 172 | ssim_index = -Inf; 173 | ssim_map = -Inf; 174 | return; 175 | end 176 | else 177 | ssim_index = -Inf; 178 | ssim_map = -Inf; 179 | return; 180 | end 181 | end 182 | 183 | C1 = (K(1)*L)^2; 184 | C2 = (K(2)*L)^2; 185 | window = window/sum(sum(window)); 186 | img1 = double(img1); 187 | img2 = double(img2); 188 | 189 | mu1 = filter2(window, img1, 'valid'); 190 | mu2 = filter2(window, img2, 'valid'); 191 | mu1_sq = mu1.*mu1; 192 | mu2_sq = mu2.*mu2; 193 | mu1_mu2 = mu1.*mu2; 194 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 195 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 196 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 197 | 198 | if (C1 > 0 & C2 > 0) 199 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 200 | else 201 | numerator1 = 2*mu1_mu2 + C1; 202 | numerator2 = 2*sigma12 + C2; 203 | denominator1 = mu1_sq + mu2_sq + C1; 204 | denominator2 = sigma1_sq + sigma2_sq + C2; 205 | ssim_map = ones(size(mu1)); 206 | index = (denominator1.*denominator2 > 0); 207 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 208 | index = (denominator1 ~= 0) & (denominator2 == 0); 209 | ssim_map(index) = numerator1(index)./denominator1(index); 210 | end 211 | 212 | mssim = mean2(ssim_map); 213 | 214 | return 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/Merge_Bnorm_Demo.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | load('sigma=25_Bnorm.mat'); 7 | 8 | [net] = vl_simplenn_mergebnorm(net); 9 | 10 | save sigma=25 net; 11 | 12 | 13 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/data_augmentation.m: -------------------------------------------------------------------------------- 1 | function image = data_augmentation(image, mode) 2 | 3 | if mode == 1 4 | return; 5 | end 6 | 7 | if mode == 2 % flipped 8 | image = flipud(image); 9 | return; 10 | end 11 | 12 | if mode == 3 % rotation 90 13 | image = rot90(image,1); 14 | return; 15 | end 16 | 17 | if mode == 4 % rotation 90 & flipped 18 | image = rot90(image,1); 19 | image = flipud(image); 20 | return; 21 | end 22 | 23 | if mode == 5 % rotation 180 24 | image = rot90(image,2); 25 | return; 26 | end 27 | 28 | if mode == 6 % rotation 180 & flipped 29 | image = rot90(image,2); 30 | image = flipud(image); 31 | return; 32 | end 33 | 34 | if mode == 7 % rotation 270 35 | image = rot90(image,3); 36 | return; 37 | end 38 | 39 | if mode == 8 % rotation 270 & flipped 40 | image = rot90(image,3); 41 | image = flipud(image); 42 | return; 43 | end 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/modcrop.m: -------------------------------------------------------------------------------- 1 | function imgs = modcrop(imgs, modulo) 2 | if size(imgs,3)==1 3 | sz = size(imgs); 4 | sz = sz - mod(sz, modulo); 5 | imgs = imgs(1:sz(1), 1:sz(2)); 6 | else 7 | tmpsz = size(imgs); 8 | sz = tmpsz(1:2); 9 | sz = sz - mod(sz, modulo); 10 | imgs = imgs(1:sz(1), 1:sz(2),:); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/shave.m: -------------------------------------------------------------------------------- 1 | function I = shave(I, border) 2 | I = I(1+border(1):end-border(1), ... 3 | 1+border(2):end-border(2), :, :); 4 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/simplenn_matlab.m: -------------------------------------------------------------------------------- 1 | function res = simplenn_matlab(net, input) 2 | 3 | %% If you did not install the matconvnet package, you can use this for testing. 4 | 5 | n = numel(net.layers); 6 | 7 | res = struct('x', cell(1,n+1)); 8 | res(1).x = input; 9 | 10 | for ilayer = 1 : n 11 | l = net.layers{ilayer}; 12 | switch l.type 13 | case 'conv' 14 | for noutmaps = 1 : size(l.weights{1},4) 15 | z = zeros(size(res(ilayer).x,1),size(res(ilayer).x,2),'single'); 16 | for ninmaps = 1 : size(res(ilayer).x,3) 17 | z = z + convn(res(ilayer).x(:,:,ninmaps), l.weights{1}(:,:,ninmaps,noutmaps),'same'); 18 | end 19 | res(ilayer+1).x(:,:,noutmaps) = z + l.weights{2}(noutmaps); 20 | end 21 | case 'relu' 22 | res(ilayer+1).x = max(res(ilayer).x,0); 23 | end 24 | res(ilayer).x = []; 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/vl_simplenn_mergebnorm.m: -------------------------------------------------------------------------------- 1 | function [net1] = vl_simplenn_mergebnorm(net) 2 | 3 | %% merge bnorm parameters into adjacent Conv layer 4 | 5 | for i = 1:numel(net.layers) 6 | if strcmp(net.layers{i}.type, 'conv') 7 | net.layers{i}.weightDecay(2) = 1; 8 | end 9 | end 10 | 11 | for i = 1:numel(net.layers) 12 | if strcmp(net.layers{i}.type, 'bnorm') 13 | ws = net.layers{i}.weights{1}; 14 | bs = net.layers{i}.weights{2}; 15 | mu_sigmas = net.layers{i}.weights{3}; 16 | for j = 1:numel(ws) 17 | net.layers{i-1}.weights{1}(:,:,:,j) =single(double(net.layers{i-1}.weights{1}(:,:,:,j))*double(ws(j))/(double(mu_sigmas(j,2)))); 18 | net.layers{i-1}.weights{2}(j) =single(double(bs(j)) - double(ws(j))*double(mu_sigmas(j,1))/(double(mu_sigmas(j,2)))); 19 | end 20 | net.layers{i-1}.learningRate(2) = 1; 21 | end 22 | end 23 | 24 | net1 = net; 25 | net1.layers = {}; 26 | net1 = rmfield(net1,'meta'); 27 | for i = 1:numel(net.layers) 28 | if ~strcmp(net.layers{i}.type, 'bnorm') 29 | net1.layers{end+1} = net.layers{i}; 30 | end 31 | end 32 | 33 | net1.layers = net1.layers(1:end-1); 34 | 35 | 36 | end 37 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/vl_srmd_concise.m: -------------------------------------------------------------------------------- 1 | function res = vl_srmd_concise(net, x) 2 | 3 | global degpar; 4 | n = numel(net.layers); 5 | res = struct('x', cell(1,n+1)); 6 | res(1).x = x ; 7 | cudnn = {'CuDNN'} ; 8 | %cudnn = {'NoCuDNN'} ; 9 | 10 | for i=1:n 11 | l = net.layers{i} ; 12 | switch l.type 13 | case 'conv' 14 | res(i+1).x = vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, ... 15 | 'pad', l.pad, ... 16 | 'stride', l.stride, ... 17 | 'dilate', l.dilate, ... 18 | l.opts{:}, ... 19 | cudnn{:}) ; 20 | 21 | case 'concat' 22 | if size(degpar,1)~=size(res(i).x,1) 23 | sigmaMap = bsxfun(@times,ones(size(res(i).x,1),size(res(i).x,2),1,size(res(i).x,4),'single'),permute(degpar,[3 4 1 2])); 24 | res(i+1).x = cat(3,res(i).x,sigmaMap); 25 | else 26 | res(i+1).x = cat(3,res(i).x,sigmaMap); 27 | end 28 | 29 | case 'SubP' 30 | res(i+1).x = vl_nnSubP(res(i).x, [],'scale',l.scale); 31 | 32 | case 'relu' 33 | res(i+1).x = max(res(i).x,0) ; 34 | end 35 | res(i).x = [] ; 36 | end 37 | 38 | 39 | -------------------------------------------------------------------------------- /TrainingCodes/utilities/vl_srmd_matlab.m: -------------------------------------------------------------------------------- 1 | function res = vl_srmd_matlab(net, input) 2 | 3 | %% If you did not install the matconvnet package, you can use this for testing. 4 | 5 | global degpar; 6 | n = numel(net.layers); 7 | res = struct('x', cell(1,n+1)); 8 | res(1).x = input; 9 | 10 | for i = 1 : n 11 | l = net.layers{i}; 12 | switch l.type 13 | 14 | case 'conv' 15 | disp(['Processing ... ',int2str(i),'/',int2str(n)]); 16 | for noutmaps = 1 : size(l.weights{1},4) 17 | z = zeros(size(res(i).x,1),size(res(i).x,2),'single'); 18 | for ninmaps = 1 : size(res(i).x,3) 19 | z = z + convn(res(i).x(:,:,ninmaps), rot90(l.weights{1}(:,:,ninmaps,noutmaps),2),'same'); % 180 degree rotation for kernel 20 | end 21 | res(i+1).x(:,:,noutmaps) = z + l.weights{2}(noutmaps); 22 | end 23 | 24 | case 'relu' 25 | res(i+1).x = max(res(i).x,0); 26 | 27 | case 'concat' 28 | if size(degpar,1)~=size(res(i).x,1) 29 | sigmaMap = bsxfun(@times,ones(size(res(i).x,1),size(res(i).x,2),1,size(res(i).x,4),'single'),permute(degpar,[3 4 1 2])); 30 | res(i+1).x = cat(3,res(i).x,sigmaMap); 31 | else 32 | res(i+1).x = cat(3,res(i).x,sigmaMap); 33 | end 34 | 35 | case 'SubP' 36 | res(i+1).x = vl_nnSubP(res(i).x, [],'scale',l.scale); 37 | 38 | end 39 | res(i).x = []; 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /TrainingCodes/vl_nnSubP.m: -------------------------------------------------------------------------------- 1 | function y = vl_nnSubP(x, dzdy, varargin) 2 | 3 | 4 | opts.scale = 2; 5 | opts = vl_argparse(opts, varargin, 'nonrecursive') ; 6 | scale = opts.scale; 7 | 8 | if scale > 1 % many (small)---> one (big) e.g., 100X100X256X128 ----> 200X200X64*128 9 | scale2 = scale^2; 10 | if nargin <= 1 || isempty(dzdy) 11 | [hei,wid,channelI,bsize] = size(x); 12 | channelO = channelI/scale2; 13 | channelI_start = 0; 14 | idx1 = scale * (1:hei); 15 | idx2 = scale * (1:wid); 16 | y = zeros([scale*hei, scale*wid, channelO, bsize],'like',x); 17 | for nchannelO = 1:channelO 18 | for i = 1:scale2 19 | a = mod(i-1, scale) + 1; 20 | b = floor((i-1)/scale) + 1; 21 | y(idx1+a-scale, idx2+b-scale, nchannelO, :) = x(:,:,channelI_start+i,:); 22 | end 23 | channelI_start = scale2 + channelI_start; 24 | end 25 | else 26 | [hei,wid,channelO,bsize] = size(dzdy); 27 | idx1 = 1:scale:hei; 28 | idx2 = 1:scale:wid; 29 | channelI = channelO*scale2; 30 | channelI_start = 0; 31 | y = zeros([hei/scale, wid/scale, channelI, bsize],'like',x); 32 | for nchannelO = 1:channelO 33 | for i = 1:scale^2 34 | a = mod(i-1, scale) + 1; 35 | b = floor((i-1)/scale) + 1; 36 | y(:, :, channelI_start+i, :) = dzdy(idx1+a-1, idx2+b-1,nchannelO,:); 37 | end 38 | channelI_start = scale2 + channelI_start; 39 | end 40 | end 41 | 42 | else % one (big) ---> many (small) e.g., 200X200X64*128--->100X100X256X128 43 | 44 | scale = round(1/scale); 45 | scale2 = scale^2; 46 | if nargin <= 1 || isempty(dzdy) 47 | [hei,wid,channelO,bsize] = size(x); 48 | idx1 = 1:scale:hei; 49 | idx2 = 1:scale:wid; 50 | channelI = channelO*scale2; 51 | channelI_start = 0; 52 | y = zeros([hei/scale, wid/scale, channelI, bsize],'like',x); 53 | for nchannelO = 1:channelO 54 | for i = 1:scale^2 55 | a = mod(i-1, scale) + 1; 56 | b = floor((i-1)/scale) + 1; 57 | y(:, :, channelI_start+i, :) = x(idx1+a-1, idx2+b-1,nchannelO,:); 58 | end 59 | channelI_start = scale2 + channelI_start; 60 | end 61 | else 62 | [hei,wid,channelI,bsize] = size(dzdy); 63 | channelO = channelI/scale2; 64 | channelI_start = 0; 65 | idx1 = scale * (1:hei); 66 | idx2 = scale * (1:wid); 67 | y = zeros([scale*hei, scale*wid, channelO, bsize],'like',x); 68 | for nchannelO = 1:channelO 69 | for i = 1:scale2 70 | a = mod(i-1, scale) + 1; 71 | b = floor((i-1)/scale) + 1; 72 | y(idx1+a-scale, idx2+b-scale, nchannelO, :) = dzdy(:,:,channelI_start+i,:); 73 | end 74 | channelI_start = scale2 + channelI_start; 75 | end 76 | end 77 | end 78 | 79 | -------------------------------------------------------------------------------- /TrainingCodes/vl_nnloss.m: -------------------------------------------------------------------------------- 1 | function Y = vl_nnloss(X,c,dzdy,varargin) 2 | 3 | % -------------------------------------------------------------------- 4 | % pixel-level L2 loss 5 | % -------------------------------------------------------------------- 6 | 7 | d = X-c; 8 | if nargin <= 2 || isempty(dzdy) 9 | t = (d.^2)/2; 10 | Y = sum(t(:))/size(X,4); 11 | else 12 | Y = d; 13 | end 14 | 15 | % -------------------------------------------------------------------- 16 | 17 | % if nargin <= 2 || isempty(dzdy) 18 | % t = ((X-c).^2)/2; 19 | % Y = sum(t(:))/size(X,4); % reconstruction error per sample; 20 | % else 21 | % Y = sign(X - c); 22 | % end 23 | 24 | % --------------fine-tune--------------------------------------------- 25 | 26 | % global sigmas; 27 | % d = X-c; 28 | % w = min(200,1./((sigmas/75*255).^1.2)); 29 | % if nargin <= 2 || isempty(dzdy) 30 | % t = (d.^2)/2; 31 | % Y = sum(t(:))/size(X,4); 32 | % else 33 | % Y = bsxfun(@times,d,reshape(w,[1,1,1,size(X,4)])); 34 | % end 35 | 36 | % -------------------------------------------------------------------- 37 | 38 | % eps = 1e-5; 39 | % d = X - c; 40 | % e = sqrt(d.^2 + eps); 41 | % 42 | % if nargin <= 2 || isempty(dzdy) 43 | % t = (d.^2)/2; 44 | % Y = sum(t(:))/size(X,4); 45 | % else 46 | % Y = d ./ e; 47 | % end -------------------------------------------------------------------------------- /figs/0991x4d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/0991x4d.png -------------------------------------------------------------------------------- /figs/0991x4d_srmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/0991x4d_srmd.png -------------------------------------------------------------------------------- /figs/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/architecture.png -------------------------------------------------------------------------------- /figs/bicubic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/bicubic1.png -------------------------------------------------------------------------------- /figs/bicubic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/bicubic2.png -------------------------------------------------------------------------------- /figs/butterfly_GT30_VDSR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT30_VDSR.png -------------------------------------------------------------------------------- /figs/butterfly_GTSRMD_x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GTSRMD_x3.png -------------------------------------------------------------------------------- /figs/butterfly_GT_x2_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT_x2_.png -------------------------------------------------------------------------------- /figs/butterfly_GT_x2_2274.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT_x2_2274.png -------------------------------------------------------------------------------- /figs/butterfly_GT_x3_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT_x3_.png -------------------------------------------------------------------------------- /figs/butterfly_GT_x3_2675.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT_x3_2675.png -------------------------------------------------------------------------------- /figs/butterfly_GT_x4_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT_x4_.png -------------------------------------------------------------------------------- /figs/butterfly_GT_x4_2771.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/butterfly_GT_x4_2771.png -------------------------------------------------------------------------------- /figs/realSR1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/realSR1.png -------------------------------------------------------------------------------- /figs/realSR2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/realSR2.png -------------------------------------------------------------------------------- /figs/track3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/track3.png -------------------------------------------------------------------------------- /figs/woman_GT30_VDSR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/woman_GT30_VDSR.png -------------------------------------------------------------------------------- /figs/woman_GTSRMD_x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/figs/woman_GTSRMD_x3.png -------------------------------------------------------------------------------- /models/Demo_show_kernels.m: -------------------------------------------------------------------------------- 1 | 2 | load SRMDNFx2.mat; 3 | 4 | %% show the Gaussian kernels 5 | 6 | 7 | kernels = net.meta.AtrpGaussianKernel; 8 | 9 | for i = 1:size(kernels,4) 10 | 11 | kernel = kernels(:,:,i); 12 | 13 | subplot 121 14 | imagesc(kernel); 15 | title([int2str(i),' / ',int2str(size(kernels,4))]) 16 | axis square; 17 | 18 | subplot 122 19 | surf(kernel); 20 | title([int2str(i),' / ',int2str(size(kernels,4))]) 21 | view(45,55) 22 | xlim([1 15]); 23 | ylim([1 15]); 24 | axis square; 25 | pause(0.1) 26 | end 27 | 28 | 29 | %% show the PCA basis 30 | 31 | 32 | for i = 1:size(net.meta.P,1) 33 | 34 | kernel = reshape(net.meta.P(i,:),15,15); 35 | 36 | subplot 121 37 | imagesc(kernel); 38 | title([int2str(i),' / ',int2str(size(net.meta.P,1))]) 39 | axis square; 40 | 41 | subplot 122 42 | surf(kernel); 43 | title([int2str(i),' / ',int2str(size(net.meta.P,1))]) 44 | view(45,55) 45 | xlim([1 15]); 46 | ylim([1 15]); 47 | axis square; 48 | pause(2) 49 | end 50 | 51 | -------------------------------------------------------------------------------- /models/SRMDNFx2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDNFx2.mat -------------------------------------------------------------------------------- /models/SRMDNFx3.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDNFx3.mat -------------------------------------------------------------------------------- /models/SRMDNFx4.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDNFx4.mat -------------------------------------------------------------------------------- /models/SRMD_non_blind.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMD_non_blind.mat -------------------------------------------------------------------------------- /models/SRMDx1_color.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDx1_color.mat -------------------------------------------------------------------------------- /models/SRMDx1_gray.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDx1_gray.mat -------------------------------------------------------------------------------- /models/SRMDx2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDx2.mat -------------------------------------------------------------------------------- /models/SRMDx3.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDx3.mat -------------------------------------------------------------------------------- /models/SRMDx4.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/models/SRMDx4.mat -------------------------------------------------------------------------------- /results/Hilbert_SRMD_x1_itrG_5_nlevel_10/Hilbert_x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/results/Hilbert_SRMD_x1_itrG_5_nlevel_10/Hilbert_x1.png -------------------------------------------------------------------------------- /results/chip_SRMD_Real_x4_itrG_17_nlevel_10/chip_x4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/results/chip_SRMD_Real_x4_itrG_17_nlevel_10/chip_x4.png -------------------------------------------------------------------------------- /testsets/Audrey_Hepburn/Audrey_Hepburn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Audrey_Hepburn/Audrey_Hepburn.jpg -------------------------------------------------------------------------------- /testsets/BSD68/test001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test001.png -------------------------------------------------------------------------------- /testsets/BSD68/test002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test002.png -------------------------------------------------------------------------------- /testsets/BSD68/test003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test003.png -------------------------------------------------------------------------------- /testsets/BSD68/test004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test004.png -------------------------------------------------------------------------------- /testsets/BSD68/test005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test005.png -------------------------------------------------------------------------------- /testsets/BSD68/test006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test006.png -------------------------------------------------------------------------------- /testsets/BSD68/test007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test007.png -------------------------------------------------------------------------------- /testsets/BSD68/test008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test008.png -------------------------------------------------------------------------------- /testsets/BSD68/test009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test009.png -------------------------------------------------------------------------------- /testsets/BSD68/test010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test010.png -------------------------------------------------------------------------------- /testsets/BSD68/test011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test011.png -------------------------------------------------------------------------------- /testsets/BSD68/test012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test012.png -------------------------------------------------------------------------------- /testsets/BSD68/test013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test013.png -------------------------------------------------------------------------------- /testsets/BSD68/test014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test014.png -------------------------------------------------------------------------------- /testsets/BSD68/test015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test015.png -------------------------------------------------------------------------------- /testsets/BSD68/test016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test016.png -------------------------------------------------------------------------------- /testsets/BSD68/test017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test017.png -------------------------------------------------------------------------------- /testsets/BSD68/test018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test018.png -------------------------------------------------------------------------------- /testsets/BSD68/test019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test019.png -------------------------------------------------------------------------------- /testsets/BSD68/test020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test020.png -------------------------------------------------------------------------------- /testsets/BSD68/test021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test021.png -------------------------------------------------------------------------------- /testsets/BSD68/test022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test022.png -------------------------------------------------------------------------------- /testsets/BSD68/test023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test023.png -------------------------------------------------------------------------------- /testsets/BSD68/test024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test024.png -------------------------------------------------------------------------------- /testsets/BSD68/test025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test025.png -------------------------------------------------------------------------------- /testsets/BSD68/test026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test026.png -------------------------------------------------------------------------------- /testsets/BSD68/test027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test027.png -------------------------------------------------------------------------------- /testsets/BSD68/test028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test028.png -------------------------------------------------------------------------------- /testsets/BSD68/test029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test029.png -------------------------------------------------------------------------------- /testsets/BSD68/test030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test030.png -------------------------------------------------------------------------------- /testsets/BSD68/test031.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test031.png -------------------------------------------------------------------------------- /testsets/BSD68/test032.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test032.png -------------------------------------------------------------------------------- /testsets/BSD68/test033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test033.png -------------------------------------------------------------------------------- /testsets/BSD68/test034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test034.png -------------------------------------------------------------------------------- /testsets/BSD68/test035.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test035.png -------------------------------------------------------------------------------- /testsets/BSD68/test036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test036.png -------------------------------------------------------------------------------- /testsets/BSD68/test037.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test037.png -------------------------------------------------------------------------------- /testsets/BSD68/test038.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test038.png -------------------------------------------------------------------------------- /testsets/BSD68/test039.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test039.png -------------------------------------------------------------------------------- /testsets/BSD68/test040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test040.png -------------------------------------------------------------------------------- /testsets/BSD68/test041.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test041.png -------------------------------------------------------------------------------- /testsets/BSD68/test042.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test042.png -------------------------------------------------------------------------------- /testsets/BSD68/test043.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test043.png -------------------------------------------------------------------------------- /testsets/BSD68/test044.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test044.png -------------------------------------------------------------------------------- /testsets/BSD68/test045.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test045.png -------------------------------------------------------------------------------- /testsets/BSD68/test046.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test046.png -------------------------------------------------------------------------------- /testsets/BSD68/test047.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test047.png -------------------------------------------------------------------------------- /testsets/BSD68/test048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test048.png -------------------------------------------------------------------------------- /testsets/BSD68/test049.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test049.png -------------------------------------------------------------------------------- /testsets/BSD68/test050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test050.png -------------------------------------------------------------------------------- /testsets/BSD68/test051.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test051.png -------------------------------------------------------------------------------- /testsets/BSD68/test052.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test052.png -------------------------------------------------------------------------------- /testsets/BSD68/test053.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test053.png -------------------------------------------------------------------------------- /testsets/BSD68/test054.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test054.png -------------------------------------------------------------------------------- /testsets/BSD68/test055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test055.png -------------------------------------------------------------------------------- /testsets/BSD68/test056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test056.png -------------------------------------------------------------------------------- /testsets/BSD68/test057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test057.png -------------------------------------------------------------------------------- /testsets/BSD68/test058.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test058.png -------------------------------------------------------------------------------- /testsets/BSD68/test059.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test059.png -------------------------------------------------------------------------------- /testsets/BSD68/test060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test060.png -------------------------------------------------------------------------------- /testsets/BSD68/test061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test061.png -------------------------------------------------------------------------------- /testsets/BSD68/test062.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test062.png -------------------------------------------------------------------------------- /testsets/BSD68/test063.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test063.png -------------------------------------------------------------------------------- /testsets/BSD68/test064.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test064.png -------------------------------------------------------------------------------- /testsets/BSD68/test065.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test065.png -------------------------------------------------------------------------------- /testsets/BSD68/test066.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test066.png -------------------------------------------------------------------------------- /testsets/BSD68/test067.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test067.png -------------------------------------------------------------------------------- /testsets/BSD68/test068.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/BSD68/test068.png -------------------------------------------------------------------------------- /testsets/Hilbert/Hilbert.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Hilbert/Hilbert.jpg -------------------------------------------------------------------------------- /testsets/Nami/Nami.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Nami/Nami.jpg -------------------------------------------------------------------------------- /testsets/Set14/baboon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/baboon.bmp -------------------------------------------------------------------------------- /testsets/Set14/barbara.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/barbara.bmp -------------------------------------------------------------------------------- /testsets/Set14/bridge.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/bridge.bmp -------------------------------------------------------------------------------- /testsets/Set14/coastguard.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/coastguard.bmp -------------------------------------------------------------------------------- /testsets/Set14/comic.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/comic.bmp -------------------------------------------------------------------------------- /testsets/Set14/face.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/face.bmp -------------------------------------------------------------------------------- /testsets/Set14/flowers.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/flowers.bmp -------------------------------------------------------------------------------- /testsets/Set14/foreman.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/foreman.bmp -------------------------------------------------------------------------------- /testsets/Set14/lenna.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/lenna.bmp -------------------------------------------------------------------------------- /testsets/Set14/man.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/man.bmp -------------------------------------------------------------------------------- /testsets/Set14/monarch.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/monarch.bmp -------------------------------------------------------------------------------- /testsets/Set14/pepper.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/pepper.bmp -------------------------------------------------------------------------------- /testsets/Set14/ppt3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/ppt3.bmp -------------------------------------------------------------------------------- /testsets/Set14/zebra.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set14/zebra.bmp -------------------------------------------------------------------------------- /testsets/Set5/baby_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set5/baby_GT.bmp -------------------------------------------------------------------------------- /testsets/Set5/bird_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set5/bird_GT.bmp -------------------------------------------------------------------------------- /testsets/Set5/butterfly_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set5/butterfly_GT.bmp -------------------------------------------------------------------------------- /testsets/Set5/head_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set5/head_GT.bmp -------------------------------------------------------------------------------- /testsets/Set5/woman_GT.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/Set5/woman_GT.bmp -------------------------------------------------------------------------------- /testsets/cat/cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/cat/cat.png -------------------------------------------------------------------------------- /testsets/chip/chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/chip/chip.png -------------------------------------------------------------------------------- /testsets/flowers/Flowers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/flowers/Flowers.png -------------------------------------------------------------------------------- /testsets/flowersL/Flowers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/flowersL/Flowers.png -------------------------------------------------------------------------------- /testsets/frog/Frog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/frog/Frog.png -------------------------------------------------------------------------------- /testsets/stars/Stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/stars/Stars.png -------------------------------------------------------------------------------- /testsets/starsL/Stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cszn/SRMD/c83995140baecd43f9f426710bf6330b3678746f/testsets/starsL/Stars.png -------------------------------------------------------------------------------- /utilities/Cal_PSNRSSIM.m: -------------------------------------------------------------------------------- 1 | function [psnr_cur, ssim_cur] = Cal_PSNRSSIM(A,B,row,col) 2 | 3 | 4 | [n,m,ch]=size(B); 5 | A = A(row+1:n-row,col+1:m-col,:); 6 | B = B(row+1:n-row,col+1:m-col,:); 7 | A=double(A); % Ground-truth 8 | B=double(B); % 9 | 10 | e=A(:)-B(:); 11 | mse=mean(e.^2); 12 | psnr_cur=10*log10(255^2/mse); 13 | 14 | if ch==1 15 | [ssim_cur, ~] = ssim_index(A, B); 16 | else 17 | ssim_cur = (ssim_index(A(:,:,1), B(:,:,1)) + ssim_index(A(:,:,2), B(:,:,2)) + ssim_index(A(:,:,3), B(:,:,3)))/3; 18 | end 19 | 20 | 21 | function [mssim, ssim_map] = ssim_index(img1, img2, K, window, L) 22 | 23 | %======================================================================== 24 | %SSIM Index, Version 1.0 25 | %Copyright(c) 2003 Zhou Wang 26 | %All Rights Reserved. 27 | % 28 | %The author is with Howard Hughes Medical Institute, and Laboratory 29 | %for Computational Vision at Center for Neural Science and Courant 30 | %Institute of Mathematical Sciences, New York University. 31 | % 32 | %---------------------------------------------------------------------- 33 | %Permission to use, copy, or modify this software and its documentation 34 | %for educational and research purposes only and without fee is hereby 35 | %granted, provided that this copyright notice and the original authors' 36 | %names appear on all copies and supporting documentation. This program 37 | %shall not be used, rewritten, or adapted as the basis of a commercial 38 | %software or hardware product without first obtaining permission of the 39 | %authors. The authors make no representations about the suitability of 40 | %this software for any purpose. It is provided "as is" without express 41 | %or implied warranty. 42 | %---------------------------------------------------------------------- 43 | % 44 | %This is an implementation of the algorithm for calculating the 45 | %Structural SIMilarity (SSIM) index between two images. Please refer 46 | %to the following paper: 47 | % 48 | %Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image 49 | %quality assessment: From error measurement to structural similarity" 50 | %IEEE Transactios on Image Processing, vol. 13, no. 1, Jan. 2004. 51 | % 52 | %Kindly report any suggestions or corrections to zhouwang@ieee.org 53 | % 54 | %---------------------------------------------------------------------- 55 | % 56 | %Input : (1) img1: the first image being compared 57 | % (2) img2: the second image being compared 58 | % (3) K: constants in the SSIM index formula (see the above 59 | % reference). defualt value: K = [0.01 0.03] 60 | % (4) window: local window for statistics (see the above 61 | % reference). default widnow is Gaussian given by 62 | % window = fspecial('gaussian', 11, 1.5); 63 | % (5) L: dynamic range of the images. default: L = 255 64 | % 65 | %Output: (1) mssim: the mean SSIM index value between 2 images. 66 | % If one of the images being compared is regarded as 67 | % perfect quality, then mssim can be considered as the 68 | % quality measure of the other image. 69 | % If img1 = img2, then mssim = 1. 70 | % (2) ssim_map: the SSIM index map of the test image. The map 71 | % has a smaller size than the input images. The actual size: 72 | % size(img1) - size(window) + 1. 73 | % 74 | %Default Usage: 75 | % Given 2 test images img1 and img2, whose dynamic range is 0-255 76 | % 77 | % [mssim ssim_map] = ssim_index(img1, img2); 78 | % 79 | %Advanced Usage: 80 | % User defined parameters. For example 81 | % 82 | % K = [0.05 0.05]; 83 | % window = ones(8); 84 | % L = 100; 85 | % [mssim ssim_map] = ssim_index(img1, img2, K, window, L); 86 | % 87 | %See the results: 88 | % 89 | % mssim %Gives the mssim value 90 | % imshow(max(0, ssim_map).^4) %Shows the SSIM index map 91 | % 92 | %======================================================================== 93 | 94 | 95 | if (nargin < 2 || nargin > 5) 96 | ssim_index = -Inf; 97 | ssim_map = -Inf; 98 | return; 99 | end 100 | 101 | if (size(img1) ~= size(img2)) 102 | ssim_index = -Inf; 103 | ssim_map = -Inf; 104 | return; 105 | end 106 | 107 | [M N] = size(img1); 108 | 109 | if (nargin == 2) 110 | if ((M < 11) || (N < 11)) 111 | ssim_index = -Inf; 112 | ssim_map = -Inf; 113 | return 114 | end 115 | window = fspecial('gaussian', 11, 1.5); % 116 | K(1) = 0.01; % default settings 117 | K(2) = 0.03; % 118 | L = 255; % 119 | end 120 | 121 | if (nargin == 3) 122 | if ((M < 11) || (N < 11)) 123 | ssim_index = -Inf; 124 | ssim_map = -Inf; 125 | return 126 | end 127 | window = fspecial('gaussian', 11, 1.5); 128 | L = 255; 129 | if (length(K) == 2) 130 | if (K(1) < 0 || K(2) < 0) 131 | ssim_index = -Inf; 132 | ssim_map = -Inf; 133 | return; 134 | end 135 | else 136 | ssim_index = -Inf; 137 | ssim_map = -Inf; 138 | return; 139 | end 140 | end 141 | 142 | if (nargin == 4) 143 | [H W] = size(window); 144 | if ((H*W) < 4 || (H > M) || (W > N)) 145 | ssim_index = -Inf; 146 | ssim_map = -Inf; 147 | return 148 | end 149 | L = 255; 150 | if (length(K) == 2) 151 | if (K(1) < 0 || K(2) < 0) 152 | ssim_index = -Inf; 153 | ssim_map = -Inf; 154 | return; 155 | end 156 | else 157 | ssim_index = -Inf; 158 | ssim_map = -Inf; 159 | return; 160 | end 161 | end 162 | 163 | if (nargin == 5) 164 | [H W] = size(window); 165 | if ((H*W) < 4 || (H > M) || (W > N)) 166 | ssim_index = -Inf; 167 | ssim_map = -Inf; 168 | return 169 | end 170 | if (length(K) == 2) 171 | if (K(1) < 0 || K(2) < 0) 172 | ssim_index = -Inf; 173 | ssim_map = -Inf; 174 | return; 175 | end 176 | else 177 | ssim_index = -Inf; 178 | ssim_map = -Inf; 179 | return; 180 | end 181 | end 182 | 183 | C1 = (K(1)*L)^2; 184 | C2 = (K(2)*L)^2; 185 | window = window/sum(sum(window)); 186 | img1 = double(img1); 187 | img2 = double(img2); 188 | 189 | mu1 = filter2(window, img1, 'valid'); 190 | mu2 = filter2(window, img2, 'valid'); 191 | mu1_sq = mu1.*mu1; 192 | mu2_sq = mu2.*mu2; 193 | mu1_mu2 = mu1.*mu2; 194 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 195 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 196 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 197 | 198 | if (C1 > 0 & C2 > 0) 199 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 200 | else 201 | numerator1 = 2*mu1_mu2 + C1; 202 | numerator2 = 2*sigma12 + C2; 203 | denominator1 = mu1_sq + mu2_sq + C1; 204 | denominator2 = sigma1_sq + sigma2_sq + C2; 205 | ssim_map = ones(size(mu1)); 206 | index = (denominator1.*denominator2 > 0); 207 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 208 | index = (denominator1 ~= 0) & (denominator2 == 0); 209 | ssim_map(index) = numerator1(index)./denominator1(index); 210 | end 211 | 212 | mssim = mean2(ssim_map); 213 | 214 | return 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /utilities/center_crop.m: -------------------------------------------------------------------------------- 1 | function [iout] = center_crop(im,a,b) 2 | 3 | [w,h,~] = size(im); 4 | c1 = w-a-(w-a)/2; 5 | c2 = h-b-(h-b)/2; 6 | iout = im(c1+1:c1+a,c2+1:c2+b,:); 7 | 8 | end 9 | 10 | -------------------------------------------------------------------------------- /utilities/data_augmentation.m: -------------------------------------------------------------------------------- 1 | function image = data_augmentation(image, mode) 2 | 3 | if mode == 1 4 | return; 5 | end 6 | 7 | if mode == 2 % flipped 8 | image = flipud(image); 9 | return; 10 | end 11 | 12 | if mode == 3 % rotation 90 13 | image = rot90(image,1); 14 | return; 15 | end 16 | 17 | if mode == 4 % rotation 90 & flipped 18 | image = rot90(image,1); 19 | image = flipud(image); 20 | return; 21 | end 22 | 23 | if mode == 5 % rotation 180 24 | image = rot90(image,2); 25 | return; 26 | end 27 | 28 | if mode == 6 % rotation 180 & flipped 29 | image = rot90(image,2); 30 | image = flipud(image); 31 | return; 32 | end 33 | 34 | if mode == 7 % rotation 270 35 | image = rot90(image,3); 36 | return; 37 | end 38 | 39 | if mode == 8 % rotation 270 & flipped 40 | image = rot90(image,3); 41 | image = flipud(image); 42 | return; 43 | end 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /utilities/im_crop.m: -------------------------------------------------------------------------------- 1 | function [im] = im_crop(im,w,h) 2 | 3 | 4 | if mod(w,2)==1 5 | im = im(1:end-1,:,:); 6 | end 7 | if mod(h,2)==1 8 | im = im(:,1:end-1,:); 9 | end 10 | 11 | end 12 | 13 | -------------------------------------------------------------------------------- /utilities/im_pad.m: -------------------------------------------------------------------------------- 1 | function [im] = im_pad(im) 2 | 3 | [w,h,~] = size(im); 4 | 5 | if mod(w,2)==1 6 | im = cat(1,im, im(end,:,:)) ; 7 | end 8 | if mod(h,2)==1 9 | im = cat(2,im, im(:,end,:)) ; 10 | end 11 | 12 | end 13 | 14 | -------------------------------------------------------------------------------- /utilities/modcrop.m: -------------------------------------------------------------------------------- 1 | function imgs = modcrop(imgs, modulo) 2 | if size(imgs,3)==1 3 | sz = size(imgs); 4 | sz = sz - mod(sz, modulo); 5 | imgs = imgs(1:sz(1), 1:sz(2)); 6 | else 7 | tmpsz = size(imgs); 8 | sz = tmpsz(1:2); 9 | sz = sz - mod(sz, modulo); 10 | imgs = imgs(1:sz(1), 1:sz(2),:); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /utilities/shave.m: -------------------------------------------------------------------------------- 1 | function I = shave(I, border) 2 | I = I(1+border(1):end-border(1), ... 3 | 1+border(2):end-border(2), :, :); 4 | -------------------------------------------------------------------------------- /utilities/vl_nnSubP.m: -------------------------------------------------------------------------------- 1 | function y = vl_nnSubP(x, dzdy, varargin) 2 | 3 | 4 | opts.scale = 2; 5 | opts = vl_argparse(opts, varargin, 'nonrecursive') ; 6 | scale = opts.scale; 7 | 8 | if scale > 1 % many (small)---> one (big) e.g., 100X100X256X128 ----> 200X200X64*128 9 | scale2 = scale^2; 10 | if nargin <= 1 || isempty(dzdy) 11 | [hei,wid,channelI,bsize] = size(x); 12 | channelO = channelI/scale2; 13 | channelI_start = 0; 14 | idx1 = scale * (1:hei); 15 | idx2 = scale * (1:wid); 16 | y = zeros([scale*hei, scale*wid, channelO, bsize],'like',x); 17 | for nchannelO = 1:channelO 18 | for i = 1:scale2 19 | a = mod(i-1, scale) + 1; 20 | b = floor((i-1)/scale) + 1; 21 | y(idx1+a-scale, idx2+b-scale, nchannelO, :) = x(:,:,channelI_start+i,:); 22 | end 23 | channelI_start = scale2 + channelI_start; 24 | end 25 | else 26 | [hei,wid,channelO,bsize] = size(dzdy); 27 | idx1 = 1:scale:hei; 28 | idx2 = 1:scale:wid; 29 | channelI = channelO*scale2; 30 | channelI_start = 0; 31 | y = zeros([hei/scale, wid/scale, channelI, bsize],'like',x); 32 | for nchannelO = 1:channelO 33 | for i = 1:scale^2 34 | a = mod(i-1, scale) + 1; 35 | b = floor((i-1)/scale) + 1; 36 | y(:, :, channelI_start+i, :) = dzdy(idx1+a-1, idx2+b-1,nchannelO,:); 37 | end 38 | channelI_start = scale2 + channelI_start; 39 | end 40 | end 41 | 42 | else % one (big) ---> many (small) e.g., 200X200X64*128--->100X100X256X128 43 | 44 | scale = round(1/scale); 45 | scale2 = scale^2; 46 | if nargin <= 1 || isempty(dzdy) 47 | [hei,wid,channelO,bsize] = size(x); 48 | idx1 = 1:scale:hei; 49 | idx2 = 1:scale:wid; 50 | channelI = channelO*scale2; 51 | channelI_start = 0; 52 | y = zeros([hei/scale, wid/scale, channelI, bsize],'like',x); 53 | for nchannelO = 1:channelO 54 | for i = 1:scale^2 55 | a = mod(i-1, scale) + 1; 56 | b = floor((i-1)/scale) + 1; 57 | y(:, :, channelI_start+i, :) = x(idx1+a-1, idx2+b-1,nchannelO,:); 58 | end 59 | channelI_start = scale2 + channelI_start; 60 | end 61 | else 62 | [hei,wid,channelI,bsize] = size(dzdy); 63 | channelO = channelI/scale2; 64 | channelI_start = 0; 65 | idx1 = scale * (1:hei); 66 | idx2 = scale * (1:wid); 67 | y = zeros([scale*hei, scale*wid, channelO, bsize],'like',x); 68 | for nchannelO = 1:channelO 69 | for i = 1:scale2 70 | a = mod(i-1, scale) + 1; 71 | b = floor((i-1)/scale) + 1; 72 | y(idx1+a-scale, idx2+b-scale, nchannelO, :) = dzdy(:,:,channelI_start+i,:); 73 | end 74 | channelI_start = scale2 + channelI_start; 75 | end 76 | end 77 | end 78 | 79 | -------------------------------------------------------------------------------- /utilities/vl_simplenn_mergebnorm.m: -------------------------------------------------------------------------------- 1 | function [net1] = vl_simplenn_mergebnorm(net) 2 | 3 | %% merge bnorm parameters into adjacent Conv layer 4 | 5 | for i = 1:numel(net.layers) 6 | if strcmp(net.layers{i}.type, 'conv') 7 | net.layers{i}.weightDecay(2) = 1; 8 | end 9 | end 10 | 11 | for i = 1:numel(net.layers) 12 | if strcmp(net.layers{i}.type, 'bnorm') 13 | ws = net.layers{i}.weights{1}; 14 | bs = net.layers{i}.weights{2}; 15 | mu_sigmas = net.layers{i}.weights{3}; 16 | for j = 1:numel(ws) 17 | net.layers{i-1}.weights{1}(:,:,:,j) =single(double(net.layers{i-1}.weights{1}(:,:,:,j))*double(ws(j))/(double(mu_sigmas(j,2)))); 18 | net.layers{i-1}.weights{2}(j) =single(double(bs(j)) - double(ws(j))*double(mu_sigmas(j,1))/(double(mu_sigmas(j,2)))); 19 | end 20 | net.layers{i-1}.learningRate(2) = 1; 21 | end 22 | end 23 | 24 | net1 = net; 25 | net1.layers = {}; 26 | net1 = rmfield(net1,'meta'); 27 | for i = 1:numel(net.layers) 28 | if ~strcmp(net.layers{i}.type, 'bnorm') 29 | net1.layers{end+1} = net.layers{i}; 30 | end 31 | end 32 | 33 | net1.layers = net1.layers(1:end-1); 34 | 35 | 36 | end 37 | -------------------------------------------------------------------------------- /utilities/vl_srmd.m: -------------------------------------------------------------------------------- 1 | function res = vl_srmd(net, x, dzdy, res, varargin) 2 | %VL_SIMPLENN Evaluate a SimpleNN network. 3 | 4 | % `Mode`:: `'normal'` 5 | % Specifies the mode of operation. It can be either `'normal'` or 6 | % `'test'`. In test mode, dropout and batch-normalization are 7 | % bypassed. Note that, when a network is deployed, it may be 8 | % preferable to *remove* such blocks altogether. 9 | % 10 | % `ConserveMemory`:: `false` 11 | % Aggressively delete intermediate results. This in practice has 12 | % a very small performance hit and allows training much larger 13 | % models. However, it can be useful to disable it for 14 | % debugging. Keeps the values in `res(1)` (input) and `res(end)` 15 | % (output) with the outputs of `loss` and `softmaxloss` layers. 16 | % It is also possible to preserve individual layer outputs 17 | % by setting `net.layers{...}.precious` to `true`. 18 | % For back-propagation, keeps only the derivatives with respect to 19 | % weights. 20 | % 21 | % `CuDNN`:: `true` 22 | % Use CuDNN when available. 23 | % 24 | % `Accumulate`:: `false` 25 | % Accumulate gradients in back-propagation instead of rewriting 26 | % them. This is useful to break the computation in sub-batches. 27 | % The gradients are accumulated to the provided RES structure 28 | % (i.e. to call VL_SIMPLENN(NET, X, DZDY, RES, ...). 29 | % 30 | % `BackPropDepth`:: `inf` 31 | % Limit the back-propagation to top-N layers. 32 | % 33 | % `SkipForward`:: `false` 34 | % Reuse the output values from the provided RES structure and compute 35 | % only the derivatives (backward pass). 36 | % 37 | 38 | 39 | % Copyright (C) 2014-15 Andrea Vedaldi. 40 | % All rights reserved. 41 | % 42 | % This file is part of the VLFeat library and is made available under 43 | % the terms of the BSD license (see the COPYING file). 44 | global degpar; 45 | opts.conserveMemory = true ; 46 | opts.sync = false ; 47 | opts.mode = 'normal' ; 48 | opts.accumulate = false ; 49 | opts.cudnn = true ; 50 | opts.backPropDepth = +inf ; 51 | opts.skipForward = false ; 52 | opts.parameterServer = [] ; 53 | opts.holdOn = false ; 54 | opts = vl_argparse(opts, varargin); 55 | 56 | n = numel(net.layers) ; 57 | assert(opts.backPropDepth > 0, 'Invalid `backPropDepth` value (!>0)'); 58 | backPropLim = max(n - opts.backPropDepth + 1, 1); 59 | 60 | if (nargin <= 2) || isempty(dzdy) 61 | doder = false ; 62 | if opts.skipForward 63 | error('simplenn:skipForwardNoBackwPass', ... 64 | '`skipForward` valid only when backward pass is computed.'); 65 | end 66 | else 67 | doder = true ; 68 | end 69 | 70 | if opts.cudnn 71 | cudnn = {'CuDNN'} ; 72 | bnormCudnn = {'NoCuDNN'} ; % ours seems slighty faster 73 | else 74 | cudnn = {'NoCuDNN'} ; 75 | bnormCudnn = {'NoCuDNN'} ; 76 | end 77 | 78 | switch lower(opts.mode) 79 | case 'normal' 80 | testMode = false ; 81 | case 'test' 82 | testMode = true ; 83 | otherwise 84 | error('Unknown mode ''%s''.', opts. mode) ; 85 | end 86 | 87 | gpuMode = isa(x, 'gpuArray') ; 88 | 89 | if nargin <= 3 || isempty(res) 90 | if opts.skipForward 91 | error('simplenn:skipForwardEmptyRes', ... 92 | 'RES structure must be provided for `skipForward`.'); 93 | end 94 | res = struct(... 95 | 'x', cell(1,n+1), ... 96 | 'dzdx', cell(1,n+1), ... 97 | 'dzdw', cell(1,n+1), ... 98 | 'aux', cell(1,n+1), ... 99 | 'stats', cell(1,n+1), ... 100 | 'time', num2cell(zeros(1,n+1)), ... 101 | 'backwardTime', num2cell(zeros(1,n+1))) ; 102 | end 103 | 104 | if ~opts.skipForward 105 | res(1).x = x ; 106 | end 107 | 108 | % ------------------------------------------------------------------------- 109 | % Forward pass 110 | % ------------------------------------------------------------------------- 111 | 112 | for i=1:n 113 | if opts.skipForward, break; end; 114 | l = net.layers{i} ; 115 | res(i).time = tic ; 116 | switch l.type 117 | case 'conv' 118 | res(i+1).x = vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, ... 119 | 'pad', l.pad, ... 120 | 'stride', l.stride, ... 121 | 'dilate', l.dilate, ... 122 | l.opts{:}, ... 123 | cudnn{:}) ; 124 | 125 | case 'concat' 126 | if size(degpar,1)~=size(res(i).x,1) 127 | sigmaMap = bsxfun(@times,ones(size(res(i).x,1),size(res(i).x,2),1,size(res(i).x,4),'single'),permute(degpar,[3 4 1 2])); 128 | res(i+1).x = cat(3,res(i).x,sigmaMap); 129 | else 130 | res(i+1).x = cat(3,res(i).x,sigmaMap); 131 | end 132 | 133 | case 'convt' 134 | res(i+1).x = vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, ... 135 | 'crop', l.crop, ... 136 | 'upsample', l.upsample, ... 137 | 'numGroups', l.numGroups, ... 138 | l.opts{:}, ... 139 | cudnn{:}) ; 140 | 141 | case 'SubP' 142 | res(i+1).x = vl_nnSubP(res(i).x, [],'scale',l.scale); 143 | 144 | case 'loss' 145 | res(i+1).x = vl_nnloss(res(i).x, l.class) ; 146 | 147 | case 'relu' 148 | if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end 149 | res(i+1).x = vl_nnrelu(res(i).x,[],leak{:}) ; 150 | 151 | case 'sigmoid' 152 | res(i+1).x = vl_nnsigmoid(res(i).x) ; 153 | 154 | case 'bnorm' 155 | if testMode 156 | res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, ... 157 | 'moments', l.weights{3}, ... 158 | 'epsilon', l.epsilon, ... 159 | bnormCudnn{:}) ; 160 | else 161 | res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, ... 162 | 'epsilon', l.epsilon, ... 163 | bnormCudnn{:}) ; 164 | end 165 | 166 | case 'custom' 167 | res(i+1) = l.forward(l, res(i), res(i+1)) ; 168 | 169 | otherwise 170 | error('Unknown layer type ''%s''.', l.type) ; 171 | end 172 | 173 | % optionally forget intermediate results 174 | needsBProp = doder && i >= backPropLim; 175 | forget = opts.conserveMemory && ~needsBProp ; 176 | if i > 1 177 | lp = net.layers{i-1} ; 178 | % forget RELU input, even for BPROP 179 | forget = forget && (~needsBProp || (strcmp(l.type, 'relu') && ~lp.precious)) ; 180 | forget = forget && ~(strcmp(lp.type, 'loss') || strcmp(lp.type, 'softmaxloss')) ; 181 | forget = forget && ~lp.precious ; 182 | end 183 | if forget 184 | res(i).x = [] ; 185 | end 186 | 187 | if gpuMode && opts.sync 188 | wait(gpuDevice) ; 189 | end 190 | res(i).time = toc(res(i).time) ; 191 | end 192 | 193 | % ------------------------------------------------------------------------- 194 | % Backward pass 195 | % ------------------------------------------------------------------------- 196 | 197 | if doder 198 | res(n+1).dzdx = dzdy ; 199 | for i=n:-1:backPropLim 200 | l = net.layers{i} ; 201 | res(i).backwardTime = tic ; 202 | switch l.type 203 | 204 | case 'conv' 205 | [res(i).dzdx, dzdw{1}, dzdw{2}] = ... 206 | vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 207 | 'pad', l.pad, ... 208 | 'stride', l.stride, ... 209 | 'dilate', l.dilate, ... 210 | l.opts{:}, ... 211 | cudnn{:}) ; 212 | 213 | case 'convt' 214 | [res(i).dzdx, dzdw{1}, dzdw{2}] = ... 215 | vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 216 | 'crop', l.crop, ... 217 | 'upsample', l.upsample, ... 218 | 'numGroups', l.numGroups, ... 219 | l.opts{:}, ... 220 | cudnn{:}) ; 221 | 222 | case 'bicubic' 223 | res(i).dzdx = vl_nnbicubic(res(i).x, res(i+1).dzdx, 'scale',l.scale) ; 224 | 225 | case 'SubP' 226 | res(i).dzdx = vl_nnSubP(res(i).x, res(i+1).dzdx,'scale',l.scale); 227 | 228 | case 'loss' 229 | res(i).dzdx = vl_nnloss(res(i).x, l.class, res(i+1).dzdx) ; 230 | 231 | case 'relu' 232 | if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end 233 | if ~isempty(res(i).x) 234 | res(i).dzdx = vl_nnrelu(res(i).x, res(i+1).dzdx, leak{:}) ; 235 | else 236 | % if res(i).x is empty, it has been optimized away, so we use this 237 | % hack (which works only for ReLU): 238 | res(i).dzdx = vl_nnrelu(res(i+1).x, res(i+1).dzdx, leak{:}) ; 239 | end 240 | 241 | 242 | case 'bnorm' 243 | [res(i).dzdx, dzdw{1}, dzdw{2}, dzdw{3}] = ... 244 | vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 245 | 'epsilon', l.epsilon, ... 246 | bnormCudnn{:}) ; 247 | % multiply the moments update by the number of images in the batch 248 | % this is required to make the update additive for subbatches 249 | % and will eventually be normalized away 250 | dzdw{3} = dzdw{3} * size(res(i).x,4) ; 251 | 252 | case 'pdist' 253 | res(i).dzdx = vl_nnpdist(res(i).x, l.class, ... 254 | l.p, res(i+1).dzdx, ... 255 | 'noRoot', l.noRoot, ... 256 | 'epsilon', l.epsilon, ... 257 | 'aggregate', l.aggregate, ... 258 | 'instanceWeights', l.instanceWeights) ; 259 | 260 | case 'custom' 261 | res(i) = l.backward(l, res(i), res(i+1)) ; 262 | 263 | end % layers 264 | 265 | switch l.type 266 | case {'conv','convt', 'bnorm'} 267 | if ~opts.accumulate 268 | res(i).dzdw = dzdw ; 269 | else 270 | for j=1:numel(dzdw) 271 | res(i).dzdw{j} = res(i).dzdw{j} + dzdw{j} ; 272 | end 273 | end 274 | dzdw = [] ; 275 | if ~isempty(opts.parameterServer) && ~opts.holdOn 276 | for j = 1:numel(res(i).dzdw) 277 | opts.parameterServer.push(sprintf('l%d_%d',i,j),res(i).dzdw{j}) ; 278 | res(i).dzdw{j} = [] ; 279 | end 280 | end 281 | end 282 | if opts.conserveMemory && ~net.layers{i}.precious && i ~= n 283 | res(i+1).dzdx = [] ; 284 | res(i+1).x = [] ; 285 | end 286 | if gpuMode && opts.sync 287 | wait(gpuDevice) ; 288 | end 289 | res(i).backwardTime = toc(res(i).backwardTime) ; 290 | end 291 | if i > 1 && i == backPropLim && opts.conserveMemory && ~net.layers{i}.precious 292 | res(i).dzdx = [] ; 293 | res(i).x = [] ; 294 | end 295 | end 296 | -------------------------------------------------------------------------------- /utilities/vl_srmd_concise.m: -------------------------------------------------------------------------------- 1 | function res = vl_srmd_concise(net, x) 2 | 3 | global degpar; 4 | n = numel(net.layers); 5 | res = struct('x', cell(1,n+1)); 6 | res(1).x = x ; 7 | cudnn = {'CuDNN'} ; 8 | %cudnn = {'NoCuDNN'} ; 9 | 10 | for i=1:n 11 | l = net.layers{i} ; 12 | switch l.type 13 | case 'conv' 14 | res(i+1).x = vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, ... 15 | 'pad', l.pad, ... 16 | 'stride', l.stride, ... 17 | 'dilate', l.dilate, ... 18 | l.opts{:}, ... 19 | cudnn{:}) ; 20 | 21 | case 'concat' 22 | if size(degpar,1)~=size(res(i).x,1) 23 | sigmaMap = bsxfun(@times,ones(size(res(i).x,1),size(res(i).x,2),1,size(res(i).x,4),'single'),permute(degpar,[3 4 1 2])); 24 | res(i+1).x = cat(3,res(i).x,sigmaMap); 25 | else 26 | res(i+1).x = cat(3,res(i).x,sigmaMap); 27 | end 28 | 29 | case 'SubP' 30 | res(i+1).x = vl_nnSubP(res(i).x, [],'scale',l.scale); 31 | 32 | case 'relu' 33 | res(i+1).x = max(res(i).x,0) ; 34 | end 35 | res(i).x = [] ; 36 | end 37 | 38 | 39 | -------------------------------------------------------------------------------- /utilities/vl_srmd_matlab.m: -------------------------------------------------------------------------------- 1 | function res = vl_srmd_matlab(net, input) 2 | 3 | %% If you did not install the matconvnet package, you can use this for testing. 4 | 5 | global degpar; 6 | n = numel(net.layers); 7 | res = struct('x', cell(1,n+1)); 8 | res(1).x = input; 9 | 10 | for i = 1 : n 11 | l = net.layers{i}; 12 | switch l.type 13 | 14 | case 'conv' 15 | disp(['Processing ... ',int2str(i),'/',int2str(n)]); 16 | for noutmaps = 1 : size(l.weights{1},4) 17 | z = zeros(size(res(i).x,1),size(res(i).x,2),'single'); 18 | for ninmaps = 1 : size(res(i).x,3) 19 | z = z + convn(res(i).x(:,:,ninmaps), rot90(l.weights{1}(:,:,ninmaps,noutmaps),2),'same'); % 180 degree rotation for kernel 20 | end 21 | res(i+1).x(:,:,noutmaps) = z + l.weights{2}(noutmaps); 22 | end 23 | 24 | case 'relu' 25 | res(i+1).x = max(res(i).x,0); 26 | 27 | case 'concat' 28 | if size(degpar,1)~=size(res(i).x,1) 29 | sigmaMap = bsxfun(@times,ones(size(res(i).x,1),size(res(i).x,2),1,size(res(i).x,4),'single'),permute(degpar,[3 4 1 2])); 30 | res(i+1).x = cat(3,res(i).x,sigmaMap); 31 | else 32 | res(i+1).x = cat(3,res(i).x,sigmaMap); 33 | end 34 | 35 | case 'SubP' 36 | res(i+1).x = vl_nnSubP(res(i).x, [],'scale',l.scale); 37 | 38 | end 39 | res(i).x = []; 40 | end 41 | 42 | end 43 | --------------------------------------------------------------------------------