Python, OpenCVでQRコードを検出・読み取り
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')
cv2.QRCodeDetector
のインスタンスを生成し、detectAndDecodeMulti()
を実行。なお、バージョンや環境によっては結果が異なる可能性もあるので注意。
qcd = cv2.QRCodeDetector()
retval, decoded_info, points, straight_qrcode = qcd.detectAndDecodeMulti(img)
retval
はbool
。QRコードが検出されるとTrue
、1つも検出されないとFalse
。
print(retval)
# True
decoded_info
はQRコードに格納された文字列を要素とするタプル。検出はできてもデコードできない場合は空文字列''
となる。
print(decoded_info)
# ('QR Code Two', '', 'QR Code One')
points
はnumpy.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_qrcode
はnumpy.ndarray
を要素とするタプル。numpy.ndarray
は0
と255
の二値で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)
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
の文字列を取得できた時点でbreak
でwhile
ループを終了し、文字列を用いた処理に移行する形になることが多いだろう。