➊:はじめに
Pythonで「QRコード作成、読み取り」が、簡単に実現できないかなと思って調べました。
・やりたいこと
やりたいことは、以下の3つです。
- PNGのQRコード画像作成
- 画像からのQRコード読み取り
- webカメラからのQRコード読み取り
・ソリューションまとめ
やりたいことに対する解決策を、以下にまとめます。
やりたいこと | 使用するモジュール | 備考 |
---|---|---|
QRコード画像作成 | PyQRCode | PNG化する場合はpypngも必要 |
QRコード読み取り1 (CV2) | opencv-python | Ver4.3以上で複数読込み可能 |
QRコード読み取り2 (pyzbar) | pyzbar | Macはzbar, Linuxはlibzbar0も必要 |
※本ページの開発環境:win10、Python 3.8.5 | ||
ということで、以下、実施していきます。 |
➋:QRコード作成
QRコードの作成は、QRコードジェネレーターであるpyqrcodeモジュールを使用します。QRコードは、SVG、PNG、およびプレーンテキストとして保存可能なようです。PNGで保存する場合は、別途、pypngモジュールを使用します。
・インストール
以下のコマンドにより、PyQRCodeモジュールをインストールします。また、今回はQRコードをPNG画像として保存するため、pypngモジュールもインストールします。
pip install PyQRCode
pip install pypng
・プログラム
import pyqrcode
FILE_PNG_A = 'qrcode_A.png'
FILE_PNG_B = 'qrcode_B.png'
# QRコード作成
code = pyqrcode.create('https://qiita.com/PoodleMaster', error='L', version=3, mode='binary')
code.png(FILE_PNG_A, scale=5, module_color=[0, 0, 0, 128], background=[255, 255, 255])
# QRコード作成
code = pyqrcode.create('https://github.com/PoodleMaster', error='L', version=3, mode='binary')
code.png(FILE_PNG_B, scale=5, module_color=[0, 0, 0, 128], background=[255, 255, 255])
・実行結果
File | Image |
---|---|
qrcode_A.png | |
qrcode_B.png |
➌:画像連結
こちらの作業は必須ではないですが、1枚の画像に複数QRコードがある状況を作っておきます。次章の「QRコード読込み」の際に、1枚の画像から複数のQRコードを読み込めることを確かめます。
・インストール
OpenCVモジュールを使用して画像を連結します。
pip install opencv-python
・プログラム
import cv2
FILE_PNG_A = 'qrcode_A.png'
FILE_PNG_B = 'qrcode_B.png'
FILE_PNG_AB = 'qrcode_AB.png'
im1 = cv2.imread(FILE_PNG_A)
im2 = cv2.imread(FILE_PNG_B)
im_h = cv2.hconcat([im1, im2])
cv2.imwrite(FILE_PNG_AB, im_h)
cv2.imshow('image', im_h)
cv2.waitKey(0)
・実施結果
File | Image |
---|---|
qrcode_AB.png |
➍:QRコード読込み
QRコードの読込みは、OpenCVモジュール、またはpyzbarモジュールのどちらかを使用します。
➍-1:「OpenCV」によるQRコード読込み
・インストール
OpenCVバージョン4.3からdetectAndDecodeMulti
メソッドがコール可能となり、1枚の画像から複数のQRコードを読み取ることができるようになりました。OpenCVは、バージョン4.3以上をインストールしてください。
pip install opencv-python
・プログラム
import cv2
import numpy as np
# -----------------------------------------------------------
# initial
# -----------------------------------------------------------
font = cv2.FONT_HERSHEY_SIMPLEX
FILE_PNG_AB = 'qrcode_AB.png'
# -----------------------------------------------------------
# function_qr_dec
# -----------------------------------------------------------
def function_qrdec_cv2(img_bgr):
# QRCodeDetectorインスタンス生成
qrd = cv2.QRCodeDetector()
# QRコードデコード
retval, decoded_info, points, straight_qrcode = qrd.detectAndDecodeMulti(img_bgr)
if retval:
points = points.astype(np.int)
for dec_inf, point in zip(decoded_info, points):
if dec_inf == '':
continue
# QRコード座標取得
x = point[0][0]
y = point[0][1]
# QRコードデータ
print('dec:', dec_inf)
img_bgr = cv2.putText(img_bgr, dec_inf, (x, y-6), font, .3, (0, 0, 255), 1, cv2.LINE_AA)
# バウンディングボックス
img_bgr = cv2.polylines(img_bgr, [point], True, (0, 255, 0), 1, cv2.LINE_AA)
cv2.imshow('image', img_bgr)
cv2.waitKey(0)
# -----------------------------------------------------------
# sample program
# -----------------------------------------------------------
img_BGR = cv2.imread(FILE_PNG_AB, cv2.IMREAD_COLOR)
function_qrdec_cv2(img_BGR)
※detectAndDecodeMultiの結果が、True(retvalがTrue)の場合でも、デコードデータが無い(dec_infがNULL)ことがあったので、「dec_inf == ''」の場合は、continueさせています。
・実行結果
➍-2:「pyzbar」によるQRコード読込み
・インストール
Windows環境以外は、以下のモジュールをインストールしてください。
brew install zbar
sudo apt-get install libzbar0
以下のコマンドでpyzbarモジュールをインストールします。
pip install pyzbar
・プログラム
import cv2
from pyzbar.pyzbar import decode, ZBarSymbol
# -----------------------------------------------------------
# initial
# -----------------------------------------------------------
font = cv2.FONT_HERSHEY_SIMPLEX
FILE_PNG_AB = 'qrcode_AB.png'
# -----------------------------------------------------------
# function_qr_dec
# -----------------------------------------------------------
def function_qrdec_pyzbar(img_bgr):
# QRコードデコード
value = decode(img_bgr, symbols=[ZBarSymbol.QRCODE])
if value:
for qrcode in value:
# QRコード座標取得
x, y, w, h = qrcode.rect
# QRコードデータ
dec_inf = qrcode.data.decode('utf-8')
print('dec:', dec_inf)
img_bgr = cv2.putText(img_bgr, dec_inf, (x, y - 6), font, .3, (255, 0, 0), 1, cv2.LINE_AA)
# バウンディングボックス
cv2.rectangle(img_bgr, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('image', img_bgr)
cv2.waitKey(0)
# -----------------------------------------------------------
# sample program
# -----------------------------------------------------------
img_BGR = cv2.imread(FILE_PNG_AB, cv2.IMREAD_COLOR)
function_qrdec_pyzbar(img_BGR)
・実行結果
➎:webカメラでQRコード自動認識
最後にwebカメラでQRコードを自動認識するプログラムを載せておきます。
➎-1:「OpenCV」プログラム
プログラムは、「'q'
」キー押下でquitします。
import cv2
import numpy as np
# -----------------------------------------------------------
# Init
# -----------------------------------------------------------
font = cv2.FONT_HERSHEY_SIMPLEX
# -----------------------------------------------------------
# 画像キャプチャ
# -----------------------------------------------------------
# VideoCaptureインスタンス生成
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# QRCodeDetectorインスタンス生成
qrd = cv2.QRCodeDetector()
while cap.isOpened():
ret, frame = cap.read()
if ret:
# QRコードデコード
retval, decoded_info, points, straight_qrcode = qrd.detectAndDecodeMulti(frame)
if retval:
points = points.astype(np.int32)
for dec_inf, point in zip(decoded_info, points):
if dec_inf == '':
continue
# QRコード座標取得
x = point[0][0]
y = point[0][1]
# QRコードデータ
print('dec:', dec_inf)
frame = cv2.putText(frame, dec_inf, (x, y - 6), font, .3, (0, 0, 255), 1, cv2.LINE_AA)
# バウンディングボックス
frame = cv2.polylines(frame, [point], True, (0, 255, 0), 1, cv2.LINE_AA)
# 画像表示
cv2.imshow('cv2', frame)
# quit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# キャプチャリソースリリース
cap.release()
➎-2:「pyzbar」プログラム
プログラムは、「'q'
」キー押下でquitします。
import cv2
from pyzbar.pyzbar import decode, ZBarSymbol
# -----------------------------------------------------------
# Init
# -----------------------------------------------------------
font = cv2.FONT_HERSHEY_SIMPLEX
# -----------------------------------------------------------
# 画像キャプチャ
# -----------------------------------------------------------
# VideoCaptureインスタンス生成
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while cap.isOpened():
ret, frame = cap.read()
if ret:
# デコード
value = decode(frame, symbols=[ZBarSymbol.QRCODE])
if value:
for qrcode in value:
# QRコード座標
x, y, w, h = qrcode.rect
# QRコードデータ
dec_inf = qrcode.data.decode('utf-8')
print('dec:', dec_inf)
frame = cv2.putText(frame, dec_inf, (x, y-6), font, .3, (255, 0, 0), 1, cv2.LINE_AA)
# バウンディングボックス
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 1)
# 画像表示
cv2.imshow('pyzbar', frame)
# quit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# キャプチャリソースリリース
cap.release()
##➎-3:実行結果
「OpenCV
」の実行結果は割愛し、「pyzbar
」の実行結果のみを載せます。「QRコードを表示した紙」をwebカメラで撮り検出させていますが、うまく認識しています!
➏:以上
お疲れ様でした。
モジュールを使うことで、かなり簡単にQRコード作成・読込みツールを作ることができました。