You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于FFT2替代DCT2的Matlab JPEG压缩:二进制导出难题

Matlab中FFT2替代DCT2实现JPEG压缩的二进制文件写入解决方案

问题背景

我正尝试在Matlab中用FFT2替代DCT2实现JPEG压缩,并导出二进制文件供解码使用,目前在二进制文件转换环节遇到较大困难。

已实现的压缩/解码流程

压缩步骤

  1. 将RGB图像转换为Y、Cb、Cr三通道
  2. 对每个通道执行以下操作:
    • 若为Cb或Cr通道,进行下采样
    • 将通道分割为8×8不重叠块
    • 对每个块执行:
      • 应用2D FFT,输出8×8频率表
      • 量化:与量化表逐元素相除后取整,Y通道与Cb、Cr通道使用不同量化表
      • 之字形(ZigZag)遍历系数,提升游程编码效率
      • 游程编码(Run Length Encoding),输出包含计数矩阵与符号矩阵的元胞数组
      • 霍夫曼(Huffman)编码,分别编码计数矩阵与符号矩阵
  3. 生成自定义二进制文件格式并导出

解码步骤

  • 读取二进制文件
  • Huffman解码
  • 逆游程编码
  • 逆ZigZag遍历
  • 乘以量化表
  • 逆2D FFT
  • 重构8×8块

二进制文件需求

需包含:Y、Cb/Cr量化表各一张,Huffman表/字典,实际图像数据。Huffman表通过扫描所有块生成字典后编码所有块。

核心难题

作为Matlab新手,不熟悉二进制文件写入操作。使用Matlab内置Huffman函数时,输出为元胞数组矩阵:第一列为符号,第二列为二进制码(以整数数组形式存储)。不知道如何将这些二进制码直接以二进制值写入文件,而非被当作十进制处理。


解决方案:二进制码的序列化与写入

Matlab中要将整数数组形式的二进制码转为实际的二进制位写入文件,需要先将零散的二进制位拼接成完整的字节(8位一组),再写入文件。以下是具体实现步骤:

1. 收集所有Huffman编码的二进制位

假设你的Huffman编码结果存储在huffman_codes元胞数组中,每个元素是一个整数数组(比如[1,0,1,1]表示二进制1011)。首先把所有二进制位拼接成一个大的逻辑数组:

% 收集所有二进制位
all_bits = [];
for i = 1:size(huffman_codes, 1)
    all_bits = [all_bits, huffman_codes{i, 2}];
end

2. 补位对齐到8位字节

因为文件是以字节为单位写入的,若总位数不是8的倍数,需要补0到最近的8的倍数:

bit_count = length(all_bits);
pad_bits = mod(8 - mod(bit_count, 8), 8);
if pad_bits > 0
    all_bits = [all_bits, zeros(1, pad_bits)];
end

3. 将二进制位转换为字节数组

把每8位一组转为十进制整数(0-255),这就是要写入的字节数据:

% 按8位分组
byte_groups = reshape(all_bits, 8, [])';
% 转换为十进制字节(高位在前)
byte_array = bi2de(byte_groups, 'left-msb');

4. 写入二进制文件

使用fwrite函数,指定'uint8'格式确保按字节写入,同时按约定顺序写入量化表、Huffman字典、补位信息和图像数据:

% 打开二进制文件(写入模式)
fid = fopen('compressed_image.bin', 'wb');
if fid == -1
    error('无法打开文件进行写入');
end

% 写入Y通道量化表(8x8矩阵,假设元素为0-255整数)
fwrite(fid, y_quant_table, 'uint8');
% 写入Cb/Cr通道量化表
fwrite(fid, cbcr_quant_table, 'uint8');

% 写入Huffman字典:先写符号数量,再逐个写入符号、码长、码
symbol_count = size(huffman_dict, 1);
fwrite(fid, symbol_count, 'uint16'); % 用uint16存储符号数量,支持最多65535个符号
for i = 1:symbol_count
    fwrite(fid, huffman_dict{i, 1}, 'int16'); % 符号可能为负数,用int16存储
    code_length = length(huffman_dict{i, 2});
    fwrite(fid, code_length, 'uint8'); % 存储二进制码的长度
    fwrite(fid, huffman_dict{i, 2}, 'uint8'); % 存储二进制码的每一位
end

% 写入补位数量(解码时需用此去除多余的补位0)
fwrite(fid, pad_bits, 'uint8');

% 写入图像数据字节数组
fwrite(fid, byte_array, 'uint8');

% 关闭文件
fclose(fid);

5. 解码时的对应处理

读取文件时需严格按照写入顺序还原数据:

fid = fopen('compressed_image.bin', 'rb');
if fid == -1
    error('无法打开文件进行读取');
end

% 读取量化表
y_quant_table = fread(fid, [8,8], 'uint8');
cbcr_quant_table = fread(fid, [8,8], 'uint8');

% 读取Huffman字典
symbol_count = fread(fid, 1, 'uint16');
huffman_dict = cell(symbol_count, 2);
for i = 1:symbol_count
    huffman_dict{i, 1} = fread(fid, 1, 'int16');
    code_length = fread(fid, 1, 'uint8');
    huffman_dict{i, 2} = fread(fid, code_length, 'uint8');
end

% 读取补位数量
pad_bits = fread(fid, 1, 'uint8');

% 读取图像字节数组
byte_array = fread(fid, inf, 'uint8');
fclose(fid);

% 将字节数组转回二进制位
byte_groups = de2bi(byte_array, 8, 'left-msb');
all_bits = byte_groups(:)';
% 去除补位的0
if pad_bits > 0
    all_bits = all_bits(1:end-pad_bits);
end

% 后续执行Huffman解码、逆游程编码等操作

注意事项

  • 若量化表元素超出0-255范围,需调整量化表或使用uint16等更大的存储格式。
  • 符号若为负数,需选择合适的整数类型存储(如int16),避免溢出。
  • Huffman字典的序列化方式可根据需求调整,只要保证解码时能正确还原即可。

内容的提问来源于stack exchange,提问作者Linn Htet Aung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 04:37:47