UnitV2内蔵識別サービス

駆動のインストール

使用のオペレーティングシステムに応じて、適切なSR9900駆動プログラムをダウンロードしてください。

Windows10

駆動圧縮ファイルをデスクトップに解凍->デバイスマネージャーで現在未識別のデバイス(名称はUSB 10/100 LANまたはSR9900を含む)を選択->右クリックでカスタム更新を選択->解凍した圧縮ファイルのパスを選択->確定をクリックして、更新を待ちます。

MacOS

駆動圧縮ファイルを解凍->SR9900_v1.x.pkgファイルをダブルクリックで開きます->指示に従い、次へをクリックしてインストールします。(圧縮ファイル内に詳細バージョンの駆動インストール教程pdfが含まれています)

  • インストール完了後、NICが正常に起動しない場合は、ターミナルを開き、下記のコマンドを入力してNICを再起動できます。
sudo ifconfig en10 down
sudo ifconfig en10 up

機器の接続

USBを接続して電源を供給すると、UnitV2は自動的に起動し、電源LEDは赤と白を表示し、起動完了後は消滅します。UnitV2内部にM5Stack開発の基礎AI識別アプリが統合され、複数の識別機能(顔認識、オブジェクト追跡等の常用機能)が内蔵され、ユーザーは迅速にAI識別アプリを構築することができます。下記の二つの接続方法を通じて、PC端/モバイル端はブラウザでドメインunitv2.pyまたはIP:10.254.239.1を訪問し、識別機能のプレビューページを表示できます。識別過程中、UnitV2はUART(底部HY2.0-4P接口)を通じて、JSON形式の識別サンプルデータ(UART: 115200bps 8N1)を出力します。

注意: 内蔵識別サービスはSafariブラウザ上に部分的な互換性問題が存在、推奨Chromeブラウザで訪問してください。

  • Ethernetモード接続: UnitV2内蔵有線NICを有している、TypeCインタフェースをPCに接続すると、自動的にUnitV2とネットワーク接続が確立されます。

  • APモード接続: UnitV2起動後、既定のAPホットスポット(SSID: M5UV2_XXX: PWD:12345678)を開設、ユーザーはWiFi接続を通じてUnitV2とネットワーク接続を確立できます。

内蔵機能

功能切替

功能ページのナビゲーションバーをクリック、またはSerial Port通信を通じてJSON指令を送信し、異なる識別功能を切替えることができます。 注意: 送信する指令文字列は、末尾以外の位置に改行文字を挿入することはできません。

//function键的值可被指定为下列功能的任意一个
Audio FFT
Code Detector
Face Detector
Lane Line Tracker
Motion Tracker
Shape Matching
Camera Stream
Online Classifier
Color Tracker
Face Recognition
Target Tracker
Shape Detector
Object Recognition
//请注意args必须为一个列表。
{
    "function":"Object Recognition",
    "args":[
        "yolo_20class"
    ]
} 

功能切替応答のデータ形式


//若功能切换成功,将收到回复
{
    "msg":"function switched to Object Recognition."
}

//若指定的功能不存在,将收到回复
{
    "error":"function Object Recognition not exist"
} 

//若功能切换失败,将收到回复
{
    "error":"invalid function."
}

1. Camera Stream

1.1 説明

480Pリアルタイムビデオプレビュー。

480P real-time video preview.

1.2 シリアル操作

切换功能至 Camera Stream

{
    "function": "Camera Stream",
    "args": ""
}

2. Code Detector

2.1 記述します

画面内の二维码を認識し、二维码の座標と内容を返却します。

2.2 ウェブ操作です

2.2 ウェブ操作

機能をCode Detectorに切替えしてください

{
    "function": "Code Detector",
    "args": ""
}

2.3 サンプル出力です

{
    "running":"Code Detector",
    "num":2, // 二维码的数目
    "code":[
        {
            "prob": 0.987152, // 置信率
            "x":10, // 0 ~ 640
            "y":10, // 0 ~ 480
            "w":30,
            "h":30, // 二维码的边界框
            "type":"QR/DM/Maxi",  // include "Background", "QR/DM/Maxi", "SmallProgramCode", "PDF-417", "EAN", "Unknown"
            "content":"m5stack"
        },
        {
            "prob": 0.987152, // 置信率
            "x":10,
            "y":10,
            "w":30,
            "h":30, // 二维码的边界框
            "type":"QR/DM/Maxi",  // include "Background", "QR/DM/Maxi", "SmallProgramCode", "PDF-417", "EAN", "Unknown"
            "content":"m5stack"
        }
    ]
}

3. Object Recongnition

3.1 記述します

YOLO FastestとNanoDetを基礎とした物体検出。V-Trainingをサポート。

3.2 ウェブ操作

  1. 点击Add上传模型文件。tar格式,训练自定义模型请查看教程UnitV2 V-Training
  2. 选中模型后点击Run可以运行指定的模型。(内置模型: nanodet_80class, yolo_20classs可直接运行使用)

3.3 シリアル操作

機能を"Object Recognition"に切り替える


//选择参数“yolo_20class”切换至该功能
{
    "function": "Object Recognition",
    "args": ["yolo_20class"]
}
//选择参数“nanodet_80class”切换至该功能
{
    "function": "Object Recognition",
    "args": ["nanodet_80class"]
}

内蔵モデルがサポートする物体認識


yolo_20class: [
    "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", 
    "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"
]

nanodet_80class: [
        "person","bicycle","car","motorbike","aeroplane","bus","train","truck","boat","traffic light",
        "fire hydrant","stop sign","parking meter","bench","bird","cat","dog","horse","sheep","cow",
        "elephant","bear","zebra","giraffe","backpack","umbrella","handbag","tie","suitcase","frisbee",
        "skis","snowboard","sports ball","kite","baseball bat","baseball glove","skateboard","surfboard",
        "tennis racket","bottle","wine glass","cup","fork","knife","spoon","bowl","banana","apple",
        "sandwich","orange","broccoli","carrot","hot dog","pizza","donut","cake","chair","sofa","pottedplant",
        "bed","diningtable","toilet","tvmonitor","laptop","mouse","remote","keyboard","cell phone","microwave",
        "oven","toaster","sink","refrigerator","book","clock","vase","scissors","teddy bear","hair drier","toothbrush"
]

3.4 サンプル出力です

{
    "num": 1,
    "obj": [
        {
            "prob": 0.938137174,
            "x": 179,
            "y": 186,
            "w": 330,
            "h": 273,
            "type": "person"
        }
    ],
    "running": "Object Recognition"
}

4. Color Tracker

4.1 説明

指定の色の領域を検出し、その領域の座標を返却します。

4.2 ウェブ操作です

LAB阈値のスライダーを調整することで背景を除去し、興味のある色の領域を取得できます。 また、画面上直接に興味のある色の領域を選択し、システムは自動的に該当領域で最も多く占める色を計算し、背景を除去します。計算の基礎上に、さらなるスライダーの調整を行いよりよい除去効果を得ることができます。 "To Mask Mode"ボタンをクリックすると、Maskモードに切り替えられ、該当の除去効果を直接確認できます。再び"To RGB Mode"ボタンをクリックすると、RGBモードに戻ります。

  • 关于CIELAB 色彩空间
  • LAB 阈值被映射至0~255.
  • LAB中的L代表亮度,通常不设置此阈值(0~255),表示忽略亮度带来的影响。但是这将会导致算法无法区分黑色和白色,请注意。
  • 算法只会返回最大的目标

4.3 シリアル操作

以下の操作を実行前に、機能を"Color Tracker"に切り替える

{
    "function": "Color Tracker",
    "args": ""
}

4.3.1 指定LAB阈値

  • Send
    // * LAB阈值映射为0~255
    {
        "config":"Color Tracker",
        "l_min":0// 0 ~ 255
        "l_max":0// 0 ~ 255
        "a_min":0// 0 ~ 255
        "a_max":0// 0 ~ 255
        "b_min":0// 0 ~ 255
        "b_max":0 // 0 ~ 255
  • Receive
    {
        "running":"Color Tracker",
        "msg":"Data updated."
    }
    

4.3.2 指定ROI (自動計算阈値)

  • Send
    {
    {
        "config":"Color Tracker",
        "x":0// 0 ~ 640
        "y":0// 0 ~ 480
        "w":30,
        "h":30,
    }
    
  • Receive
    // * va与vb指的是ROI内的色彩离散程度,若离散度较高则追踪效果较差。
    {
        "running":"Color Tracker",
        "a_cal":0.0,
        "b_cal":0.0// 计算阈值
        "va":0.0,
        "vb":0.0// 颜色分散率
        "l_min":0// 固定值 0
        "l_max":255// 固定值 255
        "a_min":0// a_cal - (10 + (int)(va / 2.0f))
        "a_max":0// a_cal + (10 + (int)(va / 2.0f))
        "b_min":0// b_cal - (10 + (int)(vb / 2.0f))
        "b_max":0  // b_cal + (10 + (int)(vb / 2.0f))

4.4 サンプル出力

{
    "running":"Color Tracker",
    "cx"0// 中心 X 轴坐标
    "cy"0// 中心 Y 轴坐标
    "r"0// 半径
    "mx"0// moment x position
    "my"0 // moment y position
}

5. LaneLine Tracker

5.1 説明

画面内の車道線を検出し、直線に近似化し、その角度と座標を返却します。

5.2 ウェブ操作です

LAB阈値のスライダーを調整することで背景を除去し、興味のある色の領域を取得できます。 また、画面上直接に興味のある色の領域を選択し、システムは自動的に該当領域で最も多く占める色を計算し、背景を除去します。計算の基礎上に、さらなるスライダーの調整を行いよりよい除去効果を得ることができます。 "To Mask Mode"ボタンをクリックすると、Maskモードに切り替えられ、該当の除去効果を直接確認できます。再び"To RGB Mode"ボタンをクリックすると、RGBモードに戻ります。

  • 关于CIELAB 色彩空间
  • LAB 阈值被映射至0~255.
  • LAB中的L代表亮度,通常不设置此阈值(0~255),表示忽略亮度带来的影响。但是这将会导致算法无法区分黑色和白色,请注意。

5.3 シリアル操作

以下の操作を実行前に、機能を"LaneLine Tracker"に切り替える

{
    "function": "Lane Line Tracker",
    "args": ""
}

5.3.1 指定 LAB 阈值

  • Send
     // * LAB阈值映射为0~255
    {
        "config":"Lane Line Tracker",
        "l_min":0// 0 ~ 255
        "l_max":0// 0 ~ 255
        "a_min":0// 0 ~ 255
        "a_max":0// 0 ~ 255
        "b_min":0// 0 ~ 255
        "b_max":0// 0 ~ 255
    }
    
  • Receive
    {
        "running":"Lane Line Tracker",
        "msg":"Data updated."
    }
    

5.3.2 指定ROI (自动计算阈值)

  • Send
    {
        "config":"Lane Line Tracker",
        "x":0// 0 ~ 640
        "y":0// 0 ~ 480
        "w":30,
        "h":30,
    }
    
  • Receive
    //* va与vb指的是ROI内的色彩离散程度,若离散度较高则分割效果较差。
    {
        "running":"Lane Line Tracker",
        "a_cal":0.0,
        "b_cal":0.0// 计算阈值
        "va":0.0,
        "vb":0.0// 颜色分散率
        "l_min":0// 固定值 0
        "l_max":255// 固定值 255
        "a_min":0// a_cal - (10 + (int)(va / 2.0f))
        "a_max":0// a_cal + (10 + (int)(va / 2.0f))
        "b_min":0// b_cal - (10 + (int)(vb / 2.0f))
        "b_max":0  // b_cal + (10 + (int)(vb / 2.0f))

5.4サンプル出力です

{
    "running":"Lane Line Tracker",
    "x":0,
    "y":0// 拟合线的基点
    "k":0  // 拟合线斜率

6. Target Tracker

6.1 説明

画面上の指定した目標を追跡します。MOSSEアルゴリズムを使用。

6.2 ウェブ操作

画面上で興味のある目標を選択するだけ。

6.3 シリアル操作

以下の操作を実行前に、機能を"Target Tracker"に切り替える


{
    "function": "Target Tracker",
    "args": ""
}

6.4 サンプル出力

{
    "running":"Target Tracker",
    "x":0,//0~640
    "y":0,//0~480
    "w":0,
    "h":0

7. Motion Tracker

7.1 説明

動くものを検出し追跡し、その座標と角度を返却します。

7.2 ウェブ操作

'Set as background'ボタンをクリックして背景を確定します。このアルゴリズムは緩やかに変化する背景にも対応できます。

7.3 シリアル操作

以下の操作を実行前に、機能を"Motion Tracker"に切り替える

{
    "function": "Motion Tracker",
    "args": ""
}

7.3.1 背景の確定

  • Send

    // 发送这条指令将会确定背景
    {
        "config":"Motion Tracker",
        "operation":"update"
  • Receive

    {
        "running":"Motion Tracker",
        "msg":"Background updated."
    }
    

7.4 サンプル出力です

{
    "running":"Motion Tracker",
    "num":2,
    "roi":[
        {
            "x":0,
            "y":0,
            "w":0,
            "h":0,
            "angle":0.0,
            "area":0
        },
        {
            "x":0,
            "y":0,
            "w":0,
            "h":0,
            "angle":0.0,
            "area":0
        }
    ]
} 

8. Online Classifier

8.1 説明

緑色の目標枠内の物体をリアルタイムで訓練し分類できます。訓練得られた特徴量はデバイス上に保存して、次回利用できます。

8.2 ウェブ操作

  1. 'Reset'ボタンをクリックして既存のカテゴリーをクリアし、訓練モードに移行。
  2. 点击'+'按钮创建新的类别。
  3. '+'ボタンをクリックして新しいカテゴリーを作成。
  4. 訓練したいカテゴリーを選択。
  5. 'Train'ボタンをクリックして一度の訓練を完了。
  6. 物体の角度を変化させて重複訓練を行い、予想の効果を達成するまで。
  7. save&run'ボタンをクリックして訓練結果をデバイス上に保存し、訓練モードを終了し、物体認識分類を開始。

8.3 シリアル操作

以下の操作を実行前に、機能を"Online Classifier"に切り替える


{
    "function": "Online Classifier",
    "args": ""
}

8.3.1 Train

  • Send

    //这条指令将使设备进入训练模式,并提取一次特征存储到指定的分类下。若class_id不存在,则会创建这个类。
    {
        "config":"Online Classifier",
        "operation":"train",
        "class_id":1// Integer (0 ~ N), class的ID
        "class":"class_1" // String, class的名字
    }
    
  • Receive

    {
        "running":"Online Classifier",
        "msg":"Training [class name] [num of training] times"
    }
    

8.3.2 Save&Run

  • Send

    {
        "config":"Online Classifier",
        "operation":"saverun",
    }
    
  • Receive

    {
        "running":"Online Classifier",
        "msg":"Save and run."
    }
    

8.3.3 Reset

  • Send

    //这条指令将会使设备进入训练模式并清除所有的分类。
    {
        "config":"Online Classifier",
        "operation":"reset",
    } 
    
  • Receive

    {
        "running":"Online Classifier",
        "msg":" Please take a picture."
    }
    

8.4 サンプル出力

{
    "running":"Online Classifier",
    "class_num":2// 识别出的class数目
    "best_match":"class_1"// 最佳匹配class
    "best_score":0.83838// 最佳匹配分数
    "class":[ // 每一个class的分数
        {
            "name":"class_1",
            "score":0.83838
        },
        {
            "name":"class_2",
            "score":0.66244
        }
    ]
}

9. Face Recognition

9.1 説明

人臉を検出し認識します。

9.2 ウェブ操作です

  1. Resetボタンをクリックして既存の全部の顔をクリア。
  2. +ボタンをクリックして新しい顔を作成。
  3. 訓練したい顔を選択。
  4. カメラを向いて、訓練したい顔を適切な位置に配置。
  5. Trainボタンをクリック。
  6. 訓練中、境界ボックスが黄色のときは訓練中、ゆっくりと頭を動かして異なる角度のサンプルを取得し、よりよい認識効果を得ることができます。
  7. 境界ボックスが赤色になったら対象が失われました。通常は顔の変化が大きすぎる為、顔の位置を調整して再び顔が認識されるまで待ちます。
  8. 予想の効果を達成したらStopをクリック、今後デバイスはこの顔を認識できるようになります。
  9. Saveボタンをクリックして特徴データをデバイス上に保存し、次回利用できるようにします。

9.3 シリアル操作

以下の操作を実行前に、機能を"Face Recognition"に切り替える

{
    "function": "Face Recognition",
    "args": ""
}

9.3.1 Train

  • Send

    //若要创建一个新的面孔,请按顺序提供face_id (0 ~ N)。
    {
        "config":"Face Recognition",
        "operation":"train",
        "face_id":1// Integer (0 ~ N), 面孔的ID
        "name":"tom" // String, 面孔的名字
    }
    //举例,目前已经有了3个面孔(0~2),要创建新的面孔,需要将id指定为3。
    
  • Receive (Success)

    {
        "running":" Face Recognition ",
        "msg":"Training tom" // 培训面名称
    }
    
  • Receive (Error)

    {
        "running":"Face Recognition",
        "msg":"Invalid face id"
    }
    

9.3.2 Stop Train

  • Send

    {
        "config":" Face Recognition ",
        "operation":" stoptrain",
    }
    
  • Receive

    {
        "running":"Face Recognition",
        "msg":"Exit training mode."
    }
    

9.3.3 Save&Run

  • Send

    {
        "config":" Face Recognition ",
        "operation":"saverun",
    }
    
  • Receive

    {
        "running":"Face Recognition",
        "msg":"Faces saved."
    }
    

9.3.4 Reset

  • Send

    //这条指令将会删除全部的面孔。
    {
        "config":"Face Recognition",
        "operation":"reset",
    }
    
  • Receive

    {
        "running":"Face Recognition",
        "msg":"Reset success"
    }
    

9.4サンプル出力です

9.4.1 Training Mode

{
    "running":"Face Recognition",
    "status":"training"// training(培训) or missing(丢失)
    "x":0,
    "y":0,
    "w":0,
    "h":0//  面部识别边界框
    "prob":0// 检测置信率
    "name":0,
}

9.4.2 Normal Mode (匹配得分>0.5)

{
    "running":"Face Recognition",
    "num":1// 识别出面部的数目
    "face":[
        {
            "x":0// 0 ~ 320
            "y":0// 0 ~ 240
            "w":30,
            "h":30// 面部识别边界框
            "prob":0// 检测置信率
            "match_prob":0.8// 匹配置信率
            "name""tom",
            "mark":[ // landmarks
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
            ]
        },
    ]
} 

9.4.3 Normal Mode (匹配得分<=0.5)

{
    "running":"Face Recognition",
    "num":1//  识别出面部的数目
    "face":[
        {
            "x":0// 0 ~ 320
            "y":0// 0 ~ 240
            "w":30,
            "h":30// 面部识别边界框
            "prob":0// 置信率
            "name""unidentified",
            "mark":[ // landmarks
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
            ]
        },
    ]
} 

10. Face Detector

10.1 説明

画面内の形状を検出し、5点のランドマークを出力。

10.2 ウェブ操作です

10.3 シリアル操作

以下の操作を実行前に、機能を"Shape Detector"に切り替える

{
    "function": "Face Detector",
    "args": ""
}

10.4サンプル出力です

{
    "running":"Face Detector",
    "num":1//  识别出面部的数目
    "face":[
        {
            "x":0,
            "y":0,
            "w":30,
            "h":30// 面部识别边界框
            "prob":0// 置信率
            "mark":[ // landmark
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                },
                {
                    "x":0,
                    "y":0
                }
            ]
        }
    ]
}

11. Shape Detector

11.1 記述します

任意の形状(が、形状に曲線は含まないことが望ましい)をマッチングします。アップロードした形状は特徴データとしてデバイス上に保存され、次回利用できます。

11.2 ウェブ操作です

「Set as background」ボタンをクリックして背景を確認します。このアルゴリズムは緩やかな変化の背景にも対応します。

11.3 シリアル操作

以下の作業を行う前に、Shape Detectorに機能を切り替えてくださいますように

{
    "function": "Shape Detector",
    "args": ""
}
  • Send

    // 发送这条指令将会确定背景
    {
        "config":"Shape Detector",
        "operation":"update"
  • Receive

    {
        "running":"Shape Detector",
        "msg":"Background updated."
    }
    

    11.4サンプル出力です

{
    "running":"Shape Detector",
    "num":2,
    "shape":[
        {
            "name":"Rectangle"// "unidentified", "triangle", "square", "rectangle", "pentagon", "circle"
            "x":0,
            "y":0,
            "w":0,
            "h":0,
            "angle":0.0// 可在形状为正方形或矩形时使用
            "area":0
        },
        {
            "name":"Rectangle"// "unidentified", "triangle", "square", "rectangle", "pentagon", "circle"
            "x":0,
            "y":0,
            "w":0,
            "h":0,
            "angle":0.0// 可在形状为正方形或矩形时使用
            "area":0
        }
    ]
} 

12. Shape Matching

12.1 記述します

デバイス上のマイクを通じて音声をキャプチャし、リアルタイムFFT(高速フーリエ変換)を施行し、時間-周波数のグラフを描画します。下の緑色のグラフは音声のRMS、即ち現在の音量を表示。

12.2 ウェブ操作です

  1. クリック "add" ボタンで形状を追加します。形状のテンプレート画像(PNG形式、黒色の形状と白色の背景)をアップロードが必要です。ファイル名は形状の名前になります。
  2. "reset" ボタンをクリックすると、すべての既にアップロードした形状をクリアできます。
  3. "Set as background" ボタンをクリックして背景を確定します。このアルゴリズムは徐々に変化する背景に適応できます。

12.3 シリアル操作

未サポート、現在開発中です。

12.4サンプル出力です

// 这里返回的shape就是上传的模板的文件名,请注意若置信率低于30%则会被标识为unidentified。
{
    "running":"Shape Matching",
    "num":2,
    "shape":[
        {
            "name":"arrow"// 您的自定义形状名称,当置信率小于30时无法识别
            "max_score":83// 置信率评分,如果形状不明,就没有
            "x":0,
            "y":0,
            "w":0,
            "h":0,
            "area":0
        },
        {
            "name":"unidentified"// 您的自定义形状名称,当信心分数小于30时无法识别
            "x":0,
            "y":0,
            "w":0,
            "h":0,
            "area":0
        },
    ]
} 

13. Audio FFT

13.1 記述します

デバイスのマイクを利用して音声をキャプチャし、リアルタイムFFT(高速フーリエ変換)を適用し、時間-周波数図を描画します。下の緑色のグラフは音声のRMSを表示し、現在の音量を示します。

  • マイクの応答遮断周波数は約10KHzです。

13.2 ウェブ操作です

13.3 シリアル操作

None

13.4サンプル出力です

None

串口读取

识别过程中,UnitV2将通过串口(底部HY2.0-4P接口)不断输出识别样本数据(JSON格式,UART: 115200bps 8N1)。下方分别为不同平台下读取识别结果的案例程序。

Arduino

認識過程中、UnitV2はシリアルポート(底部HY2.0-4P接口)を介して、継続的に認識サンプルデータ(JSON形式、UART: 115200bps 8N1)を出力します。以下は異なるプラットフォーム下の認識結果の読み取りのサンプルプログラムです。


void setup() {

  Serial.begin(115200);
  Serial2.begin(115200, SERIAL_8N1, 16, 17);

}

void loop() {

 if(Serial2.available()) {
   String recvStr = Serial2.readStringUntil('/n');
   if(recvStr[0] == '{'){
     Serial.print(recvStr);
   }
 }
  
}

Micropython


import machine
import json

uart1 = machine.UART(1, tx=16, rx=17)
uart1.init(115200, bits=8, parity=None, stop=1)

PROTOCOL_START = b'{'[0]

while True:
  if uart1.any():
    data = uart1.readline()
    if data[0] == PROTOCOL_START:
        json_data = json.loads(data)

使用python调用模型文件


from json.decoder import JSONDecodeError
import subprocess
import json
import base64
import serial
import time
from datetime import datetime
from PIL import Image
import os
import io

uart_grove = serial.Serial('/dev/ttyS0', 115200, timeout=0.1)
reconizer = subprocess.Popen(['/home/m5stack/payload/bin/object_recognition', '/home/m5stack/payload/uploads/models/nanodet_80class'],
                             stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

reconizer.stdin.write("_{\"stream\":1}\r\n".encode('utf-8'))
reconizer.stdin.flush()

img = b''

while True:
    today = datetime.now()
    path = str(today.strftime("%Y_%m_%d") + "/")
    newpath = "/media/sdcard/" + path

    line = reconizer.stdout.readline().decode('utf-8').strip()
    if not line:
        break  # Process finished or empty line

    try:
        doc = json.loads(line)
        if 'img' in doc:
            byte_data = base64.b64decode(doc["img"])
            img = bytes(byte_data)
        elif 'num' in doc:
            for obj in doc['obj']:
                uart_grove.write(str(obj['type'] + '\n').encode('utf-8'))
                if obj['type'] == "aeroplane":
                    print('aeroplane ' + today.strftime("%Y_%m_%d_%H_%M_%S"))
                    if os.path.exists(newpath):
                        image_path = newpath + today.strftime("%Y_%m_%d_%H_%M_%S") + ".jpg"
                        img = Image.open(io.BytesIO(byte_data))
                        img.save(image_path, 'jpeg')
                    else:
                        os.mkdir(newpath)
                        image_path = newpath + today.strftime("%Y_%m_%d_%H_%M_%S") + ".jpg"
                        img = Image.open(io.BytesIO(byte_data))
                        img.save(image_path, 'jpeg')
                    time.sleep(1)
                else:
                    print('Not detect '+ today.strftime("%Y_%m_%d_%H_%M_%S"))
    except JSONDecodeError as e:
        print("Error: Invalid JSON string")
        print("JSONDecodeError:", str(e))
On This Page