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更新)
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!

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

Kria
Kria SOMはアダプティブSoCデバイスを搭載しており、スマートカメラやエンベデッドビジョンなどに最適です。
AMD製品に関連する技術ブログ
- エンジニアブログの再開およびテクニカルウェビナーのご案内
- 初心者のためのPython & Numpy入門
- KR260でIntel RealSenseを動かしてみた!
- Vitis HLSで足し算IPを作ってみた!(プログラミング編)
- KD240でモータ制御してみた!
- KR260でデジタル信号処理してみた! (3)
- KR260でデジタル信号処理してみた! (2)
- KR260でデジタル信号処理してみた! (1)
- KR260でロボットアームを動かしてみた! (2)
- KR260でロボットアームを動かしてみた! (1)
- KR260でROS2を使ってキャリブレーション&マーカー検出してみた!
- KR260とPynqでAIカメラを動かしてみた!
- KR260でROS2 Perception Stack Applicationを動かしてみた!【2】
- KR260でROS2 Perception Stack Applicationを動かしてみた!
- Kria SOMでTPM2.0を動かしてみた!
- VivadoでKR260のハードウェアデザインを作って動かしてみた!
- ROS2 Multi-Node Communications via TSNを動かしてみた!
- AIBOX-ReIDを動かしてみた!