1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AITRIOS | Local Console の推論結果をCSV出力してみた

Last updated at Posted at 2024-11-27

SSS の野田です。

Local Edition という、ブラウザを利用せずにローカルPCの環境で AITRIOS のデバイスを動かせるソフトウェアがでましたね。
Local Edition については以下を参照してください。

【紹介記事】

この記事の要約

Local Edition で出力される結果はシリアライズされた txt ファイルとなっているので、サンプルコードを改造してデシリアライズ結果を csv ファイルとして出力してみます。

はじめに

こちらの記事は 2024/09/20 の情報をもとに執筆されています。
今後のアップデートでUIなど仕様が変わる可能性があるので注意してください。

(追記)2024/12/2
現在、Local Edition は v1.4.0 が公開されています。

この記事で紹介している v1.3.0 以前からは大幅にUIが変わっているため、v1.4.0 以降をお使いの方はお気を付けください。

前提

その他

  • Python を少しでも触ったことがあることが望ましいです

目次

  • 推論結果が Windows フォルダに出力された状態になっているか確認する
  • Classification のサンプルコードでデシリアライズしてみる
  • サンプルコードを改造して csv 出力してみる

本文

推論結果が Windows フォルダに出力された状態になっているか確認する

まずは Local Edition 触ってみた!! の記事を参考に推論までしてみます。

私はソニーのイヤホンを使って、イヤホンの色を判別する画像分類ができる AIモデルを作って推論結果を出力してみました。
今回の場合、6種類の Class の中から一番 Score が高い推論結果だけを使いたかったので、Configuration に設定する json 内の dnn_output_classes と max_predictions 値を 以下のように変更しました。
変更した json ファイルは以下です。

{
    "header" :
    {
        "id" : "00",
        "version" : "01.01.00"
    },
    "dnn_output_classes" : 6,
    "max_predictions" : 1
}

Class 数は違っていてもこの後のコードは利用できますが、max_predictions が 1以外の場合はこの後のコードがそのままでは利用できないので注意してください

推論

AIモデルと Edge App のデプロイ、各種設定が終わった状態で
Inference メニューから Start Streaming を実施します。

earphone.png

適宜 Stop Streaming をクリックして推論を停止しましょう。

"Inference" で設定したフォルダに以下のような推論結果ファイル
が txt ファイルとしていくつか出力されていれば csv 化するための事前準備は完了です。

{"DeviceID":"Aid-80050001-0000-2000-9002-00000000016a","ModelID":"0311030000000100","Image":true,"Inferences":[{"T":"20240730082614973","O":"DAAAAAAABgAKAAQABgAAAAwAAAAAAAYACAAEAAYAAAAEAAAAAQAAAAwAAAAIAAwABAAIAAgAAAAEAAAAAABvPw=="}]}

Classification のサンプルコードでデシリアライズしてみる

Local Edition 触ってみた!! の記事にも載っているのですが、今回のCSV化の記事を書くうえで肝になる部分なので改めてこちらにも載せておきます。
Local Consoleで推論結果が表示されましたが、Local Consoleでは一時的にデシリアライズした結果を表示しているだけで、時系列でデータを保存したり、他のアプリケーションで利用する場合には元の推論結果をデシリアライズする必要があります。

そのためには FlatBuffers のバイナリを手に入れる必要があります。
Windows 前提で説明しますが https://github.com/google/flatbuffers/releases
から Windows.flatc.binary.zip をダウンロードして解凍します。
その中の flatc.exe を Local Edition を解凍した時に出来た EdgeApp フォルダにコピーしてください。
(もしくは、EdgeApp フォルダ内の classification.fbs や objectdetection.fbs を flatc.exe と同じ場所にコピーする)

そのうえで、EdgeApp フォルダで Shift+右クリック をして、Git Bash や PowerShell などを開きます。そこで、

./flatc.exe -p ./classification.fbs

を実行すると、その場に SmartCamera フォルダが作成されます。

SmartCameraフォルダがあるディレクトリと同じディレクトリに、チュートリアルで紹介されているPythonのサンプルプログラムを配置します。
inference_dirだけ変えれば利用できると思います。

import os
import base64
import json
from SmartCamera import ClassificationTop

if __name__ == '__main__':
    # Set the path to the directory that stores inference result metadata files.
    inference_dir = '{ここは推論が保存されているディレクトリを記載}'
    ## 例
    ## inference_dir = 'C:\\Users\\UserName\\AppData\\Local\\Temp\\LocalConsole_xp7usx9k\\inferences'

    # Process all inference result files in the inference_dir
    for inf_file in os.listdir(inference_dir) :
        inf_path = '{0}/{1}'.format(inference_dir,inf_file)
        # Read one file in the folder.
        with open(inf_path, 'r', encoding='utf-8') as json_file:
            buf = json.load(json_file)

        # Base64 decode the string in the file.
        if 'O' in buf['Inferences'][0]:
            buf_decode = base64.b64decode(buf['Inferences'][0]['O'])
        else:
            with open('decoded_result_Classification.json', 'w', encoding='utf-8') as file:
                json.dump(buf, file, ensure_ascii=False, indent=4)

        # Deserialize the Base64-decoded string.
        ppl_out = ClassificationTop.ClassificationTop.GetRootAsClassificationTop(buf_decode, 0)
        cls_data = ppl_out.Perception()
        res_num = cls_data.ClassificationListLength()

        # Store the deserialized data in json format.
        buf['Inferences'][0].pop('O')
        for i in range(res_num):
            cls_list = cls_data.ClassificationList(i)
            buf['Inferences'][0][str(i + 1)] = {}
            buf['Inferences'][0][str(i + 1)]['class_id'] = cls_list.ClassId()
            buf['Inferences'][0][str(i + 1)]['score'] = round(cls_list.Score(), 6)

        # Output a json file.
        with open('{0}/decoded_{1}'.format(inference_dir,inf_file), 'w', encoding='utf-8') as file:
            json.dump(buf, file, ensure_ascii=False, indent=4)

これを実行すると、メタデータが保存されているディレクトリにdecoded_で始まるファイルが生成されており、開くとデシリアライズされていることが確認できると思います。

{
    "DeviceID": "Aid-80050001-0000-2000-9002-00000000016a",
    "ModelID": "0311030000000100",
    "Image": true,
    "Inferences": [
        {
            "T": "20240730082614973",
            "1": {
                "class_id": 4,
                "score": 0.933594
            }
        }
    ]
}

サンプルコードを改造して csv 出力してみる

Classification の場合、出力される情報で csv に出力して利用できそうな情報は以下の3つですので、上記のサンプルコードから一部だけ変更を加えて csv を出力できるようにしていきます。

  • 時間
  • class id
  • score

修正後のサンプルコードがこちらになります。
変更箇所は start code と end code で囲ってあります。

import os
import sys
import base64
import json
from pathlib import Path
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
from SmartCamera import ClassificationTop

#################### start code ######################
import csv
#columns = ["filename", "classid", "score"]
with open('data.csv', mode='w', newline='', encoding='utf-8') as f:
        pass  # clear data
#################### end code ########################

if __name__ == '__main__':
    # Set the path to the directory that stores inference result metadata files.
    inference_dir = '{ここは推論が保存されているディレクトリを記載}'
    ## 例
    ## inference_dir = 'C:\\Users\\UserName\\AppData\\Local\\Temp\\LocalConsole_xp7usx9k\\inferences'

    # Process all inference result files in the inference_dir
    for inf_file in os.listdir(inference_dir) :
        #################### start code ######################
        if 'decoded' in inf_file: continue # skip decoded file
        #################### end code ########################
        inf_path = './{0}/{1}'.format(inference_dir,inf_file)
        # Read one file in the folder.
        with open(inf_path, 'r', encoding='utf-8') as json_file:
            buf = json.load(json_file)
        # Base64 decode the string in the file.
        if 'O' in buf['Inferences'][0]:
            buf_decode = base64.b64decode(buf['Inferences'][0]['O'])
        else:
            with open('decoded_result_Classification.json', 'w', encoding='utf-8') as file:
                json.dump(buf, file, ensure_ascii=False, indent=4)
        # Deserialize the Base64-decoded string.
        ppl_out = ClassificationTop.ClassificationTop.GetRootAsClassificationTop(buf_decode, 0)
        cls_data = ppl_out.Perception()
        res_num = cls_data.ClassificationListLength()
        # Store the deserialized data in json format.
        buf['Inferences'][0].pop('O')
        for i in range(res_num):
            cls_list = cls_data.ClassificationList(i)
            buf['Inferences'][0][str(i + 1)] = {}
            buf['Inferences'][0][str(i + 1)]['class_id'] = cls_list.ClassId()
            buf['Inferences'][0][str(i + 1)]['score'] = round(cls_list.Score(), 6)
            #################### start code ######################
            time_filename = inf_file
            time = os.path.splitext(time_filename)[0] #remove extension
            classid = cls_list.ClassId()
            score = round(cls_list.Score(), 6)
            data = [time,classid,score]
            print(data)
            with open('data.csv', 'a', newline='') as f:
                writer = csv.writer(f)
                writer.writerow(data)
            #################### end code ########################
        # Output a json file.
        with open('./{0}/decoded_{1}'.format(inference_dir,inf_file), 'w', encoding='utf-8') as file:
            json.dump(buf, file, ensure_ascii=False, indent=4)

変更した箇所を順に説明します。

まず、csv ファイルを出力するために Python 標準ライブラリの csv モジュールを import します。

import csv

data.csv という名前でファイルを書き込み出来る形で新規作成します
テストで何回も実施する時に、csvにデータが入っている場合は消すようにしておきます。

#columns = ["filename", "classid", "score"]
with open('data.csv', mode='w', newline='', encoding='utf-8') as f:
        pass  # clear data

こちらのコードを2回実行すると decoded_xxx ファイル内のデータ読み取りで Error が起きてしまうのでここではスキップするように修正しておきます。

if 'decoded' in inf_file: continue # skip decoded file

時間情報は json の 'T'から取得しなくてもファイル名に同じ情報が利用されているのでファイル名を利用します。
拡張子は不要なので削除しておきます。

time_filename = inf_file
time = os.path.splitext(time_filename)[0] #remove extension

class_id と score はデシリアライズ後の情報をそれぞれ保存します。

classid = cls_list.ClassId()
score = round(cls_list.Score(), 6)

配列データにして csv ファイルに書き込みます。

data = [time,classid,score]
print(data)
with open('data.csv', 'a', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(data)

こちらの Python を実際に動かしてみます。

csv_before.png

無事に CSV ファイルが出力されていました。

csv_after.png

csv_folder.png

EXCELでも開けました

csv_excel.png

困った時は

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

また、記事の内容以外で AITRIOS についてお困りごとなどあれば以下よりお問い合わせください。

最後に

今回は Local Edition の出力テキストから csv 出力する方法について解説しました。

CSV にメタデータを出力することでデータの転送やバックアップ、データ分析や BI ツールなどでダッシュボードへのデータ入力もやりやすくなると思いますので、是非ご活用ください!

同じ流れで Object Detection でもできるのでリクエストがあれば記事化しますのでご要望あれば是非コメントください。
ご覧いただきありがとうございました!

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?