#topics h2 { background: rgba(43, 102, 149, 1); border-radius: 6px; box-shadow: 0 0 1px rgba(95, 90, 75, 1), 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: rgba(255, 255, 255, 1); font-family: "微软雅黑", "宋体", "黑体", Arial; font-size: 15px; font-weight: bold; height: 24px; line-height: 23px; margin: 12px 0 !important; padding: 5px 0 5px 10px; text-shadow: 2px 2px 3px rgba(34, 34, 34, 1) }
#topics h1 span { font-weight: bold; line-height: 1.5; font-family: "Helvetica Neue", Helvetica, Verdana, Arial, sans-serif; text-decoration: underline; text-shadow: 2px 2px 3px rgba(34, 34, 34, 1) }

  JPG编码的第3步是量化。对于经过离散余弦变化后的8*8block的数据,我们要对这8*8的数据进行量化。在JPEG中量化就是对数据V除以某个数Q,得到round(V/Q)代替原来的数据。然后在JPG解码的时候再乘以M得到V。

需要注意的是,量化会丢失图片精度,而且是不可逆的。

M的大小同时也影响压缩的效果。M越大压缩效果越好,但是图片精度损失越大。

图片引用自"Compressed Image File Formats JPEG, PNG, GIF, XBM, BMP - John Miano"[1]

1.JPEG的量化过程

首先我们会有一个8*8的量化表,这个表可以自定义,也可以用JPEG标准提供的量化表。

直接用我们的8*8的Block数据,除以对应的QuantizationTable的数据即可。

const Block QUANTIZATION_TABLE_Y = {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 }; const Block QUANTIZATION_TABLE_CBCR = { 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 };

量化表

假设我们的数据如左下,量化表如右下.

则round(V / A)就是我们需要的值了

2.代码

void JPG::quantization() {
for (uint i = 0; i < mcuHeight; i++) {
for (uint j = 0; j < mcuWidth; j++) {
MCU& currentMCU = data[i * mcuWidth + j];
//iterate over 每一个component Y, cb cr
for (uint componentID = 1; componentID <= 3; componentID++) {
//遍历block
for(uint ii = 0; ii < getVerticalSamplingFrequency(componentID); ii++) {
for(uint jj = 0; jj < getHorizontalSamplingFrequency(componentID); jj++) {
Block& currentBlock = currentMCU[componentID][ii * getHorizontalSamplingFrequency(componentID) + jj];
const Block& quantizationTable = getQuantizationTableByID(componentID);
//这一步就是对64个像素进行量化
for(uint index = 0; index < 64; index++) {
currentBlock[index] = currentBlock[index] / quantizationTable[index];
}
}
}
}
}
}
}

以上全部的代码在https://github.com/Cheemion/JPEG_COMPRESS/tree/main/Day4

完结

Thanks for reading,

Wish you have a good day.

>>>> JPG学习笔记5(待续)


参考资料

[1]https://github.com/Cheemion/JPEG_COMPRESS/blob/main/resource/Compressed%20Image%20File%20Formats%20JPEG%2C%20PNG%2C%20GIF%2C%20XBM%2C%20BMP%20-%20John%20Miano.pdf

JPG学习笔记4(附完整代码)的更多相关文章

  1. JPG学习笔记3(附完整代码)

    #topics h2 { background: rgba(43, 102, 149, 1); border-radius: 6px; box-shadow: 0 0 1px rgba(95, 90, ...

  2. Android 监听双卡信号强度(附完整代码)

    Android 监听双卡信号强度 监听单卡信号强度 监听单卡的信号强度非常简单直接用TelephonyManager.listen()去监听sim卡的信号强度. TelephonyManager = ...

  3. JPG学习笔记2(附完整代码)

    #topics h2 { background: rgba(43, 102, 149, 1); border-radius: 6px; box-shadow: 0 0 1px rgba(95, 90, ...

  4. WebGL three.js学习笔记 创建three.js代码的基本框架

    WebGL学习----Three.js学习笔记(1) webgl介绍 WebGL是一种3D绘图协议,它把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的 ...

  5. 学习笔记:python3,代码。小例子习作(2017)

    http://www.cnblogs.com/qq21270/p/7634025.html 学习笔记:python3,一些基本语句(一些基础语法的代码,被挪到这里了) 日期和时间操作 http://b ...

  6. 学习笔记:python3,代码。小例子习作

    http://www.cnblogs.com/qq21270/p/7634025.html 学习笔记:python3,一些基本语句(一些基础语法的代码,被挪到这里了) 日期和时间操作 http://b ...

  7. 雨痕 的《Python学习笔记》--附脑图(转)

    原文:http://www.pythoner.com/148.html 近日,在某微博上看到有人推荐了 雨痕 的<Python学习笔记>,从github上下载下来看了下,确实很不错. 注意 ...

  8. Linux Shell输出颜色字符学习笔记(附Python脚本实现自动化定制生成)

    齿轮发出咔嚓一声,向前进了一格.而一旦向前迈进,齿轮就不能倒退了.这就是世界的规则. 0x01背景 造了个轮子:御剑师傅的ipintervalmerge的Python版本.觉得打印的提示信息如果是普通 ...

  9. 基于C#的内网穿透学习笔记(附源码)

    如何让两台处在不同内网的主机直接互连?你需要内网穿透!          上图是一个非完整版内外网通讯图由内网端先发起,内网设备192.168.1.2:6677发送数据到外网时候必须经过nat会转换成 ...

随机推荐

  1. MySQL下载地址与Centos7安装MySQL以及启动问题排查

    目录 一.MySQL国内镜像下载 二.国内镜像相关站点 三.Centos7安装MySQL5.7 1. 下载并解压至/usr/local 2. 配置信息 3. 用户及用户组管理(提高安全) 4. 初始化 ...

  2. tcpdump抓包及tshark解包方法介绍

    tshark是wireshark的命令行工具,通过shell命令抓取.解析报文.tcpdump是Linux系统下的抓包工具.wireshark和tcpdump都共同使用 libpcap作为其底层抓包的 ...

  3. Kubernetes --(k8s)Job、CronJob

    Job https://www.kubernetes.org.cn/job https://www.kubernetes.org.cn/cronjob Job负责批量处理短暂的一次性任务 (short ...

  4. 省市县sql

    create table SYS_AREA ( ID NUMBER(18) not null, AREA_CODE VARCHAR2(50) not null, AREA_NAME VARCHAR2( ...

  5. Angular写一个Form组件-TagInput

    前端开发少不了和表单打交道; Angular中, 提供了强大的表单的支持, 响应式表单(Reactive Form) 和 模板驱动的表单(Template-driven Form) 的双向数据流给我们 ...

  6. Luogu4168 蒲公英 (分块)

    题目传送门 题意 长度为n的序列,有m次询问,每次询问求\([l,r]\) 间的众数,如果有多个,输出最小的那个 \(n\le 4\times 10^4,m\le 5\times 10^5,a_i\l ...

  7. AC自动机(转载)

    ac自动机学习博客 本来以为是很高级的算法 其实理解以后并不难 只是在字典树的基础上用fail数组标记一下回朔的位置 加速查找 就可以实现多模式串的匹配查找 模版如下: #include<cst ...

  8. HDU4358 Boring counting【dsu on tree】

    Boring counting Problem Description In this problem we consider a rooted tree with N vertices. The v ...

  9. hdu5365Shortest Path (floyd)

    Problem Description There is a path graph G=(V,E) with n vertices. Vertices are numbered from 1 to n ...

  10. 牛客小白月赛28 J.树上行走 (并查集,dfs)

    题意:有\(n\)个点,\(n-1\)条边,每个点的类型是\(0\)或\(1\),现在让你选一个点,然后所有与该点类型不同的点直接消失,问选哪些点之后,该点所在的联通块最大. 题解: 因为选完之后两个 ...