jpeg压缩过程博客一 jpeg压缩过程博客二 jpeg压缩过程博客三 jpeg维基百科 压缩率(品质因数)与量化矩阵的关系(Stack Overflow) 综合上述内容,总结提炼:
将任意原始图像经过jpeg压缩,是一个有损压缩过程,信息量的损失是按照量化矩阵对DCT系数进行round到整数量化时出现的,不同的量化矩阵会导致不同的jpeg压缩率。随着压缩率的增加相应的图像清晰度也会变低,具体压缩率与量化矩阵的关系见此链接。
压缩率由品质因数(Q)反应,Q的取值范围从1-100,取1时图像压缩率最高,最不清晰,量化矩阵的所有元素值均为255;取100时图像没有压缩,与原图相同,量化矩阵的所有元素值都为1;当Q取50时,就是现有博客中常见的量化矩阵系数:
量化矩阵作用在YUV通道经过DCT处理后的8*8矩阵上,同时需要注意的是量化矩阵有两种,一种为亮度量化矩阵,作用在Y通道,一种为色度量化矩阵,作用在U、V通道。
知道上述理论后,可以通过MATLAB制作任意压缩率的jpeg图片。在互联网上任意下载一图片并存储在m文件的同一文件夹下,虽然下载的图片也是jpg格式的,但是当在MATLAB中处理时,由于imread函数直接读取得到图片的RGB,因此,相对地,我们可以将其当成是原始图片,记为Ireference。
Ireference = imread('下载.jpg'); imwrite(Ireference,fullfile('下载Quality10.jpg'),'Quality',10); imwrite(Ireference,fullfile('下载Quality50.jpg'),'Quality',50); imwrite(Ireference,fullfile('下载Quality100.jpg'),'Quality',100); imwrite(Ireference,fullfile('下载Quality1.jpg'),'Quality',1); imwrite(Ireference,fullfile('下载Quality60.jpg'),'Quality',60); I10 = imread(fullfile('下载Quality10.jpg')); I50 = imread(fullfile('下载Quality50.jpg')); I100 = imread(fullfile('下载Quality100.jpg')); I1 = imread(fullfile('下载Quality1.jpg')); I60 = imread(fullfile('下载Quality60.jpg')); montage({I1,I10,I50,I60,I100,Ireference},'Size',[2 3]) title('JPEG-Compressed Images with Quality Factor: 1,10,50,60,100 and origin (left to right,up to down)')可以直观对比不同Quality Factor下的图片的视觉效果以及占用内存情况。
需要安装JpegLib库 JpegLib库下载、安装及使用 之后需要在visual studio 2015中包括 libjpeg.lib 然后写代码在visual studio 2015中处理上述在MATLAB中生成的不同压缩率的图片,以品质因数Q的值为50作为示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include <iostream> using namespace std; extern "C" { #include "jpeglib.h" } #pragma comment(lib, "libjpeg.lib") int main(int argc, char **argv) { FILE *file; char fileName[256]; int width; int height; struct jpeg_decompress_struct jDecompressStruct; struct jpeg_error_mgr jErrorMgr; int i = 50; //表示品质因数为50,处理"下载Quality50.jpg"这个文件 //当想处理品质因数为1或10或60或100的文件时,相应修改i的值即可 { memset(fileName, 0x00, sizeof(fileName)); strcat(fileName, "D:\\你在MATLAB中生成图片的路径\\下载Quality"); //这里需要改成你自己的路径,但"\\下载Quality"不要改变 char jpjnum[30]; itoa(i, jpjnum, 10); //方便进行批处理 数字转为字符串 char * Extend; Extend = ".jpg"; strcat(jpjnum, Extend); strcat(fileName, jpjnum); if (strcmp(fileName, "q") == 0) { exit(0); } if ((file = fopen(fileName, "rb")) == 0) { fprintf(stderr, "can't open %s\n", fileName); } // 初始化并申请解码器 jDecompressStruct.err = jpeg_std_error(&jErrorMgr); jpeg_create_decompress(&jDecompressStruct); // 指定图片文件信息 jpeg_stdio_src(&jDecompressStruct, file); // 读取头部信息 jpeg_read_header(&jDecompressStruct, TRUE); // 开始解码 jpeg_start_decompress(&jDecompressStruct); // 获取图片宽高 width = jDecompressStruct.image_width; height = jDecompressStruct.image_height; auto thisva = jDecompressStruct.quant_tbl_ptrs[0]->quantval; cout << thisva[0] << endl; //输出亮度量化矩阵的第一个元素 printf("decompress file:%s, %d x %d\n", fileName, width, height); // 释放解码器对象 jpeg_destroy_decompress(&jDecompressStruct); fclose(file); } return 0; }将断点加在下述图片所示位置进行调试 在变量区中,进入jDecompressStruct变量,找到quant_tbl_ptrs变量,可以看到quant_tbl_ptrs有四个值,索引[0]处的数值序列表示亮度量化矩阵,索引[1]处的数值序列表示色度量化矩阵。展开来看,有如下数值: 将这些数值与当Q取50时现有博客中常见的量化矩阵进行对比,发现完全一样。 进而得到了从jpg文件中获取亮度(luminance matrix)、色度(chroma matrix)量化矩阵信息的方法。 进一步地,可以修改i为1、10、60、100,通过调试程序在变量区查看对应的量化矩阵的变化。