0% found this document useful (0 votes)
27 views7 pages

Computer Vision hw5

The document outlines a MATLAB implementation of JPEG compression and decompression, detailing functions for reading images, converting color spaces, applying DCT, quantization, and reconstructing images. It includes a method to evaluate the root mean square error (RMSE) against varying quality factors. The code is structured to handle different downsampling modes and visualize the results of compression.

Uploaded by

zahraaalfaeq
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views7 pages

Computer Vision hw5

The document outlines a MATLAB implementation of JPEG compression and decompression, detailing functions for reading images, converting color spaces, applying DCT, quantization, and reconstructing images. It includes a method to evaluate the root mean square error (RMSE) against varying quality factors. The code is structured to handle different downsampling modes and visualize the results of compression.

Uploaded by

zahraaalfaeq
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Computer Vision

Homework 5:
JPEG Compression

Pesented by:

Zahraa muhaned mohammed faeq

MSc stg 1
1&2

jpeg _compression.m

function jpeg_compression(image_path, Q, downsamplingMode)

% 1. Read the image and convert it to YCbCr color space


img = imread(image_path);
img_ycbcr = rgb2ycbcr(img);
Y = img_ycbcr(:,:,1);
Cb = img_ycbcr(:,:,2);
Cr = img_ycbcr(:,:,3);

% 2. Zero-pad image components so their dimensions are divisible by 8 (or 16)


padToMultiple = @(channel, factor) padarray(channel, ...
mod(-size(channel), factor), 'post');

Y = padToMultiple(Y, [8, 8]);


Cb = padToMultiple(Cb, [8, 8]);
Cr = padToMultiple(Cr, [8, 8]);

% 3. Apply chroma subsampling depending on selected mode


switch downsamplingMode
case 'none'
% No downsampling
case 'h'
% Horizontal only
Cb = imresize(Cb, [size(Cb,1), floor(size(Cb,2)/2)], 'bilinear');
Cr = imresize(Cr, [size(Cr,1), floor(size(Cr,2)/2)], 'bilinear');
case 'h+v'
% Horizontal and vertical
Cb = imresize(Cb, floor(size(Cb)/2), 'bilinear');
Cr = imresize(Cr, floor(size(Cr)/2), 'bilinear');
otherwise
error('Invalid downsampling mode. Use "none", "h", or "h+v".');
end

% 4. Generate quantization matrices based on quality factor


[Qy, Qc] = getQuantMatrices(Q);

%% 5. Apply DCT + quantization block-by-block using blockproc


Y_q = blockproc(Y, [8 8], @(b) jpegBlockDCT(b, Qy));
Cb_q = blockproc(Cb, [8 8], @(b) jpegBlockDCT(b, Qc));
Cr_q = blockproc(Cr, [8 8], @(b) jpegBlockDCT(b, Qc));

figure;
subplot(1, 2, 1);
imshow(img);
title('Original Image');

% Reconstruct the image after compression (decoding part)


img_reconstructed = jpeg_decompression(Y, Y_q, Cb_q, Cr_q, Q, downsamplingMode);
subplot(1, 2, 2);
imshow(img_reconstructed);
title('Compressed Image');

% Optional: You can save or visualize the compressed result here


disp('JPEG compression completed successfully.');
end
% Function to compute quantization matrices based on quality factor
function [Qy, Qc] = getQuantMatrices(Q)
% Standard quantization matrices
Qy_std = [
16 11 10 16 24 40 51 61;
12 12 14 19 26 58 60 55;
14 13 16 24 40 57 69 56;
14 17 22 29 51 87 80 62;
18 22 37 56 68 109 103 77;
24 35 55 64 81 104 113 92;
49 64 78 87 103 121 120 101;
72 92 95 98 112 100 103 99];

Qc_std = [
17 18 24 47 99 99 99 99;
18 21 26 66 99 99 99 99;
24 26 56 99 99 99 99 99;
47 66 99 99 99 99 99 99;
99 99 99 99 99 99 99 99;
99 99 99 99 99 99 99 99;
99 99 99 99 99 99 99 99;
99 99 99 99 99 99 99 99];

% Compute scale factor


if Q < 50
S = 5000 / Q;
else
S = 200 - 2 * Q;
end

% Scale quantization matrices


Qy = round((S / 100) * Qy_std);
Qc = round((S / 100) * Qc_std);
end

% Function to apply range-shifting, DCT, and quantization to an 8x8 block


function outBlock = jpegBlockDCT(blockStruct, Qmat)
block = double(blockStruct.data) - 128; % Range shift to [-128, 127]
dct_block = dct2(block); % Apply 2D DCT
outBlock = round(dct_block ./ Qmat); % Quantize using Q matrix
end

function img_reconstructed = jpeg_decompression(Y, Y_q, Cb_q, Cr_q, Q, downsamplingMode)


% Reconstruct the quantization matrices
[Qy, Qc] = getQuantMatrices(Q);

% Apply inverse DCT and dequantization block-by-block


Y_dq = blockproc(Y_q, [8 8], @(b) jpegBlockInverseDCT(b, Qy));
Cb_dq = blockproc(Cb_q, [8 8], @(b) jpegBlockInverseDCT(b, Qc));
Cr_dq = blockproc(Cr_q, [8 8], @(b) jpegBlockInverseDCT(b, Qc));

% Resize the chroma channels to their original dimensions


switch downsamplingMode
case 'none'
% No resizing
case 'h'
Cb_dq = imresize(Cb_dq, [size(Cb_dq, 1), size(Cb_dq, 2) * 2], 'bilinear');
Cr_dq = imresize(Cr_dq, [size(Cr_dq, 1), size(Cr_dq, 2) * 2], 'bilinear');
case 'h+v'
Cb_dq = imresize(Cb_dq, [size(Cb_dq, 1) * 2, size(Cb_dq, 2) * 2], 'bilinear');
Cr_dq = imresize(Cr_dq, [size(Cr_dq, 1) * 2, size(Cr_dq, 2) * 2], 'bilinear');
otherwise
error('Invalid downsampling mode. Use "none", "h", or "h+v".');
end

% Reconstruct the full YCbCr image


img_ycbcr_reconstructed = cat(3, Y_dq, Cb_dq, Cr_dq);

% Convert YCbCr to RGB


img_reconstructed = ycbcr2rgb(img_ycbcr_reconstructed);

% Crop any padding added during compression


img_reconstructed = img_reconstructed(1:size(Y,1), 1:size(Y,2), :);
end

% Function to apply inverse DCT and dequantization to an 8x8 block


function outBlock = jpegBlockInverseDCT(blockStruct, Qmat)
block = double(blockStruct.data); % Get quantized block
block = block .* Qmat; % Dequantize using Q matrix
idct_block = idct2(block); % Apply inverse DCT
outBlock = uint8(idct_block + 128); % Range shift back to [0, 255]
end
In command window :

>> jpeg_compression('C:\Users\ahmed\Pictures\ph\2.jpg', 50, 'h+v');

JPEG compression completed successfully.

3. Choose an image, then apply the JPEG compression and decompression algorithms coded in steps 1
and 2 to plot the RMSE for each possible value of the quality factor Q.
function rmse_vs_q(image_path)
Q_values = 10:10:90;
RMSEs = zeros(size(Q_values));

original = im2double(imread(image_path));

for i = 1:length(Q_values)
Q = Q_values(i);
reconstructed = im2double(jpeg_compression(image_path, Q, 'h+v'));
RMSEs(i) = sqrt(mean((original(:) - reconstructed(:)).^2));
end

figure;
plot(Q_values, RMSEs, '-o');
xlabel('Quality Factor Q');
ylabel('RMSE');
title('RMSE vs JPEG Quality Factor');
grid on;
end

function img_reconstructed = jpeg_compression(image_path, Q, downsamplingMode)

img = imread(image_path);
img_ycbcr = rgb2ycbcr(img);
Y = img_ycbcr(:,:,1);
Cb = img_ycbcr(:,:,2);
Cr = img_ycbcr(:,:,3);

padToMultiple = @(channel, factor) padarray(channel, ...


mod(-size(channel), factor), 'post');

Y_padded = padToMultiple(Y, [8, 8]);


Cb_padded = padToMultiple(Cb, [8, 8]);
Cr_padded = padToMultiple(Cr, [8, 8]);

switch downsamplingMode
case 'none'
Cb_ds = Cb_padded;
Cr_ds = Cr_padded;
case 'h'
Cb_ds = imresize(Cb_padded, [size(Cb_padded,1), floor(size(Cb_padded,2)/2)],
'bilinear');
Cr_ds = imresize(Cr_padded, [size(Cr_padded,1), floor(size(Cr_padded,2)/2)],
'bilinear');
case 'h+v'
Cb_ds = imresize(Cb_padded, floor(size(Cb_padded)/2), 'bilinear');
Cr_ds = imresize(Cr_padded, floor(size(Cr_padded)/2), 'bilinear');
otherwise
error('Invalid downsampling mode. Use "none", "h", or "h+v".');
end

[Qy, Qc] = getQuantMatrices(Q);

Y_q = blockproc(Y_padded, [8 8], @(b) jpegBlockDCT(b, Qy));


Cb_q = blockproc(Cb_ds, [8 8], @(b) jpegBlockDCT(b, Qc));
Cr_q = blockproc(Cr_ds, [8 8], @(b) jpegBlockDCT(b, Qc));

img_reconstructed = jpeg_decompression(Y_padded, Y_q, Cb_q, Cr_q, Q, downsamplingMode);


img_reconstructed = img_reconstructed(1:size(Y,1), 1:size(Y,2), :);% crop to original
end
function [Qy, Qc] = getQuantMatrices(Q)
Qy_std = [
16 11 10 16 24 40 51 61;
12 12 14 19 26 58 60 55;
14 13 16 24 40 57 69 56;
14 17 22 29 51 87 80 62;
18 22 37 56 68 109 103 77;
24 35 55 64 81 104 113 92;
49 64 78 87 103 121 120 101;
72 92 95 98 112 100 103 99];

Qc_std = [
17 18 24 47 99 99 99 99;
18 21 26 66 99 99 99 99;
24 26 56 99 99 99 99 99;
47 66 99 99 99 99 99 99;
99 99 99 99 99 99 99 99;
99 99 99 99 99 99 99 99;
99 99 99 99 99 99 99 99;
99 99 99 99 99 99 99 99];

if Q < 50
S = 5000 / Q;
else
S = 200 - 2 * Q;
end

Qy = round((S / 100) * Qy_std);


Qc = round((S / 100) * Qc_std);
end

function outBlock = jpegBlockDCT(blockStruct, Qmat)


block = double(blockStruct.data) - 128;
dct_block = dct2(block);
outBlock = round(dct_block ./ Qmat);
end

function outBlock = jpegBlockInverseDCT(blockStruct, Qmat)


block = double(blockStruct.data);
block = block .* Qmat;
idct_block = idct2(block);
outBlock = uint8(idct_block + 128);
end

function img_reconstructed = jpeg_decompression(~, Y_q, Cb_q, Cr_q, Q, downsamplingMode)


[Qy, Qc] = getQuantMatrices(Q);

Y_dq = blockproc(Y_q, [8 8], @(b) jpegBlockInverseDCT(b, Qy));


Cb_dq = blockproc(Cb_q, [8 8], @(b) jpegBlockInverseDCT(b, Qc));
Cr_dq = blockproc(Cr_q, [8 8], @(b) jpegBlockInverseDCT(b, Qc));

switch downsamplingMode
case 'none'
case 'h'
Cb_dq = imresize(Cb_dq, [size(Cb_dq, 1), size(Cb_dq, 2) * 2], 'bilinear');
Cr_dq = imresize(Cr_dq, [size(Cr_dq, 1), size(Cr_dq, 2) * 2], 'bilinear');
case 'h+v'
Cb_dq = imresize(Cb_dq, [size(Cb_dq, 1) * 2, size(Cb_dq, 2) * 2],
'bilinear');
Cr_dq = imresize(Cr_dq, [size(Cr_dq, 1) * 2, size(Cr_dq, 2) * 2],
'bilinear');
otherwise
error('Invalid downsampling mode.');
end
switch downsamplingMode
case 'none'
case 'h'
Cb_dq = imresize(Cb_dq, [size(Cb_dq, 1), size(Cb_dq, 2) * 2], 'bilinear');
Cr_dq = imresize(Cr_dq, [size(Cr_dq, 1), size(Cr_dq, 2) * 2], 'bilinear');
case 'h+v'
Cb_dq = imresize(Cb_dq, [size(Cb_dq, 1) * 2, size(Cb_dq, 2) * 2],
'bilinear');
Cr_dq = imresize(Cr_dq, [size(Cr_dq, 1) * 2, size(Cr_dq, 2) * 2],
'bilinear');
otherwise
error('Invalid downsampling mode.');
end

img_ycbcr = cat(3, Y_dq, Cb_dq, Cr_dq);


img_reconstructed = ycbcr2rgb(img_ycbcr);
end

In command window

rmse_vs_q('C:\Users\ahmed\Pictures\ph\2.jpg')

You might also like