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

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

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

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

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

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

必要な物

Raspberry Pi 本体

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

ラズパイ3B+で実行するとメモリ不足でエラーになることがあるようです。
原因としては、QRコードの分類器がメモリを沢山使用してしまうためです。

解決策としては、OpenCVの分類器を使用するのではなく別のライブラリを使用することをおすすめします。

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にアップしました。