Image Compression Algorithm Error

3 views (last 30 days)
Yigit
Yigit on 5 Dec 2023
Edited: Yash on 20 Dec 2023
I'm trying to take a compression factor N and compress all color intensity values in an image according to that factor. But in the code that I wrote there is an error which makes the image wrong and I couldn't find it. Here's my code:
function [comp_img, time] = compress_image(varargin)
clc
% Replace 'outputs' and 'inputs' and the function name appropriately
%% Define different use cases of the function using varargin and nargin
path = "images/spiral.jpg";
N = 8;
switch nargin
case 1
path = varargin{1};
case 2
if ~isempty(varargin{1})
path = varargin{1};
end
N = varargin{2};
end
img = imread(path);
comp_img = zeros(size(img), "uint8");
tic
%% Define the subrange limits and mapped values
lower_limits = 0:(256/N):(256-(256/N));
upper_limits = lower_limits + (256/N) - 1;
new_values = floor((0:N-1) * 256 / N + 256 / (2 * N));
for channel = 1:3
%% Map the pixel values of the original image to their new values
for i = 1:N
mask = (img(:,:,channel) >= lower_limits(i)) & (img(:,:,channel) <= upper_limits(i));
comp_img(mask, channel) = new_values(i);
end
end
% Record the elapsed time for this step
time = toc;
%% Define a file name and save the output image as a mat file
% File name format should be '{image name}_comp_{compression factor}, '
[~, name, ~] = fileparts(path);
save(name + "_comp_" + N, '-mat');
figure;
subplot(1, 2, 1), imshow(img), title('Original Image');
subplot(1, 2, 2), imshow(comp_img), title(['Compressed Image (N=' num2str(N) ')']);
% Display the elapsed time
fprintf('Elapsed Time: %.4f seconds\n', time)
end
The output is a matrix with the size of 262144x512x3, where th
e original size of the image is 512x512x3. And this is the result:

Answers (2)

Yash
Yash on 13 Dec 2023
Edited: Yash on 20 Dec 2023
Hi Yigit,
I understand that you want to compress all color intensity values in an image according to compression factor "N". Upon investigating the code, the following line seems to be behind the error:
comp_img(mask, channel) = new_values(i);
As you want to populate "comp_img" with "new_values(i)" where the "mask" value is 1 for the given "channel" value, the correct way to do this is to extract the rows and columns where the "mask" value is 1 and update those values in "comp_img". Here is the code snippet for your reference:
for channel = 1:3
%% Map the pixel values of the original image to their new values
for i = 1:N
mask = (img(:,:,channel) >= lower_limits(i)) & (img(:,:,channel) <= upper_limits(i));
[row, col] = find(mask);
for j = 1:size(row)
comp_img(row(j), col(j), channel) = new_values(i);
end
end
end
The updated code generates a matrix of size 512x512x3, where the original size of the image is 512x512x3.
Refer here for documentation of "find" function for more information: https://www.mathworks.com/help/matlab/ref/find.html
I hope this helps!

DGM
DGM on 13 Dec 2023
Edited: DGM on 13 Dec 2023
Your problem is a matter of trying to address the pages of an ND array using a mix of 2D logical addressing and subscript addressing. I included a crude example of one way to avoid the problem (I stripped out the core functionality).
I also include an example which does the same thing, but is written in a manner which works with any image class, any color depth, and doesn't require loops.
% a test image (uint8, RGB)
%A = im2uint8(repmat(permute(parula(500),[3 1 2]),[80 1 1]));
A = imread('a.png');
N = 4;
B = testme(A,N); % your example (crudely fixed)
C = testme2(A,N); % a simplified example that does the same thing
outpict = [A;B;C];
imshow(outpict,'border','tight')
While your code relies on the image being both RGB and uint8-class, the second example does not. Both functions always return uint8-class images
A16 = im2uint16(A); % RGB, uint16
N = 4;
B = testme(A16,N); % result is almost completely truncated
C = testme2(A16,N); % result is same as before
outpict = [A;B;C];
imshow(outpict,'border','tight')
Not only is it more generalized, it's succinct, and it's faster.
tic; B = testme(A,N); toc
Elapsed time is 0.004647 seconds.
tic; C = testme2(A,N); toc
Elapsed time is 0.001389 seconds.

Products


Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!