├── LICENSE ├── Project 1 ├── Problem1.pdf └── src │ ├── Histogram_Equalization.m │ ├── data │ ├── Fig1.jpg │ └── Fig2.jpg │ ├── myEqualization.m │ └── myImhist.m ├── Project 10 ├── problem10.pdf └── src │ ├── a │ ├── boundary.m │ ├── data │ │ └── noisy_stroke.tif │ ├── draw_boundary.m │ ├── draw_line.m │ ├── draw_pixels.m │ ├── draw_subsample.m │ ├── enlarge.m │ ├── find_next_boundary.m │ ├── otsu.m │ ├── outer_boundary.m │ ├── segment.m │ ├── smallest_integer.m │ └── subsample_boundary.m │ └── b │ ├── PC.m │ ├── data │ ├── WashingtonDC_Band1.tif │ ├── WashingtonDC_Band2.tif │ ├── WashingtonDC_Band3.tif │ ├── WashingtonDC_Band4.tif │ ├── WashingtonDC_Band5.tif │ └── WashingtonDC_Band6.tif │ ├── image_description.m │ └── remap.m ├── Project 2 ├── problem2.pdf └── src │ ├── data │ ├── final_result.png │ ├── laplace_result.png │ ├── product_laplace_sobel.png │ ├── sharpened_image.png │ ├── sharpened_laplace_result.png │ ├── skeleton_orig.png │ ├── skeleton_orig.tif │ ├── smoothed_sobel_grad.png │ └── sobel_grad.png │ ├── enhance.m │ ├── imfilter.m │ └── remap.m ├── Project 3 ├── problem3.pdf └── src │ ├── butterworth_highpass_filter.m │ ├── butterworth_lowpass_filter.m │ ├── data │ └── characters_test_pattern.tif │ ├── frequency_filter.m │ ├── gaussian_highpass_filter.m │ ├── gaussian_lowpass_filter.m │ ├── ideal_highpass_filter.m │ └── ideal_lowpass_filter.m ├── Project 4 ├── problem4.pdf └── src │ ├── alpha_trimmed_mean_filter.m │ ├── arithmatic_mean_filter.m │ ├── contraharmonic_mean_filter.m │ ├── data │ └── Circuit.tif │ ├── exponential_noise.m │ ├── gamma_noise.m │ ├── gaussian_noise.m │ ├── geometric_mean_filter.m │ ├── max_filter.m │ ├── median_filter.m │ ├── min_filter.m │ ├── noise_and_recovery.m │ ├── pepper_noise.m │ ├── rayleigh_noise.m │ └── uniform_noise.m ├── Project 5 ├── problem5.pdf └── src │ ├── center_transform.m │ ├── data │ └── book_cover.jpg │ ├── filter_H.m │ ├── gaussian_noise.m │ ├── image_restore.m │ └── wiener_filter.m ├── Project 6 ├── problem6.pdf └── src │ ├── bilinear_interpolation.m │ ├── data │ └── ray_trace_bottle.tif │ ├── geometric_transform.m │ ├── nearest_neighbor_interpolation.m │ ├── rotate_matrix.m │ ├── scale_matrix.m │ └── translate_matrix.m ├── Project 7 ├── problem7.pdf └── src │ ├── data │ └── lenna.tif │ ├── dct.m │ ├── difference.m │ ├── dwt_2.m │ ├── dwt_3level.m │ ├── h_phi_to_h_psi.m │ ├── idwt_2.m │ ├── idwt_3level.m │ └── transform_image_compression.m ├── Project 8 ├── problem8.pdf └── src │ ├── data │ ├── Fig0929(a)(text_image).tif │ └── Fig0931(a)(text_image).tif │ ├── dilate.m │ ├── erode.m │ ├── geodesic_dilation.m │ └── morpholigical_processing.m ├── Project 9 ├── problem9.pdf └── src │ ├── a │ ├── canny.m │ ├── data │ │ └── building.tif │ ├── edge_detect.m │ ├── marr_hildreth.m │ ├── remap_image.m │ ├── threshold.m │ └── zero_crossing.m │ └── b │ ├── basic_global_thresholding.m │ ├── data │ └── polymersomes.tif │ ├── image_segmentation.m │ ├── otsu.m │ └── segment.m └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Xiangyu Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Project 1/Problem1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 1/Problem1.pdf -------------------------------------------------------------------------------- /Project 1/src/Histogram_Equalization.m: -------------------------------------------------------------------------------- 1 | clc;clear; 2 | %% Write a computer program for computing the histogram of an image. 3 | fig1 = imread('data/Fig1.jpg'); 4 | fig2 = imread('data/Fig2.jpg'); 5 | figure('Name', 'Original Histogram'); 6 | set(gcf, 'position', [0 0 1024 512]); 7 | subplot(1, 2, 1); 8 | [L1 D1] = myImhist(fig1); 9 | title('Fig 1'); 10 | subplot(1, 2, 2); 11 | [L2 D2] = myImhist(fig2); 12 | title('Fig 2'); 13 | 14 | %% Implement the histogram equalization technique. 15 | figure('Name', 'Transformation of Fig. 1'); 16 | set(gcf, 'position', [0 0 960 512]); 17 | subplot(1, 2, 1); 18 | imshow(fig1, []); 19 | R1 = myEqualization(L1, D1); 20 | for i = 1:size(fig1, 1) 21 | for j = 1:size(fig1, 2) 22 | fig1(i, j) = R1(fig1(i, j) + 1); 23 | end 24 | end 25 | subplot(1, 2, 2); 26 | imshow(fig1, []); 27 | 28 | figure('Name', 'Transformation of Fig. 2'); 29 | set(gcf, 'position', [0 0 1024 512]); 30 | subplot(1, 2, 1); 31 | imshow(fig2, []); 32 | R2 = myEqualization(L2, D2); 33 | for i = 1:size(fig2, 1) 34 | for j = 1:size(fig2, 2) 35 | fig2(i, j) = R2(fig2(i, j) + 1); 36 | end 37 | end 38 | subplot(1, 2, 2); 39 | imshow(fig2, []); 40 | 41 | figure('Name', 'Transformation Function'); 42 | subplot(1, 2, 1); 43 | plot(R1); 44 | subplot(1, 2, 2); 45 | plot(R2); 46 | 47 | figure('Name', 'Equalized Histogram'); 48 | set(gcf, 'position', [0 0 1024 512]); 49 | subplot(1, 2, 1); 50 | [L1 D1] = myImhist(fig1); 51 | %title('Fig 1'); 52 | subplot(1, 2, 2); 53 | [L2 D2] = myImhist(fig2); 54 | %title('Fig 2'); -------------------------------------------------------------------------------- /Project 1/src/data/Fig1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 1/src/data/Fig1.jpg -------------------------------------------------------------------------------- /Project 1/src/data/Fig2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 1/src/data/Fig2.jpg -------------------------------------------------------------------------------- /Project 1/src/myEqualization.m: -------------------------------------------------------------------------------- 1 | function [ output_distribution ] = myEqualization( L, distribution ) 2 | %MYEQUALIZATION equalizes the histogram 3 | % It returns a mapping that equalizes the original distribution 4 | 5 | output_distribution = distribution; 6 | for i = 2:size(distribution); 7 | output_distribution(i) = output_distribution(i-1) + distribution(i); 8 | end 9 | output_distribution = output_distribution * (L - 1) / sum(distribution(:)); 10 | 11 | 12 | end 13 | 14 | -------------------------------------------------------------------------------- /Project 1/src/myImhist.m: -------------------------------------------------------------------------------- 1 | function [ L, distribution ] = myImhist( fig ) 2 | %MYIMHIST creates the histogram of a given image. 3 | % The function returns the number of pixels for each gray level, 4 | % and draws a figure automatically. 5 | L = 8; 6 | if L <= max(max(fig)) 7 | L = 256; 8 | end 9 | distribution = zeros(L, 1); 10 | for i = 1:size(fig, 1) 11 | for j = 1:size(fig, 2) 12 | distribution(fig(i, j) + 1, 1) = distribution(fig(i, j) + 1, 1) + 1; 13 | end 14 | end 15 | % distribution = table(:, 2); 16 | distribution = distribution ./ size(fig, 1) ./ size(fig, 2) 17 | s = size(distribution); 18 | b = bar(distribution,'FaceColor', 'blue', 'EdgeColor', 'blue','LineWidth',0.6); 19 | set(gca,'XLim',[0 L]); 20 | set(gca,'XTick',[0:L/4:L]); 21 | set(gca,'XTickLabel',[0:L/4:L]); 22 | ylabel('Occurance'); 23 | colormap(gray); 24 | c = colorbar('Location', 'southoutside', 'FontSize',10, 'Ticks', 0:64:256, 'TickLabels', {'0', '64', '128', '192', '256'}); 25 | c.Label.String = 'Intensity'; 26 | 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /Project 10/problem10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/problem10.pdf -------------------------------------------------------------------------------- /Project 10/src/a/boundary.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/a/boundary.m -------------------------------------------------------------------------------- /Project 10/src/a/data/noisy_stroke.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/a/data/noisy_stroke.tif -------------------------------------------------------------------------------- /Project 10/src/a/draw_boundary.m: -------------------------------------------------------------------------------- 1 | function [ output ] = draw_boundary( x, y, h, w ) 2 | %DRAW_BOUNDARY 3 | output = zeros(h, w); 4 | for i = 2:size(x, 1) 5 | output = draw_line(output, x(i - 1), y(i - 1), x(i), y(i)); 6 | end 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Project 10/src/a/draw_line.m: -------------------------------------------------------------------------------- 1 | function [ output ] = draw_line( input, x1, y1, x2, y2 ) 2 | %DRAW_LINE draws a line on image 3 | output = input; 4 | if x1 == x2 5 | if y1 > y2 6 | y1 = y1 + y2; 7 | y2 = y1 - y2; 8 | y1 = y1 - y2; 9 | end 10 | for i = y1:y2 11 | output(x1, i) = 1; 12 | end 13 | elseif y1 == y2 14 | if x1 > x2 15 | x1 = x1 + x2; 16 | x2 = x1 - x2; 17 | x1 = x1 - x2; 18 | end 19 | for i = x1:x2 20 | output(i, y1) = 1; 21 | end 22 | end 23 | end 24 | 25 | -------------------------------------------------------------------------------- /Project 10/src/a/draw_pixels.m: -------------------------------------------------------------------------------- 1 | function [ output ] = draw_pixels( h, w, b_x, b_y ) 2 | %DRAW_PIXELS 3 | output = zeros(h, w); 4 | for i = 1:size(b_x, 1) 5 | output(b_x(i), b_y(i)) = 1; 6 | end 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Project 10/src/a/draw_subsample.m: -------------------------------------------------------------------------------- 1 | function [ output ] = draw_subsample( mark, H, W, radius, rate ) 2 | %DRAW_SUBSAMPLE 3 | output = zeros(H, W); 4 | [x, y] = find(mark > 0); 5 | [X, Y] = enlarge(x, y, H, W ,rate); 6 | for i = 1:size(x, 1) 7 | for j = -radius:radius 8 | for k = -radius:radius 9 | output(X(i) + j, Y(i) + k) = 1; 10 | end 11 | end 12 | end 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Project 10/src/a/enlarge.m: -------------------------------------------------------------------------------- 1 | function [ X, Y ] = enlarge( x, y, H, W ,rate ) 2 | %ENLARGE 3 | h = H / rate; 4 | w = W / rate; 5 | X = round((x - 1) * h) + 1; 6 | Y = round((y - 1) * w) + 1; 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Project 10/src/a/find_next_boundary.m: -------------------------------------------------------------------------------- 1 | function [ b1_x, b1_y, c1 ] = find_next_boundary( input, b0_x, b0_y, c, n ) 2 | %FIND_NEXT_BOUNDARY 3 | if n == 8 4 | adj_x = [0 -1 -1 -1 0 1 1 1]; 5 | adj_y = [-1 -1 0 1 1 1 0 -1]; 6 | elseif n == 4 7 | adj_x = [0 -1 0 1]; 8 | adj_y = [-1 0 1 0]; 9 | end 10 | for i = c+size(adj_x, 2)-1:c+2*size(adj_x, 2)-2 11 | d = mod(i, size(adj_x, 2)) + 1; 12 | b1_x = b0_x + adj_x(d); 13 | b1_y = b0_y + adj_y(d); 14 | if (n == 8 || b1_x + adj_x(mod(c, n) + 1) ~= b0_x || b1_y + adj_y(mod(c, n) + 1) ~= b0_y) && input(b1_x, b1_y) > 0 15 | c1 = mod(d + size(adj_x, 2) - 2, size(adj_x, 2)) + 1; 16 | break; 17 | end 18 | if n == 4 19 | c1 = c; 20 | b1_x = b0_x + adj_x(mod(c, 4) + 1); 21 | b1_y = b0_y + adj_y(mod(c, 4) + 1); 22 | end 23 | end 24 | end 25 | 26 | -------------------------------------------------------------------------------- /Project 10/src/a/otsu.m: -------------------------------------------------------------------------------- 1 | function [ output ] = otsu( input ) 2 | %OTSU 3 | % Gonzalez DIP 10.3.3 4 | [h, w] = size(input); 5 | n = h * w; 6 | mG = mean(mean(input)); 7 | P = zeros(256, 1); 8 | m = zeros(256, 1); 9 | for i = 0:255 10 | P(i + 1) = length(find(input == i)) / n; 11 | end 12 | for i = 1:255 13 | m(i + 1) = m(i) + P(i + 1) * i; 14 | P(i + 1) = P(i + 1) + P(i); 15 | end 16 | sigmaB2 = ((mG * P - m) .^ 2) ./ P ./ (1 - P); 17 | T = mean(find(sigmaB2 == max(sigmaB2))); 18 | output = segment(input, T); 19 | end 20 | 21 | -------------------------------------------------------------------------------- /Project 10/src/a/outer_boundary.m: -------------------------------------------------------------------------------- 1 | function [ b_x, b_y, C, CD ] = outer_boundary( input, n ) 2 | %OUTER_BOUNDARY computes the longest outer boundary of given image 3 | % Gonzalez DIP 11.1 4 | [h, w] = size(input); 5 | b_x = zeros(2 * (h + w), 1); 6 | b_y = zeros(2 * (h + w), 1); 7 | C = zeros(2 * (h + w), 1); 8 | [x, y] = find(input > 0); 9 | pos = min(find(x + y == min(x + y))); 10 | b_x(1) = x(pos); 11 | b_y(1) = y(pos); 12 | c = 1; 13 | [b_x(2), b_y(2), c] = find_next_boundary(input, b_x(1), b_y(1), c, n); 14 | C(1) = mod(c, n) + 1; 15 | cnt = 2; 16 | while b_x(cnt) ~= b_x(1) || b_y(cnt) ~= b_y(1) 17 | [b_x(cnt + 1), b_y(cnt + 1), c] = find_next_boundary(input, b_x(cnt), b_y(cnt), c, n); 18 | C(cnt) = mod(c, n) + 1; 19 | cnt = cnt + 1; 20 | end 21 | C = C(1:cnt - 1); 22 | if n == 4 23 | C = 2 * mod(3 - C, 4); 24 | end 25 | C = smallest_integer(C); 26 | for i = 1:cnt-2 27 | CD(i) = mod(C(i + 1) - C(i), 8); 28 | end 29 | CD(cnt - 1) = mod(-sum(CD), 8); 30 | b_x = b_x(1:cnt); 31 | b_y = b_y(1:cnt); 32 | end 33 | 34 | -------------------------------------------------------------------------------- /Project 10/src/a/segment.m: -------------------------------------------------------------------------------- 1 | function [ output ] = segment( input, k ) 2 | %SEGMENT 3 | % output(x, y) = 0, input(x, y) <= k 4 | % 1, input(x, y) > k 5 | output = zeros(size(input)); 6 | output(input > k) = 1; 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Project 10/src/a/smallest_integer.m: -------------------------------------------------------------------------------- 1 | function [ output ] = smallest_integer( input ) 2 | %SMALLEST_INTEGER 3 | % used for chain code 4 | l = size(input, 1); 5 | cnt = zeros(l, 1); 6 | if input(l) == 0 7 | cnt(l) = 1; 8 | for i = 1:l-1 9 | if input(i) == 0 10 | cnt(l) = cnt(l) + 1 11 | else 12 | break; 13 | end 14 | end 15 | end 16 | for i = l-1:-1:1 17 | if input(i) == 0 18 | cnt(i) = min(cnt(i + 1) + 1, l); 19 | end 20 | end 21 | pos = min(find(cnt == max(cnt))); 22 | output = [input(pos:l, 1); input(1:pos-1, 1)]; 23 | end 24 | 25 | -------------------------------------------------------------------------------- /Project 10/src/a/subsample_boundary.m: -------------------------------------------------------------------------------- 1 | function [ mark ] = subsample_boundary( input, rate ) 2 | %SUBSAMPLE_BOUNDARY computes the subsampled boundary of given boundary 3 | % Gonzalez DIP 11.1 4 | [H, W] = size(input); 5 | h = H / rate; 6 | w = W / rate; 7 | rate = ceil(rate) + 1; 8 | mark = zeros(rate, rate); 9 | [X, Y] = find(input > 0); 10 | x = round(X / h) + 1; 11 | y = round(Y / w) + 1; 12 | for i = 1:size(X, 1) 13 | mark(x(i), y(i)) = 1; 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /Project 10/src/b/PC.m: -------------------------------------------------------------------------------- 1 | function [ components, reconstruct ] = PC( input ) 2 | %PC = principal components 3 | c = size(input, 2); 4 | [h, w] = size(input{1, 1}); 5 | data = zeros(c, h, w); 6 | for i = 1:c 7 | data(i, :, :) = input{1, i}; 8 | end 9 | data = data(:, :); 10 | mx = mean(data, 2); 11 | cx = zeros(c, c); 12 | for i = 1:size(data, 2) 13 | cx = cx + data(:, i) * data(:, i)'; 14 | end 15 | cx = cx / size(data, 2) - mx * mx'; 16 | [A, D] = eig(cx); 17 | [D, I] = sort(diag(D), 'descend') 18 | A = A(:, I)'; 19 | y = reshape(A * (data - mx), c, h, w); 20 | components = cell(1,6); 21 | for i = 1:c 22 | components{1, i} = reshape(y(i, :, :), h, w); 23 | end 24 | x_hat = A(1:2, :)' * A(1:2, :) * (data - mx) + mx; 25 | reconstruct = cell(1,6); 26 | for i = 1:c 27 | reconstruct{1, i} = reshape(x_hat(i, :, :), h, w); 28 | end 29 | end 30 | 31 | -------------------------------------------------------------------------------- /Project 10/src/b/data/WashingtonDC_Band1.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/b/data/WashingtonDC_Band1.tif -------------------------------------------------------------------------------- /Project 10/src/b/data/WashingtonDC_Band2.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/b/data/WashingtonDC_Band2.tif -------------------------------------------------------------------------------- /Project 10/src/b/data/WashingtonDC_Band3.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/b/data/WashingtonDC_Band3.tif -------------------------------------------------------------------------------- /Project 10/src/b/data/WashingtonDC_Band4.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/b/data/WashingtonDC_Band4.tif -------------------------------------------------------------------------------- /Project 10/src/b/data/WashingtonDC_Band5.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/b/data/WashingtonDC_Band5.tif -------------------------------------------------------------------------------- /Project 10/src/b/data/WashingtonDC_Band6.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 10/src/b/data/WashingtonDC_Band6.tif -------------------------------------------------------------------------------- /Project 10/src/b/image_description.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = cell(1,6); 4 | figure('Name', 'Original images'); 5 | for i = 1:6 6 | subplot(2, 3, i); 7 | fig_original{1, i} = imread(sprintf('data/WashingtonDC_Band%d.tif', i)); 8 | imshow(fig_original{1, i}, []); 9 | imwrite(fig_original{1, i}, sprintf('data/WashingtonDC_Band%d.png', i)); 10 | end 11 | 12 | %% Principal components 13 | figure('Name', 'Principal components'); 14 | [components, reconstruct] = PC(fig_original); 15 | for i = 1:6 16 | subplot(2, 3, i); 17 | imshow(components{1, i}, []); 18 | imwrite(remap(components{1, i}), sprintf('data/components%d.png', i)); 19 | end 20 | 21 | %% Reconstructed images 22 | figure('Name', 'Reconstructed images'); 23 | for i = 1:6 24 | subplot(2, 3, i); 25 | imshow(reconstruct{1, i}, []); 26 | imwrite(remap(reconstruct{1, i}), sprintf('data/reconstruct%d.png', i)); 27 | end -------------------------------------------------------------------------------- /Project 10/src/b/remap.m: -------------------------------------------------------------------------------- 1 | function [ output ] = remap( input ) 2 | %REMAP 3 | output = uint8((input - min(min(input))) / (max(max(input)) - min(min(input))) * 255); 4 | end 5 | 6 | -------------------------------------------------------------------------------- /Project 2/problem2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/problem2.pdf -------------------------------------------------------------------------------- /Project 2/src/data/final_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/final_result.png -------------------------------------------------------------------------------- /Project 2/src/data/laplace_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/laplace_result.png -------------------------------------------------------------------------------- /Project 2/src/data/product_laplace_sobel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/product_laplace_sobel.png -------------------------------------------------------------------------------- /Project 2/src/data/sharpened_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/sharpened_image.png -------------------------------------------------------------------------------- /Project 2/src/data/sharpened_laplace_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/sharpened_laplace_result.png -------------------------------------------------------------------------------- /Project 2/src/data/skeleton_orig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/skeleton_orig.png -------------------------------------------------------------------------------- /Project 2/src/data/skeleton_orig.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/skeleton_orig.tif -------------------------------------------------------------------------------- /Project 2/src/data/smoothed_sobel_grad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/smoothed_sobel_grad.png -------------------------------------------------------------------------------- /Project 2/src/data/sobel_grad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 2/src/data/sobel_grad.png -------------------------------------------------------------------------------- /Project 2/src/enhance.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | % (a) The original image 4 | fig_original = double(imread('data/skeleton_orig.tif')) / 255; 5 | figure; 6 | subplot(2, 4, 1); 7 | imshow(fig_original); 8 | imwrite(fig_original, 'data/skeleton_orig.png'); 9 | 10 | % (b) The Laplacian of the original image 11 | laplace_result = imfilter([-1 -1 -1; -1 8 -1; -1 -1 -1], fig_original); 12 | subplot(2, 4, 2); 13 | imshow(remap(laplace_result, 0, 1)); 14 | imwrite(remap(laplace_result, 0, 1), 'data/laplace_result.png'); 15 | 16 | % (c) The sharpened image using Laplacian 17 | sharpened_laplace_result = fig_original + laplace_result; 18 | subplot(2, 4, 3); 19 | imshow(sharpened_laplace_result); 20 | imwrite(sharpened_laplace_result, 'data/sharpened_laplace_result.png'); 21 | 22 | % (d) The Sobel gradient of the original image 23 | sobel_grad = abs(imfilter([-1 -2 -1; 0 0 0; 1 2 1], fig_original)) + abs(imfilter([-1 0 1; -2 0 2; -1 0 1], fig_original)); 24 | subplot(2, 4, 4); 25 | imshow(sobel_grad); 26 | imwrite(sobel_grad, 'data/sobel_grad.png'); 27 | 28 | % (e) The smoothed Sobel gradient 29 | smoothed_sobel_grad = imfilter(ones(5)/25, sobel_grad); 30 | subplot(2, 4, 5); 31 | imshow(smoothed_sobel_grad); 32 | imwrite(smoothed_sobel_grad, 'data/smoothed_sobel_grad.png'); 33 | 34 | % (f) Mask image formed by the product of (c) and (e) 35 | product_laplace_sobel = sharpened_laplace_result .* smoothed_sobel_grad; 36 | subplot(2, 4, 6); 37 | imshow(product_laplace_sobel); 38 | imwrite(product_laplace_sobel, 'data/product_laplace_sobel.png'); 39 | 40 | % (g) Sharpened image obtained by the sum of (a) and (f) 41 | sharpened_image = max(fig_original + product_laplace_sobel, 0); 42 | subplot(2, 4, 7); 43 | imshow(sharpened_image); 44 | imwrite(sharpened_image, 'data/sharpened_image.png'); 45 | 46 | % (h) Final result obtained by applying a powerlaw transformation to (g) 47 | final_result = power(sharpened_image, 0.5); 48 | subplot(2, 4, 8); 49 | imshow(final_result); 50 | imwrite(final_result, 'data/final_result.png'); 51 | -------------------------------------------------------------------------------- /Project 2/src/imfilter.m: -------------------------------------------------------------------------------- 1 | function [ g ] = imfilter( w, x ) 2 | %IMFILTER conducts the filter operation given filter w and matrix x 3 | % Paddings are automatically computered, with stepsize = 1. 4 | [h_x, w_x] = size(x); 5 | [h_w, w_w] = size(w); 6 | h_w_half = (h_w - 1) / 2; 7 | w_w_half = (w_w - 1) / 2; 8 | g = zeros(h_x, w_x); 9 | for i = 1 : h_x 10 | for j = 1 : w_x 11 | g(i, j) = 0; 12 | for k = -h_w_half : h_w_half 13 | for l = -w_w_half : w_w_half 14 | if i + k > 0 && i + k <= h_x && j + l > 0 && j + l <= w_x 15 | g(i, j) = g(i, j) + w(k + h_w_half + 1, l + w_w_half + 1) * x(i + k, j + l); 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | 23 | -------------------------------------------------------------------------------- /Project 2/src/remap.m: -------------------------------------------------------------------------------- 1 | function [ output ] = remap( input, lb, ub ) 2 | %REMAP remaps a matrix to the interval [lb, ub] 3 | % lb = lower bound, ub = upper bound 4 | if max(max(input)) ~= min(min(input)) 5 | output = (input - min(min(input))) / (max(max(input)) - min(min(input))) * (ub - lb) + lb; 6 | else 7 | output = input - input + (ub + lb) / 2; 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /Project 3/problem3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 3/problem3.pdf -------------------------------------------------------------------------------- /Project 3/src/butterworth_highpass_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = butterworth_highpass_filter( m, n, D0, N ) 2 | %BUTTERWORTH_HIGHPASS_FILTER The Butterworth highpass filter 3 | % H(u, v) = 1 - (1 / (1 + (D(u, v) / D0)^2n)) 4 | u = [0:(m-1) -m:-1]; 5 | v = [0:(n-1) -n:-1]; 6 | [V, U] = meshgrid(v, u); 7 | D = sqrt((V.^2 + U.^2)); 8 | output = 1 - (1 ./ (1 + (D ./ D0).^(2 * N))); 9 | end 10 | 11 | -------------------------------------------------------------------------------- /Project 3/src/butterworth_lowpass_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = butterworth_lowpass_filter( m, n, D0, N ) 2 | %BUTTERWORTH_LOWPASS_FILTER The Butterworth lowpass filter 3 | % H(u, v) = 1 / (1 + (D(u, v) / D0)^2n) 4 | u = [0:(m-1) -m:-1]; 5 | v = [0:(n-1) -n:-1]; 6 | [V, U] = meshgrid(v, u); 7 | D = sqrt((V.^2 + U.^2)); 8 | output = 1 ./ (1 + (D ./ D0).^(2 * N)); 9 | end 10 | 11 | -------------------------------------------------------------------------------- /Project 3/src/data/characters_test_pattern.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 3/src/data/characters_test_pattern.tif -------------------------------------------------------------------------------- /Project 3/src/frequency_filter.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = double(imread('data/characters_test_pattern.tif')) / 255; 4 | imwrite(fig_original, 'data/characters_test_pattern.png'); 5 | 6 | %% Discrete Fourier Transformation 7 | F = fft2(fig_original, size(fig_original, 1) * 2, size(fig_original, 2) * 2); 8 | 9 | %% Ideal Lowpass Filter 10 | % The original image 11 | figure('Name', 'Ideal Lowpass Filter'); 12 | subplot(2, 3, 1); 13 | imshow(fig_original, []) 14 | title('original image'); 15 | % ILPF with cutoff frequency set at radii value 10 16 | ideal_lowpass_10 = real(ifft2(ideal_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 10) .* F)); 17 | ideal_lowpass_10 = ideal_lowpass_10(1:size(fig_original, 1), 1:size(fig_original, 2)); 18 | subplot(2, 3, 2); 19 | imshow(ideal_lowpass_10, []) 20 | title('cutoff frequency: 10'); 21 | imwrite(ideal_lowpass_10, 'data/ILPF_10.png'); 22 | % ILPF with cutoff frequency set at radii value 30 23 | ideal_lowpass_30 = real(ifft2(ideal_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 30) .* F)); 24 | ideal_lowpass_30 = ideal_lowpass_30(1:size(fig_original, 1), 1:size(fig_original, 2)); 25 | subplot(2, 3, 3); 26 | imshow(ideal_lowpass_30, []) 27 | title('cutoff frequency: 30'); 28 | imwrite(ideal_lowpass_30, 'data/ILPF_30.png'); 29 | % ILPF with cutoff frequency set at radii value 60 30 | ideal_lowpass_60 = real(ifft2(ideal_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 60) .* F)); 31 | ideal_lowpass_60 = ideal_lowpass_60(1:size(fig_original, 1), 1:size(fig_original, 2)); 32 | subplot(2, 3, 4); 33 | imshow(ideal_lowpass_60, []) 34 | title('cutoff frequency: 60'); 35 | imwrite(ideal_lowpass_60, 'data/ILPF_60.png'); 36 | % ILPF with cutoff frequency set at radii value 160 37 | ideal_lowpass_160 = real(ifft2(ideal_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 160) .* F)); 38 | ideal_lowpass_160 = ideal_lowpass_160(1:size(fig_original, 1), 1:size(fig_original, 2)); 39 | subplot(2, 3, 5); 40 | imshow(ideal_lowpass_160, []) 41 | title('cutoff frequency: 160'); 42 | imwrite(ideal_lowpass_160, 'data/ILPF_160.png'); 43 | % ILPF with cutoff frequency set at radii value 460 44 | ideal_lowpass_460 = real(ifft2(ideal_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 460) .* F)); 45 | ideal_lowpass_460 = ideal_lowpass_460(1:size(fig_original, 1), 1:size(fig_original, 2)); 46 | subplot(2, 3, 6); 47 | imshow(ideal_lowpass_460, []) 48 | title('cutoff frequency: 460'); 49 | imwrite(ideal_lowpass_460, 'data/ILPF_460.png'); 50 | 51 | %% Butterworth Lowpass Filter 52 | % The original image 53 | figure('Name', 'Butterworth Lowpass Filter'); 54 | subplot(2, 3, 1); 55 | imshow(fig_original, []) 56 | title('original image'); 57 | % BLPF with cutoff frequency set at radii value 10 58 | butterworth_lowpass_10 = real(ifft2(butterworth_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 10, 2) .* F)); 59 | butterworth_lowpass_10 = butterworth_lowpass_10(1:size(fig_original, 1), 1:size(fig_original, 2)); 60 | subplot(2, 3, 2); 61 | imshow(butterworth_lowpass_10, []) 62 | title('cutoff frequency: 10'); 63 | imwrite(butterworth_lowpass_10, 'data/BLPF_10.png'); 64 | % BLPF with cutoff frequency set at radii value 30 65 | butterworth_lowpass_30 = real(ifft2(butterworth_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 30, 2) .* F)); 66 | butterworth_lowpass_30 = butterworth_lowpass_30(1:size(fig_original, 1), 1:size(fig_original, 2)); 67 | subplot(2, 3, 3); 68 | imshow(butterworth_lowpass_30, []) 69 | title('cutoff frequency: 30'); 70 | imwrite(butterworth_lowpass_30, 'data/BLPF_30.png'); 71 | % BLPF with cutoff frequency set at radii value 60 72 | butterworth_lowpass_60 = real(ifft2(butterworth_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 60, 2) .* F)); 73 | butterworth_lowpass_60 = butterworth_lowpass_60(1:size(fig_original, 1), 1:size(fig_original, 2)); 74 | subplot(2, 3, 4); 75 | imshow(butterworth_lowpass_60, []) 76 | title('cutoff frequency: 60'); 77 | imwrite(butterworth_lowpass_60, 'data/BLPF_60.png'); 78 | % BLPF with cutoff frequency set at radii value 160 79 | butterworth_lowpass_160 = real(ifft2(butterworth_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 160, 2) .* F)); 80 | butterworth_lowpass_160 = butterworth_lowpass_160(1:size(fig_original, 1), 1:size(fig_original, 2)); 81 | subplot(2, 3, 5); 82 | imshow(butterworth_lowpass_160, []) 83 | title('cutoff frequency: 160'); 84 | imwrite(butterworth_lowpass_160, 'data/BLPF_160.png'); 85 | % BLPF with cutoff frequency set at radii value 460 86 | butterworth_lowpass_460 = real(ifft2(butterworth_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 460, 2) .* F)); 87 | butterworth_lowpass_460 = butterworth_lowpass_460(1:size(fig_original, 1), 1:size(fig_original, 2)); 88 | subplot(2, 3, 6); 89 | imshow(butterworth_lowpass_460, []) 90 | title('cutoff frequency: 460'); 91 | imwrite(butterworth_lowpass_460, 'data/BLPF_460.png'); 92 | 93 | %% Gaussian Lowpass Filter 94 | % The original image 95 | figure('Name', 'Gaussian Lowpass Filter'); 96 | subplot(2, 3, 1); 97 | imshow(fig_original, []) 98 | title('original image'); 99 | % GLPF with cutoff frequency set at radii value 10 100 | gaussian_lowpass_10 = real(ifft2(gaussian_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 10) .* F)); 101 | gaussian_lowpass_10 = gaussian_lowpass_10(1:size(fig_original, 1), 1:size(fig_original, 2)); 102 | subplot(2, 3, 2); 103 | imshow(gaussian_lowpass_10, []) 104 | title('cutoff frequency: 10'); 105 | imwrite(gaussian_lowpass_10, 'data/GLPF_10.png'); 106 | % GLPF with cutoff frequency set at radii value 30 107 | gaussian_lowpass_30 = real(ifft2(gaussian_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 30) .* F)); 108 | gaussian_lowpass_30 = gaussian_lowpass_30(1:size(fig_original, 1), 1:size(fig_original, 2)); 109 | subplot(2, 3, 3); 110 | imshow(gaussian_lowpass_30, []) 111 | title('cutoff frequency: 30'); 112 | imwrite(gaussian_lowpass_30, 'data/GLPF_30.png'); 113 | % GLPF with cutoff frequency set at radii value 60 114 | gaussian_lowpass_60 = real(ifft2(gaussian_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 60) .* F)); 115 | gaussian_lowpass_60 = gaussian_lowpass_60(1:size(fig_original, 1), 1:size(fig_original, 2)); 116 | subplot(2, 3, 4); 117 | imshow(gaussian_lowpass_60, []) 118 | title('cutoff frequency: 60'); 119 | imwrite(gaussian_lowpass_60, 'data/GLPF_60.png'); 120 | % GLPF with cutoff frequency set at radii value 160 121 | gaussian_lowpass_160 = real(ifft2(gaussian_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 160) .* F)); 122 | gaussian_lowpass_160 = gaussian_lowpass_160(1:size(fig_original, 1), 1:size(fig_original, 2)); 123 | subplot(2, 3, 5); 124 | imshow(gaussian_lowpass_160, []) 125 | title('cutoff frequency: 160'); 126 | imwrite(gaussian_lowpass_160, 'data/GLPF_160.png'); 127 | % GLPF with cutoff frequency set at radii value 460 128 | gaussian_lowpass_460 = real(ifft2(gaussian_lowpass_filter(size(fig_original, 1), size(fig_original, 2), 460) .* F)); 129 | gaussian_lowpass_460 = gaussian_lowpass_460(1:size(fig_original, 1), 1:size(fig_original, 2)); 130 | subplot(2, 3, 6); 131 | imshow(gaussian_lowpass_460, []) 132 | title('cutoff frequency: 460'); 133 | imwrite(gaussian_lowpass_460, 'data/GLPF_460.png'); 134 | 135 | %% Ideal Highpass Filter 136 | % IHPF with cutoff frequency set at radii value 30 137 | ideal_highpass_30 = real(ifft2(ideal_highpass_filter(size(fig_original, 1), size(fig_original, 2), 30) .* F)); 138 | ideal_highpass_30 = ideal_highpass_30(1:size(fig_original, 1), 1:size(fig_original, 2)); 139 | subplot(1, 3, 1); 140 | imshow(ideal_highpass_30, []) 141 | title('cutoff frequency: 30'); 142 | imwrite(ideal_highpass_30, 'data/IHPF_30.png'); 143 | % IHPF with cutoff frequency set at radii value 60 144 | ideal_highpass_60 = real(ifft2(ideal_highpass_filter(size(fig_original, 1), size(fig_original, 2), 60) .* F)); 145 | ideal_highpass_60 = ideal_highpass_60(1:size(fig_original, 1), 1:size(fig_original, 2)); 146 | subplot(1, 3, 2); 147 | imshow(ideal_highpass_60, []) 148 | title('cutoff frequency: 60'); 149 | imwrite(ideal_highpass_60, 'data/IHPF_60.png'); 150 | % IHPF with cutoff frequency set at radii value 160 151 | ideal_highpass_160 = real(ifft2(ideal_highpass_filter(size(fig_original, 1), size(fig_original, 2), 160) .* F)); 152 | ideal_highpass_160 = ideal_highpass_160(1:size(fig_original, 1), 1:size(fig_original, 2)); 153 | subplot(1, 3, 3); 154 | imshow(ideal_highpass_160, []) 155 | title('cutoff frequency: 160'); 156 | imwrite(ideal_highpass_160, 'data/IHPF_160.png'); 157 | 158 | %% Butterworth Highpass Filter 159 | % BHPF with cutoff frequency set at radii value 30 160 | butterworth_highpass_30 = real(ifft2(butterworth_highpass_filter(size(fig_original, 1), size(fig_original, 2), 30, 2) .* F)); 161 | butterworth_highpass_30 = butterworth_highpass_30(1:size(fig_original, 1), 1:size(fig_original, 2)); 162 | subplot(1, 3, 1); 163 | imshow(butterworth_highpass_30, []) 164 | title('cutoff frequency: 30'); 165 | imwrite(butterworth_highpass_30, 'data/BHPF_30.png'); 166 | % BHPF with cutoff frequency set at radii value 60 167 | butterworth_highpass_60 = real(ifft2(butterworth_highpass_filter(size(fig_original, 1), size(fig_original, 2), 60, 2) .* F)); 168 | butterworth_highpass_60 = butterworth_highpass_60(1:size(fig_original, 1), 1:size(fig_original, 2)); 169 | subplot(1, 3, 2); 170 | imshow(butterworth_highpass_60, []) 171 | title('cutoff frequency: 60'); 172 | imwrite(butterworth_highpass_60, 'data/BHPF_60.png'); 173 | % BHPF with cutoff frequency set at radii value 160 174 | butterworth_highpass_160 = real(ifft2(butterworth_highpass_filter(size(fig_original, 1), size(fig_original, 2), 160, 2) .* F)); 175 | butterworth_highpass_160 = butterworth_highpass_160(1:size(fig_original, 1), 1:size(fig_original, 2)); 176 | subplot(1, 3, 3); 177 | imshow(butterworth_highpass_160, []) 178 | title('cutoff frequency: 160'); 179 | imwrite(butterworth_highpass_160, 'data/BHPF_160.png'); 180 | 181 | %% Gaussian Highpass Filter 182 | % GHPF with cutoff frequency set at radii value 30 183 | gaussian_highpass_30 = real(ifft2(gaussian_highpass_filter(size(fig_original, 1), size(fig_original, 2), 30) .* F)); 184 | gaussian_highpass_30 = gaussian_highpass_30(1:size(fig_original, 1), 1:size(fig_original, 2)); 185 | subplot(1, 3, 1); 186 | imshow(gaussian_highpass_30, []) 187 | title('cutoff frequency: 30'); 188 | imwrite(gaussian_highpass_30, 'data/GHPF_30.png'); 189 | % GHPF with cutoff frequency set at radii value 60 190 | gaussian_highpass_60 = real(ifft2(gaussian_highpass_filter(size(fig_original, 1), size(fig_original, 2), 60) .* F)); 191 | gaussian_highpass_60 = gaussian_highpass_60(1:size(fig_original, 1), 1:size(fig_original, 2)); 192 | subplot(1, 3, 2); 193 | imshow(gaussian_highpass_60, []) 194 | title('cutoff frequency: 60'); 195 | imwrite(gaussian_highpass_60, 'data/GHPF_60.png'); 196 | % GHPF with cutoff frequency set at radii value 160 197 | gaussian_highpass_160 = real(ifft2(gaussian_highpass_filter(size(fig_original, 1), size(fig_original, 2), 160) .* F)); 198 | gaussian_highpass_160 = gaussian_highpass_160(1:size(fig_original, 1), 1:size(fig_original, 2)); 199 | subplot(1, 3, 3); 200 | imshow(gaussian_highpass_160, []) 201 | title('cutoff frequency: 160'); 202 | imwrite(gaussian_highpass_160, 'data/GHPF_160.png'); 203 | 204 | -------------------------------------------------------------------------------- /Project 3/src/gaussian_highpass_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = gaussian_highpass_filter( m, n, D0 ) 2 | %GAUSSIAN_HIGHPASS_FILTER The Gaussian highpass filter 3 | % H(u, v) = 1 - e^(-D(u, v) / (2 * D0^2)) 4 | u = [0:(m-1) -m:-1]; 5 | v = [0:(n-1) -n:-1]; 6 | [V, U] = meshgrid(v, u); 7 | D = V.^2 + U.^2; 8 | output = 1 - exp(-D./(2*(D0^2))); 9 | end 10 | -------------------------------------------------------------------------------- /Project 3/src/gaussian_lowpass_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = gaussian_lowpass_filter( m, n, D0 ) 2 | %GAUSSIAN_LOWPASS_FILTER The Gaussian lowpass filter 3 | % H(u, v) = e^(-D(u, v) / (2 * D0^2)) 4 | u = [0:(m-1) -m:-1]; 5 | v = [0:(n-1) -n:-1]; 6 | [V, U] = meshgrid(v, u); 7 | D = V.^2 + U.^2; 8 | output = exp(-D./(2*(D0^2))); 9 | end 10 | -------------------------------------------------------------------------------- /Project 3/src/ideal_highpass_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = ideal_highpass_filter( m, n, D0 ) 2 | %IDEAL_HIGHPASS_FILTER The ideal highpass filter 3 | % H(u, v) = 0, if D(u, v) <= D0 4 | % 1, if D(u, v) > D0 5 | u = [0:(m-1) -m:-1]; 6 | v = [0:(n-1) -n:-1]; 7 | [V, U] = meshgrid(v, u); 8 | D = V.^2 + U.^2; 9 | output = zeros(size(D)); 10 | output(D > D0^2) = 1; 11 | end 12 | 13 | -------------------------------------------------------------------------------- /Project 3/src/ideal_lowpass_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = ideal_lowpass_filter( m, n, D0 ) 2 | %IDEAL_LOWPASS_FILTER The ideal lowpass filter 3 | % H(u, v) = 1, if D(u, v) <= D0 4 | % 0, if D(u, v) > D0 5 | u = [0:(m-1) -m:-1]; 6 | v = [0:(n-1) -n:-1]; 7 | [V, U] = meshgrid(v, u); 8 | D = V.^2 + U.^2; 9 | output = zeros(size(D)); 10 | output(D <= D0^2) = 1; 11 | end 12 | 13 | -------------------------------------------------------------------------------- /Project 4/problem4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 4/problem4.pdf -------------------------------------------------------------------------------- /Project 4/src/alpha_trimmed_mean_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = alpha_trimmed_mean_filter( input, h, w, d ) 2 | %ALPHA_TRIMMED_MEAN_FILTER 3 | [H, W] = size(input); 4 | T = zeros(H + h * 2 - 2, W + w * 2 - 2); 5 | T(h:(h+H-1), w:(w+W-1)) = input; 6 | output = input; 7 | for i = 1:H+h-1 8 | for j = 1:W+w-1 9 | t = T(i:(i+ h - 1), j:(j + w - 1)); 10 | t = sort(t(:)); 11 | output(i, j) = mean(t((1 + ceil(d / 2)):(h * w - floor(d / 2)))); 12 | end 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /Project 4/src/arithmatic_mean_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = arithmatic_mean_filter( input, h, w ) 2 | %ARITHMATIC_MEAN_FILTER 3 | f = ones(h, w) / h / w; 4 | output = filter2(f, input); 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 4/src/contraharmonic_mean_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = contraharmonic_mean_filter( input, h, w, Q ) 2 | %CONTRAHARMONIC_MEAN_FILTER 3 | f = ones(h, w); 4 | output = filter2(f, input .^ (Q + 1)) ./ filter2(f, input .^ Q); 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 4/src/data/Circuit.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 4/src/data/Circuit.tif -------------------------------------------------------------------------------- /Project 4/src/exponential_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = exponential_noise( M, N, a ) 2 | %EXPONENTIAL_NOISE of size M * N 3 | % p(z) = ae^(-az), z >= 0 4 | % 0, z < 0 5 | output = -log(1 - rand(M, N)) / a; 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Project 4/src/gamma_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = gamma_noise( M, N, a, b ) 2 | %GAMMA_NOISE of size M * N 3 | % p(z) = a^b z^(b-1)/(b-1)!*e^(-az), z >= a 4 | % 0, z < a 5 | output = zeros(M, N); 6 | for j = 1:b 7 | output = output - log(1 - rand(M, N)) / a; 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /Project 4/src/gaussian_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = gaussian_noise( M, N, sigma, zbar ) 2 | %GAUSSIAN_NOISE of size M * N 3 | % p(z) = 1 / sqrt(2 * pi)sigma * e^(-(z - zbar)^2 / 2sigma^2) 4 | output = zbar + randn(M, N) * sigma; 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 4/src/geometric_mean_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = geometric_mean_filter( input, h, w ) 2 | %GEOMETRIC_MEAN_FILTER 3 | f = ones(h, w) / h / w; 4 | output = real(exp(filter2(f, log(input)))); 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 4/src/max_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = max_filter( input, h, w ) 2 | %MAX_FILTER 3 | [H, W] = size(input); 4 | T = zeros(H + h * 2 - 2, W + w * 2 - 2); 5 | T(h:(h+H-1), w:(w+W-1)) = input; 6 | output = input; 7 | for i = 1:H+h-1 8 | for j = 1:W+w-1 9 | t = T(i:(i+ h - 1), j:(j + w - 1)); 10 | output(i, j) = max(t(:)); 11 | end 12 | end 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Project 4/src/median_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = median_filter( input, h, w ) 2 | %MEDIAN_FILTER 3 | [H, W] = size(input); 4 | T = zeros(H + h * 2 - 2, W + w * 2 - 2); 5 | T(h:(h+H-1), w:(w+W-1)) = input; 6 | output = input; 7 | for i = 1:H+h-1 8 | for j = 1:W+w-1 9 | t = T(i:(i+ h - 1), j:(j + w - 1)); 10 | output(i, j) = median(t(:)); 11 | end 12 | end 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Project 4/src/min_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = min_filter( input, h, w ) 2 | %MIN_FILTER 3 | [H, W] = size(input); 4 | T = zeros(H + h * 2 - 2, W + w * 2 - 2); 5 | T(h:(h+H-1), w:(w+W-1)) = input; 6 | output = input; 7 | for i = 1:H+h-1 8 | for j = 1:W+w-1 9 | t = T(i:(i+ h - 1), j:(j + w - 1)); 10 | output(i, j) = min(t(:)); 11 | end 12 | end 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Project 4/src/noise_and_recovery.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = double(imread('data/Circuit.tif')) / 255; 4 | imwrite(fig_original, 'data/circuit.png'); 5 | [h, w] = size(fig_original); 6 | 7 | %% Simulate different noises 8 | figure('Name', 'Noises'); 9 | % Gaussian noise 10 | subplot(2, 3, 1); 11 | histogram(gaussian_noise(100, 100, 1, 0), 100); 12 | title('Gaussian noise, z = 0, \sigma^2 = 1'); 13 | % Rayleigh noise 14 | subplot(2, 3, 2); 15 | histogram(rayleigh_noise(100, 100, 0, 1), 100); 16 | title('Rayleigh noise, a = 0, b = 1'); 17 | % Erlang (gamma) noise 18 | subplot(2, 3, 3); 19 | histogram(gamma_noise(100, 100, 1, 2), 100); 20 | title('Erlang noise, a = 1, b = 2'); 21 | % Exponential noise 22 | subplot(2, 3, 4); 23 | histogram(exponential_noise(100, 100, 1), 100); 24 | title('Exponential noise, a = 1'); 25 | % Uniform noise 26 | subplot(2, 3, 5); 27 | histogram(uniform_noise(100, 100, 1, 10), 100); 28 | title('Uniform noise, a = 0, b = 10'); 29 | % Impulse (salt-and-pepper) noise 30 | subplot(2, 3, 6); 31 | histogram(pepper_noise(100, 100, 0.1, 0.2), 100); 32 | title('Impulse (salt-and-pepper) noise, a = 0.1, b = 0.2'); 33 | 34 | %% Display different noises 35 | figure('Name', 'Noise effects'); 36 | subplot(2, 4, 1); 37 | imshow(fig_original, []); 38 | title('Original image'); 39 | % Gaussian noise 40 | subplot(2, 4, 2); 41 | guassian_image = fig_original + gaussian_noise(h, w, 20, 0) ./ 255; 42 | imshow(guassian_image, []); 43 | imwrite(guassian_image, 'data/guassian_image.png'); 44 | title('Gaussian noised image'); 45 | % Rayleigh noise 46 | subplot(2, 4, 3); 47 | rayleigh_image = fig_original + rayleigh_noise(h, w, 0, 80) ./ 255; 48 | imshow(rayleigh_image, []); 49 | imwrite(rayleigh_image, 'data/rayleigh_image.png'); 50 | title('Rayleigh noised image'); 51 | % Erlang (gamma) noise 52 | subplot(2, 4, 4); 53 | gamma_image = fig_original + gamma_noise(h, w, 1, 80) ./ 255; 54 | imshow(gamma_image, []); 55 | imwrite(gamma_image, 'data/gamma_image.png'); 56 | title('Erlang (gamma) noised image'); 57 | % Exponential noise 58 | subplot(2, 4, 5); 59 | exponential_image = fig_original + exponential_noise(h, w, 20) ./ 255; 60 | imshow(exponential_image, []); 61 | imwrite(exponential_image, 'data/exponential_image.png'); 62 | title('Exponential noised image'); 63 | % Uniform noise 64 | subplot(2, 4, 6); 65 | uniform_image = fig_original + uniform_noise(h, w, 50, 100) ./ 255; 66 | imshow(uniform_image, []); 67 | imwrite(uniform_image, 'data/uniform_image.png'); 68 | title('Uniform noised image'); 69 | % Impulse (salt-and-pepper) noise 70 | subplot(2, 4, 7); 71 | sp_noise = pepper_noise(h, w, 0.1, 0.2); 72 | salt_pepper_image = fig_original; 73 | salt_pepper_image(sp_noise == 0) = 0; 74 | salt_pepper_image(sp_noise == 1) = 1; 75 | imshow(salt_pepper_image, []); 76 | imwrite(salt_pepper_image, 'data/salt_pepper_image.png'); 77 | title('Salt-and-pepper noised image'); 78 | % Salt noise 79 | subplot(2, 4, 8); 80 | sp_noise = pepper_noise(h, w, 0.1, 0.2); 81 | salt_image = fig_original; 82 | salt_image(sp_noise == 1) = 1; 83 | pepper_image = fig_original; 84 | pepper_image(sp_noise == 0) = 0; 85 | imshow(salt_image, []); 86 | imwrite(salt_image, 'data/salt_image.png'); 87 | title('Salt noised image'); 88 | 89 | %% Handle Gaussian noise 90 | figure('Name', 'Handle Gaussian noise'); 91 | subplot(2, 2, 1); 92 | imshow(fig_original, []); 93 | title('Original image'); 94 | % Gaussian noise 95 | subplot(2, 2, 2); 96 | imshow(guassian_image, []); 97 | title('Gaussian noised image'); 98 | % Arithmatic mean filter 99 | subplot(2, 2, 3); 100 | am_image = arithmatic_mean_filter(guassian_image, 3, 3); 101 | imshow(am_image, []); 102 | imwrite(am_image, 'data/am_image.png'); 103 | title('Arithmatic mean filtered image'); 104 | % Geometric mean filter 105 | subplot(2, 2, 4); 106 | gm_image = geometric_mean_filter(guassian_image, 3, 3); 107 | imshow(gm_image, []); 108 | imwrite(gm_image, 'data/gm_image.png'); 109 | title('Geometric mean filtered image'); 110 | 111 | %% Handle salt, pepper noise 112 | figure('Name', 'Handle salt, pepper noise'); 113 | % Pepper noise 114 | subplot(2, 2, 1); 115 | imshow(pepper_image, []); 116 | imwrite(pepper_image, 'data/pepper_image.png'); 117 | title('Image currupted by pepper noise'); 118 | % Salt noise 119 | subplot(2, 2, 2); 120 | imshow(salt_image, []); 121 | title('Image currupted by salt noise'); 122 | % Contraharmonic filter of order 1.5 123 | subplot(2, 2, 3); 124 | cm_image = contraharmonic_mean_filter(pepper_image, 3, 3, 1.5); 125 | imshow(cm_image, []); 126 | imwrite(cm_image, 'data/cm_image_1.png'); 127 | title('Contraharmonic mean filtered image of order 1.5'); 128 | % Contraharmonic filter with Q = -1.5 129 | subplot(2, 2, 4); 130 | cm_image = contraharmonic_mean_filter(salt_image, 3, 3, -1.5); 131 | imshow(cm_image, []); 132 | imwrite(cm_image, 'data/cm_image_2.png'); 133 | title('Contraharmonic mean filtered image with Q = -1.5'); 134 | 135 | %% Handle salt & pepper noise 136 | figure('Name', 'Handle salt & pepper noise'); 137 | % Salt & pepper noise 138 | subplot(2, 2, 1); 139 | imshow(salt_pepper_image, []); 140 | title('Image currupted by salt-and-pepper noise'); 141 | % median filter 142 | subplot(2, 2, 2); 143 | median1 = median_filter(salt_pepper_image, 3, 3); 144 | imshow(median1, []); 145 | imwrite(median1, 'data/median1.png'); 146 | title('Apply 3*3 median filter'); 147 | % median filter 148 | subplot(2, 2, 3); 149 | median2 = median_filter(median1, 3, 3); 150 | imshow(median2, []); 151 | imwrite(median2, 'data/median2.png'); 152 | title('Apply 3*3 median filter'); 153 | % median filter 154 | subplot(2, 2, 4); 155 | median3 = median_filter(median2, 3, 3); 156 | imshow(median3, []); 157 | imwrite(median3, 'data/median3.png'); 158 | title('Apply 3*3 median filter'); 159 | 160 | %% Re-handle salt, pepper noise 161 | figure('Name', 'Re-handle salt, pepper noise'); 162 | % Pepper noise 163 | subplot(1, 2, 1); 164 | max_image = max_filter(pepper_image, 3, 3); 165 | imshow(max_image, []); 166 | imwrite(max_image, 'data/max_image.png'); 167 | title('Pepper noise filtered with a max filter'); 168 | % Salt noise 169 | subplot(1, 2, 2); 170 | min_image = min_filter(salt_image, 3, 3); 171 | imshow(min_image, []); 172 | imwrite(min_image, 'data/min_image.png'); 173 | title('Salt noise filtered with a min filter'); 174 | 175 | %% Handle uniform + salt & pepper noise 176 | % Uniform noise 177 | subplot(3, 2, 1); 178 | imshow(uniform_image, []); 179 | title('Image corrupted by additive uniform noise'); 180 | % Add salt & pepper noise 181 | subplot(3, 2, 2); 182 | sp_noise = pepper_noise(h, w, 0.1, 0.2); 183 | usp_image = uniform_image; 184 | usp_image(sp_noise == 0) = 0; 185 | usp_image(sp_noise == 1) = 1; 186 | imshow(usp_image, []); 187 | title('Image additionally corrupted by salt & pepper noise'); 188 | % Arithmatic mean filter 189 | subplot(3, 2, 3); 190 | am_image_2 = arithmatic_mean_filter(usp_image, 3, 3); 191 | imshow(am_image_2, []); 192 | imwrite(am_image_2, 'data/am_image_2.png'); 193 | title('Arithmatic mean filtered image'); 194 | % Geometric mean filter 195 | subplot(3, 2, 4); 196 | gm_image_2 = geometric_mean_filter(usp_image, 3, 3); 197 | imshow(gm_image_2, []); 198 | imwrite(gm_image_2, 'data/gm_image_2.png'); 199 | title('Geometric mean filtered image'); 200 | % Median mean filter 201 | subplot(3, 2, 5); 202 | median_m = median_filter(usp_image, 3, 3); 203 | imshow(median_m, []); 204 | imwrite(median_m, 'data/median_m.png'); 205 | title('Apply 3*3 median filter'); 206 | % Alpha-trimmed mean filter 207 | subplot(3, 2, 6); 208 | stmf_image = alpha_trimmed_mean_filter(usp_image, 3, 3, 5); 209 | imshow(stmf_image, []); 210 | imwrite(stmf_image, 'data/stmf_image.png'); 211 | title('Apply 3*3 alpha-trimmed mean filter'); 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /Project 4/src/pepper_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = pepper_noise( M, N, a, b ) 2 | %PEPPER_NOISE of size M * N 3 | % p(z) = p_a, z = a 4 | % p_b, z = b 5 | % 1 - p_a - p_b, otherwise 6 | output = ones(M, N) * 0.5; 7 | X = rand(M, N); 8 | output(X <= a) = 0; 9 | output(a <= X & X <= b) = 1; 10 | end 11 | 12 | -------------------------------------------------------------------------------- /Project 4/src/rayleigh_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = rayleigh_noise( M, N, a, b ) 2 | %RAYLEIGH_NOISE of size M * N 3 | % p(z) = 2 / b * (z - a) * e^(-(z - a)^2 / b), z >= a 4 | % 0 , z < a 5 | output = a + sqrt((-b * log(1 - rand(M, N)))); 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Project 4/src/uniform_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = uniform_noise( M, N, a, b ) 2 | %UNIFORM_NOISE of size M * N 3 | % p(z) = 1 / (b - a), if a <= z <= b 4 | % 0, otherwise 5 | output = a + rand(M, N) * (b - a); 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Project 5/problem5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 5/problem5.pdf -------------------------------------------------------------------------------- /Project 5/src/center_transform.m: -------------------------------------------------------------------------------- 1 | function [ output ] = center_transform( input ) 2 | % CENTER_TRANSFORM centerize an image by applying 3 | % f(x, y) = f(x, y) * (-1)^{x+y} 4 | [h, w] = size(input); 5 | u = 1:h; 6 | v = 1:w; 7 | [V, U] = meshgrid(v, u); 8 | D = V + U; 9 | output = input .* power(-1, D); 10 | end -------------------------------------------------------------------------------- /Project 5/src/data/book_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 5/src/data/book_cover.jpg -------------------------------------------------------------------------------- /Project 5/src/filter_H.m: -------------------------------------------------------------------------------- 1 | function [ output ] = filter_H( M, N, a, b, T ) 2 | % FILTER_H generates a filter of size h * w 3 | % where H(u, v) = T / \pi(ua+vb) sin[\pi(ua+vb)] e^{-j\pi(ua+vb)} 4 | u = [1:M] - M / 2; 5 | v = [1:N] - N / 2; 6 | [V, U] = meshgrid(v, u); 7 | D = (V .* b + U .* a) .* pi; 8 | output = ones(M, N) .* T ./ D .* sin(D) .* exp(-j * D); 9 | output(D == 0) = 1; 10 | end -------------------------------------------------------------------------------- /Project 5/src/gaussian_noise.m: -------------------------------------------------------------------------------- 1 | function [ output ] = gaussian_noise( M, N, sigma, zbar ) 2 | %GAUSSIAN_NOISE of size M * N 3 | % p(z) = 1 / sqrt(2 * pi)sigma * e^(-(z - zbar)^2 / 2sigma^2) 4 | output = zbar + randn(M, N) * sigma; 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 5/src/image_restore.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = double(imread('data/book_cover.jpg')) / 255; 4 | [Height, Width] =size(fig_original); 5 | % Discrete Fourier Transformation 6 | F = fft2(center_transform(fig_original)); 7 | 8 | %% Blurring Degradation and Restoration 9 | figure('Name', 'Blurring Degradation'); 10 | % Display the original image 11 | subplot(2, 3, 1); 12 | imshow(fig_original, []); 13 | title('The original image'); 14 | 15 | % Blur the image using paramaters a=b=0.1 and T = 1 16 | subplot(2, 3, 2); 17 | H = filter_H(Height, Width, 0.1, 0.1, 1); 18 | blurred_image = center_transform(real(ifft2(H .* F))); 19 | imshow(blurred_image, []); 20 | imwrite(blurred_image, 'data/blurred_image.png'); 21 | title('Blurred image'); 22 | 23 | % Add Gaussian noise of 0 mean and variance of 650 to the blurred image 24 | subplot(2, 3, 3); 25 | noise = gaussian_noise(Height, Width, sqrt(650), 0) / 255; 26 | blurred_noisy_image = blurred_image + noise; 27 | imshow(blurred_noisy_image, []); 28 | imwrite(blurred_noisy_image, 'data/blurred_noisy_image.png'); 29 | title('Add Gaussian noise'); 30 | 31 | % Restore the blurred image using the inverse filter 32 | subplot(2, 3, 5); 33 | F_blurred = fft2(center_transform(blurred_image)); 34 | blurred_restored = center_transform(real(ifft2(F_blurred ./ H))); 35 | imshow(blurred_restored, []); 36 | imwrite(blurred_restored, 'data/blurred_restored.png'); 37 | title('Blurred image restored with inverse filter'); 38 | 39 | % Restore the blurred noisy image using Wiener deconvolution filter 40 | subplot(2, 3, 6); 41 | F_blurred_noisy = fft2(center_transform(blurred_noisy_image)); 42 | blurred_noisy_restored = center_transform(real(ifft2(wiener_filter(noise, F, H) .* F_blurred_noisy))); 43 | imshow(blurred_noisy_restored, []); 44 | imwrite(blurred_noisy_restored, 'data/blurred_noisy_restored.png'); 45 | title('Blurred noisy image restored with Wiener deconvolution filter'); 46 | 47 | 48 | %% Investigate the performance of the Wiener deconvolution filter using Gaussian noise of 0 and different variances 49 | figure('Name', 'Investigate Wiener deconvolution filter'); 50 | 51 | % Add Gaussian noise of 0 mean and variance of 0.1 to the blurred image 52 | subplot(1, 3, 1); 53 | noise = gaussian_noise(Height, Width, sqrt(0.1), 0) / 255; 54 | F_blurred_noisy = fft2(center_transform(blurred_image + noise)); 55 | blurred_noisy_restored = center_transform(real(ifft2(wiener_filter(noise, F, H) .* F_blurred_noisy))); 56 | imshow(blurred_noisy_restored, []); 57 | imwrite(blurred_noisy_restored, 'data/gvar0_1.png'); 58 | title('Gaussian variance = 0.1'); 59 | 60 | % Add Gaussian noise of 0 mean and variance of 10 to the blurred image 61 | subplot(1, 3, 2); 62 | noise = gaussian_noise(Height, Width, sqrt(10), 0) / 255; 63 | F_blurred_noisy = fft2(center_transform(blurred_image + noise)); 64 | blurred_noisy_restored = center_transform(real(ifft2(wiener_filter(noise, F, H) .* F_blurred_noisy))); 65 | imshow(blurred_noisy_restored, []); 66 | imwrite(blurred_noisy_restored, 'data/gvar10.png'); 67 | title('Gaussian variance = 10'); 68 | 69 | % Add Gaussian noise of 0 mean and variance of 1000 to the blurred image 70 | subplot(1, 3, 3); 71 | noise = gaussian_noise(Height, Width, sqrt(1000), 0) / 255; 72 | F_blurred_noisy = fft2(center_transform(blurred_image + noise)); 73 | blurred_noisy_restored = center_transform(real(ifft2(wiener_filter(noise, F, H) .* F_blurred_noisy))); 74 | imshow(blurred_noisy_restored, []); 75 | imwrite(blurred_noisy_restored, 'data/gvar1000.png'); 76 | title('Gaussian variance = 1000'); 77 | -------------------------------------------------------------------------------- /Project 5/src/wiener_filter.m: -------------------------------------------------------------------------------- 1 | function [ output ] = wiener_filter( N, F, H) 2 | % WIENER_FILTER generates a typical Wiener filter by definition 3 | H2 = abs(H) .^ 2; 4 | Sn = abs(fft2(center_transform(N))) .^ 2; 5 | Sf = abs(F) .^ 2; 6 | output = (H2 ./ H ./ (H2 + Sn ./ Sf)); 7 | end -------------------------------------------------------------------------------- /Project 6/problem6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 6/problem6.pdf -------------------------------------------------------------------------------- /Project 6/src/bilinear_interpolation.m: -------------------------------------------------------------------------------- 1 | function [ output ] = bilinear_interpolation( input, mat ) 2 | %BILINEAR_INTERPOLATION generates the transformed image based on 3 | % input image and transform matrix using bilinear interpolation. 4 | [h, w] = size(input); 5 | output = zeros(h, w); 6 | for i = 1:h 7 | for j = 1:w 8 | inverse_pos = round([i-h/2 j-w/2 1] / mat + [h/2 w/2 0]); 9 | x = inverse_pos(1); 10 | y = inverse_pos(2); 11 | if x >= 1 && x <= h && y >= 1 && y <= w 12 | x1 = x - floor(x); 13 | y1 = y - floor(y); 14 | output(i, j) = input(floor(x), floor(y)) * (1 - x1) * (1 - y1) + ... 15 | input(floor(x), ceil(y)) * (1 - x1) * y1 + ... 16 | input(ceil(x), floor(y)) * x1 * (1 - y1) + ... 17 | input(ceil(x), ceil(y)) * x1 * y1; 18 | end 19 | end 20 | end 21 | end 22 | 23 | -------------------------------------------------------------------------------- /Project 6/src/data/ray_trace_bottle.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 6/src/data/ray_trace_bottle.tif -------------------------------------------------------------------------------- /Project 6/src/geometric_transform.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = double(imread('data/ray_trace_bottle.tif')) / 255; 4 | imwrite(fig_original, 'data/ray_trace_bottle.png'); 5 | 6 | %% The original image 7 | figure('Name', 'Geometric Transform'); 8 | subplot(2, 4, 1); 9 | imshow(fig_original, []); 10 | title('Original image'); 11 | 12 | % Rotate 13 | rotate_mat = rotate_matrix(45); 14 | % Rotate using the nearest neighbor interpolation 15 | subplot(2, 4, 2); 16 | rotate_nn = nearest_neighbor_interpolation(fig_original, rotate_mat); 17 | imshow(rotate_nn, []); 18 | imwrite(rotate_nn, 'data/rotate_nn.png'); 19 | title('Rotate 45^{\circ} using the nearest neighbor'); 20 | 21 | % Rotate using bilinear interpolation 22 | subplot(2, 4, 6); 23 | rotate_bilinear = bilinear_interpolation(fig_original, rotate_mat); 24 | imshow(rotate_bilinear, []); 25 | imwrite(rotate_bilinear, 'data/rotate_bilinear.png'); 26 | title('Rotate 45^{\circ} using bilinear interpolation'); 27 | 28 | % Translate 29 | translate_mat = translate_matrix(60, 80); 30 | % Translate using the nearest neighbor interpolation 31 | subplot(2, 4, 3); 32 | translate_nn = nearest_neighbor_interpolation(fig_original, translate_mat); 33 | imshow(translate_nn, []); 34 | imwrite(translate_nn, 'data/translate_nn.png'); 35 | title('Translate (+60, +80) using the nearest neighbor'); 36 | 37 | % Translate using bilinear interpolation 38 | subplot(2, 4, 7); 39 | translate_bilinear = bilinear_interpolation(fig_original, translate_mat); 40 | imshow(translate_bilinear, []); 41 | imwrite(translate_bilinear, 'data/translate_bilinear.png'); 42 | title('Translate (+60, +80) using bilinear interpolation'); 43 | 44 | % Scale 45 | scale_mat = scale_matrix(0.5, 2); 46 | % Scale using the nearest neighbor interpolation 47 | subplot(2, 4, 4); 48 | scale_nn = nearest_neighbor_interpolation(fig_original, scale_mat); 49 | imshow(scale_nn, []); 50 | imwrite(scale_nn, 'data/scale_nn.png'); 51 | title('Scale (0.5, 2) using the nearest neighbor'); 52 | 53 | % Scale using bilinear interpolation 54 | subplot(2, 4, 8); 55 | scale_bilinear = bilinear_interpolation(fig_original, scale_mat); 56 | imshow(scale_bilinear, []); 57 | imwrite(scale_bilinear, 'data/scale_bilinear.png'); 58 | title('Scale (0.5, 2) using bilinear interpolation'); 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Project 6/src/nearest_neighbor_interpolation.m: -------------------------------------------------------------------------------- 1 | function [ output ] = nearest_neighbor_interpolation( input, mat ) 2 | %NEAREST_NEIGHBOR_INTERPOLATION generates the transformed image based on 3 | % input image and transform matrix using nearest neighbor interpolation. 4 | [h, w] = size(input); 5 | output = zeros(h, w); 6 | for i = 1:h 7 | for j = 1:w 8 | inverse_pos = round([i-h/2 j-w/2 1] / mat + [h/2 w/2 0]); 9 | x = inverse_pos(1); 10 | y = inverse_pos(2); 11 | if x >= 1 && x <= h && y >= 1 && y <= w 12 | output(i, j) = input(x, y); 13 | end 14 | end 15 | end 16 | end 17 | 18 | -------------------------------------------------------------------------------- /Project 6/src/rotate_matrix.m: -------------------------------------------------------------------------------- 1 | function [ output ] = rotate_matrix( angle ) 2 | %ROTATE_MATRIX 3 | angle = degtorad(angle); 4 | output = [cos(angle) sin(angle) 0; -sin(angle) cos(angle) 0; 0 0 1]; 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 6/src/scale_matrix.m: -------------------------------------------------------------------------------- 1 | function [ output ] = scale_matrix( cx, cy ) 2 | %SCALE_MATRIX 3 | output = [cx 0 0; 0 cy 0; 0 0 1]; 4 | end 5 | 6 | -------------------------------------------------------------------------------- /Project 6/src/translate_matrix.m: -------------------------------------------------------------------------------- 1 | function [ output ] = translate_matrix( tx, ty ) 2 | %TRANSLATE_MATRIX 3 | output = [1 0 0; 0 1 0; tx ty 1]; 4 | end 5 | 6 | -------------------------------------------------------------------------------- /Project 7/problem7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 7/problem7.pdf -------------------------------------------------------------------------------- /Project 7/src/data/lenna.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 7/src/data/lenna.tif -------------------------------------------------------------------------------- /Project 7/src/dct.m: -------------------------------------------------------------------------------- 1 | function [ output ] = dct( input, mask ) 2 | %DCT calculates the DCT transform given a 8*8 image & mask 3 | [h, w] = size(input); 4 | b_h = fix((h - 1) / 8) + 1; 5 | b_w = fix((w - 1) / 8) + 1; 6 | output = zeros(b_h * 8, b_w * 8); 7 | output(1:h, 1:w) = input; 8 | 9 | r = ones(8) ./ sqrt(8); 10 | r(2:8, 1:8) = r(2:8, 1:8) .* sqrt(2); 11 | r = r .* cos(pi * [0:7]' * [1:2:15] / 16); 12 | 13 | for i = 1:b_h 14 | for j = 1:b_w 15 | t = (r * output(i * 8 - 7:i * 8, j * 8 - 7:j * 8) * r') .* mask; 16 | output(i * 8 - 7:i * 8, j * 8 - 7:j * 8) = r' * t * r; 17 | end 18 | end 19 | end 20 | 21 | -------------------------------------------------------------------------------- /Project 7/src/difference.m: -------------------------------------------------------------------------------- 1 | function [ diff ] = difference( a, b ) 2 | %DIFFERENCE calculates the difference between two images 3 | % and generates a gray image \in [0, 1] 4 | diff = b - a; 5 | diff = (diff - min(min(diff))) ./ (max(max(diff)) - min(min(diff))); 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Project 7/src/dwt_2.m: -------------------------------------------------------------------------------- 1 | function [ a, h, v, d ] = dwt_2( input, h_phi ) 2 | %DWT_2 calculates the discrete wavelet transform of given input and wavelet 3 | h_psi = h_phi_to_h_psi(h_phi); 4 | [height, width] = size(input); 5 | h0 = floor((height - 1) / 2) + fix(size(h_psi, 2) / 2); 6 | w0 = floor((width - 1) / 2) + fix(size(h_psi, 2) / 2); 7 | w1 = zeros(height, w0); 8 | for i = 1:height 9 | w1(i, :) = downsample(conv(input(i, :), fliplr(h_psi)) , 2, 1); 10 | end 11 | w2 = zeros(height, w0); 12 | for i = 1:height 13 | w2(i, :) = downsample(conv(input(i, :), fliplr(h_phi)), 2, 1); 14 | end 15 | d = zeros(h0, w0); 16 | for i = 1:w0 17 | d(:, i) = downsample(conv(w1(:, i)', fliplr(h_psi)), 2, 1); 18 | end 19 | v = zeros(h0, w0); 20 | for i = 1:w0 21 | v(:, i) = downsample(conv(w1(:, i)', fliplr(h_phi)), 2, 1); 22 | end 23 | h = zeros(h0, w0); 24 | for i = 1:w0 25 | h(:, i) = downsample(conv(w2(:, i)', fliplr(h_psi)), 2, 1); 26 | end 27 | a = zeros(h0, w0); 28 | for i = 1:w0 29 | a(:, i) = downsample(conv(w2(:, i)', fliplr(h_phi)), 2, 1); 30 | end 31 | end 32 | 33 | -------------------------------------------------------------------------------- /Project 7/src/dwt_3level.m: -------------------------------------------------------------------------------- 1 | function [ c1, c2, c3, integrated ] = dwt_3level( input, h_phi ) 2 | %DWT_3LEVEL generates a 3-level wavelet transform display 3 | [ca1, chd1, cvd1, cdd1]=dwt_2(input, h_phi); 4 | [ca2, chd2, cvd2, cdd2]=dwt_2(ca1, h_phi); 5 | [ca3, chd3, cvd3, cdd3]=dwt_2(ca2, h_phi); 6 | [height, width] = size(ca3); 7 | integrated = zeros(size(ca3) * 8); 8 | 9 | integrated(1:height, 1:width) = ca3; 10 | integrated(1:height, (width+1):(2*width)) = chd3; 11 | integrated((height+1):(2*height), 1:width) = cvd3; 12 | integrated((height+1):(2*height), (width+1):(2*width)) = cdd3; 13 | 14 | height = height * 2; 15 | width = width * 2; 16 | integrated(1:size(ca2, 1), (width+1):(width+size(ca2, 2))) = chd2; 17 | integrated((height+1):(height+size(ca2, 1)), 1:size(ca2, 2)) = cvd2; 18 | integrated((height+1):(height+size(ca2, 1)), (width+1):(width+size(ca2, 2))) = cdd2; 19 | 20 | height = height * 2; 21 | width = width * 2; 22 | integrated(1:size(ca1, 1), (width+1):(width+size(ca1, 2))) = chd1; 23 | integrated((height+1):(height+size(ca1, 1)), 1:size(ca1, 2)) = cvd1; 24 | integrated((height+1):(height+size(ca1, 1)), (width+1):(width+size(ca1, 2))) = cdd1; 25 | 26 | [height, width] = size(ca1); 27 | c1 = zeros(size(ca1) * 2); 28 | c1(1:height, 1:width) = ca1; 29 | c1(1:height, (width+1):(2*width)) = chd1; 30 | c1((height+1):(2*height), 1:width) = cvd1; 31 | c1((height+1):(2*height), (width+1):(2*width)) = cdd1; 32 | 33 | [height, width] = size(ca2); 34 | c2 = zeros(size(ca2) * 2); 35 | c2(1:height, 1:width) = ca2; 36 | c2(1:height, (width+1):(2*width)) = chd2; 37 | c2((height+1):(2*height), 1:width) = cvd2; 38 | c2((height+1):(2*height), (width+1):(2*width)) = cdd2; 39 | 40 | [height, width] = size(ca3); 41 | c3 = zeros(size(ca3) * 2); 42 | c3(1:height, 1:width) = ca3; 43 | c3(1:height, (width+1):(2*width)) = chd3; 44 | c3((height+1):(2*height), 1:width) = cvd3; 45 | c3((height+1):(2*height), (width+1):(2*width)) = cdd3; 46 | 47 | 48 | c1(abs(c1)<0.01) = 0; 49 | c2(abs(c2)<0.01) = 0; 50 | c3(abs(c3)<0.01) = 0; 51 | integrated(abs(integrated)<0.01) = 0; 52 | end 53 | 54 | -------------------------------------------------------------------------------- /Project 7/src/h_phi_to_h_psi.m: -------------------------------------------------------------------------------- 1 | function [ output ] = h_phi_to_h_psi( input ) 2 | %H_PHI_TO_H_PSI calculates h_psi from h_phi 3 | % based on h_Phi(n) = (-1)^n h_phi(1-n) 4 | output = power(-1, 0:(size(input, 2)-1)) .* fliplr(input); 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 7/src/idwt_2.m: -------------------------------------------------------------------------------- 1 | function [ output ] = idwt_2( a, h, v, d, h_phi, ext_h, ext_w ) 2 | %IDWT_2 calculates the inverse discrete wavelet transform of given input and wavelet 3 | h_psi = h_phi_to_h_psi(h_phi); 4 | [height, width] = size(a); 5 | h0 = 2 * height + size(h_psi, 2) - 1; 6 | w0 = 2 * width + size(h_psi, 2) - 1; 7 | H = 2 * height - size(h_psi, 2) + ext_h; 8 | W = 2 * width - size(h_psi, 2) + ext_w; 9 | output = zeros(h0, w0); 10 | 11 | kx = size(h_psi, 2) - 1; 12 | 13 | w1 = zeros(h0, width); 14 | for i = 1:width 15 | % upsample 16 | x = [d(:, i)'; zeros(size(d(:, i)'))]; 17 | x = conv(x(:), h_psi); 18 | y = [v(:, i)'; zeros(size(v(:, i)'))]; 19 | y = conv(y(:), h_phi); 20 | w1(:, i) = x + y; 21 | end 22 | 23 | w2 = zeros(h0, width); 24 | for i = 1:width 25 | x = [h(:, i)'; zeros(size(h(:, i)'))]; 26 | x = conv(x(:), h_psi); 27 | y = [a(:, i)'; zeros(size(a(:, i)'))]; 28 | y = conv(y(:), h_phi); 29 | w2(:, i) = x + y; 30 | end 31 | 32 | for i = 1:h0 33 | x = [w1(i, :); zeros(size(w1(i, :)))]; 34 | x = conv(x(:), h_psi); 35 | y = [w2(i, :); zeros(size(w2(i, :)))]; 36 | y = conv(y(:), h_phi); 37 | output(i, :) = x + y; 38 | end 39 | output = output(kx:H+kx-1, kx:W+kx-1); 40 | end 41 | 42 | -------------------------------------------------------------------------------- /Project 7/src/idwt_3level.m: -------------------------------------------------------------------------------- 1 | function [ output ] = idwt_3level( c1, c2, c3, h_phi ) 2 | %IDWT_3LEVEL recovers the image from a 3-level wavelet transform display 3 | [height, width] = size(c3); 4 | height = fix(height / 2); 5 | width = fix(width / 2); 6 | res = idwt_2(c3(1:height, 1:width), c3(1:height, (width+1):(2*width)), c3((height+1):(2*height), 1:width), c3((height+1):(2*height), (width+1):(2*width)), h_phi, mod(size(c2, 1) / 2 + 1, 2) + 1, mod(size(c2, 2) / 2 + 1, 2) + 1); 7 | 8 | [height, width] = size(c2); 9 | height = fix(height / 2); 10 | width = fix(width / 2); 11 | c2(1:height, 1:width) = res; 12 | res = idwt_2(c2(1:height, 1:width), c2(1:height, (width+1):(2*width)), c2((height+1):(2*height), 1:width), c2((height+1):(2*height), (width+1):(2*width)), h_phi, mod(size(c1, 1) / 2 + 1, 2) + 1, mod(size(c1, 2) / 2 + 1, 2) + 1); 13 | 14 | [height, width] = size(c1); 15 | height = fix(height / 2); 16 | width = fix(width / 2); 17 | c1(1:height, 1:width) = res; 18 | res = idwt_2(c1(1:height, 1:width), c1(1:height, (width+1):(2*width)), c1((height+1):(2*height), 1:width), c1((height+1):(2*height), (width+1):(2*width)), h_phi, 2, 2); 19 | 20 | output = res; 21 | end 22 | 23 | -------------------------------------------------------------------------------- /Project 7/src/transform_image_compression.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = double(imread('data/lenna.tif')) / 255; 4 | imwrite(fig_original, 'data/lenna.png'); 5 | 6 | %% Image compression based on DCT 7 | % The original image 8 | figure('Name', 'Image compression based on DCT'); 9 | subplot(2, 3, 1); 10 | imshow(fig_original, []); 11 | 12 | % Zonal mask 13 | zonal_mask = [8:-1:1]' * [8:-1:1] > 30; 14 | zonal_output = dct(fig_original, zonal_mask); 15 | subplot(2, 3, 2); 16 | imshow(zonal_output, []); 17 | imwrite(zonal_output, 'data/zonal_output.png'); 18 | zonal_difference = difference(fig_original, zonal_output); 19 | subplot(2, 3, 5); 20 | imshow(zonal_difference, []); 21 | imwrite(zonal_difference, 'data/zonal_difference.png'); 22 | 23 | % Threshold mask 24 | threshold_mask = [1 1 0 1 0 0 0 0 25 | 1 1 1 1 0 0 0 0 26 | 1 1 0 0 0 0 0 0 27 | 1 0 0 0 0 0 0 0 28 | 0 0 0 0 0 0 0 0 29 | 0 1 0 0 0 0 0 0 30 | 0 0 0 0 0 0 0 0 31 | 0 0 0 0 0 0 0 0]; 32 | threshold_output = dct(fig_original, threshold_mask); 33 | subplot(2, 3, 3); 34 | imshow(threshold_output, []); 35 | imwrite(threshold_output, 'data/threshold_output.png'); 36 | threshold_difference = difference(fig_original, threshold_output); 37 | subplot(2, 3, 6); 38 | imshow(threshold_difference, []); 39 | imwrite(threshold_difference, 'data/threshold_difference.png'); 40 | 41 | %% Image compression based on Harr wavelet 42 | figure('Name', 'Image compression based on Harr wavelet'); 43 | haar_phi = [1/sqrt(2) 1/sqrt(2)]; 44 | subplot(1, 3, 1); 45 | [c1, c2, c3, harr_3level] = dwt_3level(fig_original, haar_phi); 46 | imshow(harr_3level, []); 47 | imwrite(harr_3level, 'data/harr_3level.png'); 48 | title('3 level wavelet transform'); 49 | subplot(1, 3, 2); 50 | reconstructed_harr = idwt_3level(c1, c2, c3, haar_phi); 51 | imshow(reconstructed_harr, []); 52 | imwrite(reconstructed_harr, 'data/reconstructed_harr.png'); 53 | title('reconstructed image'); 54 | subplot(1, 3, 3); 55 | harr_diff = difference(fig_original, reconstructed_harr); 56 | imshow(harr_diff, []); 57 | imwrite(harr_diff, 'data/harr_diff.png'); 58 | title('difference image'); 59 | 60 | %% Image compression based on Daubechies wavelet 61 | figure('Name', 'Image compression based on Daubechies wavelet'); 62 | daubechies_phi = [0.23037781 0.71484657 0.63088076 -0.02798376 -0.18703481 0.03084138 0.03288301 -0.01059740]; 63 | subplot(1, 3, 1); 64 | [c1, c2, c3, daubechies_3level] = dwt_3level(fig_original, daubechies_phi); 65 | imshow(daubechies_3level, []); 66 | imwrite(daubechies_3level, 'data/daubechies_3level.png'); 67 | title('3 level wavelet transform'); 68 | subplot(1, 3, 2); 69 | reconstructed_daubechies = idwt_3level(c1, c2, c3, daubechies_phi); 70 | imshow(reconstructed_daubechies, []); 71 | imwrite(reconstructed_daubechies, 'data/reconstructed_daubechies.png'); 72 | title('reconstructed image'); 73 | subplot(1, 3, 3); 74 | daubechies_diff = difference(fig_original, reconstructed_daubechies); 75 | imshow(daubechies_diff, []); 76 | imwrite(daubechies_diff, 'data/daubechies_diff.png'); 77 | title('difference image'); 78 | 79 | %% Image compression based on Symlet wavelet 80 | figure('Name', 'Image compression based on Symlet wavelet'); 81 | symlet_phi = [0.0322 -0.0126 -0.0992 0.2979 0.8037 0.4976 -0.0296 -0.0758]; 82 | subplot(1, 3, 1); 83 | [c1, c2, c3, symlet_3level] = dwt_3level(fig_original, symlet_phi); 84 | imshow(symlet_3level, []); 85 | imwrite(symlet_3level, 'data/symlet_3level.png'); 86 | title('3 level wavelet transform'); 87 | subplot(1, 3, 2); 88 | reconstructed_symlet = idwt_3level(c1, c2, c3, symlet_phi); 89 | imshow(reconstructed_symlet, []); 90 | imwrite(reconstructed_symlet, 'data/reconstructed_symlet.png'); 91 | title('reconstructed image'); 92 | subplot(1, 3, 3); 93 | symlet_diff = difference(fig_original, reconstructed_symlet); 94 | imshow(symlet_diff, []); 95 | imwrite(symlet_diff, 'data/symlet_diff.png'); 96 | title('difference image'); 97 | 98 | %% Image compression based on biorthogonal Cohen-Daubechies-Feauveau wavelet 99 | figure('Name', 'Image compression based on biorthogonal Cohen-Daubechies-Feauveau wavelet'); 100 | bcf_phi = [0 0.0019 -0.0019 -0.017 0.0119 0.0497 -0.0773 -0.0941 0.4208 0.8259 0.4208 -0.0941 -0.0773 0.0497 0.0119 -0.017 -0.0019 0.0010]; 101 | subplot(1, 3, 1); 102 | [c1, c2, c3, bcf_3level] = dwt_3level(fig_original, bcf_phi); 103 | imshow(bcf_3level, []); 104 | imwrite(bcf_3level, 'data/bcf_3level.png'); 105 | title('3 level wavelet transform'); 106 | subplot(1, 3, 2); 107 | reconstructed_bcf = idwt_3level(c1, c2, c3, bcf_phi); 108 | imshow(reconstructed_bcf, []); 109 | imwrite(reconstructed_bcf, 'data/reconstructed_bcf.png'); 110 | title('reconstructed image'); 111 | subplot(1, 3, 3); 112 | bcf_diff = difference(fig_original, reconstructed_bcf); 113 | imshow(bcf_diff, []); 114 | imwrite(bcf_diff, 'data/bcf_diff.png'); 115 | title('difference image'); -------------------------------------------------------------------------------- /Project 8/problem8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 8/problem8.pdf -------------------------------------------------------------------------------- /Project 8/src/data/Fig0929(a)(text_image).tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 8/src/data/Fig0929(a)(text_image).tif -------------------------------------------------------------------------------- /Project 8/src/data/Fig0931(a)(text_image).tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 8/src/data/Fig0931(a)(text_image).tif -------------------------------------------------------------------------------- /Project 8/src/dilate.m: -------------------------------------------------------------------------------- 1 | function [ output ] = dilate( A, B ) 2 | %DILATE 3 | [H, W] = size(A); 4 | [h, w] = size(B); 5 | output = zeros(H, W); 6 | [x, y] = find(A == 1); 7 | for i = 1:size(x, 1) 8 | for j = -(h-1)/2:(h-1)/2 9 | for k=-(w-1)/2:(w-1)/2 10 | if x(i) + j >= 1 && x(i) + j <= H && y(i) + k >= 1 && y(i) + k <= W 11 | output(x(i) + j, y(i) + k) = A(x(i) + j, y(i) + k) | B(j + (h+1)/2, k + (w+1)/2); 12 | end 13 | end 14 | end 15 | end 16 | end 17 | 18 | -------------------------------------------------------------------------------- /Project 8/src/erode.m: -------------------------------------------------------------------------------- 1 | function [ output ] = erode( A, B ) 2 | %ERODE 3 | output = 1 - dilate(1 - A, B); 4 | end 5 | 6 | -------------------------------------------------------------------------------- /Project 8/src/geodesic_dilation.m: -------------------------------------------------------------------------------- 1 | function [ output ] = geodesic_dilation( F, G ) 2 | %GEODESIC_DILATION 3 | output = F; 4 | old = zeros(size(F)); 5 | while (~isequal(output, old)) 6 | old = output; 7 | output = dilate(output, ones(3, 3)) & G; 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /Project 8/src/morpholigical_processing.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig29 = imread('data/Fig0929(a)(text_image).tif'); 4 | imwrite(fig29, 'data/fig29.png'); 5 | fig31 = imread('data/Fig0931(a)(text_image).tif'); 6 | imwrite(fig31, 'data/fig31.png'); 7 | 8 | %% Opening by reconstruction 9 | figure('Name', 'Opening by reconstruction'); 10 | subplot(2, 2, 1); 11 | imshow(fig29, []); 12 | 13 | % Erode 14 | subplot(2, 2, 2); 15 | erode_29 = erode(fig29, ones(51, 1)); 16 | imshow(erode_29, []); 17 | imwrite(erode_29, 'data/erode_29.png'); 18 | 19 | % Opening 20 | subplot(2, 2, 3); 21 | opening_29 = dilate(erode_29, ones(51, 1)); 22 | imshow(opening_29, []); 23 | imwrite(opening_29, 'data/opening_29.png'); 24 | 25 | % Reconstruction 26 | subplot(2, 2, 4); 27 | reconstruct29 = geodesic_dilation(opening_29, fig29); 28 | imshow(reconstruct29, []); 29 | imwrite(reconstruct29, 'data/reconstruct29.png'); 30 | 31 | %% Filling holes 32 | figure('Name', 'Filling holes'); 33 | subplot(2, 2, 1); 34 | imshow(fig31, []); 35 | 36 | % Complement 37 | subplot(2, 2, 2); 38 | IC = 1 - fig31; 39 | imshow(IC, []); 40 | imwrite(IC, 'data/IC.png'); 41 | 42 | % Marker image 43 | subplot(2, 2, 3); 44 | marker31 = zeros(size(fig31)); 45 | marker31(1, :) = 1 - fig31(1, :); 46 | marker31(:, 1) = 1 - fig31(:, 1); 47 | marker31(size(fig31, 1), :) = 1 - fig31(size(fig31, 1), :); 48 | marker31(:, size(fig31, 2)) = 1 - fig31(:, size(fig31, 2)); 49 | imshow(marker31, []); 50 | imwrite(marker31, 'data/marker31.png'); 51 | 52 | % Fill holes 53 | subplot(2, 2, 4); 54 | H = 1 - geodesic_dilation(marker31, IC); 55 | hole = H & IC; 56 | hole_filled = hole | fig31; 57 | imshow(hole_filled, []); 58 | imwrite(hole_filled, 'data/hole_filled.png'); 59 | 60 | %% Border clearing 61 | figure('Name', 'Border clearing'); 62 | % Marker image 63 | subplot(1, 2, 1); 64 | marker29 = zeros(size(fig29)); 65 | marker29(1, :) = fig29(1, :); 66 | marker29(:, 1) = fig29(:, 1); 67 | marker29(size(fig29, 1), :) = fig29(size(fig29, 1), :); 68 | marker29(:, size(fig29, 2)) = fig31(:, size(fig29, 2)); 69 | marker29 = geodesic_dilation(marker29, fig29); 70 | imshow(marker29, []); 71 | imwrite(marker29, 'data/marker29.png'); 72 | 73 | % no touch 74 | subplot(1, 2, 2); 75 | no_touch = fig29 - marker29; 76 | imshow(no_touch, []); 77 | imwrite(no_touch, 'data/no_touch.png'); 78 | 79 | -------------------------------------------------------------------------------- /Project 9/problem9.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 9/problem9.pdf -------------------------------------------------------------------------------- /Project 9/src/a/canny.m: -------------------------------------------------------------------------------- 1 | function [ output ] = canny( input, n, D0, TL, TH ) 2 | %CANNY edge detector 3 | u = (1-n)/2:(n-1)/2; 4 | v = (1-n)/2:(n-1)/2; 5 | [V, U] = meshgrid(v, u); 6 | D = V.^2 + U.^2; 7 | gaussian_filter = exp(-D./(2*(D0^2))); 8 | output = filter2(gaussian_filter, input); 9 | gx = filter2([-1 -2 -1;0 0 0;1 2 1], output); 10 | gy = filter2([-1 0 1;-2 0 2;-1 0 1], output); 11 | M = sqrt(gx .^ 2 + gy .^ 2); 12 | alpha = atan2(gy, gx); 13 | d = mod(fix((alpha + pi * 9 / 8) / pi * 4), 4); 14 | [h, w] = size(input); 15 | gN = M; 16 | dir_x = [1 -1 -1 1 0 0 1 -1]; 17 | dir_y = [0 0 -1 1 1 -1 -1 1]; 18 | for i = 1:h 19 | for j = 1:w 20 | dir = d(i, j); 21 | for k = 1:2 22 | if i + dir_x(2 * dir + k) >= 1 && i + dir_x(2 * dir + k) <= h && j + dir_y(2 * dir + k) >= 1 && j + dir_y(2 * dir + k) <= w 23 | if M(i, j) < M(i + dir_x(2 * dir + k), j + dir_y(2 * dir + k)) 24 | gN(i, j) = 0; 25 | end 26 | end 27 | end 28 | end 29 | end 30 | gNL = threshold(gN, TL); 31 | gNH = threshold(gN, TH); 32 | output = gNH; 33 | queue_x = zeros(h * w, 1); 34 | queue_y = zeros(h * w, 1); 35 | [x, y] = find(gN > TH); 36 | queue_x(1:size(x, 1)) = x; 37 | queue_y(1:size(y, 1)) = x; 38 | tail = size(x, 1) + 1; 39 | head = 1; 40 | while head < tail 41 | x = queue_x(head); 42 | y = queue_y(head); 43 | head = head + 1; 44 | for k = 1:8 45 | i = x + dir_x(k); 46 | j = y + dir_y(k); 47 | if i > 0 && i <= h && j > 0 && j <= w 48 | if output(i,j) == 0 && (gNH(i,j) > 0 || gNL(i,j) > 0) 49 | queue_x(tail) = i; 50 | queue_y(tail) = j; 51 | tail = tail + 1; 52 | output(i,j) = 1; 53 | end 54 | end 55 | end 56 | end 57 | end 58 | 59 | -------------------------------------------------------------------------------- /Project 9/src/a/data/building.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 9/src/a/data/building.tif -------------------------------------------------------------------------------- /Project 9/src/a/edge_detect.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = remap_image(double(imread('data/building.tif'))); 4 | imwrite(fig_original, 'data/building.png'); 5 | figure('Name', 'Original image'); 6 | imshow(fig_original, []); 7 | 8 | %% Roberts edge detector 9 | figure('Name', 'Roberts edge detector'); 10 | gx = [-1 0;0 1]; 11 | gy = [0 -1;1 0]; 12 | subplot(1, 3, 1); 13 | edge_x = remap_image(abs(filter2(gx, fig_original))); 14 | imshow(edge_x, []); 15 | imwrite(edge_x, 'data/roberts_x.png'); 16 | subplot(1, 3, 2); 17 | edge_y = remap_image(abs(filter2(gy, fig_original))); 18 | imshow(edge_y, []); 19 | imwrite(edge_y, 'data/roberts_y.png'); 20 | subplot(1, 3, 3); 21 | imshow(remap_image(edge_x + edge_y), []); 22 | imwrite(remap_image(edge_x + edge_y), 'data/roberts_xy.png'); 23 | 24 | %% Prewitt edge detector 25 | figure('Name', 'Prewitt edge detector'); 26 | gx = [-1 -1 -1;0 0 0;1 1 1]; 27 | gy = [-1 0 1;-1 0 1;-1 0 1]; 28 | subplot(1, 3, 1); 29 | edge_x = remap_image(abs(filter2(gx, fig_original))); 30 | imshow(edge_x, []); 31 | imwrite(edge_x, 'data/prewitt_x.png'); 32 | subplot(1, 3, 2); 33 | edge_y = remap_image(abs(filter2(gy, fig_original))); 34 | imshow(edge_y, []); 35 | imwrite(edge_y, 'data/prewitt_y.png'); 36 | subplot(1, 3, 3); 37 | imshow(remap_image(edge_x + edge_y), []); 38 | imwrite(remap_image(edge_x + edge_y), 'data/prewitt_xy.png'); 39 | 40 | %% Sobel edge detector 41 | figure('Name', 'Prewitt edge detector'); 42 | gx = [-1 -2 -1;0 0 0;1 2 1]; 43 | gy = [-1 0 1;-2 0 2;-1 0 1]; 44 | subplot(1, 3, 1); 45 | edge_x = remap_image(abs(filter2(gx, fig_original))); 46 | imshow(edge_x, []); 47 | imwrite(edge_x, 'data/sobel_x.png'); 48 | subplot(1, 3, 2); 49 | edge_y = remap_image(abs(filter2(gy, fig_original))); 50 | imshow(edge_y, []); 51 | imwrite(edge_y, 'data/sobel_y.png'); 52 | subplot(1, 3, 3); 53 | imshow(remap_image(edge_x + edge_y), []); 54 | imwrite(remap_image(edge_x + edge_y), 'data/sobel_xy.png'); 55 | 56 | %% Marr-Hildreth edge detector 57 | figure('Name', 'Marr-Hildreth edge detector'); 58 | 59 | subplot(2, 2, 1); 60 | imshow(fig_original, []); 61 | title('Original image'); 62 | 63 | subplot(2, 2, 2); 64 | mh2 = marr_hildreth(fig_original, 25, 4); 65 | imshow(uint8(mh2 * 255), []); 66 | imwrite(mh2, 'data/mh2.png'); 67 | title('Step = 2, \sigma = 4 and n = 25'); 68 | 69 | subplot(2, 2, 3); 70 | zc = zero_crossing(mh2, 0); 71 | imshow(uint8(zc * 255), []); 72 | imwrite(zc, 'data/zc.png'); 73 | title('Zero crossing using threshold of 0'); 74 | 75 | subplot(2, 2, 4); 76 | zc2 = zero_crossing(mh2, max(max(mh2)) * 0.04); 77 | imshow(uint8(zc2 * 255), []); 78 | imwrite(zc2, 'data/zc2.png'); 79 | title('Zero crossing using threshold of 4% maximum value in (b)'); 80 | 81 | %% Canny edge detector 82 | figure('Name', 'Canny edge detector'); 83 | ced = canny(fig_original, 25, 4, 3, 6); 84 | imwrite(ced, 'data/canny.png'); 85 | imshow(uint8(ced * 255), []); 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Project 9/src/a/marr_hildreth.m: -------------------------------------------------------------------------------- 1 | function [ output ] = marr_hildreth( input, n, D0 ) 2 | %MARR_HILDRETH 3 | u = (1-n)/2:(n-1)/2; 4 | v = (1-n)/2:(n-1)/2; 5 | [V, U] = meshgrid(v, u); 6 | D = V.^2 + U.^2; 7 | gaussian_filter = exp(-D./(2*(D0^2))); 8 | output = filter2(gaussian_filter, input); 9 | laplace_filter = [1 1 1; 1 -8 1; 1 1 1]; 10 | output = filter2(laplace_filter, output); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /Project 9/src/a/remap_image.m: -------------------------------------------------------------------------------- 1 | function [ output ] = remap_image( input ) 2 | %REMAP_IMAGE remaps the intensity to [0, 1] 3 | output = (input - min(min(input))) / (max(max(input)) - min(min(input))); 4 | 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Project 9/src/a/threshold.m: -------------------------------------------------------------------------------- 1 | function [ output ] = threshold( input, threshold ) 2 | %THRESHOLD computes a binary image 3 | % output(i, j) = 1, input(i, j) > threshold 4 | % 0, input(i, j) <= threshold 5 | output = input; 6 | output(input <= threshold) = 0; 7 | output(input > threshold) = 1; 8 | end 9 | 10 | -------------------------------------------------------------------------------- /Project 9/src/a/zero_crossing.m: -------------------------------------------------------------------------------- 1 | function [ output ] = zero_crossing( input, threshold ) 2 | %ZERO_CROSSING for Marr-Hildreth edge detector 3 | [h, w] = size(input); 4 | output = zeros(h, w); 5 | for i = 1:h 6 | for j = 1:w 7 | if i > 1 && i < h && input(i - 1, j) * input(i + 1, j) < 0 && abs(input(i - 1, j) - input(i + 1, j)) > threshold 8 | output(i, j) = 1; 9 | end 10 | if j > 1 && j < w && input(i, j - 1) * input(i, j + 1) < 0 && abs(input(i, j - 1) - input(i, j + 1)) > threshold 11 | output(i, j) = 1; 12 | end 13 | if i > 1 && i < h && j > 1 && j < w 14 | if input(i - 1, j - 1) * input(i + 1, j + 1) < 0 && abs(input(i - 1, j - 1) - input(i + 1, j + 1)) > threshold 15 | output(i, j) = 1; 16 | end 17 | if input(i - 1, j + 1) * input(i + 1, j - 1) < 0 && abs(input(i - 1, j + 1) - input(i + 1, j - 1)) > threshold 18 | output(i, j) = 1; 19 | end 20 | end 21 | end 22 | end 23 | end 24 | 25 | -------------------------------------------------------------------------------- /Project 9/src/b/basic_global_thresholding.m: -------------------------------------------------------------------------------- 1 | function [ output ] = basic_global_thresholding( input, delta ) 2 | %BASIC_GLOBAL_THRESHOLDING 3 | % Gonzalez DIP 10.3.2 4 | T = mean(mean(input)); 5 | old = 0; 6 | while abs(T - old) > delta 7 | old = T; 8 | c1 = input(input <= T); 9 | c2 = input(input > T); 10 | m1 = mean(c1); 11 | m2 = mean(c2); 12 | T = (m1 + m2) / 2; 13 | end 14 | output = segment(input, T); 15 | end 16 | 17 | -------------------------------------------------------------------------------- /Project 9/src/b/data/polymersomes.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxy1997/Digital-Image-Processing-Algorithms/e65f26bfa1629d67ce226f737b3dfc9c50d942af/Project 9/src/b/data/polymersomes.tif -------------------------------------------------------------------------------- /Project 9/src/b/image_segmentation.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | %% Read the original image 3 | fig_original = imread('data/polymersomes.tif'); 4 | imwrite(fig_original, 'data/polymersomes.png'); 5 | figure('Name', 'Image segmentation'); 6 | 7 | % Original image 8 | subplot(2, 2, 1); 9 | imshow(fig_original, []); 10 | title('Original image'); 11 | 12 | % Histogram 13 | subplot(2, 2, 2); 14 | imhist(fig_original); 15 | title('Histogram'); 16 | 17 | % Basic global thresholding 18 | subplot(2, 2, 3); 19 | bgt = basic_global_thresholding(fig_original, 0); 20 | imshow(bgt, []); 21 | imwrite(bgt, 'data/bgt.png'); 22 | title('Basic global thresholding'); 23 | 24 | % Otsu's method 25 | subplot(2, 2, 4); 26 | om = otsu(fig_original); 27 | imshow(om, []); 28 | imwrite(om, 'data/om.png'); 29 | title('Otsu ''s method'); -------------------------------------------------------------------------------- /Project 9/src/b/otsu.m: -------------------------------------------------------------------------------- 1 | function [ output ] = otsu( input ) 2 | %OTSU 3 | % Gonzalez DIP 10.3.3 4 | [h, w] = size(input); 5 | n = h * w; 6 | mG = mean(mean(input)) 7 | P = zeros(256, 1); 8 | m = zeros(256, 1); 9 | for i = 0:255 10 | P(i + 1) = length(find(input == i)) / n; 11 | end 12 | for i = 1:255 13 | m(i + 1) = m(i) + P(i + 1) * i; 14 | P(i + 1) = P(i + 1) + P(i); 15 | end 16 | sigmaB2 = ((mG * P - m) .^ 2) ./ P ./ (1 - P); 17 | T = mean(find(sigmaB2 == max(sigmaB2))); 18 | output = segment(input, T); 19 | end 20 | 21 | -------------------------------------------------------------------------------- /Project 9/src/b/segment.m: -------------------------------------------------------------------------------- 1 | function [ output ] = segment( input, k ) 2 | %SEGMENT 3 | % output(x, y) = 0, input(x, y) <= k 4 | % 1, input(x, y) > k 5 | output = zeros(size(input)); 6 | output(input > k) = 1; 7 | end 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Digital-Image-Processing-Algorithms 2 | SJTU CS386 Digital Image Processing course project 3 | 4 | Contents: 5 | - Project 1: Histogram Equalization 6 | - Project 2: Enhance Images with Spatial Filters 7 | - Project 3: Fourier Transform & Filtering in Frequency Domain 8 | - Project 4: Noise Models & Noise Reduction 9 | - Project 5: Image Restoration with Inverse Filter & Wiener Filter 10 | - Project 6: Geometric Transform with Nearest Neighbor and Bilinear Interpolation Methods 11 | - Project 7: Image Compression based on Discrete Cosine Transform & Wavelet Transform 12 | - Project 8: Morpholigical Processing 13 | - Project 9: Edge Detection (Roberts, Prewitt, Sobel, Marr-Hildreth and Canny edge detector) & Image Segmentation (Otsu’s method) 14 | - Project 10: Image Representation (boundary following & chain code) & Description by Principal Components 15 | --------------------------------------------------------------------------------