首页 > 其他分享 >JPEG格式研究——(3)霍夫曼解码

JPEG格式研究——(3)霍夫曼解码

时间:2024-10-09 21:50:57浏览次数:7  
标签:编码 code 解码 JPEG let 霍夫曼

因为霍夫曼编码以bit为单位,长度又不确定,读取时无法区分,JPEG采用了范式霍夫曼编码

读取并生成霍夫曼表

JPEG中DC系数和AC系数是分别进行编码将霍夫曼表保存在DQT中。

直接上代码解释可能更直接:

let mut code = 0usize;
let mut length = [0; 16];
for i in 0..16 {
    length[i] = data[offset + i + 1];
    for j in 0..length[i] as usize {
        if code >= (1 << (i + 2)) {
            return Err(HuffmanErrorType::InvalidCode(data[off + j], code));
        }
        map.insert(Binary::new(code, i + 1), data[off + j]);
        code += 1;
    }
    off += length[i] as usize;
    code <<= 1;
}

首先定义了一个变量code,用于计算对应的编码,根据范式霍夫曼编码的计算方法从0开始。因为霍夫曼编码的长度最大为16bit,所以用了长16字节的数组,保存了不同长度的编码个数

let mut code = 0usize;
let mut length = [0; 16];

然后依次读取不同长度的编码个数

for i in 0..16 {
    length[i] = data[offset + i + 1];
    ...
}

然后根据编码长度进行循环计算,相同长度的编码每计算出一个就将code+1。这里为了后面解码方便直接用map保存键值对。

Binary是一个保存了值和二进制长度的结构体,用于区分不同长度的二进制串

for j in 0..length[i] as usize {
    // 错误处理部分省略
    map.insert(Binary::new(code, i + 1), data[off + j]);
    code += 1;
}

然后在编码长度+1时将code左移一位

code <<= 1;

霍夫曼解码

选择霍夫曼表

霍夫曼表数量=颜色分量数*2,比如RGB和YCbCr都是3个颜色分量,而灰度则是1个颜色分量,颜色分量数以及每一个颜色分量的DC、AC系数解码所需的霍夫曼表编号都保存在SOF中。

选择出需要的DC、AC系数的霍夫曼表后,就可以开始解码了

解码

JPEG中将图像按8x8大小进行分块,所以都是以64个数为一组进行解码的,其中第一个数是DC系数,其余的63个则是AC系数

DC系数

DC系数需要首先读取一个经过霍夫曼编码的数据,这个数表示需要读取的bit长度。再以这一长度读取一个二进制串(未经过霍夫曼编码),如果长度为0则表示这里的数据就是0。

这一个二进制串的最高位是符号位,为1表示正数,为0表示负数,如果只有1位那就是只有符号位。然后要对符号位之外表示的数按位取反,按符号位得出正负得到DPCM编码

DPCM编码实际上也很简单,就是加上上一个DC系数就好了(如果是第一个DC系数则不用加或者加0)

代码如下:

let codeval = dc.huff.decode(bs)?;
let len = codeval as usize;
if len == 0 {
    code[0] = last_dc;
} else if len == 1 {
    code[0] = last_dc + bs.read(len)? as isize * 2 - 1; // 0 -> -1, 1 -> 1
} else {
    let sign = bs.read(1)?;
    let num = sign << (len - 1) | bs.read(len - 1)?;
    let result;
    if sign == 0 {
        result = -(((!num) & ((1 << len) - 1)) as isize); // Rust中按位取反是!有点不适应
    } else {
        result = num as isize;
    }
    code[0] = result + last_dc;
}

AC系数

先用霍夫曼解码出一个数,这个数的高4位表示0的个数,而低4位后面的数据的bit长度。其中有两种特殊情况:全为0则是EOB(End Of Block),直接结束AC系数解码,剩余的部分用0填充;高4位为1,低4为0则表示有连续16个0.

后面读取出的数据和DC系数解码的方式一样,先是1位符号位,后面跟着剩余位的数据。

代码如下:

let mut i = 1;
while i < 64 {
    let codeval = ac.huff.decode(bs)?;
    let zero = codeval >> 4;
    let len = (codeval & 0x0f) as usize;

    if len == 0 {
        if codeval == 0xf0 { // 连续16个0
            i += 16;
            continue;
        } else { // End Of Block,直接结束
            break;
        }
    } else if len == 1 {
        i += zero as usize;
        code[i] = bs.read(len)? as isize * 2 - 1; // 0 -> -1, 1 -> 1
    } else {
        let sign = bs.read(1)?;
        let num = sign << (len - 1) | bs.read(len - 1)?;
        let result;
        if sign == 0 {
            result = -(((!num) & ((1 << len) - 1)) as isize);
        } else {
            result = num as isize;
        }
        i += zero as usize;
        code[i] = result;
    }
    i += 1;
}

参考资料

博客园博客: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)

标签:编码,code,解码,JPEG,let,霍夫曼
From: https://www.cnblogs.com/Ryan1202/p/18455237

相关文章

  • 动态规划一>解码方法
    1.题目: .-力扣(LeetCode)  2.解析:版本一:图解:注意:前导0不能解码:06,或者两个数字字符:其中一个解码失败,整个也解码失败 /**1.创建dp表2.初始化3.填表4.返回*/publicintnumDecodings(Stringss){intn=ss.length();......
  • HM变化量化中的Scaling 操作(解码器)
    (1)xIntraRecBlk调用invTransformNxN处理TU块if(pcCU->getCbf(uiAbsPartIdx,compID,rTu.GetTransformDepthRel())!=0){m_pcTrQuant->invTransformNxN(rTu,compID,piResi,uiStride,pcCoeff,cQPDEBUG_STRING_PASS_INTO(psDebug));}(2)invTransform......
  • 霍夫曼树及其与B树和决策树的异同
    霍夫曼树是一种用于数据压缩的二叉树结构,通常应用于霍夫曼编码算法中。它的主要作用是通过对符号进行高效编码,减少数据的存储空间。霍夫曼树在压缩领域扮演着重要角色,与B树、决策树等数据结构都有一些相似之处,但又在应用场景和实现细节上有所区别。本文将探讨霍夫曼树的基本原......
  • H.264编解码 - I/P/B帧详解
    一、概述在H.264编解码中,I/P/B帧是一种常见的帧类型。以下是它们的解释:I帧(关键帧):也称为关键帧,它是视频序列中的第一个帧或每个关键时刻的第一个帧。I帧是完整的、自包含的图像帧,不依赖于其他帧进行解码。它存储了关键时刻的完整图像信息。P帧(预测帧):P帧是依赖于之前的关......
  • RTE 大会报名丨智能编解码和 AI 生成视频 ,RTE2024 技术专场第五弹!
       AI视频的爆炸增长,给新一代编解码技术提出了什么新挑战? 语音AI实现human-like的最后一步是什么? 当大模型进化到实时多模态,又将诞生什么样的新场景和玩法? 所有AIInfra都在探寻规格和性能的最佳平衡,如何构建高可用的云边端协同架构? AI加持下,空间计算......
  • yy语音找不到qjpeg4.dll怎么办?YY语音qjpeg4.dll修复大全:多种方法总有一款适合你
    当YY语音找不到qjpeg4.dll文件时,这通常意味着系统或YY语音的安装目录中缺少了必要的动态链接库文件。以下是一些修复方法,你可以根据自己的情况选择适合的一种或多种方法尝试解决:1.重新安装YY语音步骤:卸载当前版本的YY语音。清除可能残留的旧文件或注册表项(可选步骤,如果卸......
  • 清华:LLM解码策略实现双工对话
    ......
  • 解码数据飞轮:业务增长的秘密引擎
    解码数据飞轮:业务增长的秘密引擎在数字化时代,数据不仅是信息的记录,更是企业持续成长的生命线。从数据仓库、数据湖到数据中台,再到传送动力的“数据飞轮”,技术革新与商业模式创新始终紧密相连。今天咱们一起看看,怎么通过实践中的优秀案例,讨论数据飞轮在全链路营销和智能推荐中的应......
  • 探索EasyCVR视频融合平台:在视频编解码与转码领域的灵活性优势
    随着视频监控技术的飞速发展,各类应用场景对视频数据的处理需求日益复杂多样。从公共安全到智慧城市,再到工业监控,高效、灵活的视频处理能力成为衡量视频融合平台性能的重要标准。在众多解决方案中,EasyCVR视频融合平台凭借其在视频编解码、转码等能力上的强大灵活性,脱颖而出,成为行业......
  • JPEG的的编解码
    JPEG的的编解码过程JPEG采用YCrCb的颜色模式,通常叫着YUV,其中Y代表亮度,Cr,cb代表色度和饱和度。而我们通常熟悉的计算机系统采用RGB颜色模式1.采样-分块-量化--数据编码分块数据采样完成后就需要进行下一步操作,进行空间域向频率域转换DCT变换JPEG分别针对Y亮度、UV色度......