[Kinesis Video Streams] Jetson Nano上でインテル® RealSense の画像を処理すると同時にKinesis Video Streamsに送信してみました

2021.02.22

1 はじめに

CX事業本部の平内(SIN)です。

今回は、Jetson Nano上で、インテル® RealSense の画像を処理する(今回は、表示しているだけ)と同時に、Kinesis Video Streamsに送信する要領を確認してみました。

2 構成

構成は、以下のようなイメージです。

  • インテル® RealSense の画像は、pyrealsense2でPythonスクリプトに取り込みます
  • OpenCVは、GStreamerを入出力IOとして利用できるように構成します
  • GStreamerは、ソースをappsrc、シンクをkvssinkとして構成します
  • pyrealsense2から受け取った画像は、OpenCVのVideoWriterでGStreamerへ出力します

3 Python Wrapper

RaealSenceは、公式のラッパーをインストールし、Pythonから利用しています。 IntelRealSense/librealsense/wrappers/python/

$ git clone https://github.com/IntelRealSense/librealsense.git
$ cd librealsense
$ mkdir build && cd build
$ which python3
/usr/bin/python3
$ cmake ../ -DBUILD_PYTHON_BINDINGS:bool=true -DPYTHON_EXECUTABLE=/usr/bin/python3
$ make -j4
$ sudo make install
$ export PYTHONPATH=$PYTHONPATH:/usr/local/lib

途中CMakeが、「The Xinerama headers were not found」で止まってしまったので下記を追加しました。

$ sudo apt-get install libsdl2-dev

Pythonから利用可能になっているようすです。

$ python3
Python 3.6.9 (default, Oct  8 2020, 12:12:24)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyrealsense2.pyrealsense2 as rs
>>> rs.__version__
'2.42.0'
>>>

4 OpenCVのVideo I/O

JetPackでセットアップされたOpenCVは、ビデオ入出力で、GStreamer:YES (1.14.5) となっているので、そのまま利用可能です

$ python3
Python 3.6.9 (default, Oct  8 2020, 12:12:24)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> print(cv2.getBuildInformation())

General configuration for OpenCV 4.1.1 =====================================
  Version control:               4.1.1-2-gd5a58aa75

  Platform:
    Timestamp:                   2019-12-13T17:25:11Z
    Host:                        Linux 4.9.140-tegra aarch64
    CMake:                       3.10.2
    CMake generator:             Unix Makefiles
    CMake build tool:            /usr/bin/make
    Configuration:               Release

・・・略・・・

  Video I/O:
    FFMPEG:                      YES
      avcodec:                   YES (57.107.100)
      avformat:                  YES (57.83.100)
      avutil:                    YES (55.78.100)
      swscale:                   YES (4.8.100)
      avresample:                NO
    GStreamer:                   YES (1.14.5)
    v4l/v4l2:                    YES (linux/videodev2.h)

5 GStreamer

GStreamerでは、入力(appsrc)と出力(appsink)にOpenCVを使用する事ができます。

OpenCVとGStreamerの連携は、概ね以下の通りです。

ソースをappsrcとし、kvssinkまでのパイプラインを、そのまま、OpenCVの VideoWriter() に設定します。 送信するフレームは、VideoWriterオブジェクトに write(frame) するだけです。

GSTERAMER = 'appsrc ! パイプライン ! kvssink'
out = cv2.VideoWriter(GSTERAMER, cv2.CAP_GSTREAMER, 0, fps, (width, height), True)
out.write(frame);

6 コード

Jetson Nano上で動作しているコードです。

pyrealsense2から受け取ったオブジェクトをOpenCVで扱うためには、numpy arrayに変換が必要です。

# -*- coding: utf-8 -*-
import pyrealsense2.pyrealsense2 as rs
import numpy as np
import cv2

WIDTH = 640
HEIGHT = 480

# ストリーミング初期化
config = rs.config()
config.enable_stream(rs.stream.color, WIDTH, HEIGHT, rs.format.bgr8, 30)
config.enable_stream(rs.stream.depth, WIDTH, HEIGHT, rs.format.z16, 30)

# ストリーミング開始
pipeline = rs.pipeline()
profile = pipeline.start(config)

# 距離[m] = depth * depth_scale 
depth_sensor = profile.get_device().first_depth_sensor()
depth_scale = depth_sensor.get_depth_scale()
clipping_distance_in_meters = 0.4 # 40cm以内を検出
clipping_distance = clipping_distance_in_meters / depth_scale

# Alignオブジェクト生成
align_to = rs.stream.color
align = rs.align(align_to)

GSTERAMER = 'appsrc ! videoconvert ! nvvidconv ! nvv4l2h264enc ! h264parse ! video/x-h264,stream-format=avc,alignment=au,profile=baseline ! kvssink stream-name=Sample000 storage-size=512 access-key=xxxxxxxx secret-key=xxxxxxxxxxxxxxxx aws-region=ap-northeast-1'
try:
	out = cv2.VideoWriter(GSTERAMER, cv2.CAP_GSTREAMER, 0, 15, (640, 480), True)
	while True:
		frames = pipeline.wait_for_frames()
		aligned_frames = align.process(frames)
		color_frame = aligned_frames.get_color_frame()
		depth_frame = aligned_frames.get_depth_frame()
		if not depth_frame or not color_frame:
			continue
		color_image = np.asanyarray(color_frame.get_data())
		depth_image = np.asanyarray(depth_frame.get_data())
		depth_image = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.08), cv2.COLORMAP_JET)

		out.write(color_image)

		cv2.imshow('color_image', color_image)
		cv2.imshow('depth_image', depth_image)

		if cv2.waitKey(1) & 0xff == 27:
			break

finally:
	pipeline.stop()
	cv2.destroyAllWindows()

7 最後に

今回は、Jetson Nanoでインテル® RealSense の画像をKinesis Video Streamsに送ってみました。 OpenCVをGStreamerのソースとして扱うと、動画処理の自由度が広がると思います。