function y = jpegencode(x, quality)
%jpegencode函数用来压缩图像,x为输入图像
%quality决定了截去的系数和压缩比
error(nargchk(1, 2, nargin)); %检查输入参数
if nargin < 2
quality = 1; %默认时 quality为1
end
x = double(x) - 128; %像素层次移动-128
[xm, xn] = size(x); %得到像素尺寸
t = dctmtx(8); %得到8*8DCT矩阵
%将图像分割成8*8子图像,进行DCT,然后进行量化
y = blkproc(x, [8,8], 'P1*x*P2', t, t');
m = [16 11 10 16 24 40 51 61 %JPEG量化步长矩阵
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 110 103 99]*quality;
%用量化步长矩阵m对变换矩阵进行量化
yy = blkproc(y, [8, 8], 'round(x./P1)', m);
y = im2col(yy, [8, 8], 'distinct'); %将图像块排列成向量
xb = size(y, 2); %得到列数,也就是子图像个数
order = [1 9 2 3 10 17 25 18 11 4 5 12 19 26 33 ... %变换系数排列次序
41 34 27 20 13 6 7 14 21 28 35 42 49 57 50 ...
43 36 29 22 15 8 16 23 30 37 44 51 58 59 52 ...
45 38 31 24 32 39 46 53 60 61 54 47 40 48 55 62 63 56 64];
%用Z形扫描方式对变换系数重新排列
y = y(order, :);
eob = max(x(:)) + 1; %创建一个块结束符号
num = numel(y) + size(y, 2);
r = zeros(num, 1);
count = 0;
%将非零元素重新排列放入r中,-26-3 eob -25 1 eob
for j = 1: xb %每次对一列(即一块)进行操作
i = max(find(y(:, j))); %找最后一个非零元素
if isempty(i) %没有非零元素
i = 0;
end
p = count + 1;
q = p + i;
r(p: q) = [y(1: i, j); eob]; %截去零并加上结束符号
count = count + i + 1;
end
r((count + 1): end) = []; %删除r的没有用的部分
r = r + 128;
%保存编码信息
y.size = uint16([xm, xn]);
y.numblocks = uint16(xb);
y.quality = uint16(quality*100);
%对r进行Huffman编码
[y.huffman, y.info] = huffencode(uint8(r));
function vector = huffdecode(zipped, info, image)
% 函数对输入矩阵vector进行Huffman解码,返回解压后的图像数据
if ~isa(zipped, 'uint8')
error('input argument must be be a uint8 vector');
end
%产生0,1序列,每位占一个字节
len = length(zipped);
string = repmat(uint8(0), 1, len.*8);
bitindex = 1:8;
for index = 1:len
string(bitindex + 8.*(index-1)) = uint8(bitget(zipped(index), bitindex));
end
string = logical(string(:)');
len = length(string);
string ((len-info.pad+1):end)=[];
len = length(string);
%开始解码
weights = 2.^(0:51);
vector = repmat(uint8(0), 1, info.length);
vectorindex = 1;
codeindex = 1;
code = 0;
for index = 1:len
code = bitset(code, codeindex, string(index));
codeindex = codeindex+1;
byte = decode(bitset(code, codeindex), info);
if byte > 0
vector(vectorindex) = byte-1;
codeindex = 1;
code = 0;
vectorindex = vectorindex + 1;
end
end
vector = reshape(vector, info.rows, info.cols);
%函数decode返回码字对应的符号
function byte = decode(code, info)
byte = info.huffcodes(code);
function [zipped, info] = huffencode(vector)
% 输入和输出都是 uint8 格式
% info 返回解码需要的结构信息
% info.pad 是添加的比特数
% info.huffcodes 是 Huffman 码字
% info.rows 是原始图像行数
% info.cols 是原始图像列数
% info.length 是原始图像数据长度
% info.maxcodelen 是最大码长
if ~isa(vector, 'uint8')
error('input argument must be a uint8 vector');
end
[m, n] = size(vector);
vector = vector(:)';
f = frequency(vector); %计算各符号出现的概率
symbols = find(f~=0);
f = f(symbols);
[f, sortindex] = sort(f); %将符号按照出现的概率大小排列
symbols = symbols(sortindex);
len = length(symbols);
symbols_index = num2cell(1:len);
codeword_tmp = cell(len, 1);
% 生成 Huffman 树,得到码字编码表
while length(f)>1
index1 = symbols_index{1};
index2 = symbols_index{2};
codeword_tmp(index1) = addnode(codeword_tmp(index1), uint8(0));
codeword_tmp(index2) = addnode(codeword_tmp(index2), uint8(1));
f = [sum(f(1:2)),f(3:end)];
symbols_index = [{[index1, index2]},symbols_index(3:end)];
[f, sortindex] = sort(f);
symbols_index = symbols_index(sortindex);
end
codeword = cell(256, 1);
codeword(symbols) = codeword_tmp;
len = 0;
for index = 1:length(vector) %得到整个图像所有比特数
len = len + length(codeword{double(vector(index))+1});
end
string = repmat(uint8(0), 1, len);
pointer = 1;
for index = 1:length(vector) %对输入图像进行编码
code = codeword{double(vector(index))+1};
len = length(code);
string(pointer + (0:len-1))=code;
pointer = pointer + len;
end
len = length(string);
pad = 8-mod(len, 8);
if pad > 0
string = [string uint8(zeros(1, pad))];
end
codeword = codeword(symbols);
codelen = zeros(size(codeword));
weights = 2.^(0:23);
maxcodelen = 0;
for index = 1:length(codeword)
len = length(codeword{index});
if len > maxcodelen;
maxcodelen = len;
end
if len > 0
code = sum(weights(codeword{index} == 1));
code = bitset(code, len + 1);
codeword{index} = code;
codelen(index) = len;
end
end
codeword = [codeword{:}];
%计算压缩的向量
cols = length(string)/8;
string = reshape(string, 8, cols);
weights = 2.^(0: 7);
zipped = uint8(weights * double(string));
%码表存储到一个希疏矩阵
huffcodes = sparse(1, 1);
for index = 1:nnz(codeword) % length(codeword) %numel(codeword)
huffcodes(codeword(index), 1) = symbols(index);
end
%填写解码时所需的结构信息
info.pad = pad;
info.huffcodes = huffcodes;
info.ratio = cols./length(vector);
info.length = length(vector);
info.maxcodelen = maxcodelen;
info.rows = m;
info.cols = n;
%函数addnode添加节点
function codeword_new = addnode(codeword_old, item)
codeword_new = cell(size(codeword_old));
for index = 1:length(codeword_old)
codeword_new{index} = [item codeword_old{index}];
end
%函数frequency计算各符号出现的概率
function f = frequency(vector)
if ~isa(vector, 'uint8')
error('input argument must be a uint8 vector');
end
f = repmat(0, 1, 256);
len = length(vector);
for index = 0:255
f(index+1) = sum(vector == uint8(index));
end
f = f./len; %归一化
function x = jpegdecode(y)
%jpegdecode函数,jpegencode的解码程序
error(nargchk(1, 1, nargin)); %检查输入参数
m = [16 11 10 16 24 40 51 61 %JPEG量化步长矩阵
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 110 103 99];
order = [1 9 2 3 10 17 25 18 11 4 5 12 19 26 33 ... %变换系数排列次序
41 34 27 20 13 6 7 14 21 28 35 42 49 57 50 ...
43 36 29 22 15 8 16 23 30 37 44 51 58 59 52 ...
45 38 31 24 32 39 46 53 60 61 54 47 40 48 55 62 63 56 64];
rev = order; %计算逆序
for k = 1:length(order)
rev(k) = find(order == k);
end
% ff = max(rev(:)+1;
m = double(y.quality)/100*m;
xb = double(y.numblocks); %得到图像块数
sz = double(y.size);
xn = sz(1);
xm = sz(2);
x = huffdecode(y.huffman, y.info); %huffman1解码
x = double(x) - 128;
eob = max(x(:));
z = zeros(64, xb);
k = 1;
for j = 1: xb
for i = 1: 64
if x(k) == eob
k = k + 1;
break;
else
z(i, j) = x(k);
k = k + 1;
end
end
end
z = z(rev, :); %恢复次序
x = col2im(z, [8, 8], [xm, xn], 'distinct'); %重新排列成图像
x = blkproc(x, [8, 8], 'x.*P1', m); %逆量化
t = dctmtx(8);
x = blkproc(x, [8, 8], 'P1*x*P2', t', t); %DCT逆变换
x = uint8(x + 128); %进行位移