由于图像表示方法的原因,导致计算机想要完整、真实地保存一幅图像时需要占用非常大的空间,因此对图像进行数据压缩是一个值得重视的问题。出于节省硬盘空间的考虑,以及为了在传输过程中节省宽带资源和损耗时间,都需要对图像进行压缩。
针对不同图像压缩问题,请实现基于行程编码的图像压缩算法,并分析压缩比、图像质量和算法时间复杂度等性能指标。
图像通常在计算机中会占用非常大的空间,压缩之后,传输过程中的误码率也会相应地减少。图像编码压缩的目的是节省图像存储空间,减少传输信道的容量,缩小图像加工处理的时间。
在本课程设计中,我们主要针对的是无损压缩中的行程编码方法的算法设计及算法实现,行程编码具有简洁、无损压缩、运行速度快、消耗资源少等优点。
针对题目,我们将问题进行重新编写:
解决上述问题,我们需要理解图像压缩的理论基础,掌握行程编码的工作原理,同时了解数字图像中数据冗余的主要来源,了解有损压缩和无损压缩之间的区别,以及保真度测试。
1. 图像预处理
一张RGB彩色图像可以选择作为彩色图像、灰度图像或者二值图像进行图像压缩。每一种图像压缩有对应的设计算法。
彩色图像:将彩色图像分为R、G、B三个二维矩阵;
灰度图像:调用MATLAB自带rgb2gray()函数将彩色图像转化为灰度图像;
二值图像:在灰度图像的基础上,调用MATLAB自带的imbinarize()将灰度图像转化为二值图像。
2. 调用自编RLEcode()函数
将二值图像按行转化为一维数组;
进行数据压缩;
计算压缩比。
3. 调用自编Uncompress()函数
创建空数组unzipped,用于存储解压后图像矩阵;
图像数据还原;
重构图像矩阵。
4. 图像性能分析
输出压缩比;
计算相对数据冗余;
进行失真度检验。
clear;clc;
f=imread('D:\pa.jpg');
fprintf("——————————————————————————\n");
fprintf("请选择图像处理方式:\n");
fprintf("1:彩色图像压缩\n");
fprintf("2:灰度图像压缩\n");
fprintf("3:二值图像压缩\n");
x=input('请给出你的选择:');
fprintf("——————————————————————————\n");
switch x
case 1
num = 0;
subplot(1,2,1),imshow(f),title("原图");
[a,b,c]=size(f);
f1 = f(:,:,1);
f2 = f(:,:,2);
f3 = f(:,:,3);
t1 = cputime;
[zipped,info]=RLEcode(f1);
num = num+size(zipped,1);
e1 = cputime-t1;
t2 = cputime;
f1_new = Uncompress(zipped,info);
e2 = cputime-t2;
t3 = cputime;
[zipped,info]=RLEcode(f2);
num = num+size(zipped,1);
e3 = cputime-t3;
t4 = cputime;
f2_new = Uncompress(zipped,info);
e4 = cputime - t4;
t5 = cputime;
[zipped,info]=RLEcode(f3);
num = num+size(zipped,1);
e5 = cputime - t5;
t6 = cputime;
f3_new = Uncompress(zipped,info);
e6 = cputime - t6;
f_de = uint8(zeros(a,b,c));
f_de(:,:,1)=f1_new(:,:,1);
f_de(:,:,2)=f2_new(:,:,1);
f_de(:,:,3)=f3_new(:,:,1);
subplot(1,2,2),imshow(f_de),title("解压图像");
f_new=f;
C=a*b*c/num;
t_ya = e1+e3+e5;
fprintf("压缩运行时间: %.1f s\n",t_ya);
t_jie = e2+e4+e6;
fprintf("解压运行时间: %.1f s\n",t_jie);
case 2
subplot(2,2,1),imshow(f),title("原图");
fgray=rgb2gray(f);%灰度化
subplot(2,2,2),imshow(fgray),title("灰度图像");
t1=cputime;
[zipped,info]=RLEcode(fgray);
e1=cputime-t1;
fprintf("压缩运行时间: %.1f s\n",e1);
t2=cputime;
f_de = Uncompress(zipped,info);
e2=cputime-t2;
fprintf("解压运行时间: %.1f s\n",e2);
subplot(2,2,3),imshow(f_de),title('解压的图像');
C=info.ratio;%信息比率
f_new = fgray;
case 3
subplot(2,2,1),imshow(f),title("原图");
fgray=rgb2gray(f);%灰度化
f_bw = imbinarize(fgray); %转化为二值图像
subplot(2,2,2),imshow(f_bw),title("二值图像");
t1 = cputime;
[zipped,info]=RLEcode(f_bw);
e1=cputime-t1;
fprintf("压缩运行时间: %.1f s\n",e1);
t2=cputime;
f_de = Uncompress(zipped,info)*255;
e2=cputime-t2;
fprintf("解压运行时间: %.1f s\n",e2);
subplot(2,2,3),imshow(f_de),title('解压的图像');
C=info.ratio;%信息比率
f_new = f_bw;
otherwise
fprintf("请重新输入你的选择!\n");
end
%计算压缩比
fprintf("压缩比:%.3f : 1\n",C);
%图像相对数据冗余
R=1-1/C;
fprintf("相对数据冗余:%.3f %%\n",R*100);
%计算失真度 MSE越大失真度越高,PSNR越小失真度越高 无损
f_new=im2double(f_new);%double类型才能计算
f_de_new=im2double(f_de);
D=f_de_new-f_new;
MSE = sum(D(:).*D(:))/numel(f_de_new);%均方误差MSE
PSNR = 10*log10(255^2/MSE);%峰值信噪比
MAE=mean(mean(abs(D)));%平均绝对误差
fprintf("均方根误差 Mean Square Error = %.3f\n",MSE);
fprintf("峰值信噪比 Peak Signal to Noise Ratio = %.3f\n",PSNR);
fprintf("平均绝对误差 MNormalized Cross-Correlation = %.3f\n",MAE);
if(MAE == 0)
fprintf("RLE是无损压缩!\n");
end
function [zipped,info]=RLEcode(f)
[m,n]=size(f);
f=uint8(reshape(f',1,m*n));%类型转换,并把矩阵转为一维数组
L=length(f); %一维数组长度
c=f(1); % c代表一维数组第一个元素
e = [];
e(1,1)=double(c); %不同元素
e(1,2)=1; %相同元素个数
t=1;
for i=2:L
if(f(i)==c)
e(t,2)=(e(t,2))+1;
else
c=f(i);
t=t+1; %记录下一个元素
e(t,1)=double(c);
e(t,2)=1;
end
end
zipped=e;
info.rows=m;%传入图像的行
info.cols=n;%传入图像的列
[x,y]=size(e);
info.ratio=(info.rows*info.cols)/x;
end
function unzipped=Uncompress(zip,info)
[m,n]=size(zip);
unzipped=[];
for i=1:m
section=repmat(uint8(zip(i,1)),1,zip(i,2));%还原
unzipped=[unzipped,section];
end
unzipped=reshape(unzipped,info.cols,info.rows);%重构数组
unzipped=unzipped';
end