简单的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         }

 

posted on 2020-09-16 20:10  杨志农  阅读(272)  评论(0)    收藏  举报

导航