Python, OpenCVでバーコードを検出・読み取り

Posted: | Tags: Python, OpenCV, 画像処理

PythonとOpenCVでバーコードを検出し、格納された数値を読み取る方法について説明する。

  • cv2.barcodeはContribモジュール
  • Super Resolution Model
  • 画像からバーコードを検出・読み取り
  • カメラの動画からバーコードを検出・読み取り

バーコードではなくQRコードの検出・読み取りについては以下の記事を参照。

ZBar(pyzbar)を用いる方法もある。厳密には検証していないが、検出精度はZBarのほうが良さそう。

本記事のサンプルコードで使用しているOpenCVのバージョンは4.6.0

import cv2

print(cv2.__version__)
# 4.6.0

cv2.barcodeはContribモジュール

バーコードの検出・読み取りに用いるcv2.barcodeはContribモジュールに含まれている(バージョン4.6.0時点)。

cv2.getBuildInformation()の出力において、OpenCV modules:To be builtbarcodeが含まれていないと使えない。

例えばmacOSにおいて、HomebrewでOpenCVをインストールした場合はContribモジュールも含まれているはずだが、pipopencv-pythonをインストールした場合は含まれていない可能性がある。pip install opencv-contrib-pythonでインストールする必要がある。

Super Resolution Model

公式のチュートリアルではSuper Resolution Modelが紹介されている。

以下のリポジトリからsr.prototxt, sr.caffemodelをダウンロードして使う。

ダウンロードしたファイルのパスをcv2.barcode.BarcodeDetector()の引数に指定する。省略した場合はモデルを使わない。

bd = cv2.barcode.BarcodeDetector('/path/to/sr.prototxt', '/path/to/sr.caffemodel')

(何か間違えているのかもしれないが)手元の環境ではモデルの有無で精度の差は感じられなかった。以下のサンプルコードでは使用していない。

画像からQRコードを検出・読み取り

例として以下のバーコード画像を用いる。

img = cv2.imread('data/src/barcode.jpg')

Barcode sample

cv2.barcode.BarcodeDetectorのインスタンスを生成し、detectAndDecode()を実行。検出のみを行うdetect()や、検出した座標を元にデコードするdecode()などもあるが、ここでは触れない。

なお、バージョンや環境によっては結果が異なる可能性もあるので注意。

bd = cv2.barcode.BarcodeDetector()
# bd = cv2.barcode.BarcodeDetector('path/to/sr.prototxt', 'path/to/sr.caffemodel')

retval, decoded_info, decoded_type, points = bd.detectAndDecode(img)

retvalbool。バーコードが検出されるとTrue、1つも検出されないとFalse

print(retval)
# True

decoded_infoはバーコードに格納された文字列を要素とするタプル。検出はできてもデコードできない場合は空文字列''となる。

print(decoded_info)
# ('1923055034006', '9784873117980')

decoded_typeはバーコードのタイプを表す数値を要素とするタプル。

日本で使われるJANコードはEANコードをベースに規格化されたものでEAN_13として認識される。

print(decoded_type)
# (2, 2)

print(cv2.barcode.EAN_13)
# 2

pointsnumpy.ndarray。検出できたQRコードの四隅の座標を表す。

print(type(points))
# <class 'numpy.ndarray'>

print(points)
# [[[142.38849 221.83641]
#   [156.36218 172.35411]
#   [356.90564 228.98714]
#   [342.93195 278.46942]]
# 
#  [[180.30583 128.89304]
#   [191.59013  88.83808]
#   [371.00458 139.38284]
#   [359.72028 179.4378 ]]]

print(points.shape)
# (2, 4, 2)

検出したバーコードを枠で囲み、デコードした文字列を重畳して表示する。

img = cv2.polylines(img, points.astype(int), True, (0, 255, 0), 3)

for s, p in zip(decoded_info, points):
    img = cv2.putText(img, s, p[1].astype(int),
                      cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1, cv2.LINE_AA)

cv2.imwrite('data/dst/barcode_opencv.jpg', img)

Detect and decode barcode with OpenCV

OpenCVでの図形や文字の描画についての詳細は以下の記事を参照。

カメラの動画からバーコードを検出・読み取り

カメラのリアルタイム動画からバーコードを検出し読み取るサンプルコードを示す。

OpenCVにおける動画の扱いについては以下の記事を参照。

キーボードのqを押すと終了する。

import cv2

camera_id = 0
delay = 1
window_name = 'OpenCV Barcode'

bd = cv2.barcode.BarcodeDetector()
cap = cv2.VideoCapture(camera_id)

while True:
    ret, frame = cap.read()

    if ret:
        ret_bc, decoded_info, _, points = bd.detectAndDecode(frame)
        if ret_bc:
            frame = cv2.polylines(frame, points.astype(int), True, (0, 255, 0), 3)
            for s, p in zip(decoded_info, points):
                if s:
                    print(s)
                    frame = cv2.putText(frame, s, p[1].astype(int),
                                        cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 2, cv2.LINE_AA)
        cv2.imshow(window_name, frame)

    if cv2.waitKey(delay) & 0xFF == ord('q'):
        break

cv2.destroyWindow(window_name)

なお、実際のアプリケーションでは、decoded_infoの文字列を取得できた時点でbreakwhileループを終了し、文字列を用いた処理に移行する形になることが多いだろう。

例えば書籍の場合、一段目のバーコードからISBNを取得し、さらにopenBDなどから各種情報を取得できる。

関連カテゴリー

関連記事