反量化

反量化其实很简单,将霍夫曼解码出来的数据乘上对应的量化表就好了

通过当前色度选择出SOF中的Component,其中的Tqi指出了这一色度所需的量化表id

Component的结构如下:

名称 长度(bit) 备注
Ci 8 Compoenent的id
Hi 4 水平缩放因子
Vi 4 垂直缩放因子
Tqi 8 对应的量化表id

然后就可以根据量化表id找到量化表,将其中每一个元素与霍夫曼解码的结果相乘就OK了

// 就是简单粗暴的直接相乘
for (int i = 0; i < 8; ++i) {
for (int j = 0; j < 8; ++j) {
result[i][j] = input[i][j] * dqt[i][j];
}
}

逆ZigZag变换

逆ZigZag变换实际上和ZigZag变换做的是同样的操作,直接按Z字形重新排序就好

参考代码

// 直接查表大法
const int zigzag_table[8*8][2] = {
{0, 0}, {0, 1}, {1, 0}, {2, 0}, {1, 1}, {0, 2}, {0, 3}, {1, 2},
{2, 1}, {3, 0}, {4, 0}, {3, 1}, {2, 2}, {1, 3}, {0, 4}, {0, 5},
{1, 4}, {2, 3}, {3, 2}, {4, 1}, {5, 0}, {6, 0}, {5, 1}, {4, 2},
{3, 3}, {2, 4}, {1, 5}, {0, 6}, {0, 7}, {1, 6}, {2, 5}, {3, 4},
{4, 3}, {5, 2}, {6, 1}, {7, 0}, {7, 1}, {6, 2}, {5, 3}, {4, 4},
{3, 5}, {2, 6}, {1, 7}, {2, 7}, {3, 6}, {4, 5}, {5, 4}, {6, 3},
{7, 2}, {7, 3}, {6, 4}, {5, 5}, {4, 6}, {3, 7}, {4, 7}, {5, 6},
{6, 5}, {7, 4}, {7, 5}, {6, 6}, {5, 7}, {6, 7}, {7, 6}, {7, 7}
};
void zigzag_transform(int input[8][8], int output[8][8]) {
for (int i = 0; i < 8*8; ++i) {
int row = zigzag_table[i][0];
int col = zigzag_table[i][1];
output[row][col] = input[i/8][i%8];
}
}

IDCT变换

最后再进行IDCT2D,IDCT变换就是DCT变换的逆变换,IDCT2D就是横着变换一次再竖着变换一次。这个更多是数学上的东西我就不多说了,怕误人子弟

话不多说,上代码:

pub struct DCT {
pub idct2d_data: [[[[f32; 8]; 8]; 8]; 8],
} fn cc(i: usize, j: usize) -> f32 {
if i == 0 && j == 0 {
return 1.0 / 2.0;
} else if i == 0 || j == 0 {
return 1.0 / (2.0 as f32).sqrt();
} else {
return 1.0;
}
} impl DCT {
// 先提前算好一部分
pub fn new() -> DCT {
let mut tmp: [[[[f32; 8]; 8]; 8]; 8] = Default::default();
for i in 0..8 {
for j in 0..8 {
for x in 0..8 {
let i_cos = ((2 * i + 1) as f32 * PI / 16.0 * x as f32).cos();
for y in 0..8 {
let j_cos = ((2 * j + 1) as f32 * PI / 16.0 * y as f32).cos();
tmp[i][j][x][y] = cc(x, y) * i_cos * j_cos / 4.0;
}
}
}
}
DCT { idct2d_data: tmp }
} pub fn idct2d(&self, data: [[f32; 8]; 8]) -> [[f32; 8]; 8] {
let mut tmp: [[f32; 8]; 8] = Default::default();
for i in 0..8 {
for j in 0..8 {
tmp[i][j] = {
let mut tmp = 0.0;
for x in 0..8 {
for y in 0..8 {
tmp += self.idct2d_data[i][j][x][y] * data[x][y];
}
}
tmp
};
}
}
tmp
}
// 后面还有SSE和AVX加速的代码就不放了,直接看源代码就好了
}

尾声

到这里JPEG解码的部分就全部结束了。需要注意的是,这里解码出来的数据颜色格式并不是可以直接输出到屏幕的RGB888(其实允许这种格式,但很少见,比较常见的是YCbCr格式),还要根据需要处理。

提醒一下,解码出来的是分割出来的8x8的块,还要再拼起来

参考资料

博客园博客:JPEG解码——(4)霍夫曼解码 - OnlyTime_唯有时光 - 博客园 (cnblogs.com)

JPEG标准:Microsoft Word - T081E.DOC (w3.org)

一个Rust写的JPEG解码器:MROS/jpeg_tutorial: 跟我寫 JPEG 解碼器 (Write a JPEG decoder with me) (github.com)

友情链接

我学习过程中写的JPEG图片查看器:Ryan1202/my-tiny-jpeg-viewer: A Tiny Jpeg Viewer (github.com)

JPEG格式研究——(4)反量化、逆ZigZag变化和IDCT变换的更多相关文章

  1. JPEG解码——(5)反量化和逆ZigZag变换

    本篇是该系列的第五篇,承接上篇huffman解码,介绍接下来的两个步骤--反量化和逆zigzag变换,即IDCT前的两个步骤. 需要说明的是,这两个步骤可以颠倒,本人的实现是,先反量化,再逆ZigZa ...

  2. 图像JPEG格式介绍

    1 JPG格式介绍 JPEG (Joint PhotographicExperts GROUP)是由国际标准组织和国际电话电报咨询委员会为静态图像所建立的第一个国际数字图像压缩标准,也是至今一直在使用 ...

  3. 嵌入式Linux基于framebuffer的jpeg格式本地LCD屏显示

    在基于Linux的视频监控采集系统中,摄像头采集到的一帧视频图像数据一般都是经过硬件自动压缩成jpeg格式的,然后再保存到摄像头设备的缓冲区.如果要把采集到的jpeg格式显示在本地LCD屏上,由于我们 ...

  4. JPEG格式 介绍

    JPEG格式 jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化.在保存时有个质量参数可在[0,100]之间选择,参数越大图片就越保真,但图片的体积也就越大 ...

  5. 让阿里云的Centos,PHP组件 ImageMagick支持png和jpeg格式

    我们在Centos安装ImageMagick教程中讲述了如何安装ImageMagick,安装完毕之后发现程序并不支持png和jpeg格式的图片,但是这两种图片又是我们平时所常见的,所以我们还要进一步地 ...

  6. ecshop图片上传JPEG格式失败问题

    在根目录下找到includes文件目录,在其目录中找到cls_image.php打开并找到: $allow_file_types = '|GIF|JPG|JEPG|PNG|BMP|SWF|'; 此处J ...

  7. 超图不支持JPEG格式的WMTS服务

    就目前面而言,超图不支持JPEG格式的WMTS服务,只支持PNG格式的. <本篇完>

  8. 一般源码安装添加的GD库 是不支持 jpeg 格式的图片的

    一般源码安装添加的GD库 是不支持 jpeg 格式的图片的,只支持如下格式 GD Support enabled GD Version bundled (2.0.34 compatible) GIF ...

  9. linux下将jpg,jpeg格式转为PDF

    1.安装imagemagick(用其中的convert)和gthumb     sudo apt-get install imagemagick gthumb 2.将tiff图片转换为png或jpeg ...

  10. Call to undefined function imagecreatefromjpeg() 让GD支持JPEG格式的图片扩展

    安装扩展支持jpeg格式: 第一步:首先下载文件: 版本v8: wget http://www.ijg.org/files/jpegsrc.v8b.tar.gz 版本v9: wget http://w ...

随机推荐

  1. 小程序云开发 Collection.watch 监听器构建和销毁

    小程序云开发 Collection.watch 监听器构建和销毁 构建和销毁代码示例 // release/chatroom/index.js const db = wx.cloud.database ...

  2. CSS & JS Effect – Simulation Position Sticky (用 JavaScript 实现 position sticky)

    前言 在 CSS – Position 我有提到过, 原生的 sticky 有一些 limitation. 不是每次都闪的掉. 这篇主要是通过 JS 来模拟它, 突破那些限制. Google Ads ...

  3. 如何更改Wordpress语言为中文

    在使用WordPress的时候,一般安装默认语言是英文,可以在后台设置里面直接修改站点语言为简体中文,当后台没有语言选项框的这一栏,如下图所示,该怎么办呢? 这个时候我们可以找到文件wp-config ...

  4. vsphere8.0 VCenter部署

    一.vCenter Server 介绍 vCenter Server是VMware提供的一种集中管理平台,用于管理和监控虚拟化环境中的虚拟机.主机.存储和网络等资源.它提供了一套功能强大的工具和界面, ...

  5. USB协议详解第3讲(USB描述符-设备描述符)

    我们第一个学习要点就是USB描述符,所谓描述符其实就是C语言里面的结构体或者数组,数组包含的信息说明当前的设备具有哪些特征.USB描述符有设备描述符.配置描述符.接口描述符.端点描述符.字符串描述符, ...

  6. Android Studio自带Profiler工具内存泄露分析步骤

    1.运行需要检测内存泄露的程序 这里以"com.example.opengltest"程序为例. 2.点击Profiler按钮 3.点击SESIONS "+"号 ...

  7. 9月《中国数据库行业分析报告》已发布,47页干货带你详览 MySQL 崛起之路!

    为了帮助大家及时了解中国数据库行业发展现状.梳理当前数据库市场环境和产品生态等情况,从2022年4月起,墨天轮社区行业分析研究团队出品将持续每月为大家推出最新<中国数据库行业分析报告>,持 ...

  8. 数据库周刊59丨GaussDB(for openGauss)开放商用;人大金仓保障冬奥会演练顺利完成;MDL锁导致的MySQL问题分析;PG日志使用手册;达梦表空间查询;数据库笔试题面试题集……

    热门资讯 1.openGauss 上线华为云正式商用 - GaussDB(for openGauss) [摘要]近日,GaussDB(for openGauss)已于华为云官网全面开放商用.该产品是华 ...

  9. 过滤器 多少时间之前发布 dayjs relative'TrelativeTime

    import dayjs from "dayjs"; import relativveTime from "dayjs/plugin/relativeTime" ...

  10. 012 Python约定俗称的常量

    #!/usr/bin/env python # -*- coding:utf-8 -*- # Datatime:2022/7/18 21:13 # Filename:011 Python约定俗称的常量 ...