0
1

More than 1 year has passed since last update.

pythonでQRコードを読み取ってHTMLで表示する

Posted at

目的

こちらの記事を参考に自分のPC環境でも動くものを作りたい。
html上に表示し、QRコードを読み取り、リアルタイムで状態を変化させたい。

イメージ

スクリーンショット 2022-06-03 20.34.19.png

htmlで表示された表の状況の部分は、NGとなっています。QRコードをwebカメラで読み込むことでは、 データベースのstatusを書き換えます。すると、状況は、OKに変化します。

プログラム

手順としては、 QRコードの作成、データベースの作成、pythonのプログラムの作成になります。プログラムは、githabにあげていますので、参考にしてください。
https://github.com/yutti/study/tree/main/QR_code

QRコードの作成

今回作成した QRコードは、github上においていますので、そちらを使用してください。QRコードの作成は、文字表示付きQRコードの作成にまとめましたので、こちらを参考にしてください。

データベースの作成

github上においてあるmake_db.pyを実行するとデータベースを作成できます。データベースの作成方法について、pythonでのsqlite3データベース作成にまとめましたので、こちらを参考にしてください。

pythonのプログラムの作成

プログラムのベースは、最初に紹介した記事になります。プログラムを実行させると、webカメラが起動します。QRコードを読み取っていただくと、表の状況の部分が変わります。読み込みが終わりましたら、キーボードのqを押すと抜けることができます。表の状況を元の状態に戻したい場合は、make_db.pyを実行していただくと、戻るようにしています。

code_reader_websocket.py
import os.path
import json
import sqlite3
import webbrowser
import cv2
import winsound
import threading
from pyzbar.pyzbar import decode
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from websocket_server import WebsocketServer

class OrenoServer:

    def __init__(self):
        self.HOST = 'localhost'
        self.HTTP_PORT = 8080
        self.WS_PORT = 8081
        self.client = None     
        self.wss = WebsocketServer(host=self.HOST, port=self.WS_PORT)
        self.wss.set_fn_new_client(self.new_client)
        self.https = ThreadingHTTPServer((self.HOST, self.HTTP_PORT), HttpHandler)
        self.codes = []

    def start(self):
        threading.Thread(target=self.wss.run_forever).start()
        threading.Thread(target=self.https.serve_forever).start()
        webbrowser.open(f'http://{self.HOST}:{str(self.HTTP_PORT)}')

    def shutdown(self):
        self.wss.shutdown()
        self.https.shutdown()

    def new_client(self, client, server):
        if self.client is None:
            self.client = client
            threading.Thread(target=self.cam_capture).start()

    def cam_capture(self):
        cap = cv2.VideoCapture(0)
        font = cv2.FONT_HERSHEY_SIMPLEX
        while cap.isOpened():
            ret, frame = cap.read()

            if ret:
                d = decode(frame)

                if d:
                    for barcode in d:
                        barcode_data = barcode.data.decode('utf-8')

                        if barcode_data not in self.codes:
                            self.codes.append(barcode_data)
                            winsound.Beep(2000, 50)
                            font_color = (0, 0, 255)
                            self.wss.send_message(self.client, barcode_data)
                        else:
                            font_color = (0, 154, 87)

                        x, y, w, h = barcode.rect
                        cv2.rectangle(frame, (x, y), (x + w, y + h), font_color, 2)
                        frame = cv2.putText(frame, barcode_data, (x, y - 10), 
                                            font, .5, font_color, 2, cv2.LINE_AA)

            cv2.imshow('QRCODE READER  press q -> exit', frame)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                db = OrenoDataBase()
                db.set(self.codes)
                db.close()
                self.shutdown()
                break


class OrenoDataBase:

    def __init__(self):
        self.conn = sqlite3.connect(r"./book_list.db", check_same_thread=False)
        self.conn.row_factory = sqlite3.Row
        self.cur = self.conn.cursor()

    def get(self):
        self.cur.execute('SELECT * FROM bookitems ORDER BY code')
        rows = []

        for r in self.cur.fetchall():
            rows.append({'name': r['name'], 'code': r['code'], 'status': r['status']})

        return rows

    def set(self, codes):
        place_holder = ','.join('?'*len(codes))
        values = tuple(codes)
        self.cur.execute(
            f'UPDATE bookitems SET status = TRUE WHERE code in ({place_holder})', values)
        self.conn.commit()

    def close(self):
        self.cur.close()
        self.conn.close()


class HttpHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        with open(r"./template.html", mode='r', encoding='utf-8') as html:
            response_body = html.read()
            self.send_response(200)
            self.send_header('Content-type', 'text/html; charset=utf-8')
            self.end_headers()
            self.wfile.write(response_body.encode('utf-8'))

    def do_POST(self):
        db = OrenoDataBase()
        rows = db.get()
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        response_body = json.dumps(rows)
        self.wfile.write(response_body.encode('utf-8'))
        db.close()


server = OrenoServer()
server.start()

htmlは、下記のように設定しています。table classの設定が悪いのか、表の背景色を黒色に設定しても反映されなかったので、表の枠線が見えるものを用いてます。

template.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <title>本のリスト</title>
</head>
<body>
<div class="container">
        <table class="table mt-5 table-bordered border-primary " id="tb">
        </table>
</div>
    <script>
        const HTTP_PORT = 8080
        const WS_PORT = 8081

        let wss = new WebSocket('ws://localhost:' + WS_PORT)
        wss.onmessage = function (e) {
            $('#'+ e.data).removeClass('bg-danger').addClass('bg-success').text('OK')
        }

        $.ajax({
            url: 'http://localhost:' + HTTP_PORT,
            type: 'POST',
            dataType: 'json',
        }).then(
            function (data) {
                let elem = '<tr><th>タイトル</th><th>識別コード</th><th>状況</th></tr>'

                
                $.each(data, function (key, item) {
                    let bc
                    let status
                    if(item.status === 1){
                        bc = 'bg-success'
                        status = 'OK'
                    }else{
                        bc = 'bg-danger'
                        status = 'NG'
                    }
                    elem += '<tr>'
                    elem += '<td>' + item.name + '</td>'
                    elem += '<td>' + item.code + '</td>'
                    elem += '<td class="' + bc + '" id="' + item.code +'">' + status + '</td>'
                    elem += '</tr>'
                })

                $('#tb').html(elem)
            })
    </script>
</body>
</html>
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1