1.选择matlab自带图像cameraman.tif和westconcordorthophoto.png为编码压缩的测试图像。
2.根据设计要求选择图像编码和压缩方法;
3、设计编码与压缩的算法;
4、显示原始图像和压缩重构图像;
5、计算压缩的性能指标:压缩率和保真度;
6、画出压缩率和保真度的关系曲线。
本文章中有:
图像读取,余弦变换,亮度量化,Z字形重排,游程编码,参数文件保存,
参数文件读取,逆游程编码,逆Z字形重排,逆量化压缩,生成压缩比,保真度。
function U()
clear;
clc;
img = imread('cameraman.tif'); % 读取文件
Q = 20; % 品质(1~100),100最好
if(Q>100)
Q = 100;
end
if(Q<1)
Q = 1;
end
Q_ = 3.03-0.03*Q;
% blkproc对图像进行分块处理,分成8*8的子块,并用dct2()处理
DCT_c = blkproc(img,[8,8],'dct2');
figure('Name','cameraman.tif'); % 开一个叫cameraman.tif的窗口
subplot(2,3,1);imshow(img);title('原图'); %显示原图
% 显示余弦变换结果
subplot(2,3,2);imshow(log(abs(DCT_c)+1),[0,10]);title('余弦变换结果');
T = Y_Table(); % 用亮度量化表,用于量化压缩
DCT_c = blkproc(DCT_c,[8,8],'round(x./(P1*P2))',T,Q_); % 量化压缩
% 显示量化压缩结果
subplot(2,3,3);imshow(log(abs(DCT_c)+1),[0,10]);title('量化压缩结果');
Z = blockproc(DCT_c,[8,8],@Z_open,PadPartialBlocks=true); % Z字形重排(展开)Z_open
S = size(Z); % 记录展开后大小,方便以后复原
Z = Z(:); % 展开成一维
Z = RLC(Z); % 游程编码
save('图像.mat','Q','S','Z'); % 将大小,游程编码后结果,保存到文件中
load('图像.mat'); % 读取保存的变量
Z = iRLC(Z); % 游程解码
Z = reshape(Z,S(1),S(2)); % 重组
Z = blockproc(Z,[64,1],@Z_merge); % 逆Z字重排(合并)
DCT_c = blkproc(Z,[8,8],'x.*P1*P2',T,Q_); % 逆量化压缩
% 显示逆量化压缩结果
subplot(2,3,6);imshow(log(abs(DCT_c)+1),[0,10]);title('逆量化压缩结果');
% 显示逆变换图像
subplot(2,3,4);imshow(uint8(blkproc(DCT_c,[8,8],'idct2')));
title('逆变换图像');
s = size(img); % 得到原图像的大小,用于计算压缩率
s_ = s(1)*s(2);
x_=[];
y_=[];
for i = 1:1:100
[S,Z] = IC(img,i); % 压缩
s_Z = size(Z); % 压缩后大小
x_(length(x_(:))+1) = s_/(s_Z(1)*s_Z(2) + 3); % 压缩比,+3是要储存游程编码大小和Q
img_=iIC(i,S,Z);
img_=img_(1:s(1),1:s(2));
y_(length(y_(:))+1) = psnr(uint8(img_),img); % 信噪比,客观保真度
end
% 绘制压缩比-保真度
subplot(2,3,5);plot(x_,y_);xlabel('压缩比');ylabel('客观保真度');
title('压缩比-保真度');
end
% 图像压缩编码函数,输入图像,品质(1~100),100最好得到压缩后的数据
function [S,Z] = IC(img,Q)
% 品质(1~100),100最好
if(Q>100) % 大于一百的和小于1的都拉回来
Q = 100;
end
if(Q<1)
Q = 1;
end
Q_ = 3.03-0.03*Q; % 真正用的Q是这个
% blkproc对图像进行分块处理,分成8*8的子块,并用dct2()处理
DCT_c = blkproc(img,[8,8],'dct2');
T = Y_Table(); % 用亮度量化表压缩
DCT_c = blkproc(DCT_c,[8,8],'round(x./(P1*P2))',T,Q_);
Z = blockproc(DCT_c,[8,8],@Z_open,PadPartialBlocks=true); % Z字形重排(展开)Z_open
S = size(Z); % 记录展开后大小,方便以后复原
Z = Z(:); % 展开成一维
Z = RLC(Z); % 游程编码
end
% 图像解压函数,输入游程编码结果,Z字重排前大小,输出解码后图像
function img = iIC(Q,S,Z)
% 品质(1~100),100最好
if(Q>100) % 大于一百的和小于1的都拉回来
Q = 100;
end
if(Q<1)
Q = 1;
end
Q_ = 3.03-0.03*Q; % 真正用的Q是这个
T = Y_Table(); % 亮度量化表
Z = iRLC(Z); % 游程解码
Z = reshape(Z,S(1),S(2)); % 重组
Z = blockproc(Z,[64,1],@Z_merge); % 逆Z字重排(合并)
Z = blkproc(Z,[8,8],'x.*P1*P2',T,Q_);
img = blkproc(Z,[8,8],'idct2');
end
% 掏出一个亮度量化表
function T = Y_Table()
T =[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];
end
% 掏出Z字形重排的地址(8*8)
function T = Z_address()
T =[ 1 2 6 7 15 16 28 29
3 5 8 14 17 27 30 43
4 9 13 18 26 31 42 44
10 12 19 25 32 41 45 54
11 20 24 33 40 46 53 55
21 23 34 39 47 52 56 61
22 35 38 48 51 57 60 62
36 37 49 50 58 59 63 64 ];
end
% Z字展开(矩阵变一维)
function Z_out = Z_open(Z_input)
Z_out = zeros(64,1);
Z_out(Z_address()) = Z_input.data;
end
% Z字合并(一维变矩阵)
function Z_out = Z_merge(Z_input)
Z_out = Z_input.data(Z_address());
end
% 游程编码
function Y = RLC(X)
% 手动处理第一个
Y(1) = X(1);
Y(2) = 1;
c = 1; % 计数器,记录当前信号在Y的位置
C = 2; % 当前信号的游程,关于我为什么不用c+1,这样好看。
s = size(X); % 看看长度,一会有用
for i = (2:s) % 对于每个数据
if(X(i)~=Y(c)) % 如果和当前的不一样
c = C + 1; % 信号位置改变
C = c + 1; % 游程位置改变
Y(c) = X(i); % 记录信号
Y(C) = 1; % 计数1
else
Y(C) = Y(C) + 1; % 游程加一
end
end
end
% 游程解码
function Y = iRLC(X)
c = 1; % 计数器,记录Y该到哪里了
s = size(X); % 看看长度,一会有用
for i = (1:2:s(2)) % 记录格式为 信息 游程
for j = (1:X(i+1)) % 每个信息加游程个数个
Y(c) = X(i); % 信息录入
c = c + 1; % 计数+1
end
end
end