- 什么是 RLE ?
- RLE 在激光雕刻应用
- 实现代码:
- 总结
什么是 RLE ?
RLE 是 Run-Length Encoding(游程长度编码)的缩写。这是一种数据压缩技术,它通过减少连续重复的数据来减小文件的大小。RLE 在图像处理、无损压缩和数据传输等领域中都有广泛应用。基本上,RLE 将连续相同的数据值(或称为“游程”)替换为一个值和一个计数值的组合。这样的编码在一些情况下非常有效,特别是当数据中存在大量重复的连续值时。
在图像处理和存储中,RLE 可以用于将图像数据编码为更紧凑的格式,从而节省存储空间并加快数据传输速度。
例如,考虑一个简单的黑白图像,其中大部分区域都是连续的白色像素。在没有压缩的情况下,每个像素都需要单独存储其值,这会占用大量空间。但是,如果使用 RLE,可以将连续的白色像素游程编码为一个值(表示白色)和一个计数值(表示连续的像素数量),从而实现数据压缩。
假设有一行像素数据:FFFFFFBBBBBFFFFFFFFF
. 在 RLE 编码下,这行像素可以表示为 6F5B10F
,其中 6F
表示连续的六个白色像素,5B
表示连续的五个黑色像素,10F
表示连续的十个白色像素。
通过这种方式,可以大大减小图像的存储空间,特别是对于包含大量相同值的图像。在传输或存储图像时,RLE 编码可以在保持图像质量的同时显著减少所需的存储空间或传输带宽。
RLE 在激光雕刻应用
在激光雕刻应用中,RLE(Run-Length Encoding)可以用于优化图像或矢量图形的数据传输和处理。激光雕刻通常需要将图像或图形转换为适合激光刻录机的指令,这些指令通常以一种称为 G-code 的格式表示。
RLE 可以在以下方面对激光雕刻应用进行优化:
- 数据压缩:原始图像或图形可能包含大量相同或类似的连续像素或路径。使用 RLE 可以将这些连续的像素或路径编码为游程,并用更简洁的方式表示,从而减小传输或存储的数据量。
- 路径优化:在将图像转换为激光刻录机的指令时,RLE 可以帮助优化路径。通过识别和合并相邻的线段或轮廓,可以减少激光头在工作区域内的移动次数,从而提高雕刻效率并减少制作时间。
- 减少机器负载:在处理大型图像或复杂图形时,RLE 可以减少激光刻录机的负载。通过减少传输到激光刻录机的指令数量,可以降低激光刻录机的计算和执行负荷,提高整体效率和性能。
实现代码:
CMakeLists.txt
cmake_minimum_required(VERSION 3.28)
project(rle)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/source-charset:utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/execution-charset:utf-8>")
add_executable(rle main.cpp)
target_precompile_headers(untitled1 PRIVATE <vector> <print>)
main.cpp
#include <vector>
#include <print>
struct RLE {
int pos; // 位置
int value; // 像素的值
int length; // 像素长度
};
// LeftToRight
std::vector<RLE> buildRLELTR(const std::vector<int> &input) {
std::vector<RLE> rle;
int count = 1;
for (int i = 0; i < input.size(); ++i) {
if (i + 1 < input.size() && input[i] == input[i + 1]) {
++count;
} else {
RLE rleElement;
rleElement.pos = i - count + 1;
rleElement.value = input[i];
rleElement.length = count;
rle.push_back(rleElement);
count = 1;
}
}
return rle;
}
// RightToLeft
std::vector<RLE> buildRLERTL(const std::vector<int> &input) {
std::vector<RLE> rle;
int count = 1;
for (int i = input.size() - 1; i >= 0; --i) {
if (i - 1 >= 0 && input[i] == input[i - 1]) {
++count;
} else {
RLE rleElement;
rleElement.pos = i + 1;
rleElement.value = input[i];
rleElement.length = count;
rle.push_back(rleElement);
count = 1;
}
}
return rle;
}
std::vector<RLE> buildRLE(const std::vector<int> &input, bool rightToLeft = false) {
std::vector<RLE> rle;
int count = 1;
int start = rightToLeft ? input.size() - 1 : 0;
int end = rightToLeft ? -1 : input.size();
int step = rightToLeft ? -1 : 1;
for (int i = start; i != end; i += step) {
if ((i + step >= 0 && i + step < input.size()) && input[i] == input[i + step]) {
++count;
} else {
RLE rleElement;
rleElement.pos = i - (rightToLeft ? count - 1 : count) * step + 1;
rleElement.value = input[i];
rleElement.length = count;
if (rightToLeft) {
rle.insert(rle.begin(), rleElement);
} else {
rle.push_back(rleElement);
}
count = 1;
}
}
return rle;
}
bool buildRLELTR(const std::vector<int> &input, int &i, RLE &rle) {
int count = 1;
for (; i < input.size(); ++i) {
if (i + 1 < input.size() && input[i] == input[i + 1]) {
++count;
} else {
rle.pos = i - count + 1;
rle.value = input[i];
rle.length = count;
++i;
return true;
}
}
return false;
}
bool buildRLERTL(const std::vector<int> &input, int &i, RLE &rle) {
int count = 1;
for (; i >= 0; --i) {
if (i - 1 >= 0 && input[i] == input[i - 1]) {
++count;
} else {
rle.pos = i;
rle.value = input[i];
rle.length = count;
i--;
return true;
}
}
return false;
}
int main() {
// clang-format off
// 假设以下二维数组是灰度图像预处理后的激光强度映射,通过构建 RLE 数据结构,最后根据 RLE 生成 GCode 文本,可以实现数据压缩效果。
using grayline = std::vector<int>;
std::vector<grayline> array = {
{925, 925, 925, 921, 917, 917, 898, 902, 906, 917},
{917, 917, 917, 898, 890, 902, 902, 914, 925, 921},
{914, 921, 925, 906, 898, 902, 902, 906, 910, 914},
{910, 906, 902, 898, 886, 875, 917, 921, 906, 914},
{914, 898, 906, 910, 898, 890, 894, 886, 882, 878},
{914, 898, 906, 910, 898, 890, 894, 886, 882, 878},
// 001, 002, 003, 004, 005, 006, 007, 008, 009, 010},
};
// clang-format on
int i;
RLE rle;
i = 0;
while (1) {
auto ret = buildRLELTR(array[0], i, rle);
if (ret) {
// toCode
// X{rle.pos+rle.length} S{rle.value}
std::println("# {:3} {:3} {:3}", rle.pos, rle.value, rle.length);
} else {
break;
}
}
std::println("");
i = array[1].size() - 1;
;
while (1) {
auto ret = buildRLERTL(array[1], i, rle);
if (ret) {
std::println("# {:3} {:3} {:3}", rle.pos, rle.value, rle.length);
} else {
break;
}
}
std::println("==========================");
{
std::vector<RLE> rle = buildRLE(array[0], false);
// left to right build
for (const RLE &element: rle) {
std::println("{:3} {:3} {:3}", element.pos, element.value, element.length);
}
}
std::println("");
{
std::vector<RLE> rle = buildRLE(array[1], true);
// implment right to left build
for (const RLE &element: rle) {
std::println("{:3} {:3} {:3}", element.pos, element.value, element.length);
}
}
return 0;
}
总结
综上所述,RLE 在激光雕刻应用中可以通过数据压缩、路径优化和减少机器负载等方式提高效率并降低成本。