286.ラズパイ無双[22 QRコード読取]
初回:2022/11/23
Raspberry Pi (ラズベリーパイ、通称"ラズパイ")で何か作ってみようという新シリーズです。今回は、実務にも役立つ『QRコード』の読取プログラムをご紹介したいと思います。
P子「QRコードって何?」※1
無理くりの話の持って行き方ですけど、そのあたりも含めて、説明していきたいと思います。
【目次】
1.QRコードとは?
≪参考1≫
https://www.qrcode.com/about/
QRコードとは?
「QRコード」は株式会社デンソーウェーブさんの登録商標で、JIS X 0510、ISO/IEC18004で規格化されています。
このあたりは、≪参考1≫からさらに、『QRコードの規格化・標準化』に書かれています。
デンソーウェーブさんが保有するQRコードの特許(特許第 2938338号)も、権利行使を行わないことを宣言されているそうです。
P子「太っ腹ね」
さらに、気になるライセンス料とか、商用利用とかについても、使用料不要で、商用利用も可能です。ただし『QRコードの名称』を使用する場合には、登録商標文の記載は必要です。
≪参考2≫
https://www.qrcode.com/faq.html
FAQ
2.QRコードのバージョン
≪参考3≫
https://www.qrcode.com/about/version.html
QRコードの情報量とバージョン
以下に扱うのは、一般的なQRコードであるモデル2というQRコードです。
QRコードのバージョン(種類)は、1から40まであり、それらはセル構成(セル数)が決められています。ところが、誤り訂正レベルに応じたデータビット数(混合)が異なるので、数字、英数字、バイナリ、漢字で登録できる文字数が異なってきます。
また、実際に印字する場合は、セル自体の大きさも指定する為、QRコードの印字サイズを簡単に決めることはできません。
工業系業務システムで使用する場合には、ある程度の文字数とか文字種類は決まっていると思いますので、現品票とか作業指示書などに使用する場合は、サイズが決まってくると非常に助かります。
このあたりの知識は、QRコードの作成時に必要になってきますが、とりあえず読み取りだけなら気にしなくて構いません。
P子「ホントに気にしなくていいの?」
まあ、ほんのちょっとだけ、気にしておいてください。
3.openCVで読取
ここからが本題です。
≪参考4≫
https://note.nkmk.me/python-opencv-qrcode/
Python, OpenCVでQRコードを検出・読み取り
まずは、openCVのみでQRコードを検出・読み取る方法です。
cv2.QRCodeDetector というクラスを使用します。
qr = cv2.QRCodeDetector() で、オブジェクトを生成して、qr.detectAndDecodeMulti(frame) で検出とデコードを行います。メソッド名を見て分かるように、複数のQRコードを見つけることができます。import cv2 LIME = ( 0, 255, 0) # 明るい緑 RED = ( 0, 0, 255) # 赤 THICK = 2 # 線の太さ qr = cv2.QRCodeDetector() cap = cv2.VideoCapture(0) while True: _, frame = cap.read() # ret:検出で True、dec_inf:文字列要素のタプル、pos:QRコードの四隅の座標 ret, dec_inf, pos, _ = qr.detectAndDecodeMulti(frame) if ret: for s, p in zip(dec_inf, pos): pts = p.astype(int) # QRコードのポリゴンの座標 # [[155 132], [286 140], [281 263], [151 260]] 左上、右上、右下、左下 # print(pts) if s: print(s) # 左上の座標 (X座標の最小値と、Y座標の最小値が左上の位置) p1 = (min(pts[:,0]),min(pts[:,1])) frame = cv2.polylines(frame,[pts],True,LIME,THICK) cv2.putText(frame,s,p1,cv2.FONT_HERSHEY_PLAIN,1,LIME,1,cv2.LINE_AA) else: # バツ印の意味で、斜線を引く(各ポイントは対角線になる) frame = cv2.line(frame,pts[0],pts[2],RED,THICK) frame = cv2.line(frame,pts[1],pts[3],RED,THICK) cv2.imshow('QR CODE', frame) k = cv2.waitKey(10) # ミリ秒単位で表されるキーボード入力待ち時間 if k == ord('q') or k == 27: # q または、ESC で終了 break if cap is not None : cap.release() cv2.destroyAllWindows() # すべてのウィンドウを閉じる
QRコードを見つけたものの、エンコード...文字列に変換できなかった場合は、空文字列が得られます。
後は、QRコードの周りを囲ったり、×を付けたり、エンコード出来た文字列を表示したりしているだけです。
4.pyzbarで読取
ZBarはバーコードを読み取るためのオープンソースライブラリで、pyzbarはPythonでZBarを利用するためのライブラリです。
≪参考5≫
https://qiita.com/orengepy/items/1d405762813846765ec1
Pythonでバーコードを読み込む
まずは、インストールを行います。
$ pip3 install pyzbar
これだけで、使えるようになります。
from pyzbar.pyzbar import decode,ZBarSymbol # QRコードのスキャン import cv2 import numpy as np # polylines で使用 LIME = ( 0, 255, 0) # 明るい緑 RED = ( 0, 0, 255) # 赤 THICK = 2 # 線の太さ cap = cv2.VideoCapture(0) while True: _, frame = cap.read() # data は、(テキスト、タイプ、Rect、polygon、quality、orientation) data = decode(frame, symbols=[ZBarSymbol.QRCODE,ZBarSymbol.CODE39]) if len(data) > 0 and len(data[0]) > 0 and len(data[0][0]) > 0 : for (s,t,r,p,q,o) in data : # (テキスト、タイプ、Rect、polygon、quality、orientation) s = s.decode('utf-8', 'ignore') # コード内容 # p ⇒ [Point(x=123, y=277), Point(x=127, y=353), Point(x=202, y=346), Point(x=196, y=273)] pts = np.array(p, np.int32) # pts ⇒ [[123 277],[127 352],[202 346],[196 272]] # print(f"{o} {pts}") # 左上の座標 (X座標の最小値と、Y座標の最小値が左上の位置) p1 = (min(pts[:,0]),min(pts[:,1])) frame = cv2.polylines(frame,[pts],True,LIME,THICK) # Trueは、閉包図形 cv2.putText(frame,s,p1,cv2.FONT_HERSHEY_PLAIN,1,LIME,1,cv2.LINE_AA) # テスト用の処理 if 'ERR' in s : # サンプル。ERR 文字列を含むかどうかで判定 # バツ印の意味で、斜線を引く(各ポイントは対角線になる) frame = cv2.line(frame,pts[0],pts[2],RED,THICK*2) # 線幅(THICK)を2倍にする。 frame = cv2.line(frame,pts[1],pts[3],RED,THICK*2) # 線幅(THICK)を2倍にする。 cv2.imshow('QR CODE', frame) k = cv2.waitKey(10) # ミリ秒単位で表されるキーボード入力待ち時間 if k == ord('q') or k == 27: # q または、ESC で終了 break if cap is not None : cap.release() cv2.destroyAllWindows() # すべてのウィンドウを閉じる
5.まとめ
きちんと評価したわけではありませんが、pyzbar の方が、読み取り感度が高いようです。
ただ、ラズパイでQRコードを複数同時に読み取ることが出来れば、工業系業務システムでの運用も色々と考えられます。
なかなか楽しみです。
ほな、さいなら
======= <<注釈>>=======
※1 P子「QRコードって何?」
P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。