Custom Meta Tags

2503 Hero Banner

AMD製品に関連する技術ブログ

Long Copy

KR260とPynqでAIカメラを動かしてみた!

皆さん、こんにちは。新人エンジニアの「ノリさん」です!

今回はAIカメラをKR260とPynqにより動かしていきたいと思います。

PYNQ は、PythonでFPGAを利用するためのフレームワークです[1] 。典型的には、SoC タイプの FPGA のプロセッサ側で Linux が走り、その上で実行される Jupyter Notebook を使って Web ブラウザから Python でプログラマブルロジック上のハードウェアを制御できます[1]

今回は、ハードウェアのデザインをすることなく、KV260のようにAIカメラを動かすことを目的としています。

[1] https://www.acri.c.titech.ac.jp/wordpress/archives/29#toc1より引用

2023-09-01
(2023-10-17更新)

Long Copy_1

Step0:ハードウェア要件

  • KR260 Robotics Starter Kit ( /japan/products/product-highlights/xilinx-kr260 )
  • KR260用電源(KR260 Robotics Starter Kit に付属)
  • USB-A to micro-B ケーブル(KR260 Robotics Starter Kit に付属)
  • マイクロSDカード(最低16GB、KR260 Robotics Starter Kit に付属しているものでOK)
  • LANケーブル(KR260 Robotics Starter Kit に付属)

 

Step1: Pynqの導入

初めにaptのアップデートとアップグレードを行います。

sudo apt update
sudo apt upgrade

Kria-PYNQ の githubから git cloneします。

git clone https://github.com/Xilinx/Kria-PYNQ.git

Pynqをインストールします。

cd Kria-PYNQ
sudo bash install.sh -b KR260

 

Step2:PynqによるAIカメラプログラムの作成

AIカメラプログラムに必要なPythonライブラリをインストールします。

pip install ultralytics

モデルをダウンロードします。

wget https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt 

ダウンロードしたモデルをJupyter Notebookのあるディレクトリに移動させます。

mv yolov8n.pt /home/root/jupyter_notebooks

IPアドレスを確認します(次のコマンドでIPアドレスが表示されない場合はeth1をeth0に変更)。

ifconfig eth1

次のように表示されるので、inetの横に書かれているIPアドレスをコピーしてWebブラウザに貼り付け、Jupyter Notebook のページに移動します(ログインパスワードはxilinxです)。

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
           inet 192.168.1.36  netmask 255.255.255.0  broadcast 192.168.1.255
           ... (中略)

無事にページの移動とログインができた場合、次のような画面が表示されます。 画面右上のNewからPython3 (ipykernel) を選択して新しいPythonカーネルを立ち上げてください。

Jupter Notebook上のコマンド及びプログラムはshift + enter で実行できます。

AIカメラプログラムに必要なPythonライブラリをインストールします。

pip install ultralytics

次のソースコードをコピー&ペーストしてください。 (https://zenn.dev/opamp/articles/51ee26445a1732 を参考にさせていただきました)

from ultralytics import YOLO
import torch
import cv2
from ultralytics.data.augment import LetterBox
from ultralytics.utils.plotting import Annotator, colors
from ultralytics.utils import ops
from ultralytics.yolo.data.augment import LetterBox
from ultralytics.yolo.utils.plotting import Annotator, colors
from ultralytics.yolo.utils import ops
from copy import deepcopy
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, Image, clear_output

model = YOLO("yolov8n.pt") # モデルの設定
cap = cv2.VideoCapture(0) # カメラからデバイス情報を取得
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) # 表示画像の幅を設定
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 表示画像の高さを設定
cap.set(cv2.CAP_PROP_FPS, 60) # 表示画像のfpsを設定

# 画像を出力する関数
def imshow(frame):
    _, buf = cv2.imencode(".jpg", frame) # エンコード方法にJPEGを指定
    display(Image(data=buf.tobytes()))
    clear_output(wait=True)

# 前処理を行う関数
def preprocess(frame, size=160):
        frame = LetterBox(size, True)(image=frame) # レターボックス化
        frame = frame.transpose((2, 0, 1))[::-1] # HWCからCHW、BGRからRGBへの変換
        frame = np.ascontiguousarray(frame) # 配列が連続したメモリに位置するよう配置し直す
        frame = torch.from_numpy(frame) # numpy配列からPytorch Tensor への変換
        frame = frame.float() # 画像をintからfloatに変換
        frame /= 255 # 画像のRGB値を255で割ることで0から1への値に正規化
        return frame.unsqueeze(0)

# 後処理を行う関数
def postprocess(preds, frame, orig_frame):
    
    # Non Maximum Suppression
    preds = ops.non_max_suppression(preds, 0.25, 0.8, agnostic=False, max_det=100)
    
    # 推論結果をBoundingBoxに変換
    for _, pred in enumerate(preds):
        shape = orig_frame.shape
        pred[:, :4] = ops.scale_boxes(frame.shape[2:], pred[:, :4], shape).round()

    return preds

# ラベル付きBoundingBoxを描画する関数
def drow_bbox(pred, names, annotator):
    for *bbox, conf, cls in reversed(pred):
        label =  f'{names[int(cls)]} {conf:.2f}'
        annotator.box_label(bbox, label, color=colors(cls, True))

# メイン処理
while True:
    try:
        ret, frame = cap.read() # デバイス情報から読み込み情報と画像を取得
        
        # 画像が読み込めていない場合は処理を打ち切る
        if not ret:
            break
            
        orig_frame = deepcopy(frame)
        annotator = Annotator(orig_frame, line_width=1, example=str(model.model.names)) # ラベルの情報を取得
        frame = preprocess(frame) # 前処理
        preds = model.model(frame, augment=False) # 推論
        preds = postprocess(preds, frame, orig_frame) # 後処理
        drow_bbox(preds[0], model.model.names, annotator) # 入力画像にラベル付きBoundingBoxを描画
        imshow(orig_frame) # 処理された画像を出力
    
    # 停止ボタン■で停止
    except KeyboardInterrupt:
        break

cap.release()

実行に成功した場合、次の様な結果が得られます。

感想

個人的にVision-AIと言えばKV260だったのですが、KR260でもハードウェアデザインを新しく作成することなく、Vision-AIを動作させられたので、驚きました。次回もPynqを使う予定ですので、楽しみにしていてください。それでは、また次回お会いしましょう!See you next time!

 

 

2503 Grid Box Light - Blog

ブログ

AMDによる設計およびデバッグ手法のブログ、およびアヴネット社員によるAMD製品を用いた開発チャレンジのブログです。

2503 Grid Box Light - Kria

Kria

Kria SOMはアダプティブSoCデバイスを搭載しており、スマートカメラやエンベデッドビジョンなどに最適です。