├── function ├── vec.m ├── nuclear_norm.m └── PSNR.m ├── pic ├── re1.jpg ├── re2.jpg ├── re3.jpg ├── re4.jpg ├── re5.jpg ├── re6.jpg ├── re7.jpg ├── re8.jpg ├── re9.jpg ├── re10.jpg └── re11.jpg ├── new_pic ├── new1.jpg ├── new2.jpg ├── new3.jpg ├── new4.jpg ├── new5.jpg ├── new6.jpg ├── new7.jpg ├── new8.jpg ├── new9.jpg └── new10.jpg ├── mask ├── block_row.bmp ├── block_circle.bmp ├── block_column.bmp ├── block_square.bmp ├── block_star.bmp ├── block_text.bmp ├── block_diamond.bmp ├── block_triangle.bmp ├── block_star_small.bmp ├── block_circle_small.bmp ├── block_diamond_small.bmp ├── block_square_small.bmp └── block_increase_block.bmp ├── .gitignore ├── readme.txt ├── TNNR-admm ├── admmAXB.m └── admm_pic.m ├── TNNR-apgl ├── apglAXB.m └── apgl_pic.m ├── TNNR_synthetic.m └── TNNR_main.m /function/vec.m: -------------------------------------------------------------------------------- 1 | function Y = vec(X) 2 | Y = X(:); 3 | end -------------------------------------------------------------------------------- /pic/re1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re1.jpg -------------------------------------------------------------------------------- /pic/re2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re2.jpg -------------------------------------------------------------------------------- /pic/re3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re3.jpg -------------------------------------------------------------------------------- /pic/re4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re4.jpg -------------------------------------------------------------------------------- /pic/re5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re5.jpg -------------------------------------------------------------------------------- /pic/re6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re6.jpg -------------------------------------------------------------------------------- /pic/re7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re7.jpg -------------------------------------------------------------------------------- /pic/re8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re8.jpg -------------------------------------------------------------------------------- /pic/re9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re9.jpg -------------------------------------------------------------------------------- /pic/re10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re10.jpg -------------------------------------------------------------------------------- /pic/re11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/pic/re11.jpg -------------------------------------------------------------------------------- /new_pic/new1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new1.jpg -------------------------------------------------------------------------------- /new_pic/new2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new2.jpg -------------------------------------------------------------------------------- /new_pic/new3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new3.jpg -------------------------------------------------------------------------------- /new_pic/new4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new4.jpg -------------------------------------------------------------------------------- /new_pic/new5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new5.jpg -------------------------------------------------------------------------------- /new_pic/new6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new6.jpg -------------------------------------------------------------------------------- /new_pic/new7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new7.jpg -------------------------------------------------------------------------------- /new_pic/new8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new8.jpg -------------------------------------------------------------------------------- /new_pic/new9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new9.jpg -------------------------------------------------------------------------------- /mask/block_row.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_row.bmp -------------------------------------------------------------------------------- /new_pic/new10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/new_pic/new10.jpg -------------------------------------------------------------------------------- /mask/block_circle.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_circle.bmp -------------------------------------------------------------------------------- /mask/block_column.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_column.bmp -------------------------------------------------------------------------------- /mask/block_square.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_square.bmp -------------------------------------------------------------------------------- /mask/block_star.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_star.bmp -------------------------------------------------------------------------------- /mask/block_text.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_text.bmp -------------------------------------------------------------------------------- /mask/block_diamond.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_diamond.bmp -------------------------------------------------------------------------------- /mask/block_triangle.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_triangle.bmp -------------------------------------------------------------------------------- /mask/block_star_small.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_star_small.bmp -------------------------------------------------------------------------------- /mask/block_circle_small.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_circle_small.bmp -------------------------------------------------------------------------------- /mask/block_diamond_small.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_diamond_small.bmp -------------------------------------------------------------------------------- /mask/block_square_small.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_square_small.bmp -------------------------------------------------------------------------------- /mask/block_increase_block.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xueshengke/TNNR/HEAD/mask/block_increase_block.bmp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files except *.fig or *.m 2 | 3 | *.m~ 4 | *.asv 5 | 6 | /TNNR-admm/result 7 | /TNNR-apgl/result -------------------------------------------------------------------------------- /function/nuclear_norm.m: -------------------------------------------------------------------------------- 1 | function obj = nuclear_norm(X) 2 | if size(X, 1) > 2000 3 | sigma = svds(X, 100); 4 | else 5 | sigma = svd(X); 6 | end 7 | obj = sum(sigma); 8 | end -------------------------------------------------------------------------------- /function/PSNR.m: -------------------------------------------------------------------------------- 1 | function [ erec, psnr ] = PSNR( X_full, X_rec, missing ) 2 | %-------------------------------------------------------------------------- 3 | % Xue Shengke, Zhejiang University, April 2017. 4 | % Contact information: see readme.txt. 5 | % 6 | % Hu et al. (2013) TNNR paper, IEEE Transactions on PAMI. 7 | % First written by debingzhang, Zhejiang Universiy, November 2012. 8 | %-------------------------------------------------------------------------- 9 | % compute PSNR and reconstruction error for the recovered image and 10 | % original image 11 | % 12 | % Inputs: 13 | % X_full --- original image 14 | % X_rec --- recovered image 15 | % missing --- index matrix of missing elements 16 | % 17 | % Outputs: 18 | % erec --- reconstruction error 19 | % psnr --- PSNR (Peak Signal-to-Noise Ratio) 20 | %-------------------------------------------------------------------------- 21 | 22 | X_rec = max(X_rec, 0); 23 | X_rec = min(X_rec, 255); 24 | 25 | erec = norm(X_full(:) - X_rec(:), 2); 26 | 27 | [m, n, dim] = size(X_rec); 28 | % MSE = 0; 29 | % for i =1 : dim 30 | % MSE = MSE + norm((X_full(:,:,i)-X_rec(:,:,i)) .* missing, 'fro')^2; 31 | % end 32 | MSE = norm(vec((X_full-X_rec).*missing))^2 / nnz(missing); 33 | % MSE = MSE / (3*nnz(missing)); 34 | psnr = 10 * log10(255^2 / MSE); 35 | 36 | end -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | This code includes the detailed implementation of the paper: 2 | 3 | Reference: 4 | Hu, Y., Zhang, D., Ye, J., Li, X., & He, X. (2013). Fast and accurate matrix 5 | completion via truncated nuclear norm regularization. IEEE Transactions on 6 | Pattern Analysis and Machine Intelligence, 35(9), 2117-2130. 7 | 8 | First written by debingzhang, Zhejiang Universiy, November 2012. 9 | 10 | The code contains: 11 | |-------------- 12 | |-- TNNR_main.m entrance to start real image experiment 13 | |-- TNNR_synthetic.m entrance to start synthetic experiment 14 | |-- function 15 | |-- PSNR.m compute the PSNR and Erec for recovered image 16 | |-- nuclear_norm.m compute the nuclear norm of matrix 17 | |-- TNNR-admm/ optimization via ADMM 18 | |-- result/ directory for saving experimental results 19 | |-- admm_pic.m optimization via ADMM 20 | |-- admmAXB.m iteration to sovle ||X||_* 21 | |-- TNNR-apgl/ optimization via APGL 22 | |-- result/ directory for saving experimental results 23 | |-- admm_apgl.m optimization via APGL 24 | |-- apglAXB.m iteration to sovle ||X||_* 25 | observed elements; rows with more observed 26 | elements are given smaller weights 27 | |-- mask/ directory for various mask types, 300x300 28 | |-- pic/ directory for original images 29 | |------------- 30 | 31 | For algorithm interpretation, please read Hu et al. (2013) paper, in which 32 | more details are demonstrated. 33 | 34 | If you have any questions about this implementation, please do not hesitate 35 | to contact me. 36 | 37 | Ph.D. Candidate, Shengke Xue, 38 | College of Information Science and Electronic Engineering, 39 | Zhejiang University, Hangzhou, P. R. China, 40 | e-mail: (either one is o.k.) 41 | xueshengke@zju.edu.cn, xueshengke1993@gmail.com. -------------------------------------------------------------------------------- /TNNR-admm/admmAXB.m: -------------------------------------------------------------------------------- 1 | function [ X_opt, iter ] = admmAXB(A, B, X, M, known, para) 2 | %-------------------------------------------------------------------------- 3 | % Xue Shengke, Zhejiang University, April 2017. 4 | % Contact information: see readme.txt. 5 | % 6 | % Hu et al. (2013) TNNR paper, IEEE Transactions on PAMI. 7 | % First written by debingzhang, Zhejiang Universiy, November 2012. 8 | %-------------------------------------------------------------------------- 9 | % iteratively solve the objective: min ||X||_*-trace(A*X*B') 10 | % 11 | % Inputs: 12 | % A --- left singular vector 13 | % B --- right singular vector 14 | % X --- incomplete image 15 | % M --- original image 16 | % known --- index matrix of known elements 17 | % para --- struct of parameters 18 | % 19 | % Outputs: 20 | % X_opt --- optimized image 21 | % iter --- number of iterations 22 | %-------------------------------------------------------------------------- 23 | 24 | DISPLAY_EVERY = 10; 25 | 26 | max_iter = para.admm_iter; 27 | tol = para.admm_tol; 28 | rho = para.admm_rho; 29 | 30 | W = X; 31 | Y = X; 32 | AB = A' * B; 33 | missing = ones(size(known)) - known; 34 | M_fro = norm(M, 'fro'); 35 | obj_val = zeros(max_iter, 1); 36 | 37 | for k = 1 : max_iter 38 | % X update 39 | last_X = X; 40 | temp = W - Y / rho; 41 | [U, sigma, V] = svd(temp, 'econ'); 42 | X = U * max(sigma - 1/rho, 0) * V'; 43 | 44 | delta = norm(X - last_X, 'fro') / M_fro; 45 | if mod(k, DISPLAY_EVERY) == 0 46 | fprintf(' iter %d, ||X_k+1-X_k||_F/||M||_F=%.4f', k, delta); 47 | end 48 | if delta < tol 49 | fprintf(' converged at\n'); 50 | fprintf(' iter %d, ||X_k+1-X_k||_F/||M||_F=%.4f\n', k, delta); 51 | break ; 52 | end 53 | 54 | % W update 55 | W = X + (AB + Y) / rho; 56 | W = W .* missing + M .* known; 57 | 58 | % Y update 59 | Y = Y + rho * (X - W); 60 | 61 | obj_val(k) = nuclear_norm(X) - trace(A*W*B') ... 62 | + rho / 2 * norm(X-W, 'fro')^2 + trace(Y'*(X-W)); 63 | if mod(k, DISPLAY_EVERY) == 0 64 | fprintf(', obj value=%.4f\n', obj_val(k)); 65 | end 66 | if k > 1 && abs(obj_val(k) - obj_val(k-1)) < tol 67 | fprintf(' converged at\n'); 68 | fprintf(' iter %d, obj value=%.4f\n', k, obj_val(k)); 69 | break; 70 | end 71 | end 72 | 73 | X_opt = X; 74 | iter = k; 75 | 76 | end -------------------------------------------------------------------------------- /TNNR-apgl/apglAXB.m: -------------------------------------------------------------------------------- 1 | function [ X_opt, iter ] = apglAXB( A, B, X, M, known, para) 2 | %-------------------------------------------------------------------------- 3 | % Xue Shengke, Zhejiang University, April 2017. 4 | % Contact information: see readme.txt. 5 | % 6 | % Hu et al. (2013) TNNR paper, IEEE Transactions on PAMI. 7 | % First written by debingzhang, Zhejiang Universiy, November 2012. 8 | %-------------------------------------------------------------------------- 9 | % iteratively solve the objective: min g(x) + h(x) 10 | % g(x) = ||X||_* 11 | % h(x) = - trace(AXB') + \lambda * ||X_\Omega - M_\Omega||_F^2 12 | % Inputs: 13 | % A --- left singular vector 14 | % B --- right singular vector 15 | % X --- incomplete image 16 | % M --- original image 17 | % known --- index matrix of known elements 18 | % para --- struct of parameters 19 | % 20 | % Outputs: 21 | % X_opt --- optimized image 22 | % iter --- number of iterations 23 | %-------------------------------------------------------------------------- 24 | 25 | DISPLAY_EVERY = 10; 26 | 27 | max_iter = para.apgl_iter; 28 | tol = para.apgl_tol; 29 | lambda = para.apgl_lambda; 30 | 31 | AB = A' * B; 32 | Y = X; 33 | t = 1; 34 | M_fro = norm(M, 'fro'); 35 | obj_val = zeros(max_iter, 1); 36 | 37 | for k = 1 : max_iter 38 | % X update 39 | last_X = X; 40 | temp = Y + t * (AB - lambda * (Y - M) .* known); 41 | [U, sigma, V] = svd(temp); 42 | X = U * max(sigma - t, 0) * V'; 43 | 44 | % t update 45 | last_t = t; 46 | t = (1 + sqrt(1 + 4 * last_t^2)) / 2; 47 | 48 | % Y update 49 | Y = X + (last_t-1) / t * (X - last_X); 50 | 51 | delta = norm(X - last_X, 'fro') / M_fro; 52 | if mod(k, DISPLAY_EVERY) == 0 53 | fprintf(' iter %d, ||X_k+1-X_k||_F/||M||_F=%.4f', k, delta); 54 | end 55 | if delta < tol 56 | fprintf(' converged at\n'); 57 | fprintf(' iter %d, ||X_k+1-X_k||_F/||M||_F=%.4f\n', k, delta); 58 | break ; 59 | end 60 | 61 | obj_val(k) = nuclear_norm(X) - trace(A*X*B') ... 62 | + lambda / 2 * norm((X-M).*known, 'fro')^2; 63 | if mod(k, DISPLAY_EVERY) == 0 64 | fprintf(', obj value=%.4f\n', obj_val(k)); 65 | end 66 | if k > 1 && abs(obj_val(k) - obj_val(k-1)) < tol 67 | fprintf(' converged at\n'); 68 | fprintf(' iter %d, obj value=%.4f\n', k, obj_val(k)); 69 | break; 70 | end 71 | end 72 | 73 | X_opt = X; 74 | iter = k; 75 | 76 | end -------------------------------------------------------------------------------- /TNNR-admm/admm_pic.m: -------------------------------------------------------------------------------- 1 | function [result, X_rec] = admm_pic(result_dir, image_name, X_full, mask, para) 2 | %-------------------------------------------------------------------------- 3 | % Xue Shengke, Zhejiang University, April 2017. 4 | % Contact information: see readme.txt. 5 | % 6 | % Hu et al. (2013) TNNR paper, IEEE Transactions on PAMI. 7 | % First written by debingzhang, Zhejiang Universiy, November 2012. 8 | %-------------------------------------------------------------------------- 9 | % main part of TNNR algorithm via ADMM 10 | % 11 | % Inputs: 12 | % result_dir --- result directory for saving figures 13 | % image_name --- name of image file 14 | % X_full --- original image 15 | % mask --- index matrix of known elements 16 | % para --- struct of parameters 17 | % 18 | % Outputs: 19 | % result --- result of algorithm 20 | % X_rec --- recovered image under the best rank 21 | %-------------------------------------------------------------------------- 22 | 23 | X_miss = X_full .* mask; % incomplete image with some pixels lost 24 | [m, n, dim] = size(X_full); 25 | known = mask; % index matrix of known elements 26 | missing = ones(size(mask)) - known; % index matrix of missing elements 27 | 28 | min_R = para.min_R; % minimum rank of chosen image 29 | max_R = para.max_R; % maximum rank of chosen image 30 | max_iter = para.outer_iter; % maximum number of outer iteration 31 | tol = para.outer_tol; % tolerance of outer iteration 32 | 33 | Erec = zeros(max_R, 1); % reconstruction error, best value in each rank 34 | Psnr = zeros(max_R, 1); % PSNR, best value in each rank 35 | time_cost = zeros(max_R, 1); % consuming time, each rank 36 | iter_cost = zeros(max_R, dim); % number of iterations, each channel 37 | total_iter = zeros(max_R, dim); % number of total iterations 38 | X_rec = zeros(m, n, dim, max_iter); % recovered image under the best rank 39 | 40 | best_rank = 0; % record the best value 41 | best_psnr = 0; 42 | best_erec = 0; 43 | 44 | figure('NumberTitle', 'off', 'Name', 'TNNR-ADMM image'); 45 | subplot(1,3,1); 46 | imshow(X_full ./ 255); % show the original image 47 | xlabel('original image'); 48 | 49 | subplot(1,3,2); 50 | imshow(X_miss ./ 255); % show the incomplete image 51 | xlabel('incomplete image'); 52 | 53 | for R = min_R : max_R % test if each rank is proper for completion 54 | t_rank = tic; 55 | X_iter = zeros(m, n, dim, max_iter); 56 | X_temp = zeros(m, n, dim); 57 | for c = 1 : dim % process each channel separately 58 | fprintf('rank(r)=%d, channel(RGB)=%d\n', R, c); 59 | X = X_miss(:, :, c); 60 | M = X_full(:, :, c); 61 | M_fro = norm(M, 'fro'); 62 | last_X = X; 63 | delta = inf; 64 | for i = 1 : max_iter 65 | fprintf('iter %d\n', i); 66 | [U, sigma, V] = svd(X); 67 | A = U(:, 1:R)'; B = V(:, 1:R)'; 68 | [X, iter_count] = admmAXB(A, B, X, M, known(:,:,c), para); 69 | X_iter(:, :, c, i) = X; 70 | 71 | iter_cost(R, c) = iter_cost(R, c) + 1; 72 | total_iter(R, c) = total_iter(R, c) + iter_count; 73 | 74 | delta = norm(X - last_X, 'fro') / M_fro; 75 | fprintf('||X_k+1-X_k||_F/||M||_F %.4f\n', delta); 76 | if delta < tol 77 | fprintf('converged at iter: %d\n', i); 78 | break ; 79 | end 80 | last_X = X; 81 | end 82 | X_temp(:, :, c) = X; 83 | end 84 | time_cost(R) = toc(t_rank); 85 | X_temp = max(X_temp, 0); 86 | X_temp = min(X_temp, 255); 87 | [Erec(R), Psnr(R)] = PSNR(X_full, X_temp, missing); 88 | if best_psnr < Psnr(R) 89 | best_rank = R; 90 | best_psnr = Psnr(R); 91 | best_erec = Erec(R); 92 | X_rec = X_iter; 93 | end 94 | end 95 | %% compute the reconstruction error and PSNR in each iteration 96 | % for the best rank 97 | num_iter = min(iter_cost(best_rank, :)); 98 | psnr_iter = zeros(num_iter, 1); 99 | erec_iter = zeros(num_iter, 1); 100 | for t = 1 : num_iter 101 | X_temp = X_rec(:, :, :, t); 102 | [erec_iter(t), psnr_iter(t)] = PSNR(X_full, X_temp, missing); 103 | end 104 | X_best_rec = X_rec(:, :, :, num_iter); 105 | 106 | %% display recovered image 107 | subplot(1, 3, 3); 108 | X_best_rec = max(X_best_rec, 0); 109 | X_best_rec = min(X_best_rec, 255); 110 | imshow(X_best_rec ./ 255); % show the recovered image 111 | xlabel('recovered image'); 112 | 113 | %% save eps figure in result directory 114 | if para.save_eps 115 | fig_eps = figure; 116 | imshow(X_best_rec ./ 255, 'border', 'tight'); 117 | split_name = regexp(image_name, '[.]', 'split'); 118 | fig_name = sprintf('%s/%s_rank_%d_PSNR_%.2f_Erec_%.2f', ... 119 | result_dir, split_name{1}, best_rank, best_psnr, best_erec); 120 | saveas(gcf, [fig_name '.eps'], 'psc2'); 121 | fprintf('eps figure saved in %s.eps\n', fig_name); 122 | close(fig_eps); 123 | end 124 | 125 | %% record performances for output 126 | result.time = time_cost; 127 | result.iterations = iter_cost; 128 | result.total_iter = total_iter; 129 | result.best_rank = best_rank; 130 | result.best_psnr = best_psnr; 131 | result.best_erec = best_erec; 132 | result.Rank = (min_R : max_R)'; 133 | result.Psnr = Psnr(min_R:max_R); 134 | result.Erec = Erec(min_R:max_R); 135 | result.Psnr_iter = psnr_iter; 136 | result.Erec_iter = erec_iter; 137 | 138 | end -------------------------------------------------------------------------------- /TNNR-apgl/apgl_pic.m: -------------------------------------------------------------------------------- 1 | function [result, X_rec] = apgl_pic(result_dir, image_name, X_full, mask, para) 2 | %-------------------------------------------------------------------------- 3 | % Xue Shengke, Zhejiang University, April 2017. 4 | % Contact information: see readme.txt. 5 | % 6 | % Hu et al. (2013) TNNR paper, IEEE Transactions on PAMI. 7 | % First written by debingzhang, Zhejiang Universiy, November 2012. 8 | %-------------------------------------------------------------------------- 9 | % main part of TNNR algorithm via APGL 10 | % 11 | % Inputs: 12 | % result_dir --- result directory for saving figures 13 | % image_name --- name of image file 14 | % X_full --- original image 15 | % mask --- index matrix of known elements 16 | % para --- struct of parameters 17 | % 18 | % Outputs: 19 | % result --- result of algorithm 20 | % X_rec --- recovered image under the best rank 21 | %-------------------------------------------------------------------------- 22 | 23 | X_miss = X_full .* mask; % incomplete image with some pixels lost 24 | [m, n, dim] = size(X_full); 25 | known = mask; % index matrix of known elements 26 | missing = ones(size(mask)) - known; % index matrix of missing elements 27 | 28 | min_R = para.min_R; % minimum rank of chosen image 29 | max_R = para.max_R; % maximum rank of chosen image 30 | max_iter = para.outer_iter; % maximum number of outer iteration 31 | tol = para.outer_tol; % tolerance of outer iteration 32 | 33 | Erec = zeros(max_R, 1); % reconstruction error, best value in each rank 34 | Psnr = zeros(max_R, 1); % PSNR, best value in each rank 35 | time_cost = zeros(max_R, 1); % consuming time, each rank 36 | iter_cost = zeros(max_R, dim); % number of iterations, each channel 37 | total_iter = zeros(max_R, dim); % number of total iterations 38 | X_rec = zeros(m, n, dim, max_iter); % recovered image under the best rank 39 | 40 | best_rank = 0; % record the best value 41 | best_psnr = 0; 42 | best_erec = 0; 43 | 44 | figure('NumberTitle', 'off', 'Name', 'TNNR-APGL image'); 45 | subplot(1,3,1); 46 | imshow(X_full ./ 255); % show the original image 47 | xlabel('original image'); 48 | 49 | subplot(1,3,2); 50 | imshow(X_miss ./ 255); % show the incomplete image 51 | xlabel('incomplete image'); 52 | 53 | for R = min_R : max_R % test if each rank is proper for completion 54 | t_rank = tic; 55 | X_iter = zeros(m, n, dim, max_iter); 56 | X_temp = zeros(m, n, dim); 57 | for c = 1 : dim % process each channel separately 58 | fprintf('rank(r)=%d, channel(RGB)=%d\n', R, c); 59 | X = X_miss(:, :, c); 60 | M = X_full(:, :, c); 61 | M_fro = norm(M, 'fro'); 62 | last_X = X; 63 | delta = inf; 64 | for i = 1 : max_iter 65 | fprintf('iter %d\n', i); 66 | [U, sigma, V] = svd(X); 67 | A = U(:, 1:R)'; B = V(:, 1:R)'; 68 | [X, iter_count] = apglAXB(A, B, X, M, known(:,:,c), para); 69 | X_iter(:, :, c, i) = X; 70 | 71 | iter_cost(R, c) = iter_cost(R, c) + 1; 72 | total_iter(R, c) = total_iter(R, c) + iter_count; 73 | 74 | delta = norm(X - last_X, 'fro') / M_fro; 75 | fprintf('||X_k+1-X_k||_F/||M||_F %.4f\n', delta); 76 | if delta < tol 77 | fprintf('converged at iter: %d\n', i); 78 | break ; 79 | end 80 | last_X = X; 81 | end 82 | X_temp(:, :, c) = X; 83 | end 84 | time_cost(R) = toc(t_rank); 85 | X_temp = max(X_temp, 0); 86 | X_temp = min(X_temp, 255); 87 | [Erec(R), Psnr(R)] = PSNR(X_full, X_temp, missing); 88 | if best_psnr < Psnr(R) 89 | best_rank = R; 90 | best_psnr = Psnr(R); 91 | best_erec = Erec(R); 92 | X_rec = X_iter; 93 | end 94 | end 95 | %% compute the reconstruction error and PSNR in each iteration 96 | % for the best rank 97 | num_iter = min(iter_cost(best_rank, :)); 98 | psnr_iter = zeros(num_iter, 1); 99 | erec_iter = zeros(num_iter, 1); 100 | for t = 1 : num_iter 101 | X_temp = X_rec(:, :, :, t); 102 | [erec_iter(t), psnr_iter(t)] = PSNR(X_full, X_temp, missing); 103 | end 104 | X_best_rec = X_rec(:, :, :, num_iter); 105 | 106 | %% display recovered image 107 | subplot(1, 3, 3); 108 | X_best_rec = max(X_best_rec, 0); 109 | X_best_rec = min(X_best_rec, 255); 110 | imshow(X_best_rec ./ 255); % show the recovered image 111 | xlabel('recovered image'); 112 | 113 | %% save eps figure in result directory 114 | if para.save_eps 115 | fig_eps = figure; 116 | imshow(X_best_rec ./ 255, 'border', 'tight'); 117 | split_name = regexp(image_name, '[.]', 'split'); 118 | fig_name = sprintf('%s/%s_rank_%d_PSNR_%.2f_Erec_%.2f', ... 119 | result_dir, split_name{1}, best_rank, best_psnr, best_erec); 120 | saveas(gcf, [fig_name '.eps'], 'psc2'); 121 | fprintf('eps figure saved in %s.eps\n', fig_name); 122 | close(fig_eps); 123 | end 124 | 125 | %% record performances for output 126 | result.time = time_cost; 127 | result.iterations = iter_cost; 128 | result.total_iter = total_iter; 129 | result.best_rank = best_rank; 130 | result.best_psnr = best_psnr; 131 | result.best_erec = best_erec; 132 | result.Rank = (min_R : max_R)'; 133 | result.Psnr = Psnr(min_R:max_R); 134 | result.Erec = Erec(min_R:max_R); 135 | result.Psnr_iter = psnr_iter; 136 | result.Erec_iter = erec_iter; 137 | 138 | end -------------------------------------------------------------------------------- /TNNR_synthetic.m: -------------------------------------------------------------------------------- 1 | % Shengke Xue, Zhejiang University, April 2017. 2 | % Contact information: see readme.txt. 3 | % 4 | % Reference: 5 | % Hu, Y., Zhang, D., Ye, J., Li, X., & He, X. (2013). Fast and accurate matrix 6 | % completion via truncated nuclear norm regularization. IEEE Transactions on 7 | % Pattern Analysis and Machine Intelligence, 35(9), 2117-2130. 8 | % 9 | % First written by debingzhang, Zhejiang Universiy, November 2012. 10 | 11 | %% add path 12 | close all; clear ; clc; 13 | % addpath pic ; 14 | % addpath mask ; 15 | % addpath function ; 16 | % addpath TNNR-admm; 17 | % addpath TNNR-apgl; 18 | addpath(genpath(cd)); 19 | 20 | %% read image files directory information 21 | admm_result = './TNNR-admm/result/synthetic'; 22 | apgl_result = './TNNR-apgl/result/synthetic'; 23 | if ~exist(admm_result, 'dir'), mkdir(admm_result); end 24 | if ~exist(apgl_result, 'dir'), mkdir(apgl_result); end 25 | 26 | %% parameter configuration 27 | para.lost = 0.50; % percentage of lost elements in matrix 28 | para.save_eps = 0; % save eps figure in result directory 29 | para.min_R = 1; % minimum rank of chosen image 30 | para.max_R = 20; % maximum rank of chosen image 31 | % it requires to test all ranks from min_R to max_R, note that different 32 | % images have different ranks, and various masks affect the ranks, too. 33 | 34 | para.outer_iter = 200; % maximum number of iteration 35 | para.outer_tol = 3e-4; % tolerance of iteration 36 | 37 | para.admm_iter = 200; % iteration of the ADMM optimization 38 | para.admm_tol = 1e-4; % epsilon of the ADMM optimization 39 | para.admm_rho = 5e-2; % rho of the the ADMM optimization 40 | 41 | para.apgl_iter = 200; % iteration of the APGL optimization 42 | para.apgl_tol = 1e-4; % epsilon of the APGL optimization 43 | para.apgl_lambda = 1e-2; % lambda of the the APGL optimization 44 | para.progress = 0; 45 | 46 | %% generate synthetic data for experiment 47 | image_name = 'synthetic_data'; 48 | m = 200; 49 | n = 200; 50 | dim = 3; 51 | r = 10; 52 | sigma = 0.3; % [0.1, 0.9] 53 | 54 | %% random loss 55 | rnd_idx = randi([0, 100-1], m, n); 56 | old_idx = rnd_idx; 57 | lost = para.lost * 100; 58 | fprintf('loss: %d%% elements are missing.\n', lost); 59 | rnd_idx = double(old_idx < (100-lost)); 60 | mask = repmat(rnd_idx, [1 1 dim]); % index matrix of the known elements 61 | 62 | L = randn(m, r); 63 | R = randn(n, r); 64 | noise = sigma * randn(m, n); 65 | M = L * R' + noise * mask(:,:,1); 66 | M = mapminmax(M, 0, 255); 67 | X_full = repmat(M, [1 1 dim]); 68 | 69 | %% run truncated nuclear norm regularization through ADMM 70 | fprintf('ADMM optimization method to recovery an image with missing pixels\n'); 71 | t1 = tic; 72 | [admm_res, X_rec]= admm_pic(admm_result, image_name, X_full, mask, para); 73 | toc(t1); 74 | 75 | admm_rank = admm_res.best_rank; 76 | admm_psnr = admm_res.best_psnr; 77 | admm_erec = admm_res.best_erec ./ 255; 78 | admm_time_cost = admm_res.time(admm_rank); 79 | admm_iteration = admm_res.iterations(admm_rank, :); 80 | admm_total_iter = admm_res.total_iter(admm_rank, :); 81 | 82 | fprintf('\nTNNR-ADMM: '); 83 | fprintf('rank=%d, psnr=%f, erec=%f, time=%f s, iteration=%d(%d),%d(%d),%d(%d),\n', ... 84 | admm_rank, admm_psnr, admm_erec, admm_time_cost, admm_iteration(1), ... 85 | admm_total_iter(1), admm_iteration(2), admm_total_iter(2), admm_iteration(3), ... 86 | admm_total_iter(3)); 87 | disp(' '); 88 | 89 | figure('NumberTitle', 'off', 'Name', 'TNNR-ADMM result'); 90 | subplot(2, 2, 1); 91 | plot(admm_res.Rank, admm_res.Psnr, 'o-'); 92 | xlabel('Rank'); 93 | ylabel('PSNR'); 94 | 95 | subplot(2, 2, 2); 96 | plot(admm_res.Rank, admm_res.Erec ./ 255, 'diamond-'); 97 | xlabel('Rank'); 98 | ylabel('Recovery error'); 99 | 100 | subplot(2, 2, 3); 101 | plot(admm_res.Psnr_iter, 'square-'); 102 | xlabel('Iteration'); 103 | ylabel('PSNR'); 104 | 105 | subplot(2, 2, 4); 106 | plot(admm_res.Erec_iter ./ 255, '^-'); 107 | xlabel('Iteration'); 108 | ylabel('Recovery error'); 109 | 110 | if para.progress 111 | figure('NumberTitle', 'off', 'Name', 'TNNR-ADMM progress'); 112 | num_iter = min(admm_iteration); 113 | X_rec = X_rec / 255; 114 | for i = 1 : num_iter 115 | imshow(X_rec(:, :, :, i)); 116 | title(['iter ' num2str(i)]); 117 | end % better set a breakpoint here, to display image step by step 118 | end 119 | 120 | %% record test results 121 | outputFileName = fullfile(admm_result, 'parameters.txt'); 122 | fid = fopen(outputFileName, 'a') ; 123 | fprintf(fid, '****** %s ******\n', datestr(now,0)); 124 | fprintf(fid, '%s\n', ['image: ' image_name ]); 125 | fprintf(fid, '%s\n', ['loss ratio: ' num2str(para.lost) ]); 126 | fprintf(fid, '%s\n', ['min rank: ' num2str(para.min_R) ]); 127 | fprintf(fid, '%s\n', ['max rank: ' num2str(para.max_R) ]); 128 | fprintf(fid, '%s\n', ['max iteration: ' num2str(para.outer_iter) ]); 129 | fprintf(fid, '%s\n', ['tolerance: ' num2str(para.outer_tol) ]); 130 | fprintf(fid, '%s\n', ['ADMM iteration: ' num2str(para.admm_iter) ]); 131 | fprintf(fid, '%s\n', ['ADMM tolerance: ' num2str(para.admm_tol) ]); 132 | fprintf(fid, '%s\n', ['ADMM rho: ' num2str(para.admm_rho) ]); 133 | 134 | fprintf(fid, '%s\n', ['sigma: ' num2str(sigma) ]); 135 | fprintf(fid, '%s\n', ['rank: ' num2str(admm_rank) ]); 136 | fprintf(fid, '%s\n', ['psnr: ' num2str(admm_psnr) ]); 137 | fprintf(fid, '%s\n', ['recovery error: ' num2str(admm_erec) ]); 138 | fprintf(fid, '%s\n', ['time cost: ' num2str(admm_time_cost) ]); 139 | fprintf(fid, 'outer iteration: %d, %d, %d\n', admm_iteration(1), ... 140 | admm_iteration(2), admm_iteration(3)); 141 | fprintf(fid, 'total iteration: %d, %d, %d\n', admm_total_iter(1), ... 142 | admm_total_iter(2), admm_total_iter(3)); 143 | fprintf(fid, '--------------------\n'); 144 | fclose(fid); 145 | 146 | %% run truncated nuclear norm regularization through APGL 147 | fprintf('APGL optimization method to recovery an image with missing pixels\n'); 148 | t2 = tic; 149 | [apgl_res, X_rec]= apgl_pic(apgl_result, image_name, X_full, mask, para); 150 | toc(t2); 151 | 152 | apgl_rank = apgl_res.best_rank; 153 | apgl_psnr = apgl_res.best_psnr; 154 | apgl_erec = apgl_res.best_erec ./ 255; 155 | apgl_time_cost = apgl_res.time(apgl_rank); 156 | apgl_iteration = apgl_res.iterations(apgl_rank, :); 157 | apgl_total_iter = apgl_res.total_iter(apgl_rank, :); 158 | 159 | fprintf('\nTNNR-APGL: '); 160 | fprintf('rank=%d, psnr=%f, erec=%f, time=%f s, iteration=%d(%d),%d(%d),%d(%d),\n', ... 161 | apgl_rank, apgl_psnr, apgl_erec, apgl_time_cost, apgl_iteration(1), ... 162 | apgl_total_iter(1), apgl_iteration(2), apgl_total_iter(2), apgl_iteration(3), ... 163 | apgl_total_iter(3)); 164 | disp(' '); 165 | 166 | figure('NumberTitle', 'off', 'Name', 'TNNR-APGL result'); 167 | subplot(2, 2, 1); 168 | plot(apgl_res.Rank, apgl_res.Psnr, 'o-'); 169 | xlabel('Rank'); 170 | ylabel('PSNR'); 171 | 172 | subplot(2, 2, 2); 173 | plot(apgl_res.Rank, apgl_res.Erec ./ 255, 'diamond-'); 174 | xlabel('Rank'); 175 | ylabel('Recovery error'); 176 | 177 | subplot(2, 2, 3); 178 | plot(apgl_res.Psnr_iter, 'square-'); 179 | xlabel('Iteration'); 180 | ylabel('PSNR'); 181 | 182 | subplot(2, 2, 4); 183 | plot(apgl_res.Erec_iter ./ 255, '^-'); 184 | xlabel('Iteration'); 185 | ylabel('Recovery error'); 186 | 187 | if para.progress 188 | figure('NumberTitle', 'off', 'Name', 'TNNR-APGL progress'); 189 | num_iter = min(apgl_iteration); 190 | X_rec = X_rec / 255; 191 | for i = 1 : num_iter 192 | imshow(X_rec(:, :, :, i)); 193 | title(['iter ' num2str(i)]); 194 | end % better set a breakpoint here, to display image step by step 195 | end 196 | 197 | %% record test results 198 | outputFileName = fullfile(apgl_result, 'parameters.txt'); 199 | fid = fopen(outputFileName, 'a') ; 200 | fprintf(fid, '****** %s ******\n', datestr(now,0)); 201 | fprintf(fid, '%s\n', ['image: ' image_name ]); 202 | fprintf(fid, '%s\n', ['loss ratio: ' num2str(para.lost) ]); 203 | fprintf(fid, '%s\n', ['min rank: ' num2str(para.min_R) ]); 204 | fprintf(fid, '%s\n', ['max rank: ' num2str(para.max_R) ]); 205 | fprintf(fid, '%s\n', ['max iteration: ' num2str(para.outer_iter) ]); 206 | fprintf(fid, '%s\n', ['tolerance: ' num2str(para.outer_tol) ]); 207 | fprintf(fid, '%s\n', ['APGL iteration: ' num2str(para.apgl_iter) ]); 208 | fprintf(fid, '%s\n', ['APGL tolerance: ' num2str(para.apgl_tol) ]); 209 | fprintf(fid, '%s\n', ['APGL lambda: ' num2str(para.apgl_lambda)]); 210 | 211 | fprintf(fid, '%s\n', ['sigma: ' num2str(sigma) ]); 212 | fprintf(fid, '%s\n', ['rank: ' num2str(apgl_rank) ]); 213 | fprintf(fid, '%s\n', ['psnr: ' num2str(apgl_psnr) ]); 214 | fprintf(fid, '%s\n', ['recovery error: ' num2str(apgl_erec) ]); 215 | fprintf(fid, '%s\n', ['time cost: ' num2str(apgl_time_cost) ]); 216 | fprintf(fid, 'outer iteration: %d, %d, %d\n', apgl_iteration(1), ... 217 | apgl_iteration(2), apgl_iteration(3)); 218 | fprintf(fid, 'total iteration: %d, %d, %d\n', apgl_total_iter(1), ... 219 | apgl_total_iter(2), apgl_total_iter(3)); 220 | fprintf(fid, '--------------------\n'); 221 | fclose(fid); 222 | -------------------------------------------------------------------------------- /TNNR_main.m: -------------------------------------------------------------------------------- 1 | % Shengke Xue, Zhejiang University, April 2017. 2 | % Contact information: see readme.txt. 3 | % 4 | % Reference: 5 | % Hu, Y., Zhang, D., Ye, J., Li, X., & He, X. (2013). Fast and accurate matrix 6 | % completion via truncated nuclear norm regularization. IEEE Transactions on 7 | % Pattern Analysis and Machine Intelligence, 35(9), 2117-2130. 8 | % 9 | % First written by debingzhang, Zhejiang Universiy, November 2012. 10 | 11 | %% add path 12 | close all; clear ; clc; 13 | % addpath pic ; 14 | % addpath mask ; 15 | % addpath function ; 16 | % addpath TNNR-admm; 17 | % addpath TNNR-apgl; 18 | addpath(genpath(cd)); 19 | 20 | %% read image files directory information 21 | admm_result = './TNNR-admm/result/image'; 22 | apgl_result = './TNNR-apgl/result/image'; 23 | if ~exist(admm_result, 'dir'), mkdir(admm_result); end 24 | if ~exist(apgl_result, 'dir'), mkdir(apgl_result); end 25 | % image_list = {'re1.jpg', 're2.jpg', 're3.jpg', 're4.jpg', 're5.jpg', ... 26 | % 're6.jpg', 're7.jpg', 're8.jpg', 're9.jpg', 're10.jpg', ... 27 | % 're11.jpg' }; 28 | image_list = {'new1.jpg', 'new2.jpg', 'new3.jpg', 'new4.jpg', 'new5.jpg', ... 29 | 'new6.jpg', 'new7.jpg', 'new8.jpg', 'new9.jpg', 'new10.jpg', ... 30 | }; 31 | 32 | file_list = dir('mask'); 33 | num_mask = length(file_list) - 2; 34 | mask_list = cell(num_mask, 1); 35 | for i = 1 : num_mask 36 | mask_list{i} = file_list(i+2).name; 37 | end 38 | 39 | %% parameter configuration 40 | image_id = 9; % select an image for experiment 41 | mask_id = 4; % select a mask for experiment 42 | 43 | para.block = 0; % 1 for block occlusion, 0 for random noise 44 | para.lost = 0.50; % percentage of lost elements in matrix 45 | para.save_eps = 1; % save eps figure in result directory 46 | para.min_R = 1; % minimum rank of chosen image 47 | para.max_R = 20; % maximum rank of chosen image 48 | % it requires to test all ranks from min_R to max_R, note that different 49 | % images have different ranks, and various masks affect the ranks, too. 50 | 51 | para.outer_iter = 100; % maximum number of iteration 52 | para.outer_tol = 3e-4; % tolerance of iteration 53 | 54 | para.admm_iter = 200; % iteration of the ADMM optimization 55 | para.admm_tol = 1e-4; % epsilon of the ADMM optimization 56 | para.admm_rho = 5e-2; % rho of the the ADMM optimization 57 | 58 | para.apgl_iter = 200; % iteration of the APGL optimization 59 | para.apgl_tol = 1e-4; % epsilon of the APGL optimization 60 | para.apgl_lambda = 1e-2; % lambda of the the APGL optimization 61 | para.progress = 0; 62 | 63 | %% select an image and a mask for experiment 64 | image_name = image_list{image_id}; 65 | X_full = double(imread(image_name)); 66 | [m, n, dim] = size(X_full); 67 | fprintf('choose image: %s, ', image_name); 68 | 69 | if para.block 70 | % block occlusion 71 | mask = double(imread(mask_list{mask_id})); 72 | mask = mask ./ max(mask(:)); % index matrix of the known elements 73 | fprintf('mask: %s.\n', mask_list{mask_id}); 74 | else 75 | % random loss 76 | % rnd_idx = randi([0, 100-1], m, n); 77 | % old_idx = rnd_idx; 78 | % lost = para.lost * 100; 79 | % fprintf('loss: %d%% elements are missing.\n', lost); 80 | % rnd_idx = double(old_idx < (100-lost)); 81 | % mask = repmat(rnd_idx, [1 1 dim]); % index matrix of the known elements 82 | 83 | rnd_idx = randi([0, 100-1], m, n, dim); 84 | old_idx = rnd_idx; 85 | lost = para.lost * 100; 86 | fprintf('loss: %d%% elements are missing.\n', lost); 87 | rnd_idx = double(old_idx < (100-lost)); 88 | mask = rnd_idx; % index matrix of the known elements 89 | end 90 | 91 | %% run truncated nuclear norm regularization through ADMM 92 | fprintf('ADMM optimization method to recover an image with missing pixels\n'); 93 | t1 = tic; 94 | [admm_res, X_rec]= admm_pic(admm_result, image_name, X_full, mask, para); 95 | toc(t1); 96 | 97 | admm_rank = admm_res.best_rank; 98 | admm_psnr = admm_res.best_psnr; 99 | admm_erec = admm_res.best_erec; 100 | admm_time_cost = admm_res.time(admm_rank); 101 | admm_iteration = admm_res.iterations(admm_rank, :); 102 | admm_total_iter = admm_res.total_iter(admm_rank, :); 103 | 104 | fprintf('\nTNNR-ADMM: '); 105 | fprintf('rank=%d, psnr=%f, erec=%f, time=%f s, iteration=%d(%d),%d(%d),%d(%d),\n', ... 106 | admm_rank, admm_psnr, admm_erec, admm_time_cost, admm_iteration(1), ... 107 | admm_total_iter(1), admm_iteration(2), admm_total_iter(2), admm_iteration(3), ... 108 | admm_total_iter(3)); 109 | disp(' '); 110 | 111 | figure('NumberTitle', 'off', 'Name', 'TNNR-ADMM result'); 112 | subplot(2, 2, 1); 113 | plot(admm_res.Rank, admm_res.Psnr, 'o-'); 114 | xlabel('Rank'); 115 | ylabel('PSNR'); 116 | 117 | subplot(2, 2, 2); 118 | plot(admm_res.Rank, admm_res.Erec, 'diamond-'); 119 | xlabel('Rank'); 120 | ylabel('Recovery error'); 121 | 122 | subplot(2, 2, 3); 123 | plot(admm_res.Psnr_iter, 'square-'); 124 | xlabel('Iteration'); 125 | ylabel('PSNR'); 126 | 127 | subplot(2, 2, 4); 128 | plot(admm_res.Erec_iter, '^-'); 129 | xlabel('Iteration'); 130 | ylabel('Recovery error'); 131 | 132 | if para.progress 133 | figure('NumberTitle', 'off', 'Name', 'TNNR-ADMM progress'); 134 | num_iter = min(admm_iteration); 135 | X_rec = X_rec / 255; 136 | for i = 1 : num_iter 137 | imshow(X_rec(:, :, :, i)); 138 | title(['iter ' num2str(i)]); 139 | end % better set a breakpoint here, to display image step by step 140 | end 141 | 142 | %% record test results 143 | outputFileName = fullfile(admm_result, 'parameters.txt'); 144 | fid = fopen(outputFileName, 'a') ; 145 | fprintf(fid, '****** %s ******\n', datestr(now,0)); 146 | fprintf(fid, '%s\n', ['image: ' image_name ]); 147 | fprintf(fid, '%s\n', ['mask: ' mask_list{mask_id} ]); 148 | fprintf(fid, '%s\n', ['block or noise: ' num2str(para.block) ]); 149 | fprintf(fid, '%s\n', ['loss ratio: ' num2str(para.lost) ]); 150 | fprintf(fid, '%s\n', ['save eps figure: ' num2str(para.save_eps) ]); 151 | fprintf(fid, '%s\n', ['min rank: ' num2str(para.min_R) ]); 152 | fprintf(fid, '%s\n', ['max rank: ' num2str(para.max_R) ]); 153 | fprintf(fid, '%s\n', ['max iteration: ' num2str(para.outer_iter) ]); 154 | fprintf(fid, '%s\n', ['tolerance: ' num2str(para.outer_tol) ]); 155 | fprintf(fid, '%s\n', ['ADMM iteration: ' num2str(para.admm_iter) ]); 156 | fprintf(fid, '%s\n', ['ADMM tolerance: ' num2str(para.admm_tol) ]); 157 | fprintf(fid, '%s\n', ['ADMM rho: ' num2str(para.admm_rho) ]); 158 | 159 | fprintf(fid, '%s\n', ['rank: ' num2str(admm_rank) ]); 160 | fprintf(fid, '%s\n', ['psnr: ' num2str(admm_psnr) ]); 161 | fprintf(fid, '%s\n', ['recovery error: ' num2str(admm_erec) ]); 162 | fprintf(fid, '%s\n', ['time cost: ' num2str(admm_time_cost) ]); 163 | fprintf(fid, 'outer iteration: %d, %d, %d\n', admm_iteration(1), ... 164 | admm_iteration(2), admm_iteration(3)); 165 | fprintf(fid, 'total iteration: %d, %d, %d\n', admm_total_iter(1), ... 166 | admm_total_iter(2), admm_total_iter(3)); 167 | fprintf(fid, '--------------------\n'); 168 | fclose(fid); 169 | 170 | %% run truncated nuclear norm regularization through APGL 171 | fprintf('APGL optimization method to recover an image with missing pixels\n'); 172 | t2 = tic; 173 | [apgl_res, X_rec]= apgl_pic(apgl_result, image_name, X_full, mask, para); 174 | toc(t2); 175 | 176 | apgl_rank = apgl_res.best_rank; 177 | apgl_psnr = apgl_res.best_psnr; 178 | apgl_erec = apgl_res.best_erec; 179 | apgl_time_cost = apgl_res.time(apgl_rank); 180 | apgl_iteration = apgl_res.iterations(apgl_rank, :); 181 | apgl_total_iter = apgl_res.total_iter(apgl_rank, :); 182 | 183 | fprintf('\nTNNR-APGL: '); 184 | fprintf('rank=%d, psnr=%f, erec=%f, time=%f s, iteration=%d(%d),%d(%d),%d(%d),\n', ... 185 | apgl_rank, apgl_psnr, apgl_erec, apgl_time_cost, apgl_iteration(1), ... 186 | apgl_total_iter(1), apgl_iteration(2), apgl_total_iter(2), apgl_iteration(3), ... 187 | apgl_total_iter(3)); 188 | disp(' '); 189 | 190 | figure('NumberTitle', 'off', 'Name', 'TNNR-APGL result'); 191 | subplot(2, 2, 1); 192 | plot(apgl_res.Rank, apgl_res.Psnr, 'o-'); 193 | xlabel('Rank'); 194 | ylabel('PSNR'); 195 | 196 | subplot(2, 2, 2); 197 | plot(apgl_res.Rank, apgl_res.Erec, 'diamond-'); 198 | xlabel('Rank'); 199 | ylabel('Recovery error'); 200 | 201 | subplot(2, 2, 3); 202 | plot(apgl_res.Psnr_iter, 'square-'); 203 | xlabel('Iteration'); 204 | ylabel('PSNR'); 205 | 206 | subplot(2, 2, 4); 207 | plot(apgl_res.Erec_iter, '^-'); 208 | xlabel('Iteration'); 209 | ylabel('Recovery error'); 210 | 211 | if para.progress 212 | figure('NumberTitle', 'off', 'Name', 'TNNR-APGL progress'); 213 | num_iter = min(apgl_iteration); 214 | X_rec = X_rec / 255; 215 | for i = 1 : num_iter 216 | imshow(X_rec(:, :, :, i)); 217 | title(['iter ' num2str(i)]); 218 | end % better set a breakpoint here, to display image step by step 219 | end 220 | 221 | %% record test results 222 | outputFileName = fullfile(apgl_result, 'parameters.txt'); 223 | fid = fopen(outputFileName, 'a') ; 224 | fprintf(fid, '****** %s ******\n', datestr(now,0)); 225 | fprintf(fid, '%s\n', ['image: ' image_name ]); 226 | fprintf(fid, '%s\n', ['mask: ' mask_list{mask_id} ]); 227 | fprintf(fid, '%s\n', ['block or noise: ' num2str(para.block) ]); 228 | fprintf(fid, '%s\n', ['loss ratio: ' num2str(para.lost) ]); 229 | fprintf(fid, '%s\n', ['save eps figure: ' num2str(para.save_eps) ]); 230 | fprintf(fid, '%s\n', ['min rank: ' num2str(para.min_R) ]); 231 | fprintf(fid, '%s\n', ['max rank: ' num2str(para.max_R) ]); 232 | fprintf(fid, '%s\n', ['max iteration: ' num2str(para.outer_iter) ]); 233 | fprintf(fid, '%s\n', ['tolerance: ' num2str(para.outer_tol) ]); 234 | fprintf(fid, '%s\n', ['APGL iteration: ' num2str(para.apgl_iter) ]); 235 | fprintf(fid, '%s\n', ['APGL tolerance: ' num2str(para.apgl_tol) ]); 236 | fprintf(fid, '%s\n', ['APGL lambda: ' num2str(para.apgl_lambda)]); 237 | 238 | fprintf(fid, '%s\n', ['rank: ' num2str(apgl_rank) ]); 239 | fprintf(fid, '%s\n', ['psnr: ' num2str(apgl_psnr) ]); 240 | fprintf(fid, '%s\n', ['recovery error: ' num2str(apgl_erec) ]); 241 | fprintf(fid, '%s\n', ['time cost: ' num2str(apgl_time_cost) ]); 242 | fprintf(fid, 'outer iteration: %d, %d, %d\n', apgl_iteration(1), ... 243 | apgl_iteration(2), apgl_iteration(3)); 244 | fprintf(fid, 'total iteration: %d, %d, %d\n', apgl_total_iter(1), ... 245 | apgl_total_iter(2), apgl_total_iter(3)); 246 | fprintf(fid, '--------------------\n'); 247 | fclose(fid); 248 | --------------------------------------------------------------------------------