一、【概念】jpeg相关概念简介

jpeg—一种影像有损压缩标准方法 后缀jpg/jpeg

JPEG(Joint Photographic Experts Group 联合图像专家小组)是一种针对照片影像而广泛使用的有损压缩标准方法,面向连续色调静止图像的一种压缩标准。1992年发布了JPEG的标准而在1994年获得了ISO 10918-1的认定。和相同图象质量的其它常用文件格式(如GIF,TIFF,PCX)相比,JPEG是目前静态图象中压缩比最高的。JPEG格式是最常用的图像文件格式,后缀名为.jpg或.jpeg

JFIF—JPEG文件交换格式,文件格式标准描述

JFIF:JPEG File Interchange Format JPEG文件交换格式。JPEG本身只有描述如何将一个图像转换为字节的数据串流,但并没有说明这些字节如何在任何特定的储存媒体上存储展现。一个由独立JPEG小组(Independent JPEG Group)所建立的额外标准,称为JFIF(JPEG File Interchange Format,JPEG档案交换格式),详细说明如何从一个JPEG串流,产出一个适合于电脑储存和传输的文件。可以见 后文 文件格式介绍部分。

渐进Progressive / 线性Baseline—两种典型jpeg压缩格式

Baseline:基于DCT的连续模式(Sequential DCT-based mode of operation,基本线性格式,一次将图像由左到右、由上到下顺序处理(一次扫描处理)。Progressive:基于DCT的渐进模式(Progressive DCT-based mode of operation),渐进JPEG,当图像传输的时间较长时,将图像分数次处理,以从模糊到清晰的方式来传送和显示图像(多次扫描处理)

libjpeg/libjpeg-turbo—一个C语言编写处理JPEG图像数据格式的开源库

libjpeg-turbo是libjpeg的一个复刻,它采用单指令流多数据流(SIMD)指令来加速JPEG编码和解码基础效率。许多项目现在使用libjpeg-turbo而不是libjpeg,包括流行的GNU/Linux发行版(Fedora、Debian、Mageia、OpenSUSE等)、Mozilla和Chrome。除了性能方面,部分项目也因它允许向后保留与旧的libjpeg v6b版本的ABI(application binary interface)兼容性而选择使用libjpeg-turbo。libjpeg v7、v8和v9已打破与早期版本的ABI兼容性。

mjpeg—一种视频压缩格式(每帧独立按jpeg编码)后缀mjpeg

MJPEG(Motion Joint Photographic Experts Group )是一种视频压缩格式,技术即运动静止图像(或逐帧)压缩技术,其中每一帧图像都分别使用JPEG编码,不使用帧间编码,压缩率通常在20:1-50:1范围内(相比之下 MPEG4可以到200:1-500:1,帧间压缩)。广泛应用于非线性编辑领域可精确到帧编辑和多层图像处理,把运动的视频序列作为连续的静止图像来处理,这种压缩方式单独完整地压缩每一帧,在编辑过程中可随机存储每一帧,可进行精确到帧的编辑。

jpeg2000—兼容jpeg下代压缩技术 (更高压缩率 支持无损)后缀jp2

JPEG 2000是基于小波变换的图像压缩标准,由联合图像专家小组创建和维护。JPEG 2000通常被认为是未来取代JPEG(基于离散余弦变换)的下一代图像压缩标准,文件后缀.jp2。JPEG 2000的压缩比更高,而且不会产生原先的基于离散余弦变换的JPEG标准产生的块状模糊瑕疵。 JPEG 2000同时支持有损数据压缩和无损数据压缩。另外,JPEG 2000也支持更复杂的渐进式显示和下载。

二、【原理】jpeg编解码码原理简介

编码流程简介:转YUV-下采样-分块-DCT-量化-hufman编码,用一张图简单描述编解码流程:

1、RGB转YUV并进行色度下采样—减少色度数据(有损)

将RGB的数据转换到YUV色彩空间,基于人眼对亮度相对色度更敏感特性,方便亮色分离后对色度下采样降低数据量。举例的典型转换公式如下。转换后一个RGB像素点,对应一个YUV像素点(包含一个Y数据、U数据、V数据)。

接下来,下采样主要是对色度数据采样率降低 来降低数据大小,从YUV444(每个亮度Y对应一个U和一个V)下采样到YUV420(四个Y对应一个UV组合)或者YUV422(两个Y对应一个UV组合)。如果降低到420,数据量就只有444的一半大小。一般是按8bit存储YUV数据每个分量。
可以参考博文:https://blog.csdn.net/runafterhit/article/details/82917345

2、分块进行DCT离散余弦变换—分离低频和高频数据

先按像素区域划分方便后续处理,先要把YUV这3个分量分开,存放到3张表中去(分别存储 Y数据表 U数据表 V数据表)。然后由左及右,由上到下依次读取8x8的子块,存放在长度为64的表中。先进行数据偏移得到-128~128的对称区域数据,然后进行DCT离散余弦变换 Discrete cosine transform, 将图像的低频(人眼敏感)和高频(人眼不敏感)部分进行分离。这样得到的结果是每个 88 小块得到 88 的系数矩阵。

3、量化处理—频率系数量化取整减少高频数据(有损)

将DCT后得到的每个系数都除以量化矩阵中对应的值,然后进行取整。通常来说频率较高的部分对应的量化参数比较大,这样一来能够在较好地保留图像的低频部分并去除一些高频部分。JPEG中压缩率的调整是在这一步中,量化参数越大,压缩后的大小就会越小,但信息的损失也就越多失真更严重,这一步是有损的

4、熵编码压缩数据—Huffman编码或算术编码压缩(无损)

熵编码是无损资料压缩的一个特别形式。它影像成分以Z字体(zigzag)排列,把相似频率组群在一起(矩阵中往左上方向是越低频率之系数,往右下较方向是较高频率之系数),插入长度编码的零结束标志,且接着对剩下的使用霍夫曼编码。 JPEG标准也允许在数学上优于霍夫曼编码的算术编码之使用(一般让文件更小约5%),然而由于专利原因很少使用,且相较霍夫曼编码在编解码上更慢。
哈夫曼编码一句话描述:先统计使用到全部字符独自的数量,构建一个哈夫曼树使每个字符都对应唯一的二进制编码,然后就用这些二进制翻译原先的数据 得到编码后data,反向解码也就是把 data通过哈夫曼树反向得到字符。从树介绍到哈夫曼树 可以了解:https://blog.csdn.net/runafterhit/article/details/96769885

三、【协议】jpeg协议标准文件格式(JFIF)介绍

jpeg文件基本构成元素—分段存储与段标识

JPEG文件的格式是分段来存储的,每个段都一定包含两部分一个是段的标识,由两个字节构成:第一个字节是0xFF,第二个字节标识段类型, 部分段紧接着的两个字节存放的是这个段的长度。标识表格如下:

备注:由于jpeg用FFxx作为标识,为了避免真正压缩数据FF冲突,数据段的FF使用FF00表示,相当于只要FF后面不是00就是一个真正的标号 而非 FF数据。

jpeg文件格典型组成详细描述(配合示例)

jpeg文件格典型组成描述:SOI文件开始标识-FFD8,是不是一个jpeg文件用这个判断)+APP0应用程序保留标记0xFFE0-如分辨率/采样率等,方便应用查看)+ DQT(定义量化表FFDB)+ SOF0(图像基本信息)+ DHT(定义Huffman表FFC4) + DRI(定义重新开始间隔FFDD-可选的)+ SOS(扫描行开始FFDA)+ EOI(文件结束标识FFD9)。

从最顶层看:文件起始SOI FFD8和结束EOI FFD9之间,就是jpeg的文件数据frame部分;把jpeg文件数据展开,先有一个APPn用作应用保留信息 方便应用软件读取,和 各类表格(如DQT定义量化表FFDB) 放在Tables/misc部分,然后是真正文件头frame header,接着就是扫描段scan组合,扫描段内部可以通过RST标识 FFD0~FFD7 表示 不同熵编码段 之间的 复位标志。如下我们打开一个图片。二进制通过UltraEdit、解析工具JPEGsnoop 见 第四部分查看工具。

1、开始标志SOI FFD8

2、APPn标记,APP0 应用保留信息信息常见格式(包含9个字段):固定值0xFFE0,1 数据长度(2 bytes,1~9段字节总长度),2标识符(5 bytes,内容0x4A46494600,即字符串JFIF0),3 版本号码(2 bytes,比如0x0102表示JFIF的版本号1.2),4 X和Y的密度单位(1 bytes,0:无单位;1:点数/英寸;2:点数/厘米),5 X方向像素密度(2 bytes),6 Y方向像素密度(2 bytes),7 缩略图水平像素数目(1 bytes),8 缩略图垂直像素数目(1 bytes),9缩略图RGB位图(rgb数据,任意长度)。

3、APP0~APPn之后是各类表项。一个或者多个量化表DQT:固定0xFFDB,1 量化表长度(2 bytes), P/T(1 bypte,高四位:精度 0 表8bit 1表16bit,低四位:表ID),表项内容;

3、展开文件头frame header,里面通过SOFn(FFC0~FFCF) 开始表示start of frame market帧标识起始,里面n用来描述是哪种基础编码格式,然后是头长度Lf(头长度),P采样精度(常见8-表示8bit位深),Y帧的行数即图片高度,X图片宽度,Nf 分量的个数(如 Y、U、V 3个分量,或者纯灰度图1)。接下来 每个分量的描述参数,主要包含 (Ci分量类型标识ID,Hi分量水平采样,Vi分量垂直采样,Tqi当前分量量化表ID)。



3、文件头之后,是一个或者多个霍夫曼表DHT:固定FFC4,1 长度(2 bytes),2 每个霍夫曼表内容(A ID号;B类型 0:DC表,1:AC表;C 长16个字节的编码,其代码代数和为接下来的编码的长度;D 内容编码)

4、DRI (Define Restart Interval) 复位段,可选:固定FFDD,1 长度(2 bytes),2 MCU 块的单元中的重新开始间隔(设为n,则意思是说,每n个MCU块就有一个RSTn标记。第一个标记是RST0,然后是RST1等,RST7后再从RST0重复)。
5、SOS(Start of Scan) 扫描数据段:固定FFDA,1 长度(2 bytes),2 分量数(1 bytes,灰度1分量,YUV3分量),3 每个颜色分量(A ID,B 交流系数AC表号,C 直流系数表DC表号)4 压缩数据(A 谱选择开始 bh 0x00,B.谱选择结束 ch 0x3F,C. 两个4位字段,高位和低位的谱选择 dh 1字节在基本JPEG中总为0x00, D 数据)

6、图像结束EOI:FFD9。

四、【查看】jpeg格式查看工具

在网上找了两款,可以用一下。

JPEG分析器—雷霄骅的JPEG分析器开源项目

介绍网页:https://blog.csdn.net/leixiaohua1020/article/details/84520117
SourceForge:https://sourceforge.net/projects/jpeganalysis/
中文,还配有注释,比较好理解。

JPEGsnoop—一款开源的国外的jpeg分析工具

官网:https://www.impulseadventure.com/photo/jpeg-snoop-source.html
gitbub链接:https://github.com/ImpulseAdventure/JPEGsnoop
百度经验使用指导:https://jingyan.baidu.com/article/37bce2be53f88f1002f3a212.html

五、【使用】libjpeg使用基础

libjpeg源码下载与编译

libjpeg-turbo介绍主页:https://libjpeg-turbo.org/
libjpeg-turbo下载github链接:https://github.com/libjpeg-turbo/libjpeg-turbo
1、下载源码:在github上找到源码链接,我的调试环境是linux,下载时的版本是2.1.1(见ChangeLog.md)

root@ubuntu:~/libjpeg/code# git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git

2、readme有提示编译看BUILDING.md 文件,基本用法梳理如下(依赖cmake,apt-get install cmake下载)

#创建并进入构建文件夹
mkdir build
cd build/
# 用命令创建makefile,格式:cmake -G"Unix Makefiles" [additional CMake flags] {source_directory}
# CMake flags这里可以指定编译参数,source_directory是libjpeg源码目录
# 常见编译参数:-DCMAKE_INSTALL_PREFIX=xxx指定安装目录,如是交叉编译-DCMAKE_C_COMPILER指定编译器
cmake -G"Unix Makefiles" -DCMAKE_INSTALL_PREFIX=./ /root/libjpeg/code/libjpeg-turbo/
# 编译,可以带-j多线程加速编译
make -j
# 查看编译后内容
root@ubuntu:~/libjpeg/code/libjpeg-turbo/build# ls
cjpeg           cmake_install.cmake    djpeg         jcstest          libjpeg.map        libturbojpeg.a         Makefile    sharedlib       tjbenchtest    tjunittest-static
cjpeg-static    cmake_uninstall.cmake  djpeg-static  jpegtran         libjpeg.so         libturbojpeg.so        md5         simd            tjexample      wrjpgcom
CMakeCache.txt  croptest               jconfig.h     jpegtran-static  libjpeg.so.62      libturbojpeg.so.0      pkgscripts  tjbench         tjexampletest
CMakeFiles      CTestTestfile.cmake    jconfigint.h  libjpeg.a        libjpeg.so.62.3.0  libturbojpeg.so.0.2.0  rdjpgcom    tjbench-static  tjunittest

3、编译后最关注的libjpeg.a静态链接库,libjpeg.so动态链接库 就是我们需要的 库了,还有一些小工具。

libjpeg最简单的解码用例

有了动态链接库了,我们来写一个最简单的解码sample试试(在源码目录下example.txt有很详细的各种用法用例描述)
写一个sample_jpeg.c文件:

#include "stdio.h"
#include "jpeglib.h"
#include <setjmp.h>
struct my_error_mgr {struct jpeg_error_mgr pub;    /* "public" fields */jmp_buf setjmp_buffer;        /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
void my_error_exit (j_common_ptr cinfo) {my_error_ptr myerr = (my_error_ptr) cinfo->err;(*cinfo->err->output_message) (cinfo);longjmp(myerr->setjmp_buffer, 1);
}int main(int argc, char *argv[]) {if (argc < 2) {printf("please intput like: ./a.out xxx.jpeg\n");}// 打开输入文件FILE *infile = fopen(argv[1], "rb");if (infile == NULL) {printf("intput file %s open failed!\n", argv[1]);return -1;}// 创建输出文件FILE *outfile = fopen("./output.bit", "w+");if (outfile == NULL) {printf("out file open failed!\n");return -1;}// 定义cinfo数据结构,libjpeg定义的解码器上下文struct jpeg_decompress_struct cinfo;// 设置报错回调,如果libjpeg解析过程出错,会调用struct my_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr.pub);if (setjmp(jerr.setjmp_buffer)) {printf("set jmp error failed!\n");fclose(infile);return -1;}// 创建解码器jpeg_create_decompress(&cinfo);// 设置解码器输入,绑定文件jpeg_stdio_src(&cinfo, infile);// 读取文件头,这一步之后cinfo中文件信息才可信jpeg_read_header(&cinfo, TRUE);// 开始解码,默认输出是RGB,还可以cinfo.out_color_space设置jpeg_start_decompress(&cinfo);// 计算输出的行stride,jpeg库是按行往外读取,要计算每行读取多少数据int row_stride = cinfo.output_width * cinfo.output_components;// 调用libjpeg内存申请接口,申请一个一行长的bufferJSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);// 循环从libjpeg读取行 到 buffer,然后将buffer内容写入文件while (cinfo.output_scanline < cinfo.output_height) {jpeg_read_scanlines(&cinfo, buffer, 1);fwrite(buffer[0], row_stride, 1, outfile);}// 关闭全部文件close(infile);close(outfile);return 0;
}

编译sample,注意带上libjpeg库,然后执行sample,把jpeg图片作为输入。

gcc sample_jpeg.c -ljpeg
./a.out ./test3.jpeg

用RGB文件解析工具,查看输出的output.bit文件

六、其他补充

关于libjpeg的版本移植与升级(待补充)

关于jpeg硬解加速与设计要点(待补充)

关于jpeg常见问题的定位思路(待补充)

关于jpeg的缩略图(待补充)

参考

wiki百科介绍:https://en.wikipedia.org/wiki/JPEG (备注:页面有ITU-T81标准文档)
ITU标准官网:https://www.itu.int/zh/ITU-T/Pages/default.aspx
http://www.360doc.com/content/07/0703/09/2228_591692.shtml
https://blog.csdn.net/yun_hen/article/details/78135122
https://blog.csdn.net/huangxy10/article/details/8117469
https://zhuanlan.zhihu.com/p/27296876
https://blog.csdn.net/carson2005/article/details/7753499
http://blog.csdn.net/shelldon/article/details/54234433
JFIF文件格式:https://blog.csdn.net/johnny_83/article/details/2252599

图形图像基础 之 jpeg介绍相关推荐

  1. 图形图像基础 之 png介绍

    文章目录 一.png相关概念 png---一种无损压缩算法的位图格式 png和bmp.jpeg图片比较 libpng---一款C语言编写的读写PNG文件的跨平台的库 二.png文件格式---文件标签+ ...

  2. 图形图像基础 之 bmp介绍

    文章目录 一.bmp相关概念 位图Bitmap 与 矢量图Vector---用点表示 还是 用公式表示 bmp(Bitmap-File)---一种非压缩图形文件位图格式,后缀bmp 二.bmp文件格式 ...

  3. 4.图形图像素材编辑

    4.图形图像素材编辑 图形.图像是人类视觉所感受到的一种具象化的信息,是多媒体信息的主要类型,也是信息传递最基本.最常见的方式.它可以形象.生动和直观地表达大量的信息,具有文字和声音无可比拟的优点.图 ...

  4. OpenCV图形图像击中击不中HITMISS变换处理基础知识

    ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 博文传送门: 老猿关于HTM变换的博文目录请见: https://blog.csdn.ne ...

  5. 图形和图像计算机基础知识,计算机图形图像基础

    <计算机图形图像基础>是2011-03-01浙江大学出版社出版的图书,作者是程辉,田少煦.[1] 书    名 计算机图形图像基础 作    者 程辉,田少煦ISBN 9787308083 ...

  6. 一个C#函数学完C#图形图像编程基础

    老师说C#主要用于 1.winform开发 2.网络 3.驱动 在图形图像处理上用的比较少,不过书里有图形图像编程这一章节,为了系统的学完C#编程基础,以及为了能够更熟悉C#的特性,再加上今天晚上闲的 ...

  7. 深入理解Flutter的图形图像绘制原理——图形库skia剖析

    Flutter是目前流行的高性能跨平台UI框架,图形库skia是其跨平台的基石.本文将深入分析skia的图形.字体.图片的渲染原理,如何挖掘硬件特性,为UI性能优化提供思路. 1. 引言 Flutte ...

  8. 计算机视觉————(CV)图像基础以及数字图像处理基础

    1.数字图像 客观世界中,以自然形式呈现出的图像通常称作物理图像,也叫做连续图像,图像信号值是连续变化的.因为计算机只可以识别离散数字,因此物理图像需要经过处理转化为数字形式,即数字图像,才可以使用. ...

  9. 计算机中常用的矢量图形文件,第3章 电脑图像基础知识.ppt

    <第3章 电脑图像基础知识.ppt>由会员分享,可在线阅读,更多相关<第3章 电脑图像基础知识.ppt(15页珍藏版)>请在人人文库网上搜索. 1.第03章 电脑图像基础知识, ...

最新文章

  1. on-my-zsh git 仓库下运行卡顿
  2. 去除警告,打电话,发信息,应用程序之间跳转,打印沙盒路径,字符串名字转换方法,包装导航控制器等的代码...
  3. Sql server 2005系统表详细说明
  4. 快速排序算法C#实现
  5. 开源项目SlidingMenu的使用(Android)
  6. vue 判断同一数组内的值是否一直_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目
  7. Windows完全卸载oracle11g步骤
  8. 讲解开源项目:让你成为灵魂画手的 JS 引擎:Zdog
  9. 机器学习基础(六)—— 交叉熵代价函数(cross-entropy error)
  10. java 水晶报表教程_水晶报表 (Crystal Reports 2008)的配置
  11. 朴实无华,总结200道往年BAT机器学习面试题
  12. intel 9260AC网卡修改成Killer 1550
  13. torch中dataloader加速
  14. 注册表怎么用计算机管理打开,如何打开注册表,详细教您如何打开电脑注册表管理器...
  15. element-ui插件pagination分页中、英文语言切换
  16. 使用excel进行数据挖掘(4)---- 突出显示异常值
  17. 弥散磁共振影像处理的黎曼 芬斯勒几何方法研究
  18. 单词倒排 与 IP整数转换
  19. 计算机技术英文缩写含义,电脑技术中常见的英文缩写含义
  20. CRC循环冗余校验是如何纠错的

热门文章

  1. 前端使用xlsx.core.min.js读取excel内容
  2. 51单片机ADC0808实时转换电压十进制形式数码管显示
  3. 运算放大器——4种基本运放电路(同相放大、反相放大、加法器、差分放大电路)
  4. SpringMVC与structs2区别
  5. 火猴之图片立体翻转效果展示(firemonkey)
  6. AS导入安卓源码步骤
  7. 说一说股票自动下单接口是什么?
  8. MAXwell应用报错提问:
  9. python中的打开文件的用法_python基础之文件操作
  10. XCode8 真机测试打包,让发布测试更轻松