Cloud-Native Demo on Jetson を試す

May 28, 2020

https://github.com/NVIDIA-AI-IOT/jetson-cloudnative-demo

Cloud-Native Demo on Jetson を試したいと思います。

4つのデモンストレーションがありますが、目を引くのは、Pose detectionではないでしょうか。

やってみたい。

Docker で試す

ガイドでは、Docker での使用を説明しました。
素直に従います。

git clone https://github.com/NVIDIA-AI-IOT/jetson-cloudnative-demo
sudo apt-get install xdotool
cd jetson-cloudnative-demo
# sudo ./run_demo.sh ではなく、
sudo ./run_pose.sh

WEBカメラで試す

サンプルは、事前に撮影された動画に対する解析ですが、ここはやはり、WEBカメラで動作させたいところです。

Docker コンテナにはいる

run_pose.sh を改造して、楽をします。

cp run_pose.sh run_pose2.sh して、作成します。

変更が残るように -rm を削除、
WEBカメラ /dev/video0 を使用できるように、--device /dev/video0:/dev/video0:mwr 追加、
シェルに入るだけでいいので、最後のコマンドも削除。

Video は不要といえば不要ですが、
残しました。

#!/usr/bin/env bash

CONTAINER=nvcr.io/nvidia/jetson-pose:r32.4.2

ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
HOST_VIDEO_DIR="$ROOT_DIR/Videos"
HOST_VIDEO_NAME=
VIDEO=/videos/pose_video.mp4
#VIDEO=/userVideos/$HOST_VIDEO_NAME

echo Running pose

sudo nvpmodel -m 2
sudo jetson_clocks
xhost +

sudo xhost +si:localuser:root

sudo docker run --runtime nvidia -it --network host -e DISPLAY=$DISPLAY -v /tmp/.X11-unix/:/tmp/.X11-unix -v $HOST_VIDEO_DIR:/userVideos/ --device /dev/video0:/dev/video0:mwr --cpuset-cpus=2,3 $CONTAINER

そして、

sudo ./run_pose2.sh

コンテナ内の構造

# ls /
bin   dev  home  media  opt   proc  run   srv  tmp        trt_pose    usr    var     vision
boot  etc  lib   mnt    pose  root  sbin  sys  torch2trt  userVideos  utils  videos

# ls /userVideos/
gaze_video.mp4  pose_video.mp4

# ls /dev/video0 
/dev/video0

/userVideo/dev/video0 が作られています。

/utils/video.py を改造して /utils/cam.py を作成します。

使用可能な解像度

刺したWEBカメラで利用可能な解像度を確認します。

$ sudo apt-get install v4l-utils
$ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.042s (24.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.133s (7.500 fps)
                        Interval: Discrete 0.200s (5.000 fps)
(中略)

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.042s (24.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.133s (7.500 fps)
                        Interval: Discrete 0.200s (5.000 fps)

大量にリストされます。

大きく YUYV フォーマットと、MJPG フォーマットが有ることがわかります。

Size: Discrete 960×720 15.0 fps を使用しましょう。

cam.py

import cv2

class Cam(object):

    def __init__(self, width, height, qsize=10, loop=True, codec='h264'):
        self.width = width
        self.height = height
        self.qsize = qsize
        self.loop = loop
        self.codec = codec
        self.reset()

    def _gst_str(self):
        return 'filesrc location={path} ! qtdemux ! queue max-size-buffers={qsize} ! {codec}parse ! omx{codec}dec ! nvvidconv ! video/x-raw,format=BGRx ! queue max-size-buffers={qsize} ! videoconvert ! queue max-size-buffers={qsize} ! video/x-raw,format=BGR,width={width},height={height} ! appsink sync=0'.format(path=self.path, width=self.width, height=self.height, qsize=self.qsize, codec=self.codec)

    def reset(self):
        if hasattr(self, 'cap'):
            del self.cap
        self.cap = cv2.VideoCapture(0, cv2.CAP_GSTREAMER)
        self.cap.set(cv2.CAP_PROP_FPS, 15)
        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 960)
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

    def read(self):
        re, img = self.cap.read()
        if re:
            return img
        elif self.loop:
            self.reset()
            re, img = self.cap.read()
            if re:
                return img
            else:
                return None
        else:
            return None

    def destroy(self):
        self.cap.release()

_gst_str 関数だとかは、適当です。

cp run_pose_pipeline.py run_pose_pipeline.cam.py

変更箇所

from cam import Cam

(略)

    # parser.add_argument('video')
    parser.add_argument('--width', type=int, default=960)
    # parser.add_argument('--height', type=int, default=540)
    parser.add_argument('--height', type=int, default=720)
    parser.add_argument('--loop', action="store_true")
    parser.add_argument('--codec', type=str, default='h264')
    args = parser.parse_args()

    # media
    # video = Video(args.video, args.width, args.height, loop=args.loop, codec=args.codec)
    video = Cam(args.width, args.height, loop=args.loop, codec=args.codec)
    display = Display(args.width, args.height)

これで、とりあえずは動きます。

python3 run_pose_pipeline.cam.py

15FPS 前後でした。

終了できない・・・

Ctrl + c でもプロセスが止まりません。

Ctrl + z で停止させて、kill %1 などで kill しましょう。