JPEG的简单流程实现

您所在的位置:网站首页 jpeg的算法 JPEG的简单流程实现

JPEG的简单流程实现

2023-10-06 19:32| 来源: 网络整理| 查看: 265

JPEG——分割,DCT,量化流程 一. 前言

近期在Coursera上了一门图像处理的课程 ”Image and Video Processing: From Mars to Hollywood with a Stop at the Hospital“ 目前在学习第二章图像压缩的相关内容,其中比较详细的讲到了JPEG标准的处理流程,于是自己就尝试实现用matlab了一下。

二. 流程

jpeg流程图

(一)灰度图像压缩

要对一个仅有灰度通道的图片进行JPEG标准压缩,首先需要先进行预处理: 将图片以8*8的形式进行分割,若原图片尺寸不为8的倍数,则进行补全。接下来对图片的处理,都是以8*8的小图片为单位进行处理的。

接下来是3大步:

1. 对8*8进行DCT变换(离散余弦变换)

DCT变换目的是将图像从空间域变换到频域的方法。在课程当中还提及,使用DCT变换实际上是一种退让。最理想的变换方式是KLT变换,然而这种变换矩阵不是一个常数,需要根据图片本身进行计算,代价昂贵。因此在JPEG标准中使用了DCT变换作为一种近似。

在进行DCT变换后,其左上角至右下角的元素所包含的信息量是逐步递减的。也就是说,如果在DCT变换后,只使用左上角的部分元素,剩下元素填补为0;在进行解压缩的时候,也可以得到某种令人满意的结果。(在接下来的实验当中,将展现这一点)

2. 量化

量化的目的是为变长编码进行服务的。如哈夫曼编码(变长编码的一种),只有当某些数字以某种较高的频率出现的时候,才能达到压缩的目的。当每个数字出现的频率都相等的时候,是使用变长编码进行压缩效果最差的时候。

量化可以分为均匀量化和非均匀量化两种:

均匀量化:floor ( data / n) * n ,这种量化方法使每n个数字都变为同一个数字。比如说:当n取2的时候 一串数字:1,2,3,4,5,6,7 量化为:0,2,2,4,4,6,6非均匀量化:将量化前的值以x表示,量化后的值以y表示,那么x和y的关系就是不均匀的分段函数。比如当x在[0,3)区间时,y为0,当x在[3,9)区间时,y为3.

JPEG标准中使用的是均匀量化,但是,对于不同位置的值,使用不同的量化系数n。 对于灰度图像使用矩阵:

Qy = [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];

对于色彩通道使用矩阵:

Qc = [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;]; 4. 变长编码

变长编码以哈夫曼为例,某个数值存储时用到的长度,是与其在图片中出现的概率有关的。出现概率大的,其存储所用空间就小。这样整个图片存储所用的空间大小,就会小于等长编码的大小。

(二)色彩图像压缩

JPEG在处理色彩图像时,使用的不是RGB通道,而是YCbCr通道。(两者之间的转换有一个特征矩阵) 对于色彩图像处理,就相当于把3个通道分开都分别当作3个灰度图片进行压缩。唯一的区别就在于,对于Y和两个色彩通道进行量化时,其量化矩阵不同。

(三)图像解压缩

图像解压缩与图像压缩的步骤是正好相反的,解码-量化-逆DCT变换。 最后还要记得把图片之前为了补齐8的倍数的像素舍弃掉。

三. 代码

首先定义变量矩阵

global Qy; Qy = [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]; global Qc; Qc = [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;]; global Qn; Qn = ones(8,8); Qn = Qn*16; % Qy = Qn; % Qc = ones(8,8)*64; global mask1; global mask2; global mask3; mask1=[1 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]; mask2=[1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]; mask3=[1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];

接下来是运行的主函数部分,rgb_jpg函数即对色彩图像进行压缩算法,其中用到的转换函数选项为“dct”,“fft”,“none”,分别表示进行DCT变换,FFT(快速傅立叶变换),以及不进行变换直接进行量化。 error为不同方法下的MSE误差

img = imread("15.jpeg"); [r,c] = size(img); rgb_dct = rgb_jpg(img,"dct"); rgb_fft = rgb_jpg(img,"fft"); rgb_none = rgb_jpg(img,"none"); error_dct = (1/(r*c))*sum(sum(sum((img-rgb_dct).^2))); error_fft = (1/(r*c))*sum(sum(sum((img-rgb_fft).^2))); error_none = (1/(r*c))*sum(sum(sum((img-rgb_none).^2))); subplot(331) imshow(img); subplot(332) imshow(rgb_dct); subplot(333) imshow(img-rgb_dct); subplot(334) imshow(img); subplot(335) imshow(rgb_fft); subplot(336) imshow(img-rgb_fft); subplot(337) imshow(img); subplot(338) imshow(rgb_none); subplot(339) imshow(img-rgb_none); disp(error_dct); disp(error_fft); disp(error_none);

接下来是压缩函数:

function rgb = rgb_jpg(img,function_name) YCbCr = rgb2ycbcr(img); Y = YCbCr(:,:,1); Cb = YCbCr(:,:,2); Cr = YCbCr(:,:,3); [img_com,r_flag,c_flag] = jpeg_com_sum(Y,0,function_name); Y_j = jpeg_decom_sum(img_com,r_flag,c_flag,0,function_name); [img_com,r_flag,c_flag] = jpeg_com_sum(Cb,1,function_name); Cb_j = jpeg_decom_sum(img_com,r_flag,c_flag,1,function_name); [img_com,r_flag,c_flag] = jpeg_com_sum(Cr,1,function_name); Cr_j = jpeg_decom_sum(img_com,r_flag,c_flag,1,function_name); YCbCr_j = cat(3,Y_j,Cb_j,Cr_j); rgb = ycbcr2rgb(YCbCr_j); end function [img_com,r_flag,c_flag] = jpeg_com_sum(img,flag,function_name) n = 8; [row,col] = size(img); % divide to 8*8 % 1 fill r = ceil(row/n)*n; c = ceil(col/n)*n; r_flag = r-row; c_flag = c-col; img_fill = zeros(r,c); img_fill(1:row,1:col) = img; % 2 divide and process(dct & quantize) img_com = zeros(r,c); for i = 1:8:r-7 for j = 1:8:c-7 img_com(i:i+7,j:j+7) = compress_small_img(img_fill(i:i+7,j:j+7),flag,function_name); end end % variable-length coding end function img = compress_small_img(img,flag,function_name) % transform if(function_name == "dct") img = dct2(img); elseif(function_name == "fft") img = fft2(img); end % preserve left-top corner global mask1; img = img.* mask1; % quantize if(flag == 0) global Qy; Q = Qy; else global Qc; Q = Qc; end img = floor(img./Q); end

解压缩函数:

% jpeg 总解压缩 function img_decom = jpeg_decom_sum(img,r_flag,c_flag,flag,function_name) n = 8; [row,col] = size(img); img_decom = zeros(row,col); % 1 divide and process(dequantize & dct) for i = 1:8:row-7 for j = 1:8:col-7 img_decom(i:i+7,j:j+7) = decompress_small_img(img(i:i+7,j:j+7),flag,function_name); end end % 2 cut img_decom = img_decom(1:row-r_flag,1:col-c_flag); img_decom = uint8(img_decom); end % quantize,dct 解压缩 function img = decompress_small_img(img,flag,function_name) % dequantize if(flag == 0) global Qy; Q = Qy; else global Qc; Q = Qc; end img = img .* Q; % transform if(function_name == "dct") img = idct2(img); elseif(function_name == "fft") img = real(ifft2(img)); end end 四. 效果

左侧是原图,中间是压缩后再解压缩的,右侧是差别图 第一行是DCT,第二行是FFT,第三行是None MSE分别为:69.9985;41.8939;185.8945 此时用的量化矩阵为JPEG的标准量化矩阵;8*8进行变化后所取的像素为:

mask1=[1 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];

在这里插入图片描述 更换所取元素为mask2: MSE分别为:58.0195,41.8039,188.7869

mask2=[1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];

在这里插入图片描述 更换所取元素为mask3: MSE分别为:55.5431,46.4918,194.1467

可以看见,当所取元素越少时,DCT的误差是在稳步减小,而FFT和None两种,误差都是稳步增大的。 此外,即使在FFT的误差比DCT的误差小的时候,图片呈现出来的效果也是有一种“重影”的感觉。 这就解释了,为什么选择了DCT进行变换,而不是FFT。(从函数上看,DCT是连续周期函数,而FFT是分段周期函数。从现实角度来说,临近像素肯定具有相似的特征,而DCT的“连续”更复合这一点)



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3