簡單的LED影象壓縮實現
阿新 • • 發佈:2020-09-16
把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 }