MotoJapan's Tech-Memo

技術めも

【python】zbarでバーコードを読み取る(画像→数列) 【お家IT#17】

本件の実装の一部  
motojapan.hateblo.jp

前回の続き  
motojapan.hateblo.jp

目次

前回まででフロントエンド・バックエンドの整備が終わった。
以降は、画像処理部分を進める。

f:id:motojapan:20171026004212p:plain

今回は食品名(商品名)を取得するために、バーコード情報の読み取りをしたい。

バーコードとは

ふと、そもそもバーコードが何かをちゃんとわかっていなかったので調べる。

「黒いバーと空白の組み合わせで、数字、文字、記号を読み込めるデータ形式であり、一般的に縞模様を光学系認識機器で読み取る。
一般に普及している縞模様の一次元バーコードや、QRコードに体表される二次元バーコードをよく目にしている。
今回は食品名を取得したいので、今回は一次元バーコードを中心に考える。

バーコードの詳細は次が参考になる。
バーコードとは?|基礎知識|自動認識|デンソーウェーブ

バーコード種類は下記。

  • 統一商品コード(ユニークコード)
  • インストアコード(任意コード)

特にユニークコードで、日本で使われているのはJANコード

JANコード桁数は下記。

  • 標準タイプ(13桁)
    • 先頭7桁 : JANメーカーコード
    • 先頭9桁 : 国番号2桁 + JANメーカーコード7桁
  • 短縮タイプ(8桁)

JANコード構成要素は下記。

また、特に気になるのは、両サイドにあるマージンと呼ばれる空白は、十分な領域が必要である。<ナローバー(最も小さい黒縞)の10倍>

バーコードを読み込む方法は2つ思いつく。

  • バーコードリーダーといった専用機器で赤外線反射から読み取る
  • カメラなどの汎用機器で画像から読み取る(今回はこっち)

まぁこんな感じのバーコードリーダーでの読み取りでもよい。

ただ、それはあまりにつまらないし、「自宅で手軽に使う」というポリシーから外れるのでので今回は画像処理ベースで調べてみた。(スマホ一台で済ませたいし。)

結果的にpython上で動くスタンドアローンな画像処理ライブラリ、「zbar」を使用してみる。

環境

今まで通りRaspberry piを使用しているので、下記の通り。

zbarインストール

かなり簡単

//インストール
$ sudo apt-get install libzbar-dev  
$ sudo apt-get install python-zbar
...

//確認
$ python
import zbar
//error無しでOK

インストール時のトラブルシューティング

「error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1」がインストール時に出る場合

下記インストール時にこんなエラーが出ることがある。

$ pip install zbar

対策 : module不足なので追加

$ sudo apt-get install python-dev

「segmentation fault」が実行時に出る場合

確認時(実行時)にこんなエラーが出ることがある。

$ python
import zbar
//segmentation fault

対策 : pipで入れたzbarがconflictしているようなのでpipはアンインストール、apt-getでインストール

$ pip uninstall zbar 
$ sudo apt-get install python-zbar

実装例

//img : cv2 image(numpy)
def convert_image_to_code(img):
    print('=========== proc start =============')
    start_time = time.time()
    #init module
    scanner = zbar.ImageScanner()
    scanner.parse_config('enable') 

    #image to gray
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    h = gray.shape[0]
    w = gray.shape[1]
    zimage = zbar.Image(w, h, 'Y800', gray.tostring())

    #scan
    scanner.scan(zimage)

    result = []

    for symbol in zimage:
        print('Type: {0} |  Data: {1}'.format(symbol.type, symbol.data))
        result.append({'type':symbol.type, 'data':symbol.data})

    print 'proc_time {0:f} [ms] '.format((time.time() - start_time) * 1000)
    print('=========== proc end ===========')

    return result

結果

入力画像は★に注意して、実際にいくつか試してみるといい感じの結果となった。



平面紙印刷

レトレクパック印刷

曲面印刷

画像全体







撮影領域







結果

4970231640022

4902204411599

4902106232209

400 x 60 の画像に対して、処理速度は20-40[ms]程度。
曲面ぐにゃぐにゃ面でも割りとちゃんと認識できる。

以上。
次回はこのバーコードの数列から、食品名を取得する。