こんにちは、JS2IIUです。
Streamlitは、Pythonで記述したコードからインタラクティブなWebアプリケーションを簡単に作成できるフレームワークです。今回は、Streamlitを使って、Webカメラで撮影した映像からバーコードを読み取り、ISBNを元に書籍の表示を表示するアプリケーションを作成してみましょう。今回もよろしくお願いします。
書籍の表示を取得するためのAPI
このアプリケーションでは、国立国会図書館サーチが提供する書影APIを利用します。このAPIにISBNコードを指定することで、書籍の表示画像を取得できます。登録不要で使えます。
書影API: https://ndlsearch.ndl.go.jp/help/api/thumbnail

国立国会図書館サーチが提供する書影API | NDLサーチ | 国立国会図書館
サンプルコード
サンプルコードは以下の記事で作成したものをベースにしています。
Python
import requests
import cv2
import streamlit as st
from PIL import Image
from io import BytesIO
st.title('Webcam Barcode Reader')
# カメラ映像を配置するプレースホルダーを作成
placeholder = st.empty()
# カメラ番号は環境に合わせて調整してください (通常は0)
cap = cv2.VideoCapture(0)
# バーコードリーダーを作成
barcode_reader = cv2.barcode.BarcodeDetector()
# 検出されたバーコード情報を格納する集合
detected_codes = set()
while True:
ret, frame = cap.read()
if not ret:
break
# OpenCVはBGRフォーマットなので、RGBに変換
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# バーコード情報を取得
try:
# バーコードを検出
ok, decoded_info, decoded_type, corners = barcode_reader.detectAndDecode(frame)
except ValueError:
decoded_info, decoded_type, corners = barcode_reader.detectAndDecode(frame)
ok = bool(decoded_info)
# st.write(f"decoded_info: {decoded_info}") # デバッグ出力
if len(decoded_info) > 2:
detected_codes.add(f'{decoded_info}')
# `st.image()`でプレースホルダーに画像を表示
placeholder.image(frame, channels="RGB")
# バーコードが検出されたらループを終了
if len(detected_codes) >= 2:
l = list(detected_codes)
st.header(f'Barcodes: {l[0]}, {l[1]}')
for code in detected_codes:
isbn_code = None
if '9784' in code:
isbn_code = code
if isbn_code:
url = f'https://ndlsearch.ndl.go.jp/thumbnail/{isbn_code}.jpg'
res = requests.get(url)
image = Image.open(BytesIO(res.content))
st.image(image, caption="取得した画像")
break
cap.release()
お試しで表示させている書籍のPRです。面白い切り口で楽しく読めました。「なぜ働いていると本が読めなくなるのか」三宅著。
コードの解説
- ライブラリのインポート
requests: Webサイトへのアクセスに必要です。cv2: OpenCVライブラリで、画像処理を行います。streamlit: Webアプリケーションの構築に利用します。PIL: 画像処理ライブラリで、画像の読み込みなどに使用します。BytesIO: メモリ上でバイナリデータを扱うために使います。
- タイトルの設定
st.title('Webcam Barcode Reader'): Webアプリケーションのタイトルを「Webcam Barcode Reader」に設定します。
- カメラの設定
placeholder = st.empty(): カメラ映像を表示するためのプレースホルダーを作成します。cap = cv2.VideoCapture(1): カメラデバイスに接続します。(カメラ番号は環境に合わせて調整してください。通常、内蔵カメラは0、外部カメラは1となります。)
- バーコードリーダーの作成
barcode_reader = cv2.barcode.BarcodeDetector(): OpenCVのバーコードリーダーを作成します。
- バーコード情報の初期化
detected_codes = set(): 検出されたバーコード情報を格納する集合を初期化します。集合を使うことで、重複したバーコード情報を排除します。
- メインループ
while True: カメラから映像を取得し続けるループです。ret, frame = cap.read(): カメラから1フレームを読み込みます。retは読み込みが成功したかどうかを示すブール値、frameは画像データです。if not ret: break: 読み込みに失敗したらループを終了します。frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB): OpenCVはBGRフォーマットで画像を扱うため、Streamlitで表示するためにRGBフォーマットに変換します。try...except: バーコードの検出処理でエラーが発生した場合でもプログラムが停止しないように例外処理を行います。ok, decoded_info, decoded_type, corners = barcode_reader.detectAndDecode(frame): バーコードを検出します。okは検出が成功したかどうかを示すブール値、decoded_infoはバーコードの情報、decoded_typeはバーコードの種類、cornersはバーコードの角の位置情報です。if len(decoded_info) > 2: バーコード情報が有効な場合 (長さ2以上) に処理を行います。detected_codes.add(f'{decoded_info}'): 検出したバーコード情報を集合に追加します。placeholder.image(frame, channels="RGB"): 現在のフレームをプレースホルダーに表示します。if len(detected_codes) >= 2: 2つ以上のバーコードが検出されたらループを終了します。l = list(detected_codes): 検出されたバーコード情報をリストに変換します。st.header(f'Barcodes: {l[0]}, {l[1]}'): 検出された2つのバーコード情報を表示します。for code in detected_codes: 検出されたバーコード情報それぞれに対して処理を行います。isbn_code = None: ISBNコードを格納する変数を初期化します。if '9784' in code: バーコード情報に’9784’が含まれている場合 (日本のISBNコード) を判定します。isbn_code = code: ISBNコードを変数に格納します。
if isbn_code: ISBNコードが取得できた場合に処理を行います。url = f'https://ndlsearch.ndl.go.jp/thumbnail/{isbn_code}.jpg': 国立国会図書館のサムネイル画像を取得するためのURLを作成します。res = requests.get(url): URLにアクセスして画像データを取得します。image = Image.open(BytesIO(res.content)): 取得した画像データをPILで開きます。st.image(image, caption="取得した画像"): 取得した画像を表示します。
- 後処理
cap.release(): カメラデバイスを解放します。
参考になるWebサイト
- OpenCV公式ドキュメント
- Streamlit公式ドキュメント
- 顔認証にも使われるOpenCVをインストールして使ってみよう! – アンドエンジニア
- 【Python】OpenCV(cv2)のインストール方法(pip install)を簡単に解説 – trends – コードキャンプ
- 国立国会図書館サーチが提供する書影API | NDLサーチ | 国立国会図書館
最後に、書籍のPRです。
最新のOpenAIのチャットAPIの使い方もしっかりと解説されている良書です。2024年11月初版発行、「LangChainとLangGraphによるRAG・AIエージェント[実践]入門」西見、吉田、大嶋著。
最後まで読んでいただきありがとうございます。73




コメント