diff options
| -rw-r--r-- | data/DendrRawData.mat | bin | 0 -> 15177638 bytes | |||
| -rw-r--r-- | data/sino3D_dendrites.mat | bin | 27797233 -> 0 bytes | |||
| -rw-r--r-- | demo/Demo2.m | 156 | ||||
| -rw-r--r-- | demo/DemoRD2.m | 130 | ||||
| -rw-r--r-- | demos/Demo1.m (renamed from demo/Demo1.m) | 332 | ||||
| -rw-r--r-- | demos/DemoRD1.m (renamed from demo/DemoRD1.m) | 65 | ||||
| -rw-r--r-- | demos/DemoRD2.m | 126 | ||||
| -rw-r--r-- | license.txt | 27 | ||||
| -rw-r--r-- | main_func/FGP_TV.c | 400 | ||||
| -rw-r--r-- | main_func/FISTA_REC.m | 291 | ||||
| -rw-r--r-- | main_func/FISTA_TV.c | 331 | ||||
| -rw-r--r-- | main_func/LLT_model.c | 2 | ||||
| -rw-r--r-- | main_func/SplitBregman_TV.c | 317 | ||||
| -rw-r--r-- | main_func/compile_mex.m | 4 | ||||
| -rw-r--r-- | main_func/studentst.m | 94 | ||||
| -rw-r--r-- | supp/RMSE.m | 12 | ||||
| -rw-r--r-- | supp/add_wedges.m | 7 | ||||
| -rw-r--r-- | supp/zing_rings_add.m | 45 | 
18 files changed, 1155 insertions, 1184 deletions
| diff --git a/data/DendrRawData.mat b/data/DendrRawData.matBinary files differ new file mode 100644 index 0000000..2de7f0c --- /dev/null +++ b/data/DendrRawData.mat diff --git a/data/sino3D_dendrites.mat b/data/sino3D_dendrites.matBinary files differ deleted file mode 100644 index dc1400d..0000000 --- a/data/sino3D_dendrites.mat +++ /dev/null diff --git a/demo/Demo2.m b/demo/Demo2.m deleted file mode 100644 index 3c1592c..0000000 --- a/demo/Demo2.m +++ /dev/null @@ -1,156 +0,0 @@ -% Demonstration of tomographic reconstruction from noisy and corrupted by  -% artifacts undersampled projection data using Students t penalty  -% This is the missing wedge demo, run it after DemoFISTA_StudT - -% see ReadMe file for instructions -% clear all -% close all  - -load phantom_bone512.mat % load the phantom -load  my_red_yellowMAP.mat % load the colormap -% load sino1.mat; % load noisy sinogram - -N = 512; %  the size of the tomographic image NxN -theta = 1:1:180; % acquisition angles (in parallel beam from 0 to Pi) -theta_rad = theta*(pi/180); % conversion to radians -P = 2*ceil(N/sqrt(2))+1; % the size of the detector array -ROI = find(phantom > 0.0); - -add_wedges % apply the missing wedge mask - -%%  -fprintf('%s\n', 'Direct reconstruction using FBP...'); -FBP_1 = iradon(MW_sino_artifacts', theta, N);  - -fprintf('%s %.4f\n', 'RMSE for FBP reconstruction:', RMSE(FBP_1(:), phantom(:))); - -figure(1);  -% set(gcf, 'Position', get(0,'Screensize')); -subplot_tight(1,2,1, [0.05 0.05]);  imshow(FBP_1,[-2 0.8]);  title('FBP reconstruction of noisy and corrupted by artifacts sinogram'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]);  imshow((phantom - FBP_1).^2,[0 0.1]);  title('residual: (ideal phantom - FBP)^2'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-LS without regularization...'); -clear params -% define parameters -params.sino = MW_sino_artifacts; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 132; %max number of outer iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -params.weights = Dweights; % statistical weighting  -tic; [X_FISTA, error_FISTA, obj_FISTA, sinoFISTA] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS reconstruction:', min(error_FISTA(:))); - -figure(2); clf -%set(gcf, 'Position', get(0,'Screensize')); -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA,[0 0.6]); title('FISTA-LS reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  -figure(3); clf -subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-LS-TV...'); -clear params -% define parameters -params.sino = MW_sino_artifacts; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 200; % max number of outer iterations -params.lambdaTV = 5.39e-05; % regularization parameter for TV problem -params.tol = 1.0e-04; % tolerance to terminate TV iterations -params.iterTV = 20; % the max number of TV iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.weights = Dweights; % statistical weighting  -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -tic; [X_FISTA_TV, error_FISTA_TV, obj_FISTA_TV, sinoFISTA_TV] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS-TV reconstruction:', min(error_FISTA_TV(:))); - -figure(4); clf -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_TV,[0 0.6]); title('FISTA-LS-TV reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA_TV).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  -figure(5); clf -subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA_TV);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA_TV);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-GH-TV...'); -clear params -% define parameters -params.sino = MW_sino_artifacts; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 250; % max number of outer iterations -params.lambdaTV = 0.0019;  % regularization parameter for TV problem -params.tol = 1.0e-04; % tolerance to terminate TV iterations -params.iterTV = 20; % the max number of TV iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.weights = Dweights; % statistical weighting  -params.lambdaR_L1 = 0.002; % parameter to sparsify the "rings vector" -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -tic; [X_FISTA_GH_TV, error_FISTA_GH_TV, obj_FISTA_GH_TV, sinoFISTA_GH_TV] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-GH-TV reconstruction:', min(error_FISTA_GH_TV(:))); - -figure(6); clf -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_GH_TV,[0 0.6]); title('FISTA-GH-TV reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]);imshow((phantom - X_FISTA_GH_TV).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  - -figure(7); clf -subplot_tight(1,2,1, [0.05 0.05]);  plot(error_FISTA_GH_TV);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]);  plot(obj_FISTA_GH_TV);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-Student-TV...'); -clear params -% define parameters -params.sino = MW_sino_artifacts; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 80; % max number of outer iterations -% params.L_const = 80000; % Lipshitz constant (can be chosen manually to accelerate convergence) -params.lambdaTV = 0.0016;  % regularization parameter for TV problem -params.tol = 1.0e-04; % tolerance to terminate TV iterations -params.iterTV = 20; % the max number of TV iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.weights = Dweights; % statistical weighting  -params.fidelity = 'student'; % selecting students t fidelity -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -tic; [X_FISTA_student_TV, error_FISTA_student_TV, obj_FISTA_student_TV, sinoFISTA_student_TV] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-Student-TV reconstruction:', min(error_FISTA_student_TV(:))); - -figure(8);  -set(gcf, 'Position', get(0,'Screensize')); -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_student_TV,[0 0.6]); title('FISTA-Student-TV reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA_student_TV).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  - -figure(9);  -subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA_student_TV);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA_student_TV);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -% print all RMSE's -fprintf('%s\n', '--------------------------------------------'); -fprintf('%s %.4f\n', 'RMSE for FBP reconstruction:', RMSE(FBP_2(:), phantom(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS reconstruction:', min(error_FISTA(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS-TV reconstruction:', min(error_FISTA_TV(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-GH-TV reconstruction:', min(error_FISTA_GH_TV(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-Student-TV reconstruction:', min(error_FISTA_student_TV(:))); -%
\ No newline at end of file diff --git a/demo/DemoRD2.m b/demo/DemoRD2.m deleted file mode 100644 index a8ac2ca..0000000 --- a/demo/DemoRD2.m +++ /dev/null @@ -1,130 +0,0 @@ -% Demonstration of tomographic 3D reconstruction from X-ray synchrotron  -% dataset (dendrites) using various data fidelities  -% clear all -% close all  -%  -% % adding paths - addpath('data/');  - addpath('main_func/');  - addpath('supp/');  - -load('sino3D_dendrites.mat') % load 3D normalized sinogram -angles_rad = angles*(pi/180); % conversion to radians - -angSize = size(Sino3D,1); % angles dim -size_det = size(Sino3D, 2); % detector size -recon_size = 850; % reconstruction size - -FBP = iradon(Sino3D(:,:,10)', angles,recon_size); -figure; imshow(FBP , [0, 3]); title ('FBP reconstruction'); - -%% -fprintf('%s\n', 'Reconstruction using FISTA-LS without regularization...'); -clear params -params.sino = Sino3D; -params.N  = recon_size; -params.angles = angles_rad; -params.iterFISTA  = 80; -params.precondition  = 1; % switch on preconditioning -params.show = 0; -params.maxvalplot = 2.5; params.slice = 10; - -tic; [X_fista] = FISTA_REC(params); toc; -figure; imshow(X_fista(:,:,10) , [0, 2.5]); title ('FISTA-LS reconstruction'); -%% -fprintf('%s\n', 'Reconstruction using FISTA-LS-TV...'); -clear params -params.sino = Sino3D; -params.N  = recon_size; -params.angles = angles_rad; -params.iterFISTA  = 100; -params.lambdaTV = 0.001; % TV regularization parameter for FISTA-TV -params.tol = 1.0e-04; -params.iterTV = 20; -params.precondition  = 1; % switch on preconditioning -params.show = 0; -params.maxvalplot = 2.5; params.slice = 10; - -tic; [X_fista_TV] = FISTA_REC(params); toc; -figure; imshow(X_fista_TV(:,:,10) , [0, 2.5]); title ('FISTA-LS-TV reconstruction'); -%% -%% -fprintf('%s\n', 'Reconstruction using FISTA-GH-TV...'); -clear params -params.sino = Sino3D; -params.N  = recon_size; -params.angles = angles_rad; -params.iterFISTA  = 100; -params.lambdaTV = 0.001; % TV regularization parameter for FISTA-TV -params.tol = 1.0e-04; -params.iterTV = 20; -params.lambdaR_L1 = 0.001; % Soft-Thresh L1 ring variable parameter -params.alpha_ring = 20; % to boost ring removal procedure -params.precondition  = 1; % switch on preconditioning -params.show = 0; -params.maxvalplot = 2.5; params.slice = 10; - -tic; [X_fista_GH_TV] = FISTA_REC(params); toc; -figure; imshow(X_fista_GH_TV(:,:,10) , [0, 2.5]); title ('FISTA-GH-TV reconstruction'); -%% -%% -fprintf('%s\n', 'Reconstruction using FISTA-GH-TV-LLT...'); -clear params -params.sino = Sino3D; -params.N  = recon_size; -params.angles = angles_rad; -params.iterFISTA  = 100; -params.lambdaTV = 0.001; % TV regularization parameter for FISTA-TV -params.tol = 1.0e-04; -params.iterTV = 20; -params.lambdaHO = 35;  % regularization parameter for LLT problem -params.tauHO = 0.00011; % time-step parameter for explicit scheme -params.iterHO = 70; % the max number of TV iterations    -params.lambdaR_L1 = 0.001; % Soft-Thresh L1 ring variable parameter -params.alpha_ring = 20; % to boost ring removal procedure -params.precondition  = 1; % switch on preconditioning -params.show = 0; -params.maxvalplot = 2.5; params.slice = 10; - -tic; [X_fista_GH_TVLLT] = FISTA_REC(params); toc; -figure; imshow(X_fista_GH_TVLLT(:,:,10) , [0, 2.5]); title ('FISTA-GH-TV-LLT reconstruction'); -%% -%% -% fprintf('%s\n', 'Reconstruction using FISTA-Student-TV...'); -% %%%%<<<< Not stable with this dataset! Requires more work >>>> %%%%% -% clear params -% params.sino = Sino3D(:,:,15); -% params.N  = 950; -% params.angles = angles_rad; -% params.iterFISTA  = 150; -% params.L_const = 30; % Lipshitz constant -% params.lambdaTV = 0.009; % TV regularization parameter for FISTA-TV -% params.tol = 1.0e-04; -% params.iterTV = 20; -% params.fidelity = 'student'; % choosing Student t penalty -% % params.precondition  = 1; % switch on preconditioning -% params.show = 1; -% params.maxvalplot = 2.5; params.slice = 1; -%  -% tic; [X_fistaStudentTV] = FISTA_REC(params); toc; -% figure; imshow(X_fistaStudentTV , [0, 2.5]); title ('FISTA-Student-TV reconstruction'); -%% -slice = 10; % if 3D reconstruction - -fprintf('%s\n', 'Segmentation using OTSU method ...'); -level = graythresh(X_fista(:,:,slice)); -Segm_FISTA = im2bw(X_fista(:,:,slice),level); -figure; imshow(Segm_FISTA, []); title ('Segmented FISTA-LS reconstruction'); - -level = graythresh(X_fista_TV(:,:,slice)); -Segm_FISTA_TV = im2bw(X_fista_TV(:,:,slice),level); -figure; imshow(Segm_FISTA_TV, []); title ('Segmented FISTA-LS-TV reconstruction'); - -level = graythresh(X_fista_GH_TV(:,:,slice)); -BW_FISTA_GH_TV = im2bw(X_fista_GH_TV(:,:,slice),level); -figure; imshow(BW_FISTA_GH_TV, []); title ('Segmented FISTA-GH-TV reconstruction'); - -level = graythresh(X_fista_GH_TVLLT(:,:,slice)); -BW_FISTA_GH_TVLLT = im2bw(X_fista_GH_TVLLT(:,:,slice),level); -figure; imshow(BW_FISTA_GH_TVLLT, []); title ('Segmented FISTA-GH-TV-LLT reconstruction'); -%%
\ No newline at end of file diff --git a/demo/Demo1.m b/demos/Demo1.m index 08d46e1..486b97c 100644 --- a/demo/Demo1.m +++ b/demos/Demo1.m @@ -1,160 +1,174 @@ -% Demonstration of tomographic reconstruction from noisy and corrupted by  -% artifacts undersampled projection data using Students't penalty  -% Optimisation problem is solved using FISTA algorithm (see Beck & Teboulle) - -% see ReadMe file for instructions -clear all -close all  - -% adding paths -addpath('data/');  -addpath('main_func/');  -addpath('supp/');  - -load phantom_bone512.mat % load the phantom -load  my_red_yellowMAP.mat % load the colormap -% load sino1.mat; % load noisy sinogram - -N = 512; %  the size of the tomographic image NxN -theta = 1:1:180; % acquisition angles (in parallel beam from 0 to Pi) -theta_rad = theta*(pi/180); % conversion to radians -P = 2*ceil(N/sqrt(2))+1; % the size of the detector array -ROI = find(phantom > 0); - -zing_rings_add;    % generating data, adding zingers and stripes - -%%  -fprintf('%s\n', 'Direct reconstruction using FBP...'); -FBP_1 = iradon(sino_zing_rings', theta, N);  - -fprintf('%s %.4f\n', 'RMSE for FBP reconstruction:', RMSE(FBP_1(:), phantom(:))); - -figure(1);  -subplot_tight(1,2,1, [0.05 0.05]); imshow(FBP_1,[0 0.6]);  title('FBP reconstruction of noisy and corrupted by artifacts sinogram'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - FBP_1).^2,[0 0.1]);  title('residual: (ideal phantom - FBP)^2'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-LS without regularization...'); -clear params -% define parameters -params.sino = sino_zing_rings; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 180; %max number of outer iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -params.weights = Dweights; % statistical weighting  -tic; [X_FISTA, error_FISTA, obj_FISTA, sinoFISTA] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS reconstruction is:', min(error_FISTA(:))); - -figure(2); clf -%set(gcf, 'Position', get(0,'Screensize')); -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA,[0 0.6]); title('FISTA-LS reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  -figure(3); clf -subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-LS-TV...'); -clear params -% define parameters -params.sino = sino_zing_rings; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 200; % max number of outer iterations -params.lambdaTV = 5.39e-05; % regularization parameter for TV problem -params.tol = 1.0e-04; % tolerance to terminate TV iterations -params.iterTV = 20; % the max number of TV iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.weights = Dweights; % statistical weighting  -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -tic; [X_FISTA_TV, error_FISTA_TV, obj_FISTA_TV, sinoFISTA_TV] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS-TV reconstruction is:', min(error_FISTA_TV(:))); - -figure(4); clf -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_TV,[0 0.6]); title('FISTA-LS-TV reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA_TV).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  -figure(5); clf -subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA_TV);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA_TV);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-GH-TV...'); -clear params -% define parameters -params.sino = sino_zing_rings; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 60; % max number of outer iterations -params.lambdaTV = 0.002526;  % regularization parameter for TV problem -params.tol = 1.0e-04; % tolerance to terminate TV iterations -params.iterTV = 20; % the max number of TV iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.weights = Dweights; % statistical weighting  -params.lambdaR_L1 = 0.002; % parameter to sparsify the "rings vector" -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -tic; [X_FISTA_GH_TV, error_FISTA_GH_TV, obj_FISTA_GH_TV, sinoFISTA_GH_TV] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-GH-TV reconstruction is:', min(error_FISTA_GH_TV(:))); - -figure(6); clf -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_GH_TV,[0 0.6]); title('FISTA-GH-TV reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]);imshow((phantom - X_FISTA_GH_TV).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  - -figure(7); clf -subplot_tight(1,2,1, [0.05 0.05]);  plot(error_FISTA_GH_TV);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]);  plot(obj_FISTA_GH_TV);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -fprintf('%s\n', 'Reconstruction using FISTA-Student-TV...'); -clear params -% define parameters -params.sino = sino_zing_rings; -params.N = N; % image size  -params.angles = theta_rad; % angles in radians  -params.iterFISTA = 67; % max number of outer iterations -%params.L_const = 80000; % Lipshitz constant (can be chosen manually to accelerate convergence) -params.lambdaTV = 0.00152;  % regularization parameter for TV problem -params.tol = 1.0e-04; % tolerance to terminate TV iterations -params.iterTV = 20; % the max number of TV iterations -params.X_ideal = phantom; % ideal phantom -params.ROI = ROI; % phantom region-of-interest -params.weights = Dweights; % statistical weighting  -params.fidelity = 'student'; % selecting students t fidelity -params.show = 0; % visualize reconstruction on each iteration -params.slice = 1; params.maxvalplot = 0.6;  -tic; [X_FISTA_student_TV, error_FISTA_student_TV, obj_FISTA_student_TV, sinoFISTA_student_TV] = FISTA_REC(params); toc;  - -fprintf('%s %.4f\n', 'Min RMSE for FISTA-Student-TV reconstruction is:', min(error_FISTA_student_TV(:))); - -figure(8);  -set(gcf, 'Position', get(0,'Screensize')); -subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_student_TV,[0 0.6]); title('FISTA-Student-TV reconstruction'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA_student_TV).^2,[0 0.1]);  title('residual'); colorbar; -colormap(cmapnew);  - -figure(9);  -subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA_student_TV);  title('RMSE plot'); colorbar; -subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA_student_TV);  title('Objective plot'); colorbar; -colormap(cmapnew);  -%% -% print all RMSE's -fprintf('%s\n', '--------------------------------------------'); -fprintf('%s %.4f\n', 'RMSE for FBP reconstruction:', RMSE(FBP_2(:), phantom(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS reconstruction:', min(error_FISTA(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-LS-TV reconstruction:', min(error_FISTA_TV(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-GH-TV reconstruction:', min(error_FISTA_GH_TV(:))); -fprintf('%s %.4f\n', 'Min RMSE for FISTA-Student-TV reconstruction:', min(error_FISTA_student_TV(:))); +% Demonstration of tomographic reconstruction from noisy and corrupted by 
 +% artifacts undersampled projection data using Students't penalty 
 +% Optimisation problem is solved using FISTA algorithm (see Beck & Teboulle)
 +
 +% see Readme file for instructions
 +%%
 +% compile MEX-files ones
 +% cd ..
 +% cd main_func
 +% compile_mex
 +% cd .. 
 +% cd demos
 +%%
 +
 +close all;clc;clear all;
 +% adding paths
 +addpath('../data/'); 
 +addpath('../main_func/'); 
 +addpath('../supp/'); 
 +
 +load phantom_bone512.mat % load the phantom
 +load  my_red_yellowMAP.mat % load the colormap
 +% load sino1.mat; % load noisy sinogram
 +
 +N = 512; %  the size of the tomographic image NxN
 +theta = 1:1:180; % acquisition angles (in parallel beam from 0 to Pi)
 +theta_rad = theta*(pi/180); % conversion to radians
 +P = 2*ceil(N/sqrt(2))+1; % the size of the detector array
 +ROI = find(phantom > 0);
 +
 +% using ASTRA to set the projection geometry
 +% potentially parallel geometry can be replaced with a divergent one
 +Z_slices = 1;
 +det_row_count = Z_slices;
 +proj_geom = astra_create_proj_geom('parallel3d', 1, 1, det_row_count, P, theta_rad);
 +vol_geom = astra_create_vol_geom(N,N,Z_slices);
 +
 +zing_rings_add;    % generating data, adding zingers and stripes
 +%% 
 +fprintf('%s\n', 'Direct reconstruction using FBP...');
 +FBP_1 = iradon(sino_zing_rings', theta, N); 
 +
 +fprintf('%s %.4f\n', 'RMSE for FBP reconstruction:', RMSE(FBP_1(:), phantom(:)));
 +
 +figure(1); 
 +subplot_tight(1,2,1, [0.05 0.05]); imshow(FBP_1,[0 0.6]);  title('FBP reconstruction of noisy and corrupted by artifacts sinogram'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - FBP_1).^2,[0 0.1]);  title('residual: (ideal phantom - FBP)^2'); colorbar;
 +colormap(cmapnew); 
 +
 +%%
 +fprintf('%s\n', 'Reconstruction using FISTA-PWLS without regularization...');
 +clear params
 +% define parameters
 +params.proj_geom = proj_geom; % pass geometry to the function
 +params.vol_geom = vol_geom;
 +params.sino = sino_zing_rings; % sinogram
 +params.iterFISTA = 45; %max number of outer iterations
 +params.X_ideal = phantom; % ideal phantom
 +params.ROI = ROI; % phantom region-of-interest
 +params.show = 1; % visualize reconstruction on each iteration
 +params.slice = 1; params.maxvalplot = 0.6; 
 +params.weights = Dweights; % statistical weighting 
 +tic; [X_FISTA, output] = FISTA_REC(params); toc; 
 +
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-PWLS reconstruction is:', min(error_FISTA(:)));
 +error_FISTA = output.Resid_error; obj_FISTA = output.objective;
 +
 +figure(2); clf
 +%set(gcf, 'Position', get(0,'Screensize'));
 +subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA,[0 0.6]); title('FISTA-PWLS reconstruction'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA).^2,[0 0.1]);  title('residual'); colorbar;
 +colormap(cmapnew); 
 +figure(3); clf
 +subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA);  title('RMSE plot'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA);  title('Objective plot'); colorbar;
 +colormap(cmapnew); 
 +%%
 +fprintf('%s\n', 'Reconstruction using FISTA-PWLS-TV...');
 +clear params
 +% define parameters
 +params.proj_geom = proj_geom; % pass geometry to the function
 +params.vol_geom = vol_geom;
 +params.sino = sino_zing_rings;
 +params.iterFISTA = 45; % max number of outer iterations
 +params.Regul_LambdaTV = 0.0015; % regularization parameter for TV problem
 +params.X_ideal = phantom; % ideal phantom
 +params.ROI = ROI; % phantom region-of-interest
 +params.weights = Dweights; % statistical weighting 
 +params.show = 1; % visualize reconstruction on each iteration
 +params.slice = 1; params.maxvalplot = 0.6; 
 +tic; [X_FISTA_TV, output] = FISTA_REC(params); toc; 
 +
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-PWLS-TV reconstruction is:', min(error_FISTA_TV(:)));
 +error_FISTA_TV = output.Resid_error; obj_FISTA_TV = output.objective;
 +
 +figure(4); clf
 +subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_TV,[0 0.6]); title('FISTA-PWLS-TV reconstruction'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA_TV).^2,[0 0.1]);  title('residual'); colorbar;
 +colormap(cmapnew); 
 +figure(5); clf
 +subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA_TV);  title('RMSE plot'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA_TV);  title('Objective plot'); colorbar;
 +colormap(cmapnew); 
 +%%
 +fprintf('%s\n', 'Reconstruction using FISTA-GH-TV...');
 +clear params
 +% define parameters
 +params.proj_geom = proj_geom; % pass geometry to the function
 +params.vol_geom = vol_geom;
 +params.sino = sino_zing_rings;
 +params.iterFISTA = 50; % max number of outer iterations
 +params.Regul_LambdaTV = 0.0015;  % regularization parameter for TV problem
 +params.X_ideal = phantom; % ideal phantom
 +params.ROI = ROI; % phantom region-of-interest
 +params.weights = Dweights; % statistical weighting 
 +params.Ring_LambdaR_L1 = 0.002; % parameter to sparsify the "rings vector"
 +params.Ring_Alpha = 20; % to accelerate ring-removal procedure
 +params.show = 0; % visualize reconstruction on each iteration
 +params.slice = 1; params.maxvalplot = 0.6; 
 +tic; [X_FISTA_GH_TV, output] = FISTA_REC(params); toc; 
 +
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-GH-TV reconstruction is:', min(error_FISTA_GH_TV(:)));
 +error_FISTA_GH_TV = output.Resid_error; obj_FISTA_GH_TV = output.objective;
 +
 +figure(6); clf
 +subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_GH_TV,[0 0.6]); title('FISTA-GH-TV reconstruction'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]);imshow((phantom - X_FISTA_GH_TV).^2,[0 0.1]);  title('residual'); colorbar;
 +colormap(cmapnew); 
 +
 +figure(7); clf
 +subplot_tight(1,2,1, [0.05 0.05]);  plot(error_FISTA_GH_TV);  title('RMSE plot'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]);  plot(obj_FISTA_GH_TV);  title('Objective plot'); colorbar;
 +colormap(cmapnew); 
 +%%
 +fprintf('%s\n', 'Reconstruction using FISTA-Student-TV...');
 +clear params
 +% define parameters
 +params.proj_geom = proj_geom; % pass geometry to the function
 +params.vol_geom = vol_geom;
 +params.sino = sino_zing_rings;
 +params.iterFISTA = 55; % max number of outer iterations
 +params.L_const = 0.1; % Lipshitz constant (can be chosen manually to accelerate convergence)
 +params.Regul_LambdaTV = 0.00152;  % regularization parameter for TV problem
 +params.X_ideal = phantom; % ideal phantom
 +params.ROI = ROI; % phantom region-of-interest
 +params.weights = Dweights; % statistical weighting 
 +params.fidelity = 'student'; % selecting students t fidelity
 +params.show = 1; % visualize reconstruction on each iteration
 +params.slice = 1; params.maxvalplot = 0.6; 
 +params.initilize = 1; % warm start with SIRT
 +tic; [X_FISTA_student_TV, output] = FISTA_REC(params); toc; 
 +
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-Student-TV reconstruction is:', min(error_FISTA_student_TV(:)));
 +error_FISTA_student_TV = output.Resid_error; obj_FISTA_student_TV = output.objective;
 +
 +figure(8); 
 +set(gcf, 'Position', get(0,'Screensize'));
 +subplot_tight(1,2,1, [0.05 0.05]); imshow(X_FISTA_student_TV,[0 0.6]); title('FISTA-Student-TV reconstruction'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); imshow((phantom - X_FISTA_student_TV).^2,[0 0.1]);  title('residual'); colorbar;
 +colormap(cmapnew); 
 +
 +figure(9); 
 +subplot_tight(1,2,1, [0.05 0.05]); plot(error_FISTA_student_TV);  title('RMSE plot'); colorbar;
 +subplot_tight(1,2,2, [0.05 0.05]); plot(obj_FISTA_student_TV);  title('Objective plot'); colorbar;
 +colormap(cmapnew); 
 +%%
 +% print all RMSE's
 +fprintf('%s\n', '--------------------------------------------');
 +fprintf('%s %.4f\n', 'RMSE for FBP reconstruction:', RMSE(FBP_1(:), phantom(:)));
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-PWLS reconstruction:', min(error_FISTA(:)));
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-PWLS-TV reconstruction:', min(error_FISTA_TV(:)));
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-GH-TV reconstruction:', min(error_FISTA_GH_TV(:)));
 +fprintf('%s %.4f\n', 'Min RMSE for FISTA-Student-TV reconstruction:', min(error_FISTA_student_TV(:)));
  %
\ No newline at end of file diff --git a/demo/DemoRD1.m b/demos/DemoRD1.m index 9a43cb5..c25bb3e 100644 --- a/demo/DemoRD1.m +++ b/demos/DemoRD1.m @@ -4,9 +4,9 @@ clear all  close all   % adding paths -addpath('data/');  -addpath('main_func/');  -addpath('supp/');  +addpath('../data/');  +addpath('../main_func/');  +addpath('../supp/');   load('sino_basalt.mat') % load real neutron data @@ -16,13 +16,18 @@ recon_size = 650; % reconstruction size  FBP = iradon(sino_basalt, rad2deg(angles),recon_size);  figure; imshow(FBP , [0, 0.45]); title ('FBP reconstruction'); - +%% +% set projection/reconstruction geometry here +Z_slices = 1; +det_row_count = Z_slices; +proj_geom = astra_create_proj_geom('parallel3d', 1, 1, det_row_count, size_det, angles); +vol_geom = astra_create_vol_geom(recon_size,recon_size,Z_slices);  %%  fprintf('%s\n', 'Reconstruction using FISTA-LS without regularization...');  clear params -params.sino = sino_basalt'; -params.N  = recon_size; -params.angles = angles; +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = sino_basalt;  params.iterFISTA  = 50;  params.show = 0;  params.maxvalplot = 0.6; params.slice = 1; @@ -32,14 +37,12 @@ figure; imshow(X_fista , [0, 0.45]); title ('FISTA-LS reconstruction');  %%  fprintf('%s\n', 'Reconstruction using FISTA-LS-TV...');  clear params -params.sino = sino_basalt'; -params.N  = recon_size; -params.angles = angles; -params.iterFISTA  = 150; -params.lambdaTV = 0.0003; % TV regularization parameter -params.tol = 1.0e-04; -params.iterTV = 20; -params.show = 1; +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = sino_basalt; +params.iterFISTA  = 60; +params.Regul_LambdaTV = 0.0003; % TV regularization parameter +params.show = 0;  params.maxvalplot = 0.6; params.slice = 1;  tic; [X_fista_TV] = FISTA_REC(params); toc; @@ -48,15 +51,14 @@ figure; imshow(X_fista_TV , [0, 0.45]); title ('FISTA-LS-TV reconstruction');  %%  fprintf('%s\n', 'Reconstruction using FISTA-GH-TV...');  clear params -params.sino = sino_basalt'; -params.N  = recon_size; -params.angles = angles; -params.iterFISTA  = 350; -params.lambdaTV = 0.0003; % TV regularization parameter -params.tol = 1.0e-04; -params.iterTV = 20; -params.lambdaR_L1 = 0.001; % Soft-Thresh L1 ring variable parameter -params.show = 1; +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = sino_basalt; +params.iterFISTA  = 60; +params.Regul_LambdaTV = 0.0003; % TV regularization parameter +params.Ring_LambdaR_L1 = 0.001; % Soft-Thresh L1 ring variable parameter +params.Ring_Alpha = 20; % acceleration for ring variable +params.show = 0;  params.maxvalplot = 0.6; params.slice = 1;  tic; [X_fista_GH_TV] = FISTA_REC(params); toc; @@ -65,16 +67,15 @@ figure; imshow(X_fista_GH_TV , [0, 0.45]); title ('FISTA-GH-TV reconstruction');  %%  fprintf('%s\n', 'Reconstruction using FISTA-Student-TV...');  clear params -params.sino = sino_basalt'; -params.N  = recon_size; -params.angles = angles; -params.iterFISTA  = 350; -params.L_const = 7000; % Lipshitz constant -params.lambdaTV = 0.0003; % TV regularization parameter -params.tol = 1.0e-04; -params.iterTV = 20; +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = sino_basalt; +params.iterFISTA  = 50; +params.L_const = 3500; % Lipshitz constant +params.Regul_LambdaTV = 0.0003; % TV regularization parameter  params.fidelity = 'student'; % choosing Student t penalty  params.show = 1; +params.initilize = 1; % warm start with SIRT  params.maxvalplot = 0.6; params.slice = 1;  tic; [X_fistaStudentTV] = FISTA_REC(params); toc; diff --git a/demos/DemoRD2.m b/demos/DemoRD2.m new file mode 100644 index 0000000..ab4da96 --- /dev/null +++ b/demos/DemoRD2.m @@ -0,0 +1,126 @@ +% Demonstration of tomographic 3D reconstruction from X-ray synchrotron +% dataset (dendrites) using various data fidelities +% warning: can take up to 15-20 minutes to run for the whole 3D data +clear all +close all +%% +% % adding paths +addpath('../data/'); +addpath('../main_func/'); +addpath('../supp/'); + +load('DendrRawData.mat') % load raw data of 3D dendritic set +angles_rad = angles*(pi/180); % conversion to radians +size_det = size(data_raw3D,1); % detectors dim +angSize = size(data_raw3D, 2); % angles dim +slices_tot = size(data_raw3D, 3); % no of slices +recon_size = 950; % reconstruction size + +Sino3D = zeros(size_det, angSize, slices_tot, 'single'); % log-corrected sino +% normalizing the data +for  jj = 1:slices_tot +    sino = data_raw3D(:,:,jj); +    for ii = 1:angSize +        Sino3D(:,ii,jj) = log((flats_ar(:,jj)-darks_ar(:,jj))./(single(sino(:,ii)) - darks_ar(:,jj))); +    end +end + +Sino3D = Sino3D.*1000; +Weights3D = single(data_raw3D); % weights for PW model +clear data_raw3D +%% +% set projection/reconstruction geometry here +Z_slices = 20; +det_row_count = Z_slices; +proj_geom = astra_create_proj_geom('parallel3d', 1, 1, det_row_count, size_det, angles_rad); +vol_geom = astra_create_vol_geom(recon_size,recon_size,Z_slices); +%% +fprintf('%s\n', 'Reconstruction using FBP...'); +FBP = iradon(Sino3D(:,:,10), angles,recon_size); +figure; imshow(FBP , [0, 3]); title ('FBP reconstruction'); +%% +fprintf('%s\n', 'Reconstruction using FISTA-PWLS without regularization...'); +clear params +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = Sino3D; +params.L_const = 7.6789e+08; % found quickly for one slice first +params.iterFISTA  = 30; +params.weights = Weights3D; +params.show = 1; +params.maxvalplot = 2.5; params.slice = 4; + +tic; [X_fista, output] = FISTA_REC(params); toc; +figure; imshow(X_fista(:,:,1) , [0, 2.5]); title ('FISTA-PWLS reconstruction'); +%% +fprintf('%s\n', 'Reconstruction using FISTA-PWLS-TV...'); +clear params +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = Sino3D; +params.iterFISTA  = 40; +params.L_const = 7.6789e+08;  +params.Regul_LambdaTV = 0.005; % TV regularization parameter for FISTA-TV +params.weights = Weights3D; +params.show = 1; +params.maxvalplot = 2.5; params.slice = 10; + +tic; [X_fista_TV] = FISTA_REC(params); toc; +figure; imshow(X_fista_TV(:,:,1) , [0, 2.5]); title ('FISTA-PWLS-TV reconstruction'); +%% +%% +fprintf('%s\n', 'Reconstruction using FISTA-GH-TV...'); +clear params +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = Sino3D; +params.iterFISTA  = 40; +params.Regul_LambdaTV = 0.005; % TV regularization parameter for FISTA-TV +params.Ring_LambdaR_L1 = 0.002; % Soft-Thresh L1 ring variable parameter +params.Ring_Alpha = 21; % to boost ring removal procedure +params.weights = Weights3D; +params.show = 1; +params.maxvalplot = 2.5; params.slice = 10; + +tic; [X_fista_GH_TV] = FISTA_REC(params); toc; +figure; imshow(X_fista_GH_TV(:,:,1) , [0, 2.5]); title ('FISTA-GH-TV reconstruction'); +%% +%% +fprintf('%s\n', 'Reconstruction using FISTA-GH-TV-LLT...'); +clear params +params.proj_geom = proj_geom; % pass geometry to the function +params.vol_geom = vol_geom; +params.sino = Sino3D; +params.iterFISTA  = 40; +params.Regul_LambdaTV = 0.005; % TV regularization parameter for FISTA-TV +params.Regul_LambdaHO = 200;  % regularization parameter for LLT problem +params.Regul_tauHO = 0.0005; % time-step parameter for the explicit scheme +params.Regul_iterHO = 250; % the max number of TV iterations +params.Ring_LambdaR_L1 = 0.002; % Soft-Thresh L1 ring variable parameter +params.Ring_Alpha = 21; % to boost ring removal procedure +params.weights = Weights3D; +params.show = 1; +params.maxvalplot = 2.5; params.slice = 10; + +tic; [X_fista_GH_TVLLT] = FISTA_REC(params); toc; +figure; imshow(X_fista_GH_TVLLT(:,:,1) , [0, 2.5]); title ('FISTA-GH-TV-LLT reconstruction'); +%% +%% +% fprintf('%s\n', 'Reconstruction using FISTA-Student-TV...'); +% clear params +% params.sino = Sino3D(:,:,10); +% params.N  = recon_size; +% params.angles = angles_rad; +% params.iterFISTA  = 100; +% params.L_const = 0.01; % Lipshitz constant +% params.lambdaTV = 0.006; % TV regularization parameter for FISTA-TV +% params.tol = 1.0e-04; +% params.iterTV = 20; +% params.fidelity = 'student'; % choosing Student t penalty +% params.weights = Weights3D(:,:,10); +% params.show = 0; +% params.maxvalplot = 2.5; params.slice = 1; +%  +% tic; [X_fistaStudentTV] = FISTA_REC(params); toc; +% figure; imshow(X_fistaStudentTV(:,:,1), [0, 2.5]); title ('FISTA-Student-TV reconstruction'); +%% diff --git a/license.txt b/license.txt deleted file mode 100644 index 827b7f3..0000000 --- a/license.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2017, Daniil Kazantsev, The University of Manchester.  -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -    * Redistributions of source code must retain the above copyright -      notice, this list of conditions and the following disclaimer. -    * Redistributions in binary form must reproduce the above copyright -      notice, this list of conditions and the following disclaimer in -      the documentation and/or other materials provided with the distribution -    * Neither the name of the  nor the names -      of its contributors may be used to endorse or promote products derived -      from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/main_func/FGP_TV.c b/main_func/FGP_TV.c new file mode 100644 index 0000000..1a1fd13 --- /dev/null +++ b/main_func/FGP_TV.c @@ -0,0 +1,400 @@ +#include "mex.h" +#include <matrix.h> +#include <math.h> +#include <stdlib.h> +#include <memory.h> +#include <stdio.h> +#include "omp.h" + +/* C-OMP implementation of FGP-TV [1] denoising/regularization model (2D/3D case) + * + * Input Parameters: + * 1. Noisy image/volume [REQUIRED] + * 2. lambda - regularization parameter [REQUIRED] + * 3. Number of iterations [OPTIONAL parameter] + * 4. eplsilon: tolerance constant [OPTIONAL parameter] + * 5. TV-type: 'iso' or 'l1' [OPTIONAL parameter] + * + * Output: + * [1] Filtered/regularized image + * [2] last function value  + * + * Example of image denoising: + * figure; + * Im = double(imread('lena_gray_256.tif'))/255;  % loading image + * u0 = Im + .05*randn(size(Im)); % adding noise + * u = FGP_TV(single(u0), 0.05, 100, 1e-04); + * + * to compile with OMP support: mex FGP_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" + * This function is based on the Matlab's code and paper by + * [1] Amir Beck and Marc Teboulle, "Fast Gradient-Based Algorithms for Constrained Total Variation Image Denoising and Deblurring Problems" + * + * D. Kazantsev, 2016-17 + * + */ + +float copyIm(float *A, float *B, int dimX, int dimY, int dimZ); +float Obj_func2D(float *A, float *D, float *R1, float *R2, float lambda, int dimX, int dimY); +float Grad_func2D(float *P1, float *P2, float *D, float *R1, float *R2, float lambda, int dimX, int dimY); +float Proj_func2D(float *P1, float *P2, int methTV, int dimX, int dimY); +float Rupd_func2D(float *P1, float *P1_old, float *P2, float *P2_old, float *R1, float *R2, float tkp1, float tk, int dimX, int dimY); + +float Obj_func3D(float *A, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ); +float Grad_func3D(float *P1, float *P2, float *P3, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ); +float Proj_func3D(float *P1, float *P2, float *P3, int dimX, int dimY, int dimZ); +float Rupd_func3D(float *P1, float *P1_old, float *P2, float *P2_old, float *P3, float *P3_old, float *R1, float *R2, float *R3, float tkp1, float tk, int dimX, int dimY, int dimZ); + + +void mexFunction( +        int nlhs, mxArray *plhs[], +        int nrhs, const mxArray *prhs[]) +         +{ +    int number_of_dims, iter, dimX, dimY, dimZ, ll, j, count, methTV; +    const int  *dim_array; +    float *A, *D=NULL, *D_old=NULL, *P1=NULL, *P2=NULL, *P3=NULL, *P1_old=NULL, *P2_old=NULL, *P3_old=NULL, *R1=NULL, *R2=NULL, *R3=NULL, lambda, tk, tkp1, re, re1, re_old, epsil, funcval; +     +    number_of_dims = mxGetNumberOfDimensions(prhs[0]); +    dim_array = mxGetDimensions(prhs[0]); +     +    /*Handling Matlab input data*/ +    if ((nrhs < 2) || (nrhs > 5)) mexErrMsgTxt("At least 2 parameters is required: Image(2D/3D), Regularization parameter. The full list of parameters: Image(2D/3D), Regularization parameter, iterations number, tolerance, penalty type ('iso' or 'l1')"); +     +    A  = (float *) mxGetData(prhs[0]); /*noisy image (2D/3D) */ +    lambda =  (float) mxGetScalar(prhs[1]); /* regularization parameter */ +    iter = 50; /* default iterations number */ +    epsil = 0.001; /* default tolerance constant */ +    methTV = 0;  /* default isotropic TV penalty */ +     +    if ((nrhs == 3) || (nrhs == 4) || (nrhs == 5))  iter = (int) mxGetScalar(prhs[2]); /* iterations number */ +    if ((nrhs == 4) || (nrhs == 5))  epsil =  (float) mxGetScalar(prhs[3]); /* tolerance constant */ +    if (nrhs == 5)  { +        char *penalty_type; +        penalty_type = mxArrayToString(prhs[4]); /* choosing TV penalty: 'iso' or 'l1', 'iso' is the default */ +        if ((strcmp(penalty_type, "l1") != 0) && (strcmp(penalty_type, "iso") != 0)) mexErrMsgTxt("Choose TV type: 'iso' or 'l1',"); +        if (strcmp(penalty_type, "l1") == 0)  methTV = 1;  /* enable 'l1' penalty */ +        mxFree(penalty_type); +    } +    /*output function value (last iteration) */ +    funcval = 0.0f; +    plhs[1] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);   +    float *funcvalA = (float *) mxGetData(plhs[1]); +         +    if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input image must be in a single precision"); } +     +    /*Handling Matlab output data*/ +    dimX = dim_array[0]; dimY = dim_array[1]; dimZ = dim_array[2]; +     +    tk = 1.0f; +    tkp1=1.0f; +    count = 1; +    re_old = 0.0f; +     +    if (number_of_dims == 2) { +        dimZ = 1; /*2D case*/ +        D = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        D_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        P1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        P2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        P1_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        P2_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        R1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +        R2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); +         +        /* begin iterations */ +        for(ll=0; ll<iter; ll++) { +             +            /* computing the gradient of the objective function */ +            Obj_func2D(A, D, R1, R2, lambda, dimX, dimY); +             +            /*Taking a step towards minus of the gradient*/ +            Grad_func2D(P1, P2, D, R1, R2, lambda, dimX, dimY); +             +            /* projection step */ +            Proj_func2D(P1, P2, methTV, dimX, dimY); +             +            /*updating R and t*/ +            tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; +            Rupd_func2D(P1, P1_old, P2, P2_old, R1, R2, tkp1, tk, dimX, dimY); +             +            /* calculate norm */ +            re = 0.0f; re1 = 0.0f; +            for(j=0; j<dimX*dimY*dimZ; j++) +            { +                re += pow(D[j] - D_old[j],2); +                re1 += pow(D[j],2); +            } +            re = sqrt(re)/sqrt(re1); +            if (re < epsil)  count++; +            if (count > 3) { +                Obj_func2D(A, D, P1, P2, lambda, dimX, dimY);             +                funcval = 0.0f;  +                for(j=0; j<dimX*dimY*dimZ; j++) funcval += pow(D[j],2);                            +                funcvalA[0] = sqrt(funcval);      +                break; } +             +            /* check that the residual norm is decreasing */ +            if (ll > 2) { +                if (re > re_old) { +                    Obj_func2D(A, D, P1, P2, lambda, dimX, dimY);             +                    funcval = 0.0f;  +                    for(j=0; j<dimX*dimY*dimZ; j++) funcval += pow(D[j],2);                            +                    funcvalA[0] = sqrt(funcval);                      +                    break; }}             +            re_old = re; +            /*printf("%f %i %i \n", re, ll, count); */ +             +            /*storing old values*/ +            copyIm(D, D_old, dimX, dimY, dimZ); +            copyIm(P1, P1_old, dimX, dimY, dimZ); +            copyIm(P2, P2_old, dimX, dimY, dimZ); +            tk = tkp1; +             +            /* calculating the objective function value */ +            if (ll == (iter-1)) { +            Obj_func2D(A, D, P1, P2, lambda, dimX, dimY);             +            funcval = 0.0f;  +            for(j=0; j<dimX*dimY*dimZ; j++) funcval += pow(D[j],2);                            +            funcvalA[0] = sqrt(funcval);             +            } +        } +        printf("FGP-TV iterations stopped at iteration %i with the function value %f \n", ll, funcvalA[0]); +    } +    if (number_of_dims == 3) { +        D = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        D_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        P1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        P2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        P3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        P1_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        P2_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        P3_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        R1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        R2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        R3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +         +        /* begin iterations */ +        for(ll=0; ll<iter; ll++) { +             +            /* computing the gradient of the objective function */ +            Obj_func3D(A, D, R1, R2, R3,lambda, dimX, dimY, dimZ); +             +            /*Taking a step towards minus of the gradient*/ +            Grad_func3D(P1, P2, P3, D, R1, R2, R3, lambda, dimX, dimY, dimZ); +             +            /* projection step */ +            Proj_func3D(P1, P2, P3, dimX, dimY, dimZ); +             +            /*updating R and t*/ +            tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; +            Rupd_func3D(P1, P1_old, P2, P2_old, P3, P3_old, R1, R2, R3, tkp1, tk, dimX, dimY, dimZ); +             +            /* calculate norm - stopping rules*/ +            re = 0.0f; re1 = 0.0f; +            for(j=0; j<dimX*dimY*dimZ; j++) +            { +                re += pow(D[j] - D_old[j],2); +                re1 += pow(D[j],2); +            } +            re = sqrt(re)/sqrt(re1); +            /* stop if the norm residual is less than the tolerance EPS */ +            if (re < epsil)  count++; +            if (count > 3) { +                Obj_func3D(A, D, P1, P2, P3,lambda, dimX, dimY, dimZ); +                funcval = 0.0f;  +                for(j=0; j<dimX*dimY*dimZ; j++) funcval += pow(D[j],2);                            +                funcvalA[0] = sqrt(funcval);                   +                break;} +             +            /* check that the residual norm is decreasing */ +            if (ll > 2) { +                if (re > re_old) { +                Obj_func3D(A, D, P1, P2, P3,lambda, dimX, dimY, dimZ); +                funcval = 0.0f;  +                for(j=0; j<dimX*dimY*dimZ; j++) funcval += pow(D[j],2);                            +                funcvalA[0] = sqrt(funcval);   +                break; }} +             +            re_old = re; +            /*printf("%f %i %i \n", re, ll, count); */ +             +            /*storing old values*/ +            copyIm(D, D_old, dimX, dimY, dimZ); +            copyIm(P1, P1_old, dimX, dimY, dimZ); +            copyIm(P2, P2_old, dimX, dimY, dimZ); +            copyIm(P3, P3_old, dimX, dimY, dimZ); +            tk = tkp1; +             +            if (ll == (iter-1)) { +            Obj_func3D(A, D, P1, P2, P3,lambda, dimX, dimY, dimZ); +            funcval = 0.0f;  +            for(j=0; j<dimX*dimY*dimZ; j++) funcval += pow(D[j],2);                            +            funcvalA[0] = sqrt(funcval);             +            } +             +        } +        printf("FGP-TV iterations stopped at iteration %i with the function value %f \n", ll, funcvalA[0]); +    } +} + +/* 2D-case related Functions */ +/*****************************************************************/ +float Obj_func2D(float *A, float *D, float *R1, float *R2, float lambda, int dimX, int dimY) +{ +    float val1, val2; +    int i,j; +#pragma omp parallel for shared(A,D,R1,R2) private(i,j,val1,val2) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            /* boundary conditions  */ +            if (i == 0) {val1 = 0.0f;} else {val1 = R1[(i-1)*dimY + (j)];} +            if (j == 0) {val2 = 0.0f;} else {val2 = R2[(i)*dimY + (j-1)];} +            D[(i)*dimY + (j)] = A[(i)*dimY + (j)] - lambda*(R1[(i)*dimY + (j)] + R2[(i)*dimY + (j)] - val1 - val2); +        }} +    return *D; +} +float Grad_func2D(float *P1, float *P2, float *D, float *R1, float *R2, float lambda, int dimX, int dimY) +{ +    float val1, val2, multip; +    int i,j; +    multip = (1.0f/(8.0f*lambda)); +#pragma omp parallel for shared(P1,P2,D,R1,R2,multip) private(i,j,val1,val2) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            /* boundary conditions */ +            if (i == dimX-1) val1 = 0.0f; else val1 = D[(i)*dimY + (j)] - D[(i+1)*dimY + (j)]; +            if (j == dimY-1) val2 = 0.0f; else val2 = D[(i)*dimY + (j)] - D[(i)*dimY + (j+1)]; +            P1[(i)*dimY + (j)] = R1[(i)*dimY + (j)] + multip*val1; +            P2[(i)*dimY + (j)] = R2[(i)*dimY + (j)] + multip*val2; +        }} +    return 1; +} +float Proj_func2D(float *P1, float *P2, int methTV, int dimX, int dimY) +{ +    float val1, val2, denom; +    int i,j; +    if (methTV == 0) { +        /* isotropic TV*/ +#pragma omp parallel for shared(P1,P2) private(i,j,denom) +        for(i=0; i<dimX; i++) { +            for(j=0; j<dimY; j++) { +                denom = pow(P1[(i)*dimY + (j)],2) +  pow(P2[(i)*dimY + (j)],2); +                if (denom > 1) { +                    P1[(i)*dimY + (j)] = P1[(i)*dimY + (j)]/sqrt(denom); +                    P2[(i)*dimY + (j)] = P2[(i)*dimY + (j)]/sqrt(denom); +                } +            }} +    } +    else { +        /* anisotropic TV*/ +#pragma omp parallel for shared(P1,P2) private(i,j,val1,val2) +        for(i=0; i<dimX; i++) { +            for(j=0; j<dimY; j++) { +                val1 = fabs(P1[(i)*dimY + (j)]); +                val2 = fabs(P2[(i)*dimY + (j)]); +                if (val1 < 1.0f) {val1 = 1.0f;} +                if (val2 < 1.0f) {val2 = 1.0f;} +                P1[(i)*dimY + (j)] = P1[(i)*dimY + (j)]/val1; +                P2[(i)*dimY + (j)] = P2[(i)*dimY + (j)]/val2; +            }} +    } +    return 1; +} +float Rupd_func2D(float *P1, float *P1_old, float *P2, float *P2_old, float *R1, float *R2, float tkp1, float tk, int dimX, int dimY) +{ +    int i,j; +    float multip; +    multip = ((tk-1.0f)/tkp1); +#pragma omp parallel for shared(P1,P2,P1_old,P2_old,R1,R2,multip) private(i,j) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            R1[(i)*dimY + (j)] = P1[(i)*dimY + (j)] + multip*(P1[(i)*dimY + (j)] - P1_old[(i)*dimY + (j)]); +            R2[(i)*dimY + (j)] = P2[(i)*dimY + (j)] + multip*(P2[(i)*dimY + (j)] - P2_old[(i)*dimY + (j)]); +        }} +    return 1; +} + +/* 3D-case related Functions */ +/*****************************************************************/ +float Obj_func3D(float *A, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ) +{ +    float val1, val2, val3; +    int i,j,k; +#pragma omp parallel for shared(A,D,R1,R2,R3) private(i,j,k,val1,val2,val3) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            for(k=0; k<dimZ; k++) { +                /* boundary conditions */ +                if (i == 0) {val1 = 0.0f;} else {val1 = R1[(dimX*dimY)*k + (i-1)*dimY + (j)];} +                if (j == 0) {val2 = 0.0f;} else {val2 = R2[(dimX*dimY)*k + (i)*dimY + (j-1)];} +                if (k == 0) {val3 = 0.0f;} else {val3 = R3[(dimX*dimY)*(k-1) + (i)*dimY + (j)];} +                D[(dimX*dimY)*k + (i)*dimY + (j)] = A[(dimX*dimY)*k + (i)*dimY + (j)] - lambda*(R1[(dimX*dimY)*k + (i)*dimY + (j)] + R2[(dimX*dimY)*k + (i)*dimY + (j)] + R3[(dimX*dimY)*k + (i)*dimY + (j)] - val1 - val2 - val3); +            }}} +    return *D; +} +float Grad_func3D(float *P1, float *P2, float *P3, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ) +{ +    float val1, val2, val3, multip; +    int i,j,k; +    multip = (1.0f/(8.0f*lambda)); +#pragma omp parallel for shared(P1,P2,P3,D,R1,R2,R3,multip) private(i,j,k,val1,val2,val3) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            for(k=0; k<dimZ; k++) { +                /* boundary conditions */ +                if (i == dimX-1) val1 = 0.0f; else val1 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*k + (i+1)*dimY + (j)]; +                if (j == dimY-1) val2 = 0.0f; else val2 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*k + (i)*dimY + (j+1)]; +                if (k == dimZ-1) val3 = 0.0f; else val3 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*(k+1) + (i)*dimY + (j)]; +                P1[(dimX*dimY)*k + (i)*dimY + (j)] = R1[(dimX*dimY)*k + (i)*dimY + (j)] + multip*val1; +                P2[(dimX*dimY)*k + (i)*dimY + (j)] = R2[(dimX*dimY)*k + (i)*dimY + (j)] + multip*val2; +                P3[(dimX*dimY)*k + (i)*dimY + (j)] = R3[(dimX*dimY)*k + (i)*dimY + (j)] + multip*val3; +            }}} +    return 1; +} +float Proj_func3D(float *P1, float *P2, float *P3, int dimX, int dimY, int dimZ) +{ +    float val1, val2, val3; +    int i,j,k; +#pragma omp parallel for shared(P1,P2,P3) private(i,j,k,val1,val2,val3) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            for(k=0; k<dimZ; k++) { +                val1 = fabs(P1[(dimX*dimY)*k + (i)*dimY + (j)]); +                val2 = fabs(P2[(dimX*dimY)*k + (i)*dimY + (j)]); +                val3 = fabs(P3[(dimX*dimY)*k + (i)*dimY + (j)]); +                if (val1 < 1.0f) {val1 = 1.0f;} +                if (val2 < 1.0f) {val2 = 1.0f;} +                if (val3 < 1.0f) {val3 = 1.0f;} +                 +                P1[(dimX*dimY)*k + (i)*dimY + (j)] = P1[(dimX*dimY)*k + (i)*dimY + (j)]/val1; +                P2[(dimX*dimY)*k + (i)*dimY + (j)] = P2[(dimX*dimY)*k + (i)*dimY + (j)]/val2; +                P3[(dimX*dimY)*k + (i)*dimY + (j)] = P3[(dimX*dimY)*k + (i)*dimY + (j)]/val3; +            }}} +    return 1; +} +float Rupd_func3D(float *P1, float *P1_old, float *P2, float *P2_old, float *P3, float *P3_old, float *R1, float *R2, float *R3, float tkp1, float tk, int dimX, int dimY, int dimZ) +{ +    int i,j,k; +    float multip; +    multip = ((tk-1.0f)/tkp1); +#pragma omp parallel for shared(P1,P2,P3,P1_old,P2_old,P3_old,R1,R2,R3,multip) private(i,j,k) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            for(k=0; k<dimZ; k++) { +                R1[(dimX*dimY)*k + (i)*dimY + (j)] = P1[(dimX*dimY)*k + (i)*dimY + (j)] + multip*(P1[(dimX*dimY)*k + (i)*dimY + (j)] - P1_old[(dimX*dimY)*k + (i)*dimY + (j)]); +                R2[(dimX*dimY)*k + (i)*dimY + (j)] = P2[(dimX*dimY)*k + (i)*dimY + (j)] + multip*(P2[(dimX*dimY)*k + (i)*dimY + (j)] - P2_old[(dimX*dimY)*k + (i)*dimY + (j)]); +                R3[(dimX*dimY)*k + (i)*dimY + (j)] = P3[(dimX*dimY)*k + (i)*dimY + (j)] + multip*(P3[(dimX*dimY)*k + (i)*dimY + (j)] - P3_old[(dimX*dimY)*k + (i)*dimY + (j)]); +            }}} +    return 1; +} + +/* General Functions */ +/*****************************************************************/ +/* Copy Image */ +float copyIm(float *A, float *B, int dimX, int dimY, int dimZ) +{ +    int j; +#pragma omp parallel for shared(A, B) private(j) +    for(j=0; j<dimX*dimY*dimZ; j++)  B[j] = A[j]; +    return *B; +} diff --git a/main_func/FISTA_REC.m b/main_func/FISTA_REC.m index 79369a5..ed74181 100644 --- a/main_func/FISTA_REC.m +++ b/main_func/FISTA_REC.m @@ -1,34 +1,36 @@ -function [X,  error, objective, residual] = FISTA_REC(params) +function [X,  output] = FISTA_REC(params) -% <<<< FISTA-based reconstruction algorithm using ASTRA-toolbox (parallel beam) >>>> +% <<<< FISTA-based reconstruction algorithm using ASTRA-toolbox >>>>  % ___Input___:  % params.[] file: -%       - .sino (2D or 3D sinogram) [required] -%       - .N (image dimension) [required] -%       - .angles (in radians) [required] +%       - .proj_geom (geometry of the projector) [required] +%       - .vol_geom (geometry of the reconstructed object) [required] +%       - .sino (vectorized in 2D or 3D sinogram) [required]  %       - .iterFISTA (iterations for the main loop)  %       - .L_const (Lipschitz constant, default Power method)                                                                                                    )  %       - .X_ideal (ideal image, if given) -%       - .weights (statisitcal weights, size of sinogram) +%       - .weights (statisitcal weights, size of the sinogram)  %       - .ROI (Region-of-interest, only if X_ideal is given) -%       - .lambdaTV (TV regularization parameter, default 0 - reg. TV is switched off) -%       - .tol (tolerance to terminate TV regularization, default 1.0e-04) -%       - .iterTV (iterations for the TV penalty, default 0) -%       - .lambdaHO (Higher Order LLT regularization parameter, default 0 - LLT reg. switched off) -%       - .iterHO (iterations for HO penalty, default 50) -%       - .tauHO (time step parameter for HO term) -%       - .lambdaR_L1 (regularization parameter for L1 ring minimization, if lambdaR_L1 > 0 then switch on ring removal, default 0) -%       - .alpha_ring (larger values can accelerate convergence but check stability, default 1) +%       - .Regul_LambdaTV (TV regularization parameter, default 0 - reg. TV is switched off) +%       - .Regul_tol (tolerance to terminate TV regularization, default 1.0e-04) +%       - .Regul_iterTV (iterations for the TV penalty, default 0) +%       - .Regul_LambdaHO (Higher Order LLT regularization parameter, default 0 - LLT reg. switched off) +%       - .Regul_iterHO (iterations for HO penalty, default 50) +%       - .Regul_tauHO (time step parameter for HO term) +%       - .Ring_LambdaR_L1 (regularization parameter for L1 ring minimization, if lambdaR_L1 > 0 then switch on ring removal, default 0) +%       - .Ring_Alpha (larger values can accelerate convergence but check stability, default 1)  %       - .fidelity (choose between "LS" and "student" data fidelities) +%       - .initializ (a 'warm start' using SIRT method from ASTRA)  %       - .precondition (1 - switch on Fourier filtering before backprojection)  %       - .show (visualize reconstruction 1/0, (0 default))  %       - .maxvalplot (maximum value to use for imshow[0 maxvalplot])  %       - .slice (for 3D volumes - slice number to imshow)  % ___Output___:  % 1. X - reconstructed image/volume -% 2. error - residual error (if X_ideal is given) +% 2. Resid_error - residual error (if X_ideal is given)  % 3. value of the objective function -% 4. forward projection(X) +% 4. forward projection of X +  % References:  % 1. "A Fast Iterative Shrinkage-Thresholding Algorithm for Linear Inverse  % Problems" by A. Beck and M Teboulle @@ -38,49 +40,53 @@ function [X,  error, objective, residual] = FISTA_REC(params)  % D. Kazantsev, 2016-17  % Dealing with input parameters -if (isfield(params,'sino')) -    sino = params.sino; -    [anglesNumb, Detectors, SlicesZ] = size(sino); -    fprintf('%s %i %s %i %s %i %s \n', 'Sinogram has a dimension of', anglesNumb, 'projections;', Detectors, 'detectors;', SlicesZ, 'vertical slices.'); +if (isfield(params,'proj_geom') == 0) +    error('%s \n', 'Please provide ASTRA projection geometry - proj_geom');  else -    fprintf('%s \n', 'Please provide a sinogram'); +    proj_geom = params.proj_geom;  end -if (isfield(params,'N')) -    N = params.N; +if (isfield(params,'vol_geom') == 0) +    error('%s \n', 'Please provide ASTRA object geometry - vol_geom');  else -    fprintf('%s \n', 'Please provide N-size for the reconstructed image [N x N]'); +    vol_geom = params.vol_geom;  end -if (isfield(params,'N')) -    angles = params.angles; -    if (length(angles) ~= anglesNumb) -        fprintf('%s \n', 'Sinogram angular dimension does not correspond to the angles dimension provided'); -    end +N = params.vol_geom.GridColCount; +if (isfield(params,'sino')) +    sino = params.sino; +    [Detectors, anglesNumb, SlicesZ] = size(sino); +    fprintf('%s %i %s %i %s %i %s \n', 'Sinogram has a dimension of', Detectors, 'detectors;', anglesNumb, 'projections;', SlicesZ, 'vertical slices.');  else -    fprintf('%s \n', 'Please provide a vector of angles'); +    error('%s \n', 'Please provide a sinogram');  end  if (isfield(params,'iterFISTA'))      iterFISTA = params.iterFISTA;  else      iterFISTA = 30;  end +if (isfield(params,'weights')) +    weights = params.weights; +else +    weights = ones(size(sino)); +end  if (isfield(params,'L_const'))      L_const = params.L_const;  else      % using Power method (PM) to establish L constant -    vol_geom = astra_create_vol_geom(N, N); -    proj_geom = astra_create_proj_geom('parallel', 1.0, Detectors, angles); -     -    niter = 10; % number of iteration for PM -    x = rand(N,N); -    [sino_id, y] = astra_create_sino_cuda(x, proj_geom, vol_geom); -    astra_mex_data2d('delete', sino_id); +    niter = 5; % number of iteration for PM +    x = rand(N,N,SlicesZ); +    sqweight = sqrt(weights); +    [sino_id, y] = astra_create_sino3d_cuda(x, proj_geom, vol_geom); +    y = sqweight.*y; +    astra_mex_data3d('delete', sino_id);      for i = 1:niter -        x = astra_create_backprojection_cuda(y, proj_geom, vol_geom); -        s = norm(x); +        [id,x] = astra_create_backprojection3d_cuda(sqweight.*y, proj_geom, vol_geom); +        s = norm(x(:));          x = x/s; -        [sino_id, y] = astra_create_sino_cuda(x, proj_geom, vol_geom); -        astra_mex_data2d('delete', sino_id); +        [sino_id, y] = astra_create_sino3d_cuda(x, proj_geom, vol_geom); +        y = sqweight.*y; +        astra_mex_data3d('delete', sino_id); +        astra_mex_data3d('delete', id);      end      L_const = s;  end @@ -89,53 +95,48 @@ if (isfield(params,'X_ideal'))  else      X_ideal = 'none';  end -if (isfield(params,'weights')) -    weights = params.weights; -else -    weights = 1; -end  if (isfield(params,'ROI'))      ROI = params.ROI;  else      ROI = find(X_ideal>=0.0);  end -if (isfield(params,'lambdaTV')) -    lambdaTV = params.lambdaTV; +if (isfield(params,'Regul_LambdaTV')) +    lambdaTV = params.Regul_LambdaTV;  else      lambdaTV = 0;  end -if (isfield(params,'tol')) -    tol = params.tol; +if (isfield(params,'Regul_tol')) +    tol = params.Regul_tol;  else      tol = 1.0e-04;  end -if (isfield(params,'iterTV')) -    iterTV = params.iterTV; +if (isfield(params,'Regul_iterTV')) +    iterTV = params.Regul_iterTV;  else -    iterTV = 10; +    iterTV = 25;  end -if (isfield(params,'lambdaHO')) -    lambdaHO = params.lambdaHO; +if (isfield(params,'Regul_LambdaHO')) +    lambdaHO = params.Regul_LambdaHO;  else      lambdaHO = 0;  end -if (isfield(params,'iterHO')) -    iterHO = params.iterHO; +if (isfield(params,'Regul_iterHO')) +    iterHO = params.Regul_iterHO;  else      iterHO = 50;  end -if (isfield(params,'tauHO')) -    tauHO = params.tauHO; +if (isfield(params,'Regul_tauHO')) +    tauHO = params.Regul_tauHO;  else      tauHO = 0.0001;  end -if (isfield(params,'lambdaR_L1')) -    lambdaR_L1 = params.lambdaR_L1;     +if (isfield(params,'Ring_LambdaR_L1')) +    lambdaR_L1 = params.Ring_LambdaR_L1;  else      lambdaR_L1 = 0;  end -if (isfield(params,'alpha_ring'))     -    alpha_ring = params.alpha_ring; % higher values can accelerate ring removal procedure +if (isfield(params,'Ring_Alpha')) +    alpha_ring = params.Ring_Alpha; % higher values can accelerate ring removal procedure  else      alpha_ring = 1;  end @@ -164,21 +165,43 @@ if (isfield(params,'slice'))  else      slice = 1;  end +if (isfield(params,'initilize')) +    % Create a data object for the reconstruction +    rec_id = astra_mex_data3d('create', '-vol', vol_geom); +     +    sinogram_id = astra_mex_data3d('create', '-proj3d', proj_geom, sino); +     +    % Set up the parameters for a reconstruction algorithm using the GPU +    cfg = astra_struct('SIRT3D_CUDA'); +    cfg.ReconstructionDataId = rec_id; +    cfg.ProjectionDataId = sinogram_id; +     +    % Create the algorithm object from the configuration structure +    alg_id = astra_mex_algorithm('create', cfg); +    astra_mex_algorithm('iterate', alg_id, 35); +    % Get the result +    X = astra_mex_data3d('get', rec_id); +     +    % Clean up. Note that GPU memory is tied up in the algorithm object, +    % and main RAM in the data objects. +    astra_mex_algorithm('delete', alg_id); +    astra_mex_data3d('delete', rec_id); +    astra_mex_data3d('delete', sinogram_id); +else +    X = zeros(N,N,SlicesZ, 'single'); % storage for the solution +end +  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% building geometry (parallel-beam) -vol_geom = astra_create_vol_geom(N, N); -proj_geom = astra_create_proj_geom('parallel', 1.0, Detectors, angles); -error = zeros(iterFISTA,1); % error vector +Resid_error = zeros(iterFISTA,1); % error vector  objective = zeros(iterFISTA,1); % obhective vector  if (lambdaR_L1 > 0)      % do reconstruction WITH ring removal (Group-Huber fidelity)      t = 1; -    X = zeros(N,N,SlicesZ, 'single');      X_t = X; -    add_ring = zeros(anglesNumb, Detectors, SlicesZ, 'single'); % size of sinogram array +    add_ring = zeros(size(sino),'single'); % size of sinogram array      r = zeros(Detectors,SlicesZ, 'single'); % 2D array (for 3D data) of sparse "ring" vectors      r_x = r; @@ -189,47 +212,40 @@ if (lambdaR_L1 > 0)          t_old = t;          r_old = r; -        % all slices loop -        for j = 1:SlicesZ -             -            [sino_id, sino_updt] = astra_create_sino_cuda(X_t(:,:,j), proj_geom, vol_geom); -             -            for kkk = 1:anglesNumb -                add_ring(kkk,:,j) =  sino(kkk,:,j) - alpha_ring.*r_x(:,j)'; -            end -             -            residual =  sino_updt - add_ring(:,:,j); -             -            if (precondition == 1) -                residual = filtersinc(residual'); % filtering residual (Fourier preconditioning) -                residual = residual'; -            end -             -            vec = sum(residual); -            r(:,j) = r_x(:,j) - (1/L_const).*vec'; -             -            x_temp = astra_create_backprojection_cuda(residual, proj_geom, vol_geom); -             -            X(:,:,j) = X_t(:,:,j) - (1/L_const).*x_temp; -            astra_mex_data2d('delete', sino_id); +        [sino_id, sino_updt] = astra_create_sino3d_cuda(X_t, proj_geom, vol_geom); +         +        for kkk = 1:anglesNumb +            add_ring(:,kkk,:) =  sino(:,kkk,:) - alpha_ring.*r_x; +        end +         +        residual =  weights.*(sino_updt - add_ring); +         +        if (precondition == 1) +            residual = filtersinc(residual'); % filtering residual (Fourier preconditioning) +            residual = residual';          end +        vec = sum(residual,2); +         +        r = r_x - (1./L_const).*vec; +         +        [id, x_temp] = astra_create_backprojection3d_cuda(residual, proj_geom, vol_geom); +         +        X = X_t - (1/L_const).*x_temp; +        astra_mex_data3d('delete', sino_id); +        astra_mex_data3d('delete', id); +                  if ((lambdaTV > 0) && (lambdaHO == 0)) -            if (size(X,3) > 1)  -                [X] = FISTA_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA -                 gradTV = 1; -            else -                [X, gradTV] = FISTA_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA -            end -            objective(i) = 0.5.*norm(residual(:))^2 + norm(gradTV(:)); +            [X, f_val] = FGP_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA +            objective(i) = 0.5.*norm(residual(:))^2 + f_val;              %       X = SplitBregman_TV(single(X), lambdaTV, iterTV, tol);  % TV-Split Bregman regularization on CPU (memory limited)          elseif ((lambdaHO > 0) && (lambdaTV == 0))              % Higher Order regularization              X = LLT_model(single(X), lambdaHO, tauHO, iterHO, tol, 0);   % LLT higher order model          elseif ((lambdaTV > 0) && (lambdaHO > 0))              %X1 = SplitBregman_TV(single(X), lambdaTV, iterTV, tol);     % TV-Split Bregman regularization on CPU (memory limited) -            X1 = FISTA_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA -            X2 = LLT_model(single(X), lambdaHO, tauHO, iterHO, tol, 0);   % LLT higher order model +            X1 = FGP_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA +            X2 = LLT_model(single(X), lambdaHO, tauHO, iterHO, 3.0e-05, 0);   % LLT higher order model              X = 0.5.*(X1 + X2); % averaged combination of two solutions          elseif ((lambdaTV == 0) && (lambdaHO == 0))              objective(i) = 0.5.*norm(residual(:))^2; @@ -244,11 +260,11 @@ if (lambdaR_L1 > 0)          if (show == 1)              figure(10); imshow(X(:,:,slice), [0 maxvalplot]);              figure(11); plot(r); title('Rings offset vector') -            pause(0.03);             +            pause(0.03);          end          if (strcmp(X_ideal, 'none' ) == 0) -            error(i) = RMSE(X(ROI), X_ideal(ROI)); -            fprintf('%s %i %s %s %.4f  %s %s %.4f \n', 'Iteration Number:', i, '|', 'Error RMSE:', error(i), '|', 'Objective:', objective(i)); +            Resid_error(i) = RMSE(X(ROI), X_ideal(ROI)); +            fprintf('%s %i %s %s %.4f  %s %s %.4f \n', 'Iteration Number:', i, '|', 'Error RMSE:', Resid_error(i), '|', 'Objective:', objective(i));          else              fprintf('%s %i  %s %s %.4f \n', 'Iteration Number:', i, '|', 'Objective:', objective(i));          end @@ -258,50 +274,42 @@ if (lambdaR_L1 > 0)  else      % WITHOUT ring removal      t = 1; -    X = zeros(N,N,SlicesZ, 'single');      X_t = X; -    % iterations loop +    % FISTA outer iterations loop      for i = 1:iterFISTA          X_old = X;          t_old = t; -        % slices loop -        for j = 1:SlicesZ -            [sino_id, sino_updt] = astra_create_sino_cuda(X_t(:,:,j), proj_geom, vol_geom); -            residual = weights.*(sino_updt - sino(:,:,j)); -             -            % employ students t fidelity term -            if (strcmp(fidelity,'student') == 1) -                res_vec = reshape(residual, anglesNumb*Detectors,1); -                %s = 100; -                %gr = (2)*res_vec./(s*2 + conj(res_vec).*res_vec); -                [ff, gr] = studentst(res_vec,1); -                residual = reshape(gr, anglesNumb, Detectors); -            end -             -            if (precondition == 1) -                residual = filtersinc(residual'); % filtering residual (Fourier preconditioning) -                residual = residual'; -            end            -             -            x_temp = astra_create_backprojection_cuda(residual, proj_geom, vol_geom); -            X(:,:,j) = X_t(:,:,j) - (1/L_const).*x_temp; -            astra_mex_data2d('delete', sino_id); +        [sino_id, sino_updt] = astra_create_sino3d_cuda(X_t, proj_geom, vol_geom); +        residual = weights.*(sino_updt - sino); +         +        % employ students t fidelity term +        if (strcmp(fidelity,'student') == 1) +            res_vec = reshape(residual, anglesNumb*Detectors*SlicesZ,1); +            %s = 100; +            %gr = (2)*res_vec./(s*2 + conj(res_vec).*res_vec); +            [ff, gr] = studentst(res_vec,1); +            residual = reshape(gr, Detectors, anglesNumb, SlicesZ); +        end +         +        if (precondition == 1) +            residual = filtersinc(residual'); % filtering residual (Fourier preconditioning) +            residual = residual';          end +        [id, x_temp] = astra_create_backprojection3d_cuda(residual, proj_geom, vol_geom); +        X = X_t - (1/L_const).*x_temp; +        astra_mex_data3d('delete', sino_id); +        astra_mex_data3d('delete', id); +                  if ((lambdaTV > 0) && (lambdaHO == 0)) -            if (size(X,3) > 1)  -                [X] = FISTA_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA -                gradTV = 1; -            else -                [X, gradTV] = FISTA_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA -            end +            [X,f_val] = FGP_TV(single(X), lambdaTV, iterTV, tol); % TV regularization using FISTA              if (strcmp(fidelity,'student') == 1) -                objective(i) = ff + norm(gradTV(:)); +                objective(i) = ff + f_val;              else -                objective(i) = 0.5.*norm(residual(:))^2 + norm(gradTV(:)); +                objective(i) = 0.5.*norm(residual(:))^2 + f_val;              end              %  X = SplitBregman_TV(single(X), lambdaTV, iterTV, tol);  % TV-Split Bregman regularization on CPU (memory limited)          elseif ((lambdaHO > 0) && (lambdaTV == 0)) @@ -315,24 +323,25 @@ else              objective(i) = 0.5.*norm(residual(:))^2;          end -                  t = (1 + sqrt(1 + 4*t^2))/2; % updating t          X_t = X + ((t_old-1)/t).*(X - X_old); % updating X          if (show == 1)              figure(11); imshow(X(:,:,slice), [0 maxvalplot]); -            pause(0.03);             +            pause(0.03);          end          if (strcmp(X_ideal, 'none' ) == 0) -            error(i) = RMSE(X(ROI), X_ideal(ROI)); -            fprintf('%s %i %s %s %.4f  %s %s %.4f \n', 'Iteration Number:', i, '|', 'Error RMSE:', error(i), '|', 'Objective:', objective(i)); +            Resid_error(i) = RMSE(X(ROI), X_ideal(ROI)); +            fprintf('%s %i %s %s %.4f  %s %s %.4f \n', 'Iteration Number:', i, '|', 'Error RMSE:', Resid_error(i), '|', 'Objective:', objective(i));          else              fprintf('%s %i  %s %s %.4f \n', 'Iteration Number:', i, '|', 'Objective:', objective(i));          end -              end  end +output.Resid_error = Resid_error; +output.objective = objective; +output.L_const = L_const;  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  end diff --git a/main_func/FISTA_TV.c b/main_func/FISTA_TV.c deleted file mode 100644 index 87681bc..0000000 --- a/main_func/FISTA_TV.c +++ /dev/null @@ -1,331 +0,0 @@ -#include "mex.h" -#include <matrix.h> -#include <math.h> -#include <stdlib.h> -#include <memory.h> -#include <stdio.h> -#include "omp.h" - -/* C-OMP implementation of FISTA-TV denoising-regularization model (2D/3D) - * - * Input Parameters: - * 1. Noisy image/volume - * 2. lambda - regularization parameter - * 3. Number of iterations - * 4. eplsilon - tolerance constant - * - * Output: - * Filtered/regularized image - * - * Example: - * figure; - * Im = double(imread('lena_gray_256.tif'))/255;  % loading image - * u0 = Im + .05*randn(size(Im)); % adding noise - * u = FISTA_TV(single(u0), 0.05, 150, 1e-04); - * - * to compile with OMP support: mex FISTA_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall" LDFLAGS="\$LDFLAGS -fopenmp" - * References: A. Beck & M. Teboulle - * - * D. Kazantsev, 2016* - */ - -float copyIm(float *A, float *B, int dimX, int dimY, int dimZ); -float Obj_func2D(float *A, float *D, float *R1, float *R2, float *grad, float lambda, int dimX, int dimY); -float Grad_func2D(float *P1, float *P2, float *D, float *R1, float *R2, float lambda, int dimX, int dimY); -float Proj_func2D(float *P1, float *P2, int dimX, int dimY); -float Rupd_func2D(float *P1, float *P1_old, float *P2, float *P2_old, float *R1, float *R2, float tkp1, float tk, int dimX, int dimY); - -float Obj_func3D(float *A, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ); -float Grad_func3D(float *P1, float *P2, float *P3, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ); -float Proj_func3D(float *P1, float *P2, float *P3, int dimX, int dimY, int dimZ); -float Rupd_func3D(float *P1, float *P1_old, float *P2, float *P2_old, float *P3, float *P3_old, float *R1, float *R2, float *R3, float tkp1, float tk, int dimX, int dimY, int dimZ); - - -void mexFunction( -        int nlhs, mxArray *plhs[], -        int nrhs, const mxArray *prhs[]) -         -{ -    int number_of_dims, iter, dimX, dimY, dimZ, ll, j, count; -    const int  *dim_array; -    float *A, *grad=NULL, *D=NULL, *D_old=NULL, *P1=NULL, *P2=NULL, *P3=NULL, *P1_old=NULL, *P2_old=NULL, *P3_old=NULL, *R1=NULL, *R2=NULL, *R3=NULL, lambda, tk, tkp1, re, re1, re_old, epsil; -     -    number_of_dims = mxGetNumberOfDimensions(prhs[0]); -    dim_array = mxGetDimensions(prhs[0]); -     -    if(nrhs != 4) mexErrMsgTxt("Four input parameters is reqired: Image(2D/3D), Regularization parameter, Iterations, Tolerance"); -     -    /*Handling Matlab input data*/ -    A  = (float *) mxGetData(prhs[0]); /*noisy image (2D/3D) */ -    lambda =  (float) mxGetScalar(prhs[1]); /* regularization parameter */ -    iter =  (int) mxGetScalar(prhs[2]); /* iterations number */ -    epsil =  (float) mxGetScalar(prhs[3]); /* tolerance constant */ -         -    /*Handling Matlab output data*/ -    dimX = dim_array[0]; dimY = dim_array[1]; dimZ = dim_array[2]; -     -    tk = 1.0f; -    tkp1=1.0f; -    count = 1; -    re_old = 0.0f;    -     -    if (number_of_dims == 2) { -        dimZ = 1; /*2D case*/ -        D = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        grad = (float*)mxGetPr(plhs[1] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        D_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        P1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        P2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        P1_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        P2_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        R1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        R2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -         -        /* begin iterations */ -        for(ll=0; ll<iter; ll++) { -             -            /*storing old values*/ -            copyIm(D, D_old, dimX, dimY, dimZ); -            copyIm(P1, P1_old, dimX, dimY, dimZ); -            copyIm(P2, P2_old, dimX, dimY, dimZ); -            tk = tkp1; -             -            /* computing the gradient of the objective function */ -            Obj_func2D(A, D, R1, R2, grad, lambda, dimX, dimY); -             -            /*Taking a step towards minus of the gradient*/ -            Grad_func2D(P1, P2, D, R1, R2, lambda, dimX, dimY); -             -            /* projection step */ -            Proj_func2D(P1, P2, dimX, dimY); -             -            /*updating R and t*/ -            tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; -            Rupd_func2D(P1, P1_old, P2, P2_old, R1, R2, tkp1, tk, dimX, dimY); -             -            /* calculate norm */ -            re = 0.0f; re1 = 0.0f; -            for(j=0; j<dimX*dimY*dimZ; j++) -            { -                re += pow(D[j] - D_old[j],2); -                re1 += pow(D[j],2); -            } -            re = sqrt(re)/sqrt(re1); -            if (re < epsil)  count++; -            if (count > 3) break; -             -            /* check that the residual norm is decreasing */ -            if (ll > 2) { -                if (re > re_old) break; } -             -            re_old = re;             -            /*printf("%f %i %i \n", re, ll, count); */             -        } -        printf("TV iterations stopped at iteration: %i\n", ll);    -    } -    if (number_of_dims == 3) { -        D = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        D_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        P1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        P2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        P3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        P1_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        P2_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        P3_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        R1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        R2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        R3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));         -      -                /* begin iterations */ -        for(ll=0; ll<iter; ll++) { -             -            /*storing old values*/ -            copyIm(D, D_old, dimX, dimY, dimZ); -            copyIm(P1, P1_old, dimX, dimY, dimZ); -            copyIm(P2, P2_old, dimX, dimY, dimZ); -            copyIm(P3, P3_old, dimX, dimY, dimZ); -             -            tk = tkp1; -             -            /* computing the gradient of the objective function */ -            Obj_func3D(A, D, R1, R2, R3,lambda, dimX, dimY, dimZ); -             -            /*Taking a step towards minus of the gradient*/ -            Grad_func3D(P1, P2, P3, D, R1, R2, R3, lambda, dimX, dimY, dimZ); -             -            /* projection step */ -            Proj_func3D(P1, P2, P3, dimX, dimY, dimZ); -             -            /*updating R and t*/ -            tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; -            Rupd_func3D(P1, P1_old, P2, P2_old, P3, P3_old, R1, R2, R3, tkp1, tk, dimX, dimY, dimZ); -             -            /* calculate norm - stopping rules*/ -            re = 0.0f; re1 = 0.0f;  -            for(j=0; j<dimX*dimY*dimZ; j++) -            {                -                re += pow(D[j] - D_old[j],2); -                re1 += pow(D[j],2); -            }             -            re = sqrt(re)/sqrt(re1);     -            /* stop if the norm residual is less than the tolerance EPS */ -            if (re < epsil)  count++; -            if (count > 3) break; -             -            /* check that the residual norm is decreasing */ -            if (ll > 2) { -                if (re > re_old) break; } -             -            re_old = re;             -            /*printf("%f %i %i \n", re, ll, count); */             -        } -        printf("TV iterations stopped at iteration: %i\n", ll);    -    }     -} - -/* 2D-case related Functions */ -/*****************************************************************/ -float Obj_func2D(float *A, float *D, float *R1, float *R2, float *grad, float lambda, int dimX, int dimY) -{ -    float val1, val2; -    int i,j; -#pragma omp parallel for shared(A,D,R1,R2) private(i,j,val1,val2) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            /* symmetric boundary conditions (Neuman) */ -            if (i == 0) {val1 = R1[(i+1)*dimY + (j)];} else {val1 = R1[(i-1)*dimY + (j)];} -            if (j == 0) {val2 = R2[(i)*dimY + (j+1)];} else {val2 = R2[(i)*dimY + (j-1)];} -            D[(i)*dimY + (j)] = A[(i)*dimY + (j)] - lambda*(R1[(i)*dimY + (j)] + R2[(i)*dimY + (j)] - val1 - val2); -            grad[(i)*dimY + (j)] = lambda*(R1[(i)*dimY + (j)] + R2[(i)*dimY + (j)] - val1 - val2); -        }} -    return *D; -} -float Grad_func2D(float *P1, float *P2, float *D, float *R1, float *R2, float lambda, int dimX, int dimY) -{ -    float val1, val2; -    int i,j; -#pragma omp parallel for shared(P1,P2,D,R1,R2) private(i,j,val1,val2) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            /* symmetric boundary conditions (Neuman) */ -             -            if (i == dimX-1) {val1 = D[(i)*dimY + (j)] - D[(i-1)*dimY + (j)];} else {val1 = D[(i)*dimY + (j)] - D[(i+1)*dimY + (j)];} -            if (j == dimY-1) {val2 = D[(i)*dimY + (j)] - D[(i)*dimY + (j-1)];} else {val2 = D[(i)*dimY + (j)] - D[(i)*dimY + (j+1)];} -             -            P1[(i)*dimY + (j)] = R1[(i)*dimY + (j)] + (1.0f/(8.0f*lambda))*val1; -            P2[(i)*dimY + (j)] = R2[(i)*dimY + (j)] + (1.0f/(8.0f*lambda))*val2; -        }} -    return 1; -} -float Proj_func2D(float *P1, float *P2, int dimX, int dimY) -{ -    float val1, val2; -    int i,j; -#pragma omp parallel for shared(P1,P2) private(i,j,val1,val2) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            val1 = fabs(P1[(i)*dimY + (j)]); -            val2 = fabs(P2[(i)*dimY + (j)]); -            if (val1 < 1.0f) {val1 = 1.0f;} -            if (val2 < 1.0f) {val2 = 1.0f;} -             -            P1[(i)*dimY + (j)] = P1[(i)*dimY + (j)]/val1; -            P2[(i)*dimY + (j)] = P2[(i)*dimY + (j)]/val2; -        }} -    return 1; -} -float Rupd_func2D(float *P1, float *P1_old, float *P2, float *P2_old, float *R1, float *R2, float tkp1, float tk, int dimX, int dimY) -{ -    int i,j; -#pragma omp parallel for shared(P1,P2,P1_old,P2_old,R1,R2) private(i,j) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            R1[(i)*dimY + (j)] = P1[(i)*dimY + (j)] + ((tk-1.0f)/tkp1)*(P1[(i)*dimY + (j)] - P1_old[(i)*dimY + (j)]); -            R2[(i)*dimY + (j)] = P2[(i)*dimY + (j)] + ((tk-1.0f)/tkp1)*(P2[(i)*dimY + (j)] - P2_old[(i)*dimY + (j)]); -        }} -    return 1; -} - - -/* 3D-case related Functions */ -/*****************************************************************/ -float Obj_func3D(float *A, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ) -{ -    float val1, val2, val3; -    int i,j,k; -#pragma omp parallel for shared(A,D,R1,R2,R3) private(i,j,k,val1,val2,val3) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            for(k=0; k<dimZ; k++) { -            /* symmetric boundary conditions (Neuman) */ -            if (i == 0) {val1 = R1[(dimX*dimY)*k + (i+1)*dimY + (j)];} else {val1 = R1[(dimX*dimY)*k + (i-1)*dimY + (j)];} -            if (j == 0) {val2 = R2[(dimX*dimY)*k + (i)*dimY + (j+1)];} else {val2 = R2[(dimX*dimY)*k + (i)*dimY + (j-1)];} -            if (k == 0) {val3 = R3[(dimX*dimY)*(k+1) + (i)*dimY + (j)];} else {val3 = R3[(dimX*dimY)*(k-1) + (i)*dimY + (j)];} -            D[(dimX*dimY)*k + (i)*dimY + (j)] = A[(dimX*dimY)*k + (i)*dimY + (j)] - lambda*(R1[(dimX*dimY)*k + (i)*dimY + (j)] + R2[(dimX*dimY)*k + (i)*dimY + (j)] + R3[(dimX*dimY)*k + (i)*dimY + (j)] - val1 - val2 - val3); -        }}} -    return *D; -} -float Grad_func3D(float *P1, float *P2, float *P3, float *D, float *R1, float *R2, float *R3, float lambda, int dimX, int dimY, int dimZ) -{ -    float val1, val2, val3; -    int i,j,k; -#pragma omp parallel for shared(P1,P2,P3,D,R1,R2,R3) private(i,j,k,val1,val2,val3) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -             for(k=0; k<dimZ; k++) { -            /* symmetric boundary conditions (Neuman) */             -            if (i == dimX-1) {val1 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*k + (i-1)*dimY + (j)];} else {val1 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*k + (i+1)*dimY + (j)];} -            if (j == dimY-1) {val2 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*k + (i)*dimY + (j-1)];} else {val2 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*k + (i)*dimY + (j+1)];} -            if (k == dimZ-1) {val3 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*(k-1) + (i)*dimY + (j)];} else {val3 = D[(dimX*dimY)*k + (i)*dimY + (j)] - D[(dimX*dimY)*(k+1) + (i)*dimY + (j)];} -             -            P1[(dimX*dimY)*k + (i)*dimY + (j)] = R1[(dimX*dimY)*k + (i)*dimY + (j)] + (1.0f/(8.0f*lambda))*val1; -            P2[(dimX*dimY)*k + (i)*dimY + (j)] = R2[(dimX*dimY)*k + (i)*dimY + (j)] + (1.0f/(8.0f*lambda))*val2; -            P3[(dimX*dimY)*k + (i)*dimY + (j)] = R3[(dimX*dimY)*k + (i)*dimY + (j)] + (1.0f/(8.0f*lambda))*val3; -        }}} -    return 1; -} -float Proj_func3D(float *P1, float *P2, float *P3, int dimX, int dimY, int dimZ) -{ -    float val1, val2, val3; -    int i,j,k; -#pragma omp parallel for shared(P1,P2,P3) private(i,j,k,val1,val2,val3) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            for(k=0; k<dimZ; k++) { -            val1 = fabs(P1[(dimX*dimY)*k + (i)*dimY + (j)]); -            val2 = fabs(P2[(dimX*dimY)*k + (i)*dimY + (j)]); -            val3 = fabs(P3[(dimX*dimY)*k + (i)*dimY + (j)]); -            if (val1 < 1.0f) {val1 = 1.0f;} -            if (val2 < 1.0f) {val2 = 1.0f;} -            if (val3 < 1.0f) {val3 = 1.0f;} -             -            P1[(dimX*dimY)*k + (i)*dimY + (j)] = P1[(dimX*dimY)*k + (i)*dimY + (j)]/val1; -            P2[(dimX*dimY)*k + (i)*dimY + (j)] = P2[(dimX*dimY)*k + (i)*dimY + (j)]/val2; -            P3[(dimX*dimY)*k + (i)*dimY + (j)] = P3[(dimX*dimY)*k + (i)*dimY + (j)]/val3; -        }}} -    return 1; -} -float Rupd_func3D(float *P1, float *P1_old, float *P2, float *P2_old, float *P3, float *P3_old, float *R1, float *R2, float *R3, float tkp1, float tk, int dimX, int dimY, int dimZ) -{ -    int i,j,k; -#pragma omp parallel for shared(P1,P2,P3,P1_old,P2_old,P3_old,R1,R2,R3) private(i,j,k) -    for(i=0; i<dimX; i++) { -        for(j=0; j<dimY; j++) { -            for(k=0; k<dimZ; k++) { -            R1[(dimX*dimY)*k + (i)*dimY + (j)] = P1[(dimX*dimY)*k + (i)*dimY + (j)] + ((tk-1.0f)/tkp1)*(P1[(dimX*dimY)*k + (i)*dimY + (j)] - P1_old[(dimX*dimY)*k + (i)*dimY + (j)]); -            R2[(dimX*dimY)*k + (i)*dimY + (j)] = P2[(dimX*dimY)*k + (i)*dimY + (j)] + ((tk-1.0f)/tkp1)*(P2[(dimX*dimY)*k + (i)*dimY + (j)] - P2_old[(dimX*dimY)*k + (i)*dimY + (j)]); -            R3[(dimX*dimY)*k + (i)*dimY + (j)] = P3[(dimX*dimY)*k + (i)*dimY + (j)] + ((tk-1.0f)/tkp1)*(P3[(dimX*dimY)*k + (i)*dimY + (j)] - P3_old[(dimX*dimY)*k + (i)*dimY + (j)]); -        }}} -    return 1; -} - -/* General Functions */ -/*****************************************************************/ -/* Copy Image */ -float copyIm(float *A, float *B, int dimX, int dimY, int dimZ) -{ -    int j; -#pragma omp parallel for shared(A, B) private(j) -    for(j=0; j<dimX*dimY*dimZ; j++)  B[j] = A[j]; -    return *B; -}
\ No newline at end of file diff --git a/main_func/LLT_model.c b/main_func/LLT_model.c index a611e54..0aed31e 100644 --- a/main_func/LLT_model.c +++ b/main_func/LLT_model.c @@ -6,7 +6,7 @@  #include <stdio.h>  #include "omp.h" -#define EPS 0.001 +#define EPS 0.01  /* C-OMP implementation of Lysaker, Lundervold and Tai (LLT) model of higher order regularization penalty   * diff --git a/main_func/SplitBregman_TV.c b/main_func/SplitBregman_TV.c index 691ccce..f143aa6 100644 --- a/main_func/SplitBregman_TV.c +++ b/main_func/SplitBregman_TV.c @@ -11,8 +11,9 @@   * Input Parameters:   * 1. Noisy image/volume   * 2. lambda - regularization parameter - * 3. Number of iterations - * 4. eplsilon - tolerance constant + * 3. Number of iterations [OPTIONAL parameter] + * 4. eplsilon - tolerance constant [OPTIONAL parameter] + * 5. TV-type: 'iso' or 'l1' [OPTIONAL parameter]   *   * Output:   * Filtered/regularized image @@ -31,12 +32,13 @@  float copyIm(float *A, float *B, int dimX, int dimY, int dimZ);  float gauss_seidel2D(float *U,  float *A, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda, float mu); -float updDxDy_shrink2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda);  float updDxDy_shrinkAniso2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda); +float updDxDy_shrinkIso2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda);  float updBxBy2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY);  float gauss_seidel3D(float *U, float *A, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda, float mu); -float updDxDyDz_shrink3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda); +float updDxDyDz_shrinkAniso3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda); +float updDxDyDz_shrinkIso3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda);  float updBxByBz3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ);  void mexFunction( @@ -44,28 +46,39 @@ void mexFunction(          int nrhs, const mxArray *prhs[])  { -    int number_of_dims, iter, dimX, dimY, dimZ, ll, j, count; +    int number_of_dims, iter, dimX, dimY, dimZ, ll, j, count, methTV;      const int  *dim_array;      float *A, *U=NULL, *U_old=NULL, *Dx=NULL, *Dy=NULL, *Dz=NULL, *Bx=NULL, *By=NULL, *Bz=NULL, lambda, mu, epsil, re, re1, re_old;      number_of_dims = mxGetNumberOfDimensions(prhs[0]);      dim_array = mxGetDimensions(prhs[0]); -    if(nrhs != 4) mexErrMsgTxt("Four input parameters is reqired: Image(2D/3D), Regularization parameter, Iterations, Tolerance"); +    /*Handling Matlab input data*/ +    if ((nrhs < 2) || (nrhs > 5)) mexErrMsgTxt("At least 2 parameters is required: Image(2D/3D), Regularization parameter. The full list of parameters: Image(2D/3D), Regularization parameter, iterations number, tolerance, penalty type ('iso' or 'l1')");      /*Handling Matlab input data*/      A  = (float *) mxGetData(prhs[0]); /*noisy image (2D/3D) */      mu =  (float) mxGetScalar(prhs[1]); /* regularization parameter */ -    iter =  (int) mxGetScalar(prhs[2]); /* iterations number */ -    epsil =  (float) mxGetScalar(prhs[3]); /* tolerance constant */ +    iter = 35; /* default iterations number */ +    epsil = 0.0001; /* default tolerance constant */ +    methTV = 0;  /* default isotropic TV penalty */ +    if ((nrhs == 3) || (nrhs == 4) || (nrhs == 5))  iter = (int) mxGetScalar(prhs[2]); /* iterations number */ +    if ((nrhs == 4) || (nrhs == 5))  epsil =  (float) mxGetScalar(prhs[3]); /* tolerance constant */ +    if (nrhs == 5)  { +        char *penalty_type; +        penalty_type = mxArrayToString(prhs[4]); /* choosing TV penalty: 'iso' or 'l1', 'iso' is the default */ +        if ((strcmp(penalty_type, "l1") != 0) && (strcmp(penalty_type, "iso") != 0)) mexErrMsgTxt("Choose TV type: 'iso' or 'l1',"); +        if (strcmp(penalty_type, "l1") == 0)  methTV = 1;  /* enable 'l1' penalty */ +        mxFree(penalty_type); +    } +    if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input image must be in a single precision"); } -    lambda = 2.0f*2.0f; +    lambda = 2.0f*mu;      count = 1; -    re_old = 0.0f;    +    re_old = 0.0f;      /*Handling Matlab output data*/      dimY = dim_array[0]; dimX = dim_array[1]; dimZ = dim_array[2]; -          if (number_of_dims == 2) {          dimZ = 1; /*2D case*/          U = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); @@ -73,7 +86,7 @@ void mexFunction(          Dx = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));          Dy = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));          Bx = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); -        By = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));        +        By = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));          copyIm(A, U, dimX, dimY, dimZ); /*initialize */ @@ -82,13 +95,14 @@ void mexFunction(              /*storing old values*/              copyIm(U, U_old, dimX, dimY, dimZ); -            -            gauss_seidel2D(U, A, Dx, Dy, Bx, By, dimX, dimY, lambda, mu);    -           -            updDxDy_shrink2D(U, Dx, Dy, Bx, By, dimX, dimY, lambda); -            //updDxDy_shrinkAniso2D(U, Dx, Dy, Bx, By, dimX, dimY, lambda); -            updBxBy2D(U, Dx, Dy, Bx, By, dimX, dimY);                     +            /*GS iteration */ +            gauss_seidel2D(U, A, Dx, Dy, Bx, By, dimX, dimY, lambda, mu); +             +            if (methTV == 1)  updDxDy_shrinkAniso2D(U, Dx, Dy, Bx, By, dimX, dimY, lambda); +            else updDxDy_shrinkIso2D(U, Dx, Dy, Bx, By, dimX, dimY, lambda); +             +            updBxBy2D(U, Dx, Dy, Bx, By, dimX, dimY);              /* calculate norm to terminate earlier */              re = 0.0f; re1 = 0.0f; @@ -97,20 +111,20 @@ void mexFunction(                  re += pow(U_old[j] - U[j],2);                  re1 += pow(U_old[j],2);              } -            re = sqrt(re)/sqrt(re1);            +            re = sqrt(re)/sqrt(re1);              if (re < epsil)  count++; -            if (count > 4) break;             +            if (count > 4) break;              /* check that the residual norm is decreasing */              if (ll > 2) { -                if (re > re_old) break;  +                if (re > re_old) break;              } -            re_old = re;                -            /*printf("%f %i %i \n", re, ll, count); */             +            re_old = re; +            /*printf("%f %i %i \n", re, ll, count); */ -           /*copyIm(U_old, U, dimX, dimY, dimZ); */ +            /*copyIm(U_old, U, dimX, dimY, dimZ); */          } -        printf("SB iterations stopped at iteration: %i\n", ll);    +        printf("SB iterations stopped at iteration: %i\n", ll);      }      if (number_of_dims == 3) {          U = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); @@ -119,22 +133,24 @@ void mexFunction(          Dy = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));          Dz = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));          Bx = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); -        By = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));        -        Bz = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));        +        By = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); +        Bz = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));          copyIm(A, U, dimX, dimY, dimZ); /*initialize */          /* begin outer SB iterations */          for(ll=0; ll<iter; ll++) { -        /*storing old values*/ -        copyIm(U, U_old, dimX, dimY, dimZ); -            -        gauss_seidel3D(U, A, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ, lambda, mu);         -         -        updDxDyDz_shrink3D(U, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ, lambda); +            /*storing old values*/ +            copyIm(U, U_old, dimX, dimY, dimZ); +             +            /*GS iteration */ +            gauss_seidel3D(U, A, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ, lambda, mu); +             +            if (methTV == 1) updDxDyDz_shrinkAniso3D(U, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ, lambda); +            else updDxDyDz_shrinkIso3D(U, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ, lambda); -        updBxByBz3D(U, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ);                     +            updBxByBz3D(U, Dx, Dy, Dz, Bx, By, Bz, dimX, dimY, dimZ);              /* calculate norm to terminate earlier */              re = 0.0f; re1 = 0.0f; @@ -143,17 +159,17 @@ void mexFunction(                  re += pow(U[j] - U_old[j],2);                  re1 += pow(U[j],2);              } -            re = sqrt(re)/sqrt(re1);            +            re = sqrt(re)/sqrt(re1);              if (re < epsil)  count++; -            if (count > 4) break;             +            if (count > 4) break;              /* check that the residual norm is decreasing */              if (ll > 2) {                  if (re > re_old) break; }              /*printf("%f %i %i \n", re, ll, count); */ -            re_old = re;                        +            re_old = re;          } -        printf("SB iterations stopped at iteration: %i\n", ll);         +        printf("SB iterations stopped at iteration: %i\n", ll);      }  } @@ -167,92 +183,92 @@ float gauss_seidel2D(float *U, float *A, float *Dx, float *Dy, float *Bx, float  #pragma omp parallel for shared(U) private(i,j,i1,i2,j1,j2,sum)      for(i=0; i<dimX; i++) { -            /* symmetric boundary conditions (Neuman) */ -            i1 = i+1; if (i1 == dimX) i1 = i-1; -            i2 = i-1; if (i2 < 0) i2 = i+1; +        /* symmetric boundary conditions (Neuman) */ +        i1 = i+1; if (i1 == dimX) i1 = i-1; +        i2 = i-1; if (i2 < 0) i2 = i+1;          for(j=0; j<dimY; j++) { -            /* symmetric boundary conditions (Neuman) */            +            /* symmetric boundary conditions (Neuman) */              j1 = j+1; if (j1 == dimY) j1 = j-1; -            j2 = j-1; if (j2 < 0) j2 = j+1;            +            j2 = j-1; if (j2 < 0) j2 = j+1; -            sum = Dx[(i2)*dimY + (j)] - Dx[(i)*dimY + (j)] + Dy[(i)*dimY + (j2)] - Dy[(i)*dimY + (j)] - Bx[(i2)*dimY + (j)] + Bx[(i)*dimY + (j)] - By[(i)*dimY + (j2)] + By[(i)*dimY + (j)];               +            sum = Dx[(i2)*dimY + (j)] - Dx[(i)*dimY + (j)] + Dy[(i)*dimY + (j2)] - Dy[(i)*dimY + (j)] - Bx[(i2)*dimY + (j)] + Bx[(i)*dimY + (j)] - By[(i)*dimY + (j2)] + By[(i)*dimY + (j)];              sum += (U[(i1)*dimY + (j)] + U[(i2)*dimY + (j)] + U[(i)*dimY + (j1)] + U[(i)*dimY + (j2)]);              sum *= lambda; -			sum += mu*A[(i)*dimY + (j)];			 +            sum += mu*A[(i)*dimY + (j)];              U[(i)*dimY + (j)] = normConst*sum;          }}      return *U;  } -float updDxDy_shrink2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda)  +float updDxDy_shrinkAniso2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda)  { -   int i,j,i1,j1; -   float val1, val11, val2, val22; -    -   #pragma omp parallel for shared(U) private(i,j,i1,j1,val1,val11,val2,val22) -   for(i=0; i<dimX; i++) { +    int i,j,i1,j1; +    float val1, val11, val2, val22, denom_lam; +    denom_lam = 1.0f/lambda; +#pragma omp parallel for shared(U,denom_lam) private(i,j,i1,j1,val1,val11,val2,val22) +    for(i=0; i<dimX; i++) {          for(j=0; j<dimY; j++) {              /* symmetric boundary conditions (Neuman) */              i1 = i+1; if (i1 == dimX) i1 = i-1;              j1 = j+1; if (j1 == dimY) j1 = j-1; -            +                          val1 = (U[(i1)*dimY + (j)] - U[(i)*dimY + (j)]) + Bx[(i)*dimY + (j)];              val2 = (U[(i)*dimY + (j1)] - U[(i)*dimY + (j)]) + By[(i)*dimY + (j)]; -            val11 = fabs(val1) - 1.0f/lambda; if (val11 < 0) val11 = 0;  -            val22 = fabs(val2) - 1.0f/lambda; if (val22 < 0) val22 = 0;              +            val11 = fabs(val1) - denom_lam; if (val11 < 0) val11 = 0; +            val22 = fabs(val2) - denom_lam; if (val22 < 0) val22 = 0;              if (val1 !=0) Dx[(i)*dimY + (j)] = (val1/fabs(val1))*val11; else Dx[(i)*dimY + (j)] = 0;              if (val2 !=0) Dy[(i)*dimY + (j)] = (val2/fabs(val2))*val22; else Dy[(i)*dimY + (j)] = 0; -        }}    +        }}      return 1;  } -float updDxDy_shrinkAniso2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda)  +float updDxDy_shrinkIso2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY, float lambda)  { -   int i,j,i1,j1; -   float val1, val11, val2, denom, denom_lam;    -   denom_lam = 1.0f/lambda; -    -   #pragma omp parallel for shared(U) private(i,j,i1,j1,val1,val11,val2,denom,denom_lam) -   for(i=0; i<dimX; i++) { +    int i,j,i1,j1; +    float val1, val11, val2, denom, denom_lam; +    denom_lam = 1.0f/lambda; +     +#pragma omp parallel for shared(U,denom_lam) private(i,j,i1,j1,val1,val11,val2,denom) +    for(i=0; i<dimX; i++) {          for(j=0; j<dimY; j++) {              /* symmetric boundary conditions (Neuman) */              i1 = i+1; if (i1 == dimX) i1 = i-1;              j1 = j+1; if (j1 == dimY) j1 = j-1; -            +                          val1 = (U[(i1)*dimY + (j)] - U[(i)*dimY + (j)]) + Bx[(i)*dimY + (j)];              val2 = (U[(i)*dimY + (j1)] - U[(i)*dimY + (j)]) + By[(i)*dimY + (j)];              denom = sqrt(val1*val1 + val2*val2); -            val11 = (denom - denom_lam); if (val11 < 0) val11 = 0.0f;              -                         +            val11 = (denom - denom_lam); if (val11 < 0) val11 = 0.0f; +                          if (denom != 0.0f) { -            Dx[(i)*dimY + (j)] = val11*(val1/denom);  -            Dy[(i)*dimY + (j)] = val11*(val2/denom);  -            }             +                Dx[(i)*dimY + (j)] = val11*(val1/denom); +                Dy[(i)*dimY + (j)] = val11*(val2/denom); +            }              else {                  Dx[(i)*dimY + (j)] = 0;                  Dy[(i)*dimY + (j)] = 0;              } -        }}    +        }}      return 1;  }  float updBxBy2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX, int dimY)  { -   int i,j,i1,j1;    -   #pragma omp parallel for shared(U) private(i,j,i1,j1) -   for(i=0; i<dimX; i++) { +    int i,j,i1,j1; +#pragma omp parallel for shared(U) private(i,j,i1,j1) +    for(i=0; i<dimX; i++) {          for(j=0; j<dimY; j++) {              /* symmetric boundary conditions (Neuman) */              i1 = i+1; if (i1 == dimX) i1 = i-1; -            j1 = j+1; if (j1 == dimY) j1 = j-1;                   +            j1 = j+1; if (j1 == dimY) j1 = j-1;              Bx[(i)*dimY + (j)] = Bx[(i)*dimY + (j)] + ((U[(i1)*dimY + (j)] - U[(i)*dimY + (j)]) - Dx[(i)*dimY + (j)]); -            By[(i)*dimY + (j)] = By[(i)*dimY + (j)] + ((U[(i)*dimY + (j1)] - U[(i)*dimY + (j)]) - Dy[(i)*dimY + (j)]);                -        }}           -       return 1; +            By[(i)*dimY + (j)] = By[(i)*dimY + (j)] + ((U[(i)*dimY + (j1)] - U[(i)*dimY + (j)]) - Dy[(i)*dimY + (j)]); +        }} +    return 1;  } @@ -261,78 +277,115 @@ float updBxBy2D(float *U, float *Dx, float *Dy, float *Bx, float *By, int dimX,  float gauss_seidel3D(float *U, float *A, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda, float mu)  {      float normConst, d_val, b_val, sum; -    int i,j,i1,i2,j1,j2,k,k1,k2;     +    int i,j,i1,i2,j1,j2,k,k1,k2;      normConst = 1.0f/(mu + 6.0f*lambda);  #pragma omp parallel for shared(U) private(i,j,i1,i2,j1,j2,k,k1,k2,d_val,b_val,sum)      for(i=0; i<dimX; i++) {          for(j=0; j<dimY; j++) {              for(k=0; k<dimZ; k++) { -            /* symmetric boundary conditions (Neuman) */ -            i1 = i+1; if (i1 == dimX) i1 = i-1; -            i2 = i-1; if (i2 < 0) i2 = i+1; -            j1 = j+1; if (j1 == dimY) j1 = j-1; -            j2 = j-1; if (j2 < 0) j2 = j+1; -            k1 = k+1; if (k1 == dimZ) k1 = k-1; -            k2 = k-1; if (k2 < 0) k2 = k+1;         -             -            d_val = Dx[(dimX*dimY)*k + (i2)*dimY + (j)] - Dx[(dimX*dimY)*k + (i)*dimY + (j)] + Dy[(dimX*dimY)*k + (i)*dimY + (j2)] - Dy[(dimX*dimY)*k + (i)*dimY + (j)] + Dz[(dimX*dimY)*k2 + (i)*dimY + (j)] - Dz[(dimX*dimY)*k + (i)*dimY + (j)]; -            b_val = -Bx[(dimX*dimY)*k + (i2)*dimY + (j)] + Bx[(dimX*dimY)*k + (i)*dimY + (j)] - By[(dimX*dimY)*k + (i)*dimY + (j2)] + By[(dimX*dimY)*k + (i)*dimY + (j)] - Bz[(dimX*dimY)*k2 + (i)*dimY + (j)] + Bz[(dimX*dimY)*k + (i)*dimY + (j)];                     -            sum =  d_val + b_val; -            sum += U[(dimX*dimY)*k + (i1)*dimY + (j)] + U[(dimX*dimY)*k + (i2)*dimY + (j)] + U[(dimX*dimY)*k + (i)*dimY + (j1)] + U[(dimX*dimY)*k + (i)*dimY + (j2)] + U[(dimX*dimY)*k1 + (i)*dimY + (j)] + U[(dimX*dimY)*k2 + (i)*dimY + (j)]; -            sum *= lambda; -			sum += mu*A[(dimX*dimY)*k + (i)*dimY + (j)];             -            U[(dimX*dimY)*k + (i)*dimY + (j)] = normConst*sum;                  -        }}} -    return *U;    +                /* symmetric boundary conditions (Neuman) */ +                i1 = i+1; if (i1 == dimX) i1 = i-1; +                i2 = i-1; if (i2 < 0) i2 = i+1; +                j1 = j+1; if (j1 == dimY) j1 = j-1; +                j2 = j-1; if (j2 < 0) j2 = j+1; +                k1 = k+1; if (k1 == dimZ) k1 = k-1; +                k2 = k-1; if (k2 < 0) k2 = k+1; +                 +                d_val = Dx[(dimX*dimY)*k + (i2)*dimY + (j)] - Dx[(dimX*dimY)*k + (i)*dimY + (j)] + Dy[(dimX*dimY)*k + (i)*dimY + (j2)] - Dy[(dimX*dimY)*k + (i)*dimY + (j)] + Dz[(dimX*dimY)*k2 + (i)*dimY + (j)] - Dz[(dimX*dimY)*k + (i)*dimY + (j)]; +                b_val = -Bx[(dimX*dimY)*k + (i2)*dimY + (j)] + Bx[(dimX*dimY)*k + (i)*dimY + (j)] - By[(dimX*dimY)*k + (i)*dimY + (j2)] + By[(dimX*dimY)*k + (i)*dimY + (j)] - Bz[(dimX*dimY)*k2 + (i)*dimY + (j)] + Bz[(dimX*dimY)*k + (i)*dimY + (j)]; +                sum =  d_val + b_val; +                sum += U[(dimX*dimY)*k + (i1)*dimY + (j)] + U[(dimX*dimY)*k + (i2)*dimY + (j)] + U[(dimX*dimY)*k + (i)*dimY + (j1)] + U[(dimX*dimY)*k + (i)*dimY + (j2)] + U[(dimX*dimY)*k1 + (i)*dimY + (j)] + U[(dimX*dimY)*k2 + (i)*dimY + (j)]; +                sum *= lambda; +                sum += mu*A[(dimX*dimY)*k + (i)*dimY + (j)]; +                U[(dimX*dimY)*k + (i)*dimY + (j)] = normConst*sum; +            }}} +    return *U;  } -float updDxDyDz_shrink3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda) +float updDxDyDz_shrinkAniso3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda)  { -   int i,j,i1,j1,k,k1; -   float val1, val11, val2, val22, val3, val33; -    -   #pragma omp parallel for shared(U) private(i,j,i1,j1,k,k1,val1,val11,val2,val22,val3,val33) -   for(i=0; i<dimX; i++) { +    int i,j,i1,j1,k,k1,index; +    float val1, val11, val2, val22, val3, val33, denom_lam; +    denom_lam = 1.0f/lambda; +#pragma omp parallel for shared(U,denom_lam) private(index,i,j,i1,j1,k,k1,val1,val11,val2,val22,val3,val33) +    for(i=0; i<dimX; i++) {          for(j=0; j<dimY; j++) {              for(k=0; k<dimZ; k++) { -            /* symmetric boundary conditions (Neuman) */ -            i1 = i+1; if (i1 == dimX) i1 = i-1; -            j1 = j+1; if (j1 == dimY) j1 = j-1; -            k1 = k+1; if (k1 == dimZ) k1 = k-1; -            -            val1 = (U[(dimX*dimY)*k + (i1)*dimY + (j)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) + Bx[(dimX*dimY)*k + (i)*dimY + (j)]; -            val2 = (U[(dimX*dimY)*k + (i)*dimY + (j1)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) + By[(dimX*dimY)*k + (i)*dimY + (j)]; -            val3 = (U[(dimX*dimY)*k1 + (i)*dimY + (j)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) + Bz[(dimX*dimY)*k + (i)*dimY + (j)]; -             -            val11 = fabs(val1) - 1.0f/lambda; if (val11 < 0) val11 = 0;  -            val22 = fabs(val2) - 1.0f/lambda; if (val22 < 0) val22 = 0;              -            val33 = fabs(val3) - 1.0f/lambda; if (val33 < 0) val33 = 0;              -             -            if (val1 !=0) Dx[(dimX*dimY)*k + (i)*dimY + (j)] = (val1/fabs(val1))*val11; else Dx[(dimX*dimY)*k + (i)*dimY + (j)] = 0; -            if (val2 !=0) Dy[(dimX*dimY)*k + (i)*dimY + (j)] = (val2/fabs(val2))*val22; else Dy[(dimX*dimY)*k + (i)*dimY + (j)] = 0; -            if (val3 !=0) Dz[(dimX*dimY)*k + (i)*dimY + (j)] = (val3/fabs(val3))*val33; else Dz[(dimX*dimY)*k + (i)*dimY + (j)] = 0; -             -        }}} +                index = (dimX*dimY)*k + (i)*dimY + (j); +                /* symmetric boundary conditions (Neuman) */ +                i1 = i+1; if (i1 == dimX) i1 = i-1; +                j1 = j+1; if (j1 == dimY) j1 = j-1; +                k1 = k+1; if (k1 == dimZ) k1 = k-1; +                 +                val1 = (U[(dimX*dimY)*k + (i1)*dimY + (j)] - U[index]) + Bx[index]; +                val2 = (U[(dimX*dimY)*k + (i)*dimY + (j1)] - U[index]) + By[index]; +                val3 = (U[(dimX*dimY)*k1 + (i)*dimY + (j)] - U[index]) + Bz[index]; +                 +                val11 = fabs(val1) - denom_lam; if (val11 < 0) val11 = 0; +                val22 = fabs(val2) - denom_lam; if (val22 < 0) val22 = 0; +                val33 = fabs(val3) - denom_lam; if (val33 < 0) val33 = 0; +                 +                if (val1 !=0) Dx[index] = (val1/fabs(val1))*val11; else Dx[index] = 0; +                if (val2 !=0) Dy[index] = (val2/fabs(val2))*val22; else Dy[index] = 0; +                if (val3 !=0) Dz[index] = (val3/fabs(val3))*val33; else Dz[index] = 0; +                 +            }}} +    return 1; +} +float updDxDyDz_shrinkIso3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ, float lambda) +{ +    int i,j,i1,j1,k,k1,index; +    float val1, val11, val2, val3, denom, denom_lam; +    denom_lam = 1.0f/lambda; +#pragma omp parallel for shared(U,denom_lam) private(index,denom,i,j,i1,j1,k,k1,val1,val11,val2,val3) +    for(i=0; i<dimX; i++) { +        for(j=0; j<dimY; j++) { +            for(k=0; k<dimZ; k++) { +                index = (dimX*dimY)*k + (i)*dimY + (j); +                /* symmetric boundary conditions (Neuman) */ +                i1 = i+1; if (i1 == dimX) i1 = i-1; +                j1 = j+1; if (j1 == dimY) j1 = j-1; +                k1 = k+1; if (k1 == dimZ) k1 = k-1; +                 +                val1 = (U[(dimX*dimY)*k + (i1)*dimY + (j)] - U[index]) + Bx[index]; +                val2 = (U[(dimX*dimY)*k + (i)*dimY + (j1)] - U[index]) + By[index]; +                val3 = (U[(dimX*dimY)*k1 + (i)*dimY + (j)] - U[index]) + Bz[index]; +                 +                denom = sqrt(val1*val1 + val2*val2 + val3*val3); +                 +                val11 = (denom - denom_lam); if (val11 < 0) val11 = 0.0f; +                 +                if (denom != 0.0f) { +                    Dx[index] = val11*(val1/denom); +                    Dy[index] = val11*(val2/denom); +                    Dz[index] = val11*(val3/denom); +                } +                else { +                    Dx[index] = 0; +                    Dy[index] = 0; +                    Dz[index] = 0; +                }                +            }}}      return 1;  }  float updBxByBz3D(float *U, float *Dx, float *Dy, float *Dz, float *Bx, float *By, float *Bz, int dimX, int dimY, int dimZ)  { -   int i,j,k,i1,j1,k1;    -   #pragma omp parallel for shared(U) private(i,j,k,i1,j1,k1) -   for(i=0; i<dimX; i++) { +    int i,j,k,i1,j1,k1; +#pragma omp parallel for shared(U) private(i,j,k,i1,j1,k1) +    for(i=0; i<dimX; i++) {          for(j=0; j<dimY; j++) {              for(k=0; k<dimZ; k++) { -            /* symmetric boundary conditions (Neuman) */ -            i1 = i+1; if (i1 == dimX) i1 = i-1; -            j1 = j+1; if (j1 == dimY) j1 = j-1;     -            k1 = k+1; if (k1 == dimZ) k1 = k-1; -             -            Bx[(dimX*dimY)*k + (i)*dimY + (j)] = Bx[(dimX*dimY)*k + (i)*dimY + (j)] + ((U[(dimX*dimY)*k + (i1)*dimY + (j)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) - Dx[(dimX*dimY)*k + (i)*dimY + (j)]); -            By[(dimX*dimY)*k + (i)*dimY + (j)] = By[(dimX*dimY)*k + (i)*dimY + (j)] + ((U[(dimX*dimY)*k + (i)*dimY + (j1)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) - Dy[(dimX*dimY)*k + (i)*dimY + (j)]);                -            Bz[(dimX*dimY)*k + (i)*dimY + (j)] = Bz[(dimX*dimY)*k + (i)*dimY + (j)] + ((U[(dimX*dimY)*k1 + (i)*dimY + (j)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) - Dz[(dimX*dimY)*k + (i)*dimY + (j)]);                -             -        }}}           -       return 1; +                /* symmetric boundary conditions (Neuman) */ +                i1 = i+1; if (i1 == dimX) i1 = i-1; +                j1 = j+1; if (j1 == dimY) j1 = j-1; +                k1 = k+1; if (k1 == dimZ) k1 = k-1; +                 +                Bx[(dimX*dimY)*k + (i)*dimY + (j)] = Bx[(dimX*dimY)*k + (i)*dimY + (j)] + ((U[(dimX*dimY)*k + (i1)*dimY + (j)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) - Dx[(dimX*dimY)*k + (i)*dimY + (j)]); +                By[(dimX*dimY)*k + (i)*dimY + (j)] = By[(dimX*dimY)*k + (i)*dimY + (j)] + ((U[(dimX*dimY)*k + (i)*dimY + (j1)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) - Dy[(dimX*dimY)*k + (i)*dimY + (j)]); +                Bz[(dimX*dimY)*k + (i)*dimY + (j)] = Bz[(dimX*dimY)*k + (i)*dimY + (j)] + ((U[(dimX*dimY)*k1 + (i)*dimY + (j)] - U[(dimX*dimY)*k + (i)*dimY + (j)]) - Dz[(dimX*dimY)*k + (i)*dimY + (j)]); +                 +            }}} +    return 1;  }  /* General Functions */  /*****************************************************************/ diff --git a/main_func/compile_mex.m b/main_func/compile_mex.m index ea6e3a5..4d97bc2 100644 --- a/main_func/compile_mex.m +++ b/main_func/compile_mex.m @@ -1,4 +1,4 @@  % compile mex's  mex LLT_model.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -mex FISTA_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -mex SplitBregman_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp"
\ No newline at end of file +mex FGP_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +mex SplitBregman_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" diff --git a/main_func/studentst.m b/main_func/studentst.m index 99fed1e..93e0a0a 100644 --- a/main_func/studentst.m +++ b/main_func/studentst.m @@ -1,47 +1,47 @@ -function [f,g,h,s,k] = studentst(r,k,s) -% Students T penalty with 'auto-tuning' -% -% use: -%   [f,g,h,{k,{s}}] = studentst(r)     - automatically fits s and k -%   [f,g,h,{k,{s}}] = studentst(r,k)   - automatically fits s -%   [f,g,h,{k,{s}}] = studentst(r,k,s) - use given s and k -% -% input: -%   r - residual as column vector -%   s - scale (optional) -%   k - degrees of freedom (optional) -%  -% output: -%   f - misfit (scalar) -%   g - gradient (column vector) -%   h - positive approximation of the Hessian (column vector, Hessian is a diagonal matrix) -%   s,k - scale and degrees of freedom -% -% Tristan van Leeuwen, 2012. -% tleeuwen@eos.ubc.ca - -% fit both s and k -if nargin == 1 -    opts = optimset('maxFunEvals',1e2); -    tmp = fminsearch(@(x)st(r,x(1),x(2)),[1;2],opts); -    s   = tmp(1); -    k   = tmp(2); -end - - -if nargin == 2 -    opts = optimset('maxFunEvals',1e2); -    tmp = fminsearch(@(x)st(r,x,k),[1],opts); -    s   = tmp(1); -end - -% evaulate penalty -[f,g,h] = st(r,s,k); - - -function [f,g,h] = st(r,s,k) -n = length(r); -c = -n*(gammaln((k+1)/2) - gammaln(k/2) - .5*log(pi*s*k)); -f = c + .5*(k+1)*sum(log(1 + conj(r).*r/(s*k))); -g = (k+1)*r./(s*k + conj(r).*r); -h = (k+1)./(s*k + conj(r).*r); +function [f,g,h,s,k] = studentst(r,k,s)
 +% Students T penalty with 'auto-tuning'
 +%
 +% use:
 +%   [f,g,h,{k,{s}}] = studentst(r)     - automatically fits s and k
 +%   [f,g,h,{k,{s}}] = studentst(r,k)   - automatically fits s
 +%   [f,g,h,{k,{s}}] = studentst(r,k,s) - use given s and k
 +%
 +% input:
 +%   r - residual as column vector
 +%   s - scale (optional)
 +%   k - degrees of freedom (optional)
 +% 
 +% output:
 +%   f - misfit (scalar)
 +%   g - gradient (column vector)
 +%   h - positive approximation of the Hessian (column vector, Hessian is a diagonal matrix)
 +%   s,k - scale and degrees of freedom
 +%
 +% Tristan van Leeuwen, 2012.
 +% tleeuwen@eos.ubc.ca
 +
 +% fit both s and k
 +if nargin == 1
 +    opts = optimset('maxFunEvals',1e2);
 +    tmp = fminsearch(@(x)st(r,x(1),x(2)),[1;2],opts);
 +    s   = tmp(1);
 +    k   = tmp(2);
 +end
 +
 +
 +if nargin == 2
 +    opts = optimset('maxFunEvals',1e2);
 +    tmp = fminsearch(@(x)st(r,x,k),[1],opts);
 +    s   = tmp(1);
 +end
 +
 +% evaulate penalty
 +[f,g,h] = st(r,s,k);
 +
 +
 +function [f,g,h] = st(r,s,k)
 +n = length(r);
 +c = -n*(gammaln((k+1)/2) - gammaln(k/2) - .5*log(pi*s*k));
 +f = c + .5*(k+1)*sum(log(1 + conj(r).*r/(s*k)));
 +g = (k+1)*r./(s*k + conj(r).*r);
 +h = (k+1)./(s*k + conj(r).*r);
 diff --git a/supp/RMSE.m b/supp/RMSE.m index 734e4b8..002f776 100644 --- a/supp/RMSE.m +++ b/supp/RMSE.m @@ -1,7 +1,7 @@ -function err = RMSE(signal1, signal2) -%RMSE Root Mean Squared Error - -err = sum((signal1 - signal2).^2)/length(signal1);  % MSE -err = sqrt(err);                                    % RMSE - +function err = RMSE(signal1, signal2)
 +%RMSE Root Mean Squared Error
 +
 +err = sum((signal1 - signal2).^2)/length(signal1);  % MSE
 +err = sqrt(err);                                    % RMSE
 +
  end
\ No newline at end of file diff --git a/supp/add_wedges.m b/supp/add_wedges.m index 8b8f2a7..5bc215c 100644 --- a/supp/add_wedges.m +++ b/supp/add_wedges.m @@ -27,4 +27,9 @@ grayImage(173:end,:) = 0;  %figure; imshow(grayImage, [0 1]);  MW_sino_artifacts = sino_zing_rings.*double(grayImage); -%Dweights = Dweights.*double(grayImage);
\ No newline at end of file +% !!! +% note that we do not re-calculate Dweights for MW_sino_artifacts +% if one does: Dweights = Dweights.*double(grayImage); +% then the MW artifacts will be reduced substantially,  +% through weighting. However we would like to explore  +% the effect of the penalty instead.
\ No newline at end of file diff --git a/supp/zing_rings_add.m b/supp/zing_rings_add.m index 023ac27..d197b1f 100644 --- a/supp/zing_rings_add.m +++ b/supp/zing_rings_add.m @@ -1,14 +1,23 @@  %  uncomment this part of script to generate data with different noise characterisitcs  fprintf('%s\n', 'Generating Projection Data...'); -multfactor = 1000; +  % Creating RHS (b) - the sinogram (using a strip projection model) -vol_geom = astra_create_vol_geom(N, N); -proj_geom = astra_create_proj_geom('parallel', 1.0, P, theta_rad); -proj_id_temp = astra_create_projector('strip', proj_geom, vol_geom); -[sinogram_id, sinogramIdeal] = astra_create_sino(phantom./multfactor, proj_id_temp); -astra_mex_data2d('delete',sinogram_id); -astra_mex_algorithm('delete',proj_id_temp); +% vol_geom = astra_create_vol_geom(N, N); +% proj_geom = astra_create_proj_geom('parallel', 1.0, P, theta_rad); +% proj_id_temp = astra_create_projector('strip', proj_geom, vol_geom); +% [sinogram_id, sinogramIdeal] = astra_create_sino(phantom, proj_id_temp); +% astra_mex_data2d('delete',sinogram_id); +% astra_mex_algorithm('delete',proj_id_temp); + +%% +% inverse crime data generation +[sino_id, sinogramIdeal] = astra_create_sino3d_cuda(phantom, proj_geom, vol_geom); +astra_mex_data3d('delete', sino_id); + +% [id,x] = astra_create_backprojection3d_cuda(sinogramIdeal, proj_geom, vol_geom); +% astra_mex_data3d('delete', id); +%%  %  % % adding Gaussian noise  % eta = 0.04;  % Relative noise level @@ -20,7 +29,7 @@ astra_mex_algorithm('delete',proj_id_temp);  %%  % adding zingers  val_offset = 0; -sino_zing = sinogramIdeal; +sino_zing = sinogramIdeal';  vec1 = [60, 80, 80, 70, 70, 90, 90, 40, 130, 145, 155, 125];  vec2 = [350, 450, 190, 500, 250, 530, 330, 230, 550, 250, 450, 195];  for jj = 1:length(vec1) @@ -58,19 +67,17 @@ sino_zing_rings(sino_zing_rings < 0) = 0;  % adding Poisson noise  dose = 50000; -dataExp = dose.*exp(-sino_zing_rings); % noiseless raw data -dataPnoise = astra_add_noise_to_sino(dataExp,2*dose); % pre-log noisy raw data (weights) -Dweights = dataPnoise;  -sinogram = log(dose./dataPnoise);  %log corrected data -> sinogram -sinogram = abs(sinogram); -clear dataPnoise dataExp +multifactor = 0.002; -% normalizing -sinogram = sinogram.*multfactor; -sino_zing_rings = sinogram; -Dweights = multfactor./Dweights; +dataExp = dose.*exp(-sino_zing_rings*multifactor); % noiseless raw data +dataPnoise = astra_add_noise_to_sino(dataExp, dose); % pre-log noisy raw data (weights) +sino_zing_rings = log(dose./max(dataPnoise,1))/multifactor; %log corrected data -> sinogram +Dweights = dataPnoise'; % statistical weights +sino_zing_rings = sino_zing_rings'; +clear dataPnoise dataExp  + +% w = dose./exp(sinogram*multifactor); % getting back raw data from log-cor -%  % figure(1);  % set(gcf, 'Position', get(0,'Screensize'));  % subplot(1,2,1); imshow(phantom,[0 0.6]); title('Ideal Phantom'); colorbar; | 
