This repository has been archived by the owner on Apr 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ImageCompressionGUI.m
386 lines (314 loc) · 14.5 KB
/
ImageCompressionGUI.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
%Unused GUI Elements
function varargout = ImageCompressionGUI(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @ImageCompressionGUI_OpeningFcn, ...
'gui_OutputFcn', @ImageCompressionGUI_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
function pushbutton_upload_CreateFcn(hObject, eventdata, handles)
function figure1_CreateFcn(hObject, eventdata, handles)
function ImageCompressionGUI_OpeningFcn(hObject, eventdata, handles, varargin)
handles.UserMessages = hObject;
guidata(hObject, handles);
function varargout = ImageCompressionGUI_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.UserMessages;
function text_stage1_Callback(hObject, eventdata, handles)
function text_stage1_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function text_stage2_Callback(hObject, eventdata, handles)
function text_stage2_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function text_stage3_Callback(hObject, eventdata, handles)
function text_stage3_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function DR_Text_Callback(hObject, eventdata, handles)
function DR_Text_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function CR_Text_Callback(hObject, eventdata, handles)
function CR_Text_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function CSlider_Callback(hObject, eventdata, handles)
sliderValue = get(handles.CSlider, 'Value');
set(handles.SValue, 'String', num2str(round(sliderValue)))
function CSlider_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function SValue_Callback(hObject, eventdata, handles)
function SValue_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function printMsg_Callback(hObject, eventdata, handles)
function printMsg_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function SVDNumber_Callback(hObject, eventdata, handles)
function SVDNumber_CreateFcn(hObject, eventdata, handles)
% hObject handle to SVDNumber (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function SVDSlider_Callback(hObject, eventdata, handles)
sliderValue = get(handles.SVDSlider, 'Value');
set(handles.SVDNumber, 'String', num2str(round(sliderValue)))
function SVDSlider_CreateFcn(hObject, eventdata, handles)
% hObject handle to SVDSlider (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider2_Callback(hObject, eventdata, handles)
function slider2_CreateFcn(hObject, eventdata, handles)
% hObject handle to slider2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor',[.9 .9 .9]);
end
%Main Functions
function pushbutton_upload_Callback(hObject, eventdata, handles)
global OrigfileSize %Button for uploading image
[filename, pathname] = uigetfile({'*.jpg;*.png;*.bmp', 'Image Files (*.jpg, *.png, *.bmp)'}, 'Select an Image File');
if isequal(filename,0) || isequal(pathname,0)
return;
else
fullfilename = fullfile(pathname, filename);
originalImage = imread(fullfilename);
axes(handles.Image1); %Display uploaded image
imshow(originalImage);
title('Uploaded Image');
OrigfileInfo = dir(fullfilename);
OrigfileSize = OrigfileInfo.bytes; %Get image size and store globally
set(handles.text_stage1, 'String', ['Original Image']);
handles.originalImage = originalImage;
guidata(hObject, handles);
end
%loads a UIgetfile window and returns if they dont select a file.
%If they select a file then it gets stored in "originalImage"
%Also the bytes is calculated using .bytes command and stored globally
%to be refrenced in other functions
function pushbutton_compress_Callback(hObject, eventdata, handles)
global OrigfileSize
if isfield(handles, 'originalImage')
originalImage = handles.originalImage;
%Get slider value for compression amount
compressionSliderValue = get(handles.CSlider, 'Value');
CompressionAmount = round(compressionSliderValue);
outputFileName = 'compressed_image.jpg';
outputFilePath = fullfile(pwd, outputFileName);
tic
%Compress and save the image
imwrite(originalImage, outputFilePath, 'Quality', CompressionAmount);
toc
%Get file info for compressed image
CompfileInfo = dir(outputFilePath);
if isempty(CompfileInfo)
msgbox('Compressed image not found.', 'Error', 'error');
return;
end
CompfileSize = CompfileInfo.bytes;
%Display compressed image and size
CompressedImage = imread(outputFilePath);
axes(handles.Image2);
imshow(CompressedImage);
title('Compressed Image');
set(handles.text_stage2, 'String', ['Compressed Image']);
%Store compressed image and update compression ratio
handles.CompressedImage = CompressedImage;
guidata(hObject, handles);
mse = immse(originalImage, CompressedImage);
updateCompressionRatio(OrigfileSize, CompfileSize, mse, handles)
else
msgbox('Please upload an image first.', 'Error', 'error');
end
%Function uses inbuilt compression in matlab using "imwrite" and passes
%in the "Qaulity" parameter. This compresses the file along with a
%value which is calculated using the slider.
function updateCompressionRatio(originalSize, compressedSize, mse, handles)
% ompression ratio calculation
format short;
compressionRatio = originalSize / compressedSize;
displayString = sprintf('Original Size: %d\nCompressed Size: %d\nCompression Ratio: %.2f\nMSE: %.2f', ...
originalSize, compressedSize, compressionRatio, mse);
%Update Info Box
set(handles.InfoBoxText, 'String', displayString);
%update compression ratio just displays all the information in a box at
%the end. including original size, new size, the ratio between them and
%an mse value if needed for comparison (lossy)
function svdcompress_Callback(hObject, ~, handles)
global OrigfileSize
if isfield(handles, 'originalImage')
originalImage = handles.originalImage;
outputFileName = 'SVDcompressed_image.jpg';
outputFilePath = fullfile(pwd, outputFileName);
tic
h = waitbar(0, 'Performing SVD Compression...');
%Separate colour channels
R = originalImage(:, :, 1);
G = originalImage(:, :, 2);
B = originalImage(:, :, 3);
k = round(get(handles.SVDSlider, 'Value'));
%Perform SVD for each channel
[U_R, S_R, V_R] = svd(double(R));
[U_G, S_G, V_G] = svd(double(G));
[U_B, S_B, V_B] = svd(double(B));
%Keep all singular values
k_R = size(S_R, 1);
k_G = size(S_G, 1);
k_B = size(S_B, 1);
%Compression process for each colour channel
compressed_R = uint8(U_R(:, 1:k) * S_R(1:k, 1:k) * V_R(:, 1:k)');
waitbar(0.33, h, 'Performing SVD Compression - Red Channel...');
compressed_G = uint8(U_G(:, 1:k) * S_G(1:k, 1:k) * V_G(:, 1:k)');
waitbar(0.66, h, 'Performing SVD Compression - Green Channel...');
compressed_B = uint8(U_B(:, 1:k) * S_B(1:k, 1:k) * V_B(:, 1:k)');
waitbar(1, h, 'Performing SVD Compression - Blue Channel...');
%Combine the compressed colour channels
compressedImage = cat(3, compressed_R, compressed_G, compressed_B);
%Save the compressed image
imwrite(compressedImage, outputFilePath);
%Get the compressed image file size
CompfileInfo = dir(outputFilePath);
CompfileSize = CompfileInfo.bytes;
close(h);
%Display the compressed image and size
axes(handles.Image2);
imshow(compressedImage);
title('SVD Compressed Image');
set(handles.text_stage2, 'String', ['SVD Compressed Image']);
%Store compressed image and update compression ratio
handles.CompressedImage = compressedImage;
guidata(hObject, handles);
mse = immse(originalImage, compressedImage);
updateCompressionRatio(OrigfileSize, CompfileSize, mse, handles)
toc
else
msgbox('Please upload an image first.', 'Error', 'error');
end
%svd splits the image down into three matricies
%the first is how the rows relate to each other
%the second is how the columns relate to each other
%the third is the weight of each to show whats more important
%for RGB we did it for each channel. "K" value only keeps the most
%important values. More you keep the less information is lost but the
%lower the compression rate.
function RLC_Callback(hObject, eventdata, handles)
if isfield(handles, 'originalImage')
set(handles.printMsg, 'String', 'Performing RLE Compression...');
originalImage = handles.originalImage;
%RUns RLE compression
rleCompression(originalImage);
% Display status in gui box
set(handles.printMsg, 'String', 'RLE Compression Finished');
else
msgbox('Please load an image first.', 'Error', 'error');
end
%button function to just call the rlecompression method
function rleCompression(image)
tic
%Convert image to 1D array
input_data = image(:)';
%Initialise variables
n = length(input_data);
encoded_image = zeros(1, 2 * n);
%Loop through input data
count = 1;
for i = 2:n
if input_data(i) == input_data(i-1) %numbers are the same
count = count + 1; %so add 1 to count
else
encoded_image(2*i-3:2*i-2) = [input_data(i-1), count]; %updates the encoded array to the final result of that count
count = 1; %resets the count
end
% Display progress of SVD
if mod(i, 10000) == 0
fprintf('Encoded %d elements, %d elements remaining\n', i, n - i);
end
end
%Handle last run
encoded_image(2*n-1:2*n) = [input_data(end), count];
%Trim excess zeros
encoded_image = encoded_image(encoded_image ~= 0);
%Save encoded data
save('encoded_data.mat', 'encoded_image');
toc
function RLD_Callback(hObject, eventdata, handles)
global OrigfileSize
if isfield(handles, 'originalImage')
if exist('encoded_data.mat', 'file') == 2
set(handles.printMsg, 'String', 'Performing RLE Decompression...');
%Load original image
originalImage = handles.originalImage;
%Run decompression function
decoded_image = rleDecompression(originalImage);
%Display decompressed image
axes(handles.Image2);
imshow(decoded_image, []);
title('Decompressed Image');
handles.decompressedImage = decoded_image;
guidata(hObject, handles);
set(handles.printMsg, 'String', 'RLE Decompression Finished');
fileInfo = dir('encoded_data.mat');
compressedSize = fileInfo.bytes;
set(handles.text_stage2, 'String', ['RLE decompressed Image']);
updateCompressionRatio(OrigfileSize, compressedSize, 0, handles)
else
set(handles.printMsg, 'String', 'No compressed file found');
return;
end
else
msgbox('Please load an image first.', 'Error', 'error');
end
%rle decompression button to call the rleDecompression method
%also updates the text boxes and calls the calculation method
function decoded_image = rleDecompression(originalImage)
%Load matlab array data
load("encoded_data.mat");
%Initialise variables
decoded_data = [];
%Loop through the encoded data
for i = 1:2:length(encoded_image)
value = encoded_image(i);
count = encoded_image(i+1);
% Append the decoded data (repeated values)
decoded_data = [decoded_data, repmat(value, 1, count)];
end
%Expected elements in original
expected_num_elements = numel(originalImage);
%Decoded_data matches the original image
decoded_data = [decoded_data, zeros(1, expected_num_elements - length(decoded_data))];
%Reshape array to the original size
decoded_image = reshape(decoded_data, size(originalImage));
%Save the image
imwrite(decoded_image, 'decoded_image.bmp');
%inverses the RLE compression back into an image matrix. saves the
%image to be returned in the button function.