简单的LED图像压缩实现
把LED屏幕数据传到下位机传屏中数据有点大,串口速度有点慢,整个过程大约需要200ms, 故想到了图像压缩提高传数效率, 虽然gzip压缩率基本能到1/3, 但单片机好像很难使用这些库, 故网上查了一下无损压缩的原理,自已实现了一个最简单的. 基本能达到压缩1/2的样子. 压缩和解压速度也很快!
原理:
字符串行程编码
这里压缩一段字符串:RRRRRGGGBBBBBRRRRGB
压缩的结果为:5R3G5B4R1G1B
这种方法叫做行程编码run-ength encoding(RLE),应用于像BMP,TIFF格式的图像文件中。
1 //调用程序示例
2 private void btnTestZip_Click(object sender, EventArgs e)
3 {
4 //获取LED图像数据.
5 // LED宽度<=255, 每行按上面的原理 故长度信息可以放在1个字节中
6 // LED图像每8行,换成一个点(即一个字节)
7 var srcData = GetData(); //获取LED图像数据.
8 var zipData = ZipLedData(srcData);
9 var unZipData = UnZipLedData(zipData);
10 Debug.Assert(srcData.Length == unZipData.Length);
11 for (var i=0; i<srcData.Length; i++)
12 {
13 Debug.Assert(srcData[i] == unZipData[i]);
14 }
15 }
1 /*=================压缩===============*/
2 private byte[] ZipLedData(byte[] srcData)
3 {
4 if (srcData == null || srcData.Length < 1) throw new Exception("参数异常");
5 Console.WriteLine(srcData.Length);
6 Stopwatch stopwatch = new Stopwatch();
7 stopwatch.Start();
8
9 using var ms = new System.IO.MemoryStream();
10 using var bw = new System.IO.BinaryWriter(ms);
11
12 var width = pic.Width; // LED宽度<=255, 每行扫描,差异 故长度信息可以放在1个字节中
13 var rows = pic.Height / 8; //LED图像每8行,换成一个点(即一个字节)
14 for (var row = 0; row < rows; row++)
15 {
16 var idx = row * width; //行起始索引
17 var v = srcData[idx]; //行第一个元素
18 bw.Write(v); //写入第0个像素值
19 byte cnt = 1;
20 for (var col = 1; col < width; col++)
21 {
22 idx++;
23 if (srcData[idx] == v)
24 {
25 //数据未发生变化, 长度字节增加
26 cnt++;
27 }
28 else
29 {
30 //数据发生变化
31 bw.Write(cnt); //写入长度字节
32 v = srcData[idx]; //记录新值
33 bw.Write(v); //写入新值
34 cnt = 1; //重置统计长度字节=1
35 }
36 }
37 bw.Write(cnt); //写每行最后一个长度信息
38 }
39 bw.Flush();
40 bw.Close();
41 var retData = ms.ToArray();
42 stopwatch.Stop();
43 Console.WriteLine($"总时长: {stopwatch.Elapsed.TotalMilliseconds}");
44 Console.WriteLine(retData.Length);
45 return retData;
46 }
1 /*=================解压===============*/
2 private byte[] UnZipLedData(byte[] zipData)
3 {
4 Stopwatch stopwatch = new Stopwatch();
5 stopwatch.Start();
6 using var ms = new System.IO.MemoryStream();
7 using var bw = new BinaryWriter(ms);
8
9 var i = 0;
10 var zipDataLen = zipData.Length;
11 while (i< zipDataLen)
12 {
13 var v = zipData[i++];
14 var len = zipData[i++];
15 bw.Write(v);
16 for(var j=len-1; j>0; j--)
17 {
18 bw.Write(v);
19 }
20 }
21 bw.Flush();
22 bw.Close();
23 var ret = ms.ToArray();
24 stopwatch.Stop();
25 Console.WriteLine($"总时长: {stopwatch.Elapsed.TotalMilliseconds}");
26 return ret;
27 }
浙公网安备 33010602011771号