反量化

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

通过当前色度选择出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. Kubelet证书自动续签(为 kubelet 配置证书轮换)

    1.概述 Kubelet 使用证书进行 Kubernetes API 的认证. 默认情况下,这些证书的签发期限为一年,所以不需要太频繁地进行更新. Kubernetes 包含特性 Kubelet 证书 ...

  2. 深入理解JavaScript中的try catch finally

    在日常开发中,我们经常使用try catch 来捕捉错误,来提升应用程序的健壮性,但是,大部分时候,只是惯性使用,很少静下来去深入理解一下try catch finally,所以本文将对try cat ...

  3. JavaScript – Iterator

    参考 阮一峰 – Iterator 和 for...of 循环 前言 es6 以后经常可以看到 for...of 的踪迹. 如果你细看会发现它挺神奇的. 不只是 Array 可以被 for...of, ...

  4. @vue/cli typescript插件使用指南

    步骤 使用 yarn add 安装 @vue/cli-service 对应版本的 @vue/cli-plugin-typescript 例如:"@vue/cli-service": ...

  5. IDEA 换了电脑,如何导入和导出配置?

    前言 我们在使用IDEA开发时,经常会设置各种各样的配置,时间一长,就会有很多个性化的东西.用起来也越来越顺手.   不过这里可能会有个问题,那就是哪一天我们要换个电脑了,或者想安装新版本的IDEA时 ...

  6. CSP提高组模拟1

    我的微軟輸入法莫名其妙變成繁體了,你們有什麽頭緒嗎 狀態 題目 20 Time Exceeded A 最短路 25 Time Exceeded B 方格取数 0 Time Exceeded C 数组 ...

  7. 常用的linux命令 docker常用命令

    mkdir 新建目录 rmdir 删除目录 rm只能删除文件,不能删除目录 cp test.txt Documents 进入容器的目录 docker exec -it <container_id ...

  8. Monaco Editor 实现一个日志查看器

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:文长 前言 在 Web IDE 中,控制台中展示日志是至关 ...

  9. KubeSphere 社区双周报 | OpenFunction v1.0.0 发布 | 2023.03.03-03.16

    KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...

  10. 使用idea搭建springBoot项目

    转载至:https://blog.csdn.net/baidu_39298625/article/details/98102453 整体步骤同上 分享其中遇到的坑 一.maven依赖 springBo ...