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 built
にbarcode
が含まれていないと使えない。
例えばmacOSにおいて、HomebrewでOpenCVをインストールした場合はContribモジュールも含まれているはずだが、pip
でopencv-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')
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)
retval
はbool
。バーコードが検出されると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
points
はnumpy.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)
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
の文字列を取得できた時点でbreak
でwhile
ループを終了し、文字列を用いた処理に移行する形になることが多いだろう。
例えば書籍の場合、一段目のバーコードからISBNを取得し、さらにopenBDなどから各種情報を取得できる。