識別快遞單號(1) - 圖像處理


前言: 

   最近一個項目要發快遞, 發完以后需要把單號錄入后台. 暫時想到兩方案:
  1. 手機拍照上傳服務器, 服務器識別. (優點 不用開發手機端; 缺點 費流量, 雖然手機畫質調最小一張照片也就100k)
  2. 做手機混合App, 手機端識別. (優點 省流量, 更便捷; 缺點 僅會一點Android, 蘋果完全沒玩過)

Anyway, 先把圖像識別做出來, 其他都好說. 因為各個快遞公司條碼編碼方式不同, 圖像識別也有兩種方案:
 1. 識別條碼. (優點 識別簡單; 缺點 需要學習多種編碼方式)
 2. 識別條碼下方數字單號. (優點 直接; 缺點 需要進行機器學習, 不過應該不難, 畢竟都是打印的數字)

大概流程是這樣的: a. 獲得照片(一般是快遞單條碼的特寫), b. 找到識別部分(條碼或單號), c. 識別.
ac暫且不說, 先做做b.

這個系列是我一邊做一邊寫的, 所以並不能保證寫的步驟, 代碼就一定沒問題沒Bug, 有些東西可能在以后的博文中會有所調整.

  轉載請聲明出處: http://www.cnblogs.com/zaiyuzhong/p/purify-photo.html

正文:

一. 圖像二值化
  我首先想到的就是這個, 因為條碼和單號都是黑色, 快遞單又是多層的, 下層的單號很容易就透上來了.
  1. 用RGB平均值將圖片灰度化; (與人眼無關不需要用加權平均, RGB最大值得出圖像偏亮)
  2. 因為拍照環境的光線問題, 使用的OTSU算法不能很有效的去除手機遮擋光源產生的陰影, 所以我沒有取1/2點作為閥值.
  測試幾張圖片后發現1/2.1~1/2.5之間效果較好, 於是取1/2.3, 這個需要再多一些圖片做測試, 但是我准備換個算法.
原圖 1/2灰度點閥值 1/3灰度點閥值
          (白色塊是后補的, 位置稍微不同別介意, 綠色邊框是CSS)

  測試了一些算法發現Yen算法效果最好(測試圖片有限, 沒有代表性), 如下圖:
Yen法效果
  具體算法見參考資料.

二. 去除多余圖像
  這一步我也不確定應該做什么, 首先想到的是做閉操作(將黑色像素周邊白色像素染黑, 然后再將白色像素周邊染白, 這樣能連通鄰近的黑色像素)將條碼連成一片, 再找最大的黑塊. 后來發現所有快遞單條碼下方都是填寫信息的表格, 而人工拍照時條碼都在圖片中央, 四周空白, 於是考慮先將表格去除.
  我的做法是先在水平方向上找到超過一定長度的線, 然后將該線第一個像素豎直方向有黑色點的...... 好復雜, 一會直接上代碼吧, 先看效果.
去除多余圖像
 1 private static void RemoveTable(Bitmap img)
 2 {
 3     var thrY = LongLineY(img);
 4     for (int i = 0; i < img.Height; i++)
 5     {
 6         var r = img.GetPixel(0, i).R;
 7         if (r == 0)
 8         {
 9             if (r > thrY)
10                 for (int x = 0; x < img.Width; x++)
11                     for (int y = 0; y < thrY; y++)
12                         img.SetPixel(x, y, Color.White);
13             else
14                 for (int x = 0; x < img.Width; x++)
15                     for (int y = img.Height - 1; y >= thrY; y--)
16                         img.SetPixel(x, y, Color.White);
17         }
18     }
19 }
20 
21 // 找到一條長線的Y坐標
22 private static int LongLineY(Bitmap img)
23 {
24     int thr = img.Width / 5;
25     for (int y = 0; y < img.Height; y++)
26     {
27         int black = 0, white = 0;
28         for (int x = 0; x < img.Width; x++)
29         {
30             var r = img.GetPixel(x, y).R;
31             if (r == 0) { black++; white = 0; }
32             else if (r == 255) { white++; black = 0; }
33             if (white > thr) break;
34             if (black > thr) return y;
35         }
36     }
37     return img.Height;
38 }
嗯~ 就是找到一條比較長的線(我這里定義的是超過寬度的五分之一), 看它里上邊近還是下邊近, 那邊近刪掉那邊.

三. 確定二維碼位置
  我想在做這步之前把多余的白色像素去掉這步可以在上面的過程中處理.

突然發現有個問題需要考慮一下, 請看下篇: 加載圖片到canvas

參考資料: 十三種基於直方圖的圖像全局二值化算法原理、實現、代碼及效果

本系列目錄: 1. 圖像處理

         2. 加載圖片到canvas

                3. 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM