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

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

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

  • cv2.QRCodeDetector
  • 画像からQRコードを検出・読み取り
  • カメラの動画からQRコードを検出・読み取り

QRコードの作成については以下の記事を参照。

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

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

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

import cv2

print(cv2.__version__)
# 4.6.0

※QRコードは株式会社デンソーウェーブの登録商標です。

cv2.QRCodeDetector

QRコードの検出・読み取りにはcv2.QRCodeDetectorクラスを利用する。

バージョン4.3で複数のQRコードを一括で検出・デコードできるdetectAndDecodeMulti()が追加された。基本的にはこれを用いればよい。

検出のみを行うdetect()や、検出した座標を元にデコードするdecode()などもあるが、ここでは触れない。

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

例として以下の画像を用いる。

各QRコードに格納された文字列は左からQR Code One, QR Code Two, QR Code Three。一番右のQRコードは読み取りがしにくいように中央を白い四角でマスクしている。

img = cv2.imread('data/src/qrcode.png')

QR code sample

cv2.QRCodeDetectorのインスタンスを生成し、detectAndDecodeMulti()を実行。なお、バージョンや環境によっては結果が異なる可能性もあるので注意。

qcd = cv2.QRCodeDetector()

retval, decoded_info, points, straight_qrcode = qcd.detectAndDecodeMulti(img)

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

print(retval)
# True

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

print(decoded_info)
# ('QR Code Two', '', 'QR Code One')

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

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

print(points)
# [[[290.9108    106.20954  ]
#   [472.8162      0.8958926]
#   [578.5836    184.1002   ]
#   [396.0495    287.81277  ]]
# 
#  [[620.         40.       ]
#   [829.         40.       ]
#   [829.        249.       ]
#   [620.        249.       ]]
# 
#  [[ 40.         40.       ]
#   [249.         40.       ]
#   [249.        249.       ]
#   [ 40.        249.       ]]]

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

straight_qrcodenumpy.ndarrayを要素とするタプル。numpy.ndarray0255の二値でQRコードの各セルの白黒を表している。

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

print(type(straight_qrcode))
# <class 'tuple'>

print(type(straight_qrcode[0]))
# <class 'numpy.ndarray'>

print(straight_qrcode[0].shape)
# (21, 21)

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

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[0].astype(int),
                      cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)

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

Detect and decode QR code with OpenCV

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

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

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

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

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

import cv2

camera_id = 0
delay = 1
window_name = 'OpenCV QR Code'

qcd = cv2.QRCodeDetector()
cap = cv2.VideoCapture(camera_id)

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

    if ret:
        ret_qr, decoded_info, points, _ = qcd.detectAndDecodeMulti(frame)
        if ret_qr:
            for s, p in zip(decoded_info, points):
                if s:
                    print(s)
                    color = (0, 255, 0)
                else:
                    color = (0, 0, 255)
                frame = cv2.polylines(frame, [p.astype(int)], True, color, 8)
        cv2.imshow(window_name, frame)

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

cv2.destroyWindow(window_name)

QRコードを検出できてもデコードができない場合は赤の枠、デコードができた場合は緑の枠が表示されるようにしている。デコードした文字列も表示したい場合は、上述の画像(静止画)の例を参考にされたい。

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

関連カテゴリー

関連記事