RaspberryPi Ai CameraとLocalStudioを使ってデジタルメータ検知を行う

こんにちは！ソニーセミコンダクタソリューションズ（SSS）の山田和樹です。普段はAIを用いたアプリケーションの開発などをしています。
今回はAITRIOSのLocalStudioサービスの一つであるBrainBuilderとPiAICameraを使って、デジタルメータ検知(DigitalMeterDetection)を行います。

## この記事を読んでわかること
- Brain Builder for AITRIOSの使い方
- PiAICameraの使い方
- ApplicationModuleLibraryの使い方
  

## はじめに
インフラ系の現場では機器のメータを人が目視で読み取っており、苦労していると聞きます。
そこでこの記事では、BrainBuilderのDetector、RaspberryPiから出ているPiAICamera、Applicationを簡単に作れるApplicationModuleLibraryを使ってガスメータを読み取りを行います。

:::note info
この記事は2025年3月16日時点の情報に基づいて作成されています。  
:::

## BrainBuilder
[BrainBuilder](https://developer.aitrios.sony-semicon.com/en/studio/brain-builder)とはSSSのAITRIOSプラットフォーム上でエッジAIモデルを簡単に構築・トレーニングできるツールです。現在は画像分類、物体認識、異常検知等のモデル学習環境を用意しています。BrainBuilderを使うと簡単にPiAICamera上で動作するモデルの学習を行うことができるので、今回はこれを使っていきます！
基本的にはインストール手順から使用方法まで公式ドキュメントの[GetStarted](https://developer.aitrios.sony-semicon.com/en/studio/get-started-guide?version=2024-12-12&progLang=)に記載されています。この記事では公式ドキュメントに従って進めていきます。

 ### 1.インストール＆セットアップ
 BrainBuilderのダウンロードページから各環境にあったインストーラをダウンロードします。５GB以上あるので、PCの容量をあけてからダウンロードしてみてください。 基本は有料サービスなのですが、１０日間の無料トライアルから始めることができます。(2025/3月現在)

![image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/b58fb79c-1bea-40cb-8d62-f9bae9e9b469.png)
インストーラを起動して、指示に従ってインストールを進めます。  


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/28e7fb47-0eea-4e66-a402-baebb096e069.png" width="30%">  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/0796684b-7731-4301-800a-33bfb7442b3e.png" width="30%">  
ライセンスの設定後、BrainBuilderを起動出来たら、アカウントを作成し、ログインします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/88a0dedf-1c00-4d7e-9f3a-ece1b2c7393f.png" width="40%"> 　　
ログインできれば準備完了です！

:::note info
もし上手くインストールできなかった場合は[公式のトラブルシューティングページ](https://support.neurala.com/docs/via-for-sony-aitrios#troubleshooting-via-for-aitrios)をご覧ください。よくある不具合事例がまとめられています。
:::

### 2.データセット作成
ログインするとこのような画面が出てくると思います。自分は既にプロジェクトがありますが、新規にモデルを作りたい場合は右上の`プロジェクトを作成`をクリックします。　　
![image-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/f6d2f8c0-ad71-42ac-b4a2-ad3f08144bd4.png)
 
`新しいデータセットの作成`を選択
![image-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/6d59829d-8b71-43e2-b672-718cbe993365.png)

データセットの名前と使用するモデルタイプを選択します。今回はObjectDetectionを使ってデジタルメータ読み取りを行うので、`Detector`を選択します
![image-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/fb1d1bb9-dca1-4b8d-880e-cd0c0bf733f7.png)

`アップロードデータ`より、学習させたいデータをアップロードします。  
![image-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/2c1472e2-f06a-46ba-bafb-23187e9c50bc.png)

今回は自宅のガスメータをスマホで撮ったものを使います。  
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/84570671-5eee-43ce-8982-408af55919af.jpeg" width="50%">  

### 3.アノテーション
アップロード出来たら次に、アノテーションというAIモデルに正解を教えてあげる作業を行います。
ここでの作業が今から作るAIモデルにとっての正解になるので、とても大切な作業です。BrainBuilderではUIから簡単にアノテーション作業ができます。とはいえ、何枚もの画像をアノテーションするのはなかなか大変ですが、根気よくアノテーションしていきます。
![image-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/41eda020-d10f-42cd-a0a1-3e9c7bee6e47.png)


### 4.学習
一通りアノテーションを終えたら、いよいよモデルの学習です。と言ってもほとんどすることはなく、指示に従ってポチポチしていくだけで学習が始まります。
![image-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/5dd314d2-6f72-41a8-86a0-7aadc10713c6.png)

終わりました！
![image-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/0936237d-917e-43b0-ab4f-666ae5706d63.png)

### 5.検証
学習が終わると、以下の様に検証結果を見ることができます。データセットの一部を学習に使わずに、検証用に振り分け、それを使って精度評価をしてくれます。この学習では同じ数字で角度を変えた画像を数枚学習させただけなので、100%になっています。
![image-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/9bef9981-d48c-419d-b105-d7833f55ed60.png)


検証結果の詳細も見られます。100%となっていた通り、すべて検出されていることが分かります。
![image-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/b0d26010-5f33-45ab-983e-b6e05a7e7b90.png)


それでは学習に使っていない数字を認識させたらどうなるでしょうか？BrainBuilder内で試すことができます。
以下の`テスト`に試したい画像をアップロードします。学習に使っていない数字を含んだ画像をアップロードしてみます。
![image-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/f430ab19-2e0b-4d2b-a1b3-ee24cd436cb8.png)

以下のような結果になりました。0と１は正しく認識できていますが、２は検出されず、７は横の１と合わせて０と認識されてしまっています。今回の学習データでには`0,8,1`しか入っていなかったので、このモデルにとってはこれ以外の数字は認識することができません。そのことから考えると今回の結果は納得です。
![image-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/12ca28fe-cdd4-4511-8853-47276da4703f.png)

学習データセットの一部を使ったデータでの検証では、学習が上手く行ったかの判断はできますが、運用時の精度評価としてはまた別ものであることが分かります。当たり前のことではありますが、`学習データセットと似たデータでの推論`は高い精度が出せ、`学習データセットにないデータの推論`の精度は低くなります。なので、実際に使う環境を意識して、データセット収集、アノテーションを行う事が重要になりそうです。



### 6.モデルのエクスポート
それでは学習したモデルをAI Cameraに載せて動かしていきましょう！！  
ちなみに先ほどのデータでは精度やクラス数で不十分だったので、データを集めて学習し直したモデルを使います。  
`AIモデルのダウンロード`をクリックしてモデルをダウンロードします。
![image-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/96f6156d-5ff2-4a0f-8b77-7b8023508ccb.png)

様々なフォーマットでモデルがエクスポートされます。この後の作業ではモデル変換過程の中間生成物である`PackerOut.zip`を使います。
![image-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/85a00582-af03-49fb-a677-e9493ba689b6.png)

ちなみに”.keras”のモデルを[Netron](https://netron.app/)というアプリで開くと、以下の様にモデルの構造を見ることができます。このブロックのつながりにデータを流すことで、先ほどの様な推論が行われています。ワクワクしますね。
![image-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/31e08c19-f7a6-429d-bdbd-4368d31b5f20.png)


## モデルのパッケージング
[RPiの公式ページのPackaging](https://www.raspberrypi.com/documentation/accessories/ai-camera.html#packaging)を参考にモデルのパッケージングをして行きます。これはモデルをAI Cameraで動作させるために、RPKというファイルにパッケージングする作業です。先ほどダウンロードした`PackerOut.zip`を使います。

```bash
sudo apt install imx500-tools
imx500-package -i <path to packerOut.zip> -o <output folder>
# ex) imx500-package -i ./packerOut.zip -o ./digitalmeter
```
これで`.rpk`が生成されればモデルの準備は完了です！！！

## RaspberryPi AI Cameraの準備  
[RaspberryPi AICamera](https://www.raspberrypi.com/products/ai-camera/)とはソニーが出している[IMX500](https://www.aitrios.sony-semicon.com/edge-ai-devices/imx500)をRaspberryPi用にモジュール化したものです。基本的には[公式ドキュメント](https://www.raspberrypi.com/documentation/accessories/ai-camera.html)を参考にセットアップできます。ただ、英語なので[Raspberry Pi AI Cameraのセットアップ手順](https://qiita.com/daiki0321/items/4223611adb453d6c7aa2)がとてもまとまっていて分かりやすいです。こちらの2章が完了すればOKです！


## ApplicationModuleLibrary(ModLib)
[ModLib](https://github.com/SonySemiconductorSolutions/aitrios-rpi-application-module-library)とはAITRIOSから出している、IMX500向けのアプリケーションを簡単に実装できるライブラリです。今回はこれを使ってDigitalMeterDetectionを行ってみようと思います。まずはサンプルを動かしてみようと思います。
1. git clone  
```bash
git clone https://github.com/SonySemiconductorSolutions/aitrios-rpi-sample-app-gui-tool-client
```
1. ReadMeにある手順に従ってbuild
   
```bash
make build
sudo apt update && sudo apt full-upgrade
sudo apt install imx500-all
sudo apt install python3-opencv python3-munkres python3-picamera2
python -m venv .venv --system-site-packages
. .venv/bin/activate
pip install unify-<version>-py3-none-any.whl
```
3. Exampleの実行    
`aitrios-rpi-application-module-library/examples/aicam/detector.py`のサンプルを実行してみます。ラズパイが出している[Raspberry Pi Model Zoo](https://github.com/raspberrypi/imx500-models)の`SSDMobileNetV2FPNLite320x320`を動かすサンプルです。

```bash
. .venv/bin/activate
python ./examples/aicam/detector.py
```
動きました！  
![image-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/d636c61d-9979-48d6-ada2-56edd1611344.png)

コードを見てみるととてもシンプルですね。これだけでAIモデルを動かせるのは有り難いです。
```python
from modlib.apps import Annotator
from modlib.devices import AiCamera
from modlib.models.zoo import SSDMobileNetV2FPNLite320x320

device = AiCamera() #デバイス選択
model = SSDMobileNetV2FPNLite320x320() #モデル選択
device.deploy(model) #IMX500へデプロイ

#推論結果を表示するモジュール
annotator = Annotator(thickness=1, text_thickness=1, text_scale=0.4)

#推論開始
with device as stream:
    for frame in stream: #１フレーム分のループ処理
        detections = frame.detections[frame.detections.confidence > 0.55]
        labels = [f"{model.labels[class_id]}: {score:0.2f}" for _, score, class_id, _ in detections]
        annotator.annotate_boxes(frame, detections, labels=labels)
        frame.display()
```

### 作成したモデルを動かしてみる
BrainBuilderのモデルをModLibを使って動かしてみたいと思います。基本的には先のサンプルで動かした`SSDMobileNetV2FPNLite320x320`と同じなのですが、BrainBuilderのモデルはoutput tensorの配列が違うので、そこだけ書き換えたclassを用意します。
他のモデルを動かしたいときは`modlib/models/zoo/models.py`にデフォルトで対応しているモデルclassがあるので、参考にしてみてください。

```python
from modlib.apps import Annotator
from modlib.devices import AiCamera
from modlib.models import COLOR_FORMAT, MODEL_TYPE, Model, Detections
from modlib.models.post_processors import pp_od_bcsn
import numpy as np
* from typing import List

# BrainBuilderのモデル用のmodelクラス
class DigitalMeterDetection(Model):
    def __init__(self, model_path, label_path):
        super().__init__(
            model_file=model_path,
            model_type=MODEL_TYPE.RPK_PACKAGED,
            color_format=COLOR_FORMAT.RGB,
            preserve_aspect_ratio=False,
        )
        self.labels = np.genfromtxt(label_path, dtype=str, delimiter="\n")

    def pre_process(self, image: np.ndarray) -> np.ndarray:
        raise NotImplementedError("Pre-processing not implemented for this model.")

    # BrainBuilderモデルのoutput tensorの並びは Boxes - Classes - Scores - Numberなのでbcsnを選択
    def post_process(self, output_tensors: List[np.ndarray]) -> Detections:
        return pp_od_bcsn(output_tensors)

## 以降は基本的に先ほどのサンプルと同じ

device = AiCamera()
# 作成したDMDモデル用のクラス呼び出し
model = DigitalMeterDetection(
                # 先ほど作成したrpkへのpath
                model_path="/home/pi/ws/DigitalMeter-imx500/dm/dmd_v1.rpk",
                # BrainBuilderで生成されたlebels.txtへのPATH
                label_path=f"/home/pi/ws/DigitalMeter-imx500/labels.txt"
                )
device.deploy(model)
annotator = Annotator(thickness=1, text_thickness=1, text_scale=0.4)

with device as stream:
    for frame in stream:
        detections = frame.detections[frame.detections.confidence > 0.55]
        print(detections)
        labels = [f"{model.labels[class_id]}: {score:0.2f}" for _, score, class_id, _ in detections]
        annotator.annotate_boxes(frame, detections, labels=labels)
        frame.display() 
```



## 結果
いざ動作チェック！  
ガスメータの前でラズパイ＆電源をもってうろうろするわけにはいかなかったので、ディスプレイにガスメータを写したものを検出させました。  
![Application_screenshot_16.03.2025.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724579/5f624f9e-81d8-464e-9c61-82732adec656.png)

ちゃんと検出してますね！成功です！

## おわりに
BrainBuilder、PiAICamera、ApplicationModuleLibraryを使って、デジタルメータ検知を行いました。実際の現場ではデジタルメータを人が目視で読み取っており、手間がかかっているケースがあると聞きます。メータ自体をIoT化する手もあると思いますが、Raspberry PiとAICameraを置くだけのソリューションもコストメリットの観点から一つの選択肢になるのではないでしょうか。  
　また、実は今回一番苦労したのがデータセットを集めるところでした。自宅のガスメータだとあまり数字が変わらず、数字のバラエティーを集めるのが大変でした。(いつもより長めにシャワーを浴びてみたのですが…)
結局は同僚にガスメータを送ってもらったり、数字部分だけを加工してデータセットを作りました。おそらく実運用する際にもこのような課題は出てくると思います。最近では今あるデータセットを元に、欲しいデータを生成することも簡単に出来るので、次はそれを試してみたいと思います。

# 困った時は

もし、記事の途中でうまくいかなかった場合は、気軽にこの記事にコメントいただいたり、以下のサポートのページもご覧ください。  
コメントのお返事にはお時間を頂く可能性もありますがご了承ください。

- [Support (FAQ)](https://developer.aitrios.sony-semicon.com/edge-ai-sensing/support)

また、記事の内容以外で AITRIOS についてお困りごとなどあれば以下よりお問い合わせください。
- [Contact Us](https://developer.aitrios.sony-semicon.com/edge-ai-sensing/contact-us)

RaspberryPiに関連する疑問がある場合は、下記フォーラムをご確認、ご活用ください。
- [Raspberry Pi Forums](https://forums.raspberrypi.com/)