2种嵌入式的简单压缩算法
这两个解码函数都适合嵌入式系统,内存占用小,计算效率高,使用时要明确自己的数据是否适合这样的压缩算法,否则可能会让数据得不到压缩,反而会是数据量变大。
·
在嵌入式系统中,由于内存和计算资源有限,选择压缩算法时需要考虑以下因素:
- 内存占用:算法需要尽量少的 RAM 和 ROM。
- 计算效率:算法需要快速执行,适合嵌入式处理器。
- 压缩率:在资源限制下尽可能提高压缩率。
1. Run-Length Encoding (RLE)
- 特点:简单高效,适合数据中有大量重复值的场景。
- 优点:实现简单,占用极少的内存。
- 缺点:对随机数据或无重复数据的压缩率较低。
压缩代码示例:
size_t rle_compress(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) {
size_t input_index = 0, output_index = 0;
while (input_index < input_size) {
uint8_t current = input[input_index];
size_t run_length = 1;
// 计算连续相同字节的长度
while (input_index + run_length < input_size && input[input_index + run_length] == current && run_length < 255) {
run_length++;
}
// 写入压缩数据 (字节值 + 运行长度)
if (output_index + 2 > output_size) {
return 0; // 输出缓冲区不足
}
output[output_index++] = current;
output[output_index++] = run_length;
input_index += run_length;
}
return output_index; // 返回压缩后的数据大小
}
解压缩代码示例:
size_t rle_decompress(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) {
size_t input_index = 0, output_index = 0;
while (input_index < input_size) {
if (input_index + 1 >= input_size) {
// 输入数据格式错误(值和长度必须成对出现)
return 0;
}
uint8_t value = input[input_index++];
uint8_t run_length = input[input_index++];
// 检查输出缓冲区是否足够
if (output_index + run_length > output_size) {
return 0; // 输出缓冲区不足
}
// 填充解压后的数据
memset(&output[output_index], value, run_length);
output_index += run_length;
}
return output_index; // 返回解压后的数据大小
}
2. Lightweight Entropy Encoding (如 Delta Encoding)
- 特点:适合传感器数据等连续变化较小的场景。
- 优点:实现简单,压缩率高。
- 缺点:仅适用于特定类型的数据。
压缩代码示例:
size_t delta_compress(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) {
if (input_size == 0) return 0;
size_t output_index = 0;
uint8_t prev = input[0];
// 写入第一个字节
if (output_index + 1 > output_size) return 0;
output[output_index++] = prev;
for (size_t i = 1; i < input_size; i++) {
int8_t delta = input[i] - prev;
prev = input[i];
// 写入差值
if (output_index + 1 > output_size) return 0;
output[output_index++] = (uint8_t)delta;
}
return output_index; // 返回压缩后的数据大小
}
解压缩代码示例:
size_t delta_decompress(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) {
if (input_size == 0 || output_size == 0) {
return 0; // 输入或输出缓冲区为空
}
size_t output_index = 0;
// 第一个字节直接复制
output[output_index++] = input[0];
for (size_t i = 1; i < input_size; i++) {
if (output_index >= output_size) {
return 0; // 输出缓冲区不足
}
// 当前值 = 前一个值 + 差值
output[output_index] = output[output_index - 1] + (int8_t)input[i];
output_index++;
}
return output_index; // 返回解压后的数据大小
}
3.两种解码示例
3.1 RLE 解码
uint8_t compressed_rle[] = {0xAA, 5, 0xBB, 3}; // 压缩数据:0xAA 重复 5 次,0xBB 重复 3 次
uint8_t decompressed_rle[10];
size_t decompressed_size_rle = rle_decompress(compressed_rle, sizeof(compressed_rle), decompressed_rle, sizeof(decompressed_rle));
// 解压后:decompressed_rle = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB}
3.2 Delta 解码
uint8_t compressed_delta[] = {0x10, 2, -1, 3}; // 压缩数据:第一个值为 0x10,后续为差值
uint8_t decompressed_delta[10];
size_t decompressed_size_delta = delta_decompress(compressed_delta, sizeof(compressed_delta), decompressed_delta, sizeof(decompressed_delta));
// 解压后:decompressed_delta = {0x10, 0x12, 0x11, 0x14}
4.注意事项
-
RLE 解码:
- 输入数据必须是
(值, 长度)成对出现。 - 输出缓冲区必须足够大以容纳解压后的数据。
- 输入数据必须是
-
Delta 解码:
- 输入的第一个字节是原始数据的起始值。
- 后续字节是差值,可能为负数(需要用
int8_t处理)。
这两个解码函数都适合嵌入式系统,内存占用小,计算效率高,使用时要明确自己的数据是否适合这样的压缩算法,否则可能会让数据得不到压缩,反而会是数据量变大。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐

所有评论(0)