ラズパイカメラとPicamera2及びOpenCVを使ってQRコード読み取り
ここを参考にしました。
ラズパイOSのバージョンがBookworm以降ではラズパイにリボンケーブルで接続するカメラはUSBカメラのように/dev/video0などデバイスファイルを使ってアクセスできない。なので以下のようなpythonプログラムでは動かない。
cap = cv2.VideoCapture(0)
動かすにはPicamera2パッケージを使う。
github copilotを使いながら簡潔なプログラムを作れたので、とりあえず残しておく。
使ったもの
- ラズベリーパイ4
- OSバージョンはTrixie
- カメラモジュールで写ったものを確認するのでLite版は止めておいた方が良い。
- ラズベリーパイカメラモジュール(OV5647)
- 互換品でも可。
- 多分カメラモジュールv2, v3でも動くはず。
とりあえずラズパイOSをクリーンインストール。
SSHまたはGUIでのターミナルを開いて以下コマンドを実行してPythonパッケージを入れる。
sudo apt install python3-picamera2
sudo apt install python3-opencv
rpicam-helloコマンドを実行してちゃんとカメラモジュールで写るか確認もしておく。
メニューからThonnyを開いて以下プログラムをコピペして実行。
読み取り成功するとしたのShellタブに読み取り結果が出て来る。
from picamera2 import Picamera2
import cv2
# Picamera2 の初期化
picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration()) # mode3: FHD
picam2.start()
# QRコード検出器を初期化
qrCodeDetector = cv2.QRCodeDetector()
while True:
frame = picam2.capture_array()
# QRコードを検出し、その位置を取得
decodedText, points, _ = qrCodeDetector.detectAndDecode(frame)
if points is not None:
points = points[0]
# Debugging: Print the points to check their structure.
#print(f"Points: {points}")
# Validate and draw lines around QR code
if len(points) == 4 and all(len(point) == 2 for point in points):
for i in range(len(points)):
start_point = tuple(map(int, points[i]))
end_point = tuple(map(int, points[(i + 1) % len(points)]))
cv2.line(frame, start_point, end_point, (0, 255, 0), 3)
# デコードされたテキストを表示
print(decodedText)
# フレームを表示
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
display_frame = cv2.resize(frame_rgb, (960, 540), interpolation=cv2.INTER_AREA) # Quarter HDにリサイズ
cv2.imshow('QR Code Scanner', display_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
picam2.stop()
<追記>
・create_preview_configuration() とやると640x480の解像度のフレームとなる。解像度が低くてLNURLがやっと検出できるぐらい。つらい。
サンプルプログラムにあるcreate_video_configuration()だと1920x1080のFHDになる。ただこのサイズだとimshow()でウィンドウに表示するとデカすぎるのでresize()でアスペクト比そのまま小さくしてる。
<おまけ>
Thonnyを仮想環境で使うには
GUIでPythonプログラミングできるThonnyはOS側のパッケージしか使えないし、pipでパッケージを入れることもできない。
仮想環境を作り、さらにシステム側パッケージも使えるようにしてThonnyを動かせば便利。そのやり方は以下。
1. Thonnyを終了させる。
2. 仮想環境を作る
--system-site-packageによって仮想環境からOS側パッケージが使えるようになる。
cd ~
python3 -m venv --system-site-packages ~/python-env
3. Thonnyを起動し、仮想環境のインタプリタを使うように設定
ツール > 設定 > インタープリタ
「カスタムインタープリタを使用する」を選択し、仮想環境の Python インタープリタを指定。/home/<ユーザー名>/python-env/bin/python3
4. Thonnyをいったん終了、起動してShellタブで以下コマンド実行して確認
import sys
print(sys.prefix)
/home/<ユーザー名>/python-env が表示されたらOK
ツール > パッケージの管理で任意のパッケージをインストール可能になる。
※個人的意見だが、仮想環境と聞くと仮想マシンとか仮想化みたいな事を連想する。そうじゃなくてOS側パッケージ管理とは別のパッケージ管理の状態を指すみたいな。そこならOS側からpipでパッケージいれるな!と怒られずに任意のパッケージを使ってプログラミングできる。apt installで入れるpythonパッケージはOSやデバイスに依存するものに限定して、その他は仮想環境でpipで入れて使うのが良さそう。
pipで入れ放題になったのでOpenCVのQRコード検出より高性能pyzbarを使ったプログラムがこれ。やってみたところOpenCVでは読めないライトニングインボイスがpyzbarだとすぐ読めた。すごい。
from picamera2 import Picamera2
from pyzbar.pyzbar import decode
import cv2
# Picamera2 の初期化
picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration()) # mode3: FHD
picam2.start()
while True:
# Picamera2 からフレームを取得
frame = picam2.capture_array()
# QR コードを検出してデコード
qr_codes = decode(frame) # `pyzbar` を使用してデコード
for qr in qr_codes:
# デコードされたデータを取得
decoded_text = qr.data.decode('utf-8') # QR コードの中身
print(f"QRコードのデータ: {decoded_text}")
# QR コードの位置情報を取得
points = qr.polygon
# QR コールにポリゴンを描く
if len(points) == 4: # ポリゴンが正方形であるか確認
for i in range(len(points)):
start_point = tuple(points[i]) # 始点
end_point = tuple(points[(i + 1) % len(points)]) # 次の点
cv2.line(frame, start_point, end_point, (0, 255, 0), 3) # 線を描画
# フレームを表示
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
display_frame = cv2.resize(frame_rgb, (960, 540), interpolation=cv2.INTER_AREA) # Quarter HDにリサイズ
cv2.imshow('QR Code Scanner', display_frame)
# 'q' キーでプログラムを終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# リソースを解放
picam2.stop() # Picamera2 を停止
cv2.destroyAllWindows()
有料パートには上記のpyzbarのプログラムに読み取ったインボイスをwebhookで飛ばす機能を追加したプログラムがあります。




