はじめに
ソニーセミコンダクタソリューションズ株式会社の萩尾と申します。
近年、エッジAI技術の進歩により、小型デバイス上でのリアルタイムなデータ処理が可能となり、様々な分野での応用が広がっています。その中でも、Raspberry Pi AI Cameraは、ソニーのIMX500センサを搭載し、画像認識などAIモデルの推論を行うことができるエッジデバイスとして注目されています。
データの収集・解析・可視化の重要性が増しており、ビジネスや研究の現場では、データを適切に管理し、迅速に意思決定を行うためのツールとしてBI (Business Intelligence) ツールの活用が求められています。特にGrafanaのようなBIツールは、リアルタイムデータの可視化や分析が可能であり、エッジデバイスからのデータ監視、運用状況の把握など幅広い用途に活用されています。
本記事では、Raspberry Pi AI Cameraを用いて、物体検出によるタグとスコアを取得し、それらのデータをMy SQLデータベースに格納、さらにBIツールであるGrafanaを活用し可視化する簡単なサンプルアプリケーションを紹介します。ぜひ最後までご覧ください。
1. セットアップ
まずはRaspberry PiとRaspberry Pi AI Cameraのセットアップを行いましょう。
1.1. Raspberry Pi OSの書き込み
Raspberry Pi OS Imager (ダウンロード先) を使うことで、SDカードへのOSイメージの書き込みができます。Windows、MacOS、Ubuntu対応です。
手順はこちらを参照ください。
1.2. AI Cameraの接続
Raspberry Pi公式ドキュメントに沿って進めていきます。こちらの記事も参考になります。
Picamera2のサンプルアプリケーションが動作すればAI Cameraのセットアップは完了です。
1.3. Docker
本記事ではDockerを使用してMy SQLとGrafanaを立ち上げます。
公式ドキュメントに沿ってDockerをRaspberry Piにインストールしましょう。
以下のスクリプトを実行するとDockerがインストールできます。
Docker インストール用スクリプト
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
# Dockerの動作確認
docker run hello-world
2. My SQLのセットアップ
それでは、My SQLをセットアップしましょう。今回はdocker composeを使用してコンテナを立ち上げます。
-
プロジェクトフォルダを作成
mkdir ~/sample_BI_tool cd ~/sample_BI_tool
-
docker-compose.ymlの作成
docker-compose.ymlではアプリケーションの立ち上げとユーザー名やパスワードの設定をしています。
また、My SQLだけでなくGrafanaも同時に立ち上げるように設定しました。docker-compose.yml
docker-compose.ymlservices: mysql: image: mysql:8.0 container_name: mysql restart: always environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: detection_data MYSQL_USER: user MYSQL_PASSWORD: userpassword ports: - "3306:3306" volumes: - ./mysql_data:/var/lib/mysql security_opt: - no-new-privileges=false grafana: image: grafana/grafana:11.5.2 container_name: grafana restart: always ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_USER=user - GF_SECURITY_ADMIN_PASSWORD=userpassword volumes: - ./grafana_data:/var/lib/grafana
-
My SQLとGrafanaの起動
事前に必要なフォルダを作成します。
mkdir mysql_data mkdir grafana_data chmod 777 mysql_data chmod 777 grafana_data
次に、Docker Composeを使用してコンテナを起動しましょう
docker compose up -d
docker ps -a
でMy SQLとGrafanaのコンテナが起動しているか確認しましょう。 -
テーブルの作成
立ち上げたMy SQLコンテナに接続し、物体検知の推論結果を格納するデータベースとテーブルを作成します。
接続に必要なユーザー名とパスワードはdocker-compose.yml内で設定しました。
rootユーザーの場合のパスワードはrootpassword
です。docker exec -it mysql mysql -u root -p
ログイン後、推論結果を格納するテーブルを作成します。
/* 操作するデータベースの選択 */ USE detection_data; /* テーブルの作成 */ CREATE TABLE detections ( id INT AUTO_INCREMENT PRIMARY KEY, label VARCHAR(255), score FLOAT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ); /* ログアウト */ exit
以上で推論結果を格納するデータベースの構築が完了しました。
3. AI Cameraを使った物体検知
GitHub上で公開されているAI Camera向けModel ZooからスクリプトとAIモデルをお借りして実装していきます。
作成するフォルダの構成は以下の通りです。
# 新たに用意するファイルは、app.py, coco_labels_80.txt, network.rpk
# 上記以外は前のセクションで作成済み
~/sample_BI_tool
├── app.py
├── assets
│ └── coco_labels_80.txt
├── network.rpk
├── docker-compose.yml
├── grafana_data
└── mysql_data
-
AI Camera向けModel Zooをclone
git clone https://github.com/SonySemiconductorSolutions/aitrios-rpi-model-zoo.git
-
仮想環境のセットアップ
My SQLをPythonスクリプトで操作するためにパッケージをインストールする必要があります。
python -m venv .venv --system-site-packages source .venv/bin/activate # 仮想環境内 pip install mysql-connector-python==9.2.0
以降は仮想環境内で実行していきます。
-
物体検知およびデータベースへ格納するスクリプトの実装
ソースコードはModel Zooから物体検知のスクリプトをコピーして使用します。
コピーしてきたスクリプトにMySQLの接続情報と推論結果をデータベースに格納するinsert_detection関数を追加します。
My SQL操作の詳細は省きますが、推論結果から取り出したタグ情報とスコア情報をデータベースに格納しています。最終的な
app.py
は以下になります。app.py
app.pyimport time import cv2 from picamera2.devices.imx500 import IMX500 from picamera2.devices.imx500 import (NetworkIntrinsics, postprocess_nanodet_detection) from picamera2 import MappedArray, Picamera2 import mysql.connector # 【追加】My SQLデータベースの接続情報 DB_CONFIG = { "host": "localhost", "user": "user", "password": "userpassword", "database": "detection_data", } THRESHOLD = 0.55 IOU = 0.65 MAX_DETECTION = 10 last_detections = [] with open("./aitrios-rpi-model-zoo/assets/coco_labels_80.txt", "r") as f: labels = f.read().split("\n") class Detection: def __init__(self, coords, category, conf, metadata): """Create a Detection object, recording the bounding box, category and confidence.""" self.category = category self.conf = conf self.box = imx500.convert_inference_coords(coords, metadata, picam2) def parse_and_draw_detections(request): """Analyse the detected objects in the output tensor and draw them on the main output image.""" detections = parse_detections(request.get_metadata()) # 【追加】物体が検知された場合、データベースに格納する関数を呼び出す if len(detections) > 0: for detection in detections: label = labels[int(detection.category)] score = detection.conf insert_detection(label, score) draw_detections(request, detections) def insert_detection(label, score): """【追加】検知された物体のlabelとscoreの情報をデータベースに格納する関数""" try: conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() cursor.execute( "INSERT INTO detections (label, score) VALUES (%s, %s)", (label, score) ) conn.commit() print(f"Inserted: {label} with score: {score}") except mysql.connector.Error as err: print(f"Error: {err}") finally: cursor.close() conn.close() def parse_detections(metadata: dict): """Parse the output tensor into a number of detected objects, scaled to the ISP out.""" global last_detections np_outputs = imx500.get_outputs(metadata, add_batch=True) input_w, input_h = imx500.get_input_size() if np_outputs is None: return last_detections boxes, scores, classes = \ postprocess_nanodet_detection(outputs=np_outputs[0], conf=THRESHOLD, iou_thres=IOU, max_out_dets=MAX_DETECTION)[0] from picamera2.devices.imx500.postprocess import scale_boxes boxes = scale_boxes(boxes, 1, 1, input_h, input_w, False, False) last_detections = [ Detection(box, category, score, metadata) for box, score, category in zip(boxes, scores, classes) if score > THRESHOLD ] return last_detections def draw_detections(request, detections, stream="main"): """Draw the detections for this request onto the ISP output.""" with MappedArray(request, stream) as m: for detection in detections: x, y, w, h = detection.box label = f"{labels[int(detection.category)]} ({detection.conf:.2f})" cv2.putText(m.array, label, (x + 5, y + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) cv2.rectangle(m.array, (x, y), (x + w, y + h), (0, 0, 255, 0)) b_x, b_y, b_w, b_h = imx500.get_roi_scaled(request) cv2.putText(m.array, "ROI", (b_x + 5, b_y + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) cv2.rectangle(m.array, (b_x, b_y), (b_x + b_w, b_y + b_h), (255, 0, 0, 0)) if __name__ == "__main__": # This must be called before instantiation of Picamera2 imx500 = IMX500("./aitrios-rpi-model-zoo/models/object-detection/nanodet_plus_416x416/network.rpk") picam2 = Picamera2() config = picam2.create_preview_configuration(controls={"FrameRate": 1}, buffer_count=28) imx500.show_network_fw_progress_bar() picam2.start(config, show_preview=True) imx500.set_auto_aspect_ratio() picam2.pre_callback = parse_and_draw_detections while True: time.sleep(0.5)
-
app.py
の実行Model Zooレポジトリのcloneと
app.py
の準備ができたら、以下のスクリプトで実行してみましょう。python app.py
COCOデータセット1の画像を画面越しに撮影して、
Inserted: person with score: 0.622459352016449
のような出力が確認できれば正しくデータベースに推論結果を格納できています。
4. Grafanaで可視化してみよう
いよいよGrafanaを使って推論結果を可視化してみましょう。
4.1. Grafanaのセットアップ
-
Grafanaへログイン
既にGrafanaコンテナは立ち上げてあるので、Webブラウザで
localhost:3000
にアクセスするとログインページが表示されます。
docker-compose.yml内で設定したユーザー名user
とパスワードuserpassword
でログインします。 -
データソースの追加
Grafanaが参照するデータベースをMy SQLに設定します。
ページ左のメニューバーから Data Sourcesページに移動し、My SQLを追加します。MySQLを選択すると設定ページが表示されます。
docker-compose.yml
内で設定したデータベースの接続情報を記入していきます。入力する情報は以下の通りです。
設定項目 設定値 Host URL mysql:3306 Database name detection_data Username user Password userpassword 入力したらページ下部の
Save & test
をクリックします。 -
ダッシュボードの追加
データを表示するダッシュボードを作っていきます。
サイドバーの
Dashboards
を選択し、"Create dashboard > Create dashboard > Add visualization"の順でクリックします。
データソースを選択する画面でMy SQLを選択し、パネル編集ページを開きます。
4.2. パネルを追加してみよう
まずは、検知されたクラスの数を集計し上位5クラスのクラス名と検知数を表示するパネルを作成してみます。
右のサイドバーから "Bar chart"を選択し、My SQLのクエリを入力する画面を開きます。
開いたコードスペースに以下のクエリを入力すると、上部にグラフが確認できます!
SELECT label, count(*) AS total_count FROM detection_data.detections GROUP BY label ORDER BY total_count DESC LIMIT 5;
グラフが確認できれば、画面上部の "Back to dashboard" をクリックし、"Save dashboard" をクリックして保存します。
4.3. TreeMapを使ったパネルを追加してみよう
BIツールの強みと言えば視覚的に情報を確認できる部分です。
先ほどのセクションで作成したバーチャートとは別の方法で可視化してみましょう。
-
プラグインページからTreeMapプラグインをインストール
-
パネルの追加
ダッシュボードを開き、新しいパネルを追加します。右のサイドバーからTreemapを選択し、My SQLのコードスペースを開きます。
-
クエリを入力し、パネルを完成させる
コードスペースに以下のクエリを入力し "Run query" をクリックすると、上部にグラフが確認できます。Treemapでは最大上位20クラスを可視化しています。
SELECT label, count(*) AS total_count FROM detection_data.detections GROUP BY label ORDER BY total_count DESC LIMIT 20;
さらに、右のサイドバーでパネルを操作して、以下のように設定していきます。設定が完了したらダッシュボードに戻り、保存します。
設定項目 設定値 Treemap > Tiling algorithm Binary Dimensions > Label by label Dimensions > Size by total_count Dimensions > Color by total_count Standard options Green-Yellow-Red
4.4. 物体検知を実行しながら可視化してみよう
実行前にGrafanaの自動読み込みを5s
に設定します。
完成したGrafanaのダッシュボードを使って物体検知の推論結果による変化を確認しましょう。
python app.py
pythonスクリプトを実行し、物体検知を実行してみると検知結果に応じてパネルが変化していることが確認できます。
おわりに
本記事では、Raspberry Pi AI Cameraを活用し、物体検出のデータをMy SQLに保存し、Grafanaで可視化する方法を紹介しました。エッジデバイスで得られた情報をBIツールで可視化することで、データの活用範囲が広がることが分かりました。
今回のシステムは基本的なサンプルですが、データの蓄積や分析を深めることで、より高度な可視化やアラート機能の追加、他のBIツールとの連携など、さらに発展させることができます。また、クラウドと連携することで、より広範なデータ活用の可能性も広がります。
まだまだ拡張性があるので、ぜひ試してみてください。
困った時は
もし、記事の途中でうまくいかなかった場合は、気軽にこの記事にコメントいただくか、以下のサポートのページもご覧ください。
コメントのお返事にはお時間を頂く可能性もありますがご了承ください。
Raspberry Piに関連する疑問がある場合は、下記フォーラムを確認、活用ください。
-
Microsoft COCO: Common Objects in Context[2014] https://arxiv.org/abs/1405.0312 ↩