使用Matlab实现JPEG压缩

来源:互联网 发布:sql的with语句 编辑:程序博客网 时间:2024/06/15 23:04

一、 图像压缩原理

图像分成 8*8 小块 –> DCT 变换 –>用量化表对其量化 –>编码生成压缩数据

二、 具体压缩过程

  • 1、将原始图像分为 8 * 8 的小块, 每个 block 里有 64 个像素。

  • 2、 将图像中每个 8 * 8 的 block 进行 DCT 变换。8 * 8 的图象经过 DCT 变换后,其低频分量都集中在左上角,高频分量分布在右下角。由于该低频分量包含了图象的主要信息(如亮度),而高频与之相比,就不那么重要了,所以我们可以忽略高频分量。

  • 3、 利用量化表抑制高频变量。量化操作,就是将某一个值除以量化表中对应的值。由 于量化表左上角的值较小,右上角的值较大,这样就起到了保持低频分量,抑制高 频分量的目的。压缩时候将彩色图像的颜色空间由 RGB 转化为 YUV 格式。其中 Y 分量代表了亮度信息,UV 分量代表了色差信息。相比而言,Y 分量更重要一些。 我们可以对 Y 采用细量化,对 UV 采用粗量化,可进一步提高压缩比。所以量化表 通常有两张,一张是针对 Y 的标准亮度量化表;一张是针对 UV 的标准色彩量化表。

  • 4、 经过量化之后右下角大部分数据变成了 0,左上角为非零数据。这时使用 Z 字型(如 图所示)的顺序来重新排列数据生成一个整数数组,这样 0 就位于数组都后端。找到数组最后一个非零元素,将其后的数据都舍弃,并加上结束标志。

三、 关键代码

Compress.m

function [comp_image_Y,comp_image_U,comp_image_V] = Compress(orig_image)RGB=orig_image;%下面是对 RGB 三个分量进行分离 R=RGB(:,:,1);G=RGB(:,:,2);B=RGB(:,:,3);%RGB->YUV Y=0.299*double(R)+0.587*double(G) +0.114*double(B); [xm, xn] = size(Y);             U=-0.169*double(R)-0.3316*double(G)+0.5*double(B);  V=0.5*double(R)-0.4186*double(G)-0.0813*double(B);%产生一个 8*8 的 DCT 变换举证 T=dctmtx(8);%进行 DCT 变换 BY BU BV 是 double 类型BY=blkproc(Y,[8 8],'P1*x*P2',T,T'); BU=blkproc(U,[8 8],'P1*x*P2',T,T'); BV=blkproc(V,[8 8],'P1*x*P2',T,T');     %低频分量量化表a=[16 11 10 16 24 40 51 61;12 12 14 19 26 58 60 55;14 13 16 24 40 57 69 55;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;]; %高频分量量化表b=[17 18 24 47 99 99 99 99; 18 21 26 66 99 99 99 99; 24 26 56 99 99 99 99 99; 47 66 99 99 99 99 99 99; 99 99 99 99 99 99 99 99; 99 99 99 99 99 99 99 99; 99 99 99 99 99  99 99 99; 99 99 99 99 99 99 99 99;];%使用量化表对三个分量进行量化 BY2=blkproc(BY,[8 8],'round(x./P1)',a); BU2=blkproc(BU,[8 8],'round(x./ P1)',b); BV2=blkproc(BV,[8 8],'round(x./P1)',b);%调用压缩函数 comp_image_Y=img2jpg(BY2,1);        comp_image_U=img2jpg(BU2,2);                    comp_image_V=img2jpg(BV2,3);

img2jpg.m

function [ y ] = img2jpg( x,flag )[xm, xn] = size(x);%z字型读取数据顺序表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];y = im2col(x, [8 8], 'distinct');  % 将8x8 的块转化为列xb = size(y, 2);                   % 分块数y = y(order, :);                   % 按照order的顺序排列数据eob = max(y(:)) + 1;               % 设置块尾结束标志r = zeros(numel(y) + size(y, 2), 1);count = 0;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;          % 计数endr((count + 1):end) = [];           % 删除r 中不需要的元素[r1,r2]=size(r);y           = struct;y.realsize = r1;y.size      = uint16([xm xn]);y.numblocks = uint16(xb);y.r   = r;y.flag = flag;end

jpg2img

function [ x ] = jpg2img( y )%低频分量量化表   a=[16 11 10 16 24 40 51 61;  12 12 14 19 26 58 60 55;  14 13 16 24 40 57 69 55;  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;];  %高频分量量化表    b=[17 18 24 47 99 99 99 99;   18 21 26 66 99 99 99 99;   24 26 56 99 99 99 99 99;   47 66 99 99 99 99 99 99;   99 99 99 99 99 99 99 99;   99 99 99 99 99 99 99 99;   99 99 99 99 99 99 99 99;   99 99 99 99 99 99 99 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);endxb = double(y.numblocks);             % 块的个数sz = double(y.size);xn = sz(2);                           % 列数xm = sz(1);                           % 行数x = y.r;                              % 压缩后的数据eob = max(x(:));                      % 返回块尾标志z = zeros(64, xb);   k = 1;           % 生成 64 * xb 的零矩阵for j = 1:xb                          % x中的值放入z中,如果遇到eob就转入下一列    for i = 1:64                               if x(k) == eob                              k = k + 1;               break;                  else            z(i, j) = x(k);            k = k + 1;        end    endendT=dctmtx(8);                                   %产生一个8*8的DCT变换举证  z = z(rev, :);                                 % 按order恢复之前排列x = col2im(z, [8 8], [xm xn], 'distinct');     % 生成矩阵if y.flag==1    x = blkproc(x, [8 8], 'x .* P1', a);       % 反量化,乘量化表的值else    x = blkproc(x, [8 8], 'x .* P1', b);endx = blkproc(x, [8 8], 'P1 * x * P2', T', T);   % 反DCT变换end

Decompress.m

function reco_image = Decompress(orig_image_Y,orig_image_U,orig_image_V) %解压缩YI=jpg2img(orig_image_Y);UI=jpg2img(orig_image_U);VI=jpg2img(orig_image_V);%YUV 转为 RGBRI=YI-0.001*UI+1.402*VI; GI=YI-0.344*UI-0.714*VI; BI=YI+1.772*UI+0.001*VI;%经过 DCT 变换和量化后的 YUV 图像 RGBI=cat(3,RI,GI,BI);RGBI=uint8(RGBI);reco_image = RGBI;

运行结果


https://github.com/geekzph/JPEGCompression

0 0
原创粉丝点击