【ラズパイ】QRコードリーダーを作ろう【Python/OpenCV】

【Raspberry Pi】PythonとOpencvでQRコードリーダーを作る

こんにちは! けい(Twitter)です。

今回は、Raspberry Pi でQRコードリーダーの作り方についてご紹介していきます。

PythonとOpenCVを組み合わせると簡単に作ることができます。

QRコードの情報を読み取り、webサイトを開く所までをプログラミングしていきたいと思います。

必要な物

Raspberry Pi 本体

今回用いるRaspberry Pi は、ラズパイ4Bです。

もちろん、ラズパイ3B+などでも動作します。

Raspberry Piカメラ or Webカメラ

Raspberry Pi のカメラモジュールか、Webカメラを接続することができます。

私はどちらも持っていますが、Webカメラの方が利便性が高いのでWebカメラで動作させたいと思います。

基本的にどんなWebカメラでも動作すると思います。
私は家にあった、logicoolのwebカメラを使用しました。

他にも使用できるカメラなどを以前の記事でまとめているで、ぜひ参考にしてみてください。

>【Raspberry Pi】webカメラを接続する方法

環境構築

環境設定

以下の環境で、プログラムを動作させました。

  • Raspbian buster 10
  • python3.7.3
  • opencv:4.1.0

opencvは画像処理用のライブラリですが、opencvのバージョンが4以上のものをインストールする必要があります。
バージョン4以上で、QRコードを認識できる関数が用意されました。

それでは、opencvのインストール手順を見ていきましょう。

opencvをインストール

ラズパイへのopencvのインストールは少々面倒くさい作業です。

OpenCVの依存ライブラリを先にインストールします。
下記コマンドをターミナルで実行してください。

sudo apt install libavutil56 libcairo-gobject2 libgtk-3-0 libqtgui4 libpango-1.0-0 libqtcore4 libavcodec58 libcairo2 libswscale5 libtiff5 libqt4-test libatk1.0-0 libavformat58 libgdk-pixbuf2.0-0 libilmbase23 libjasper1 libopenexr23 libpangocairo-1.0-0 libwebp6

バージョンを指定してopencvをインストールします。

sudo pip3 install opencv-python==4.1.0

これでインストールが完了すると思います。

QRコードを認識するプログラム

ソースコード

まずは、QRコードをwebカメラで取り込んで、QRコードを認識し情報を取り込むプログラムを見ていきましょう。

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
# initialize the cv2 QRCode detector
detector = cv2.QRCodeDetector()

while True:
    frame, img = cap.read()
    output_img = img.copy()
    data, bbox, _ = detector.detectAndDecode(img)
    
    if data:
        cv2.putText(output_img, data, (0, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 5, cv2.LINE_AA)
        for i in range(4):
            cv2.line(output_img, tuple(bbox[i][0]), tuple(bbox[(i+1)%len(bbox)][0]), (0, 0, 255), 4)
    cv2.imshow("QRCODEscanner", output_img)    
    if cv2.waitKey(1) == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

実行中に、qキーを押すとプログラムが終了します。

実行結果

実際に動作させた様子はYoutubeにアップしました。

コード解説

6行目の「cv2.QRCodeDetector()」の部分で、QRコードを認識するOpencvのクラスを呼び出しています。

11行目の「detector.detectAndDecode(img)」で、元画像imgからQRコードを認識しています。
返り値として3つあり、順に「QRコードからデコードされたデータ」「QRコードの四角形の頂点の配列」「整形されたQRコード画像の配列」です。

よって、「data」にはQRコードを読み取った情報、bboxにはQRコードの四隅の座標の配列が格納されています。

14行目で、QRコードの情報を画面に青文字で表示しています。

15,6行目で、QRコードの四隅を結ぶ線を赤色で引いています。

WebサイトをPythonで操作する

先ほどのプログラムは、QRコードの情報を読み取っただけで、実際にQRコードリーダーとしては機能していません。何か足りないですよね。

そう、QRコードを読み取って、Webサイトを開くまでがQRコードリーダーです。

  1. カメラでQRコードの情報を読み取る
  2. QRコードの情報を元にWebサイトを開く

先ほどのプログラムで①はできたので、次は②のWebサイトを操作する部分を見ていきましょう

環境構築②

PythonでWebサイトを操作するためのパッケージとドライバを新たに追加していきます。

  • selenium
  • Chroniumドライバ

seleniumは、PythonでWebサイトの操作を自動化する際に用いるパッケージです。

Chroniumドライバは、ラズパイにプリインストールされているChroniumをPythonで操作させるために必要なドライバです。

この2つを追加していきましょう。

seleniumのインストール

次のコマンドをターミナルで実行します。

pip3 install selenium

これでインストールは完了したのですが、seleniumパッケージがどこにインストールされたのかが後に必要になってくるので、次のコマンドで場所を確認します。

pip3 show selenium

私の場合は、「/home/pi/.local/lib/python3.7/site-packages/」にインストールされていました。

chroniumドライバのインストール

次のコマンドをターミナルで実行します。

sudo apt-get install chromium-chromedriver

私はこれだけで、自分の使っているChroniumのバージョンと同じバージョンのドライバがインストールされました。
(88.0.4324.187(Official Build)Built on Raspbian , running on Raspbian 10 (32 ビット))

seleniumでChroniumを操作してみる

それでは、最小構成のPythonファイルでseleniumを使って、Chroniumを動作させることができるかを試してみましょう。

import sys
sys.path.insert(0, "/home/pi/.local/lib/python3.7/site-packages/")
from selenium import webdriver

browser = webdriver.Chrome(executable_path="/usr/lib/chromium-browser/chromedriver")
browser.get('https://hellobreak.net')
プログラム解説

2行目の「sys.path.insert」は、importできるようにパスに追加しています。

デフォルトのimportできるパスにseleniumがインストールされた場所が登録されていないため、2行目の文を追加してあげないと、importできないので注意です。

ここの部分のパスに先ほど確認した、「 /home/pi/.local/lib/python3.7/site-packages/ 」を記述しています。

このプログラムの実行に成功すると、私のブログのトップ画面が表示されるはずです。

QRコードリーダー

これで、パーツはそろったのでいよいよQRコードリーダーのプログラムを書いていきます。

  1. カメラでQRコードの情報を読み取る
  2. QRコードの情報を元にWebサイトを開く

ソースコード

import cv2
import sys
sys.path.insert(0, "/home/pi/.local/lib/python3.7/site-packages/")
from selenium import webdriver

cap = cv2.VideoCapture(0)
detector = cv2.QRCodeDetector()

while True:
    frame, img = cap.read()
    output_img = img.copy()
    data, bbox, _ = detector.detectAndDecode(img)
    
    if data:
        cv2.putText(output_img, data, (0, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 5, cv2.LINE_AA)
        for i in range(4):
            cv2.line(output_img, tuple(bbox[i][0]), tuple(bbox[(i+1)%len(bbox)][0]), (0, 0, 255), 4)
        if cv2.waitKey(1) == ord('a'):
            browser = webdriver.Chrome(executable_path="/usr/lib/chromium-browser/chromedriver")
            browser.get(data)
            break
    cv2.imshow("QRCODEscanner", output_img)
    
    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

QRコードをカメラで読み取っている時にaキーを押すと、そのQRコードのサイトに飛ぶことができます。

実行結果

実際に動作させた様子はYoutubeにアップしました。