みらいテックラボ

音声・画像認識や機械学習など, 週末プログラマである管理人が興味のある技術の紹介や実際にトライしてみた様子などメモしていく.

Pythonではじめる3Dセンシング!!

先日(2018/7/22), 大江橋Pythonの会#1で, 「Pythonではじめる3Dセンシング」と題して, 3Dセンシングの概要やPythonIntel Real Sense D400シリーズを使用する方法などについて紹介した.

soleildatadojo.connpass.com

Intel Real Sense D400シリーズの開発ツールとしては, RealSense SDK 2.xがあるのだが, Pythonから扱う際の情報がまだまだ少ないので, こちらでも少し紹介しておく.


1. 開発環境構築
RealSense SDK 2.xの概要は以下の通り.
・RealSense D400シリーズのソフトウェア開発キット
 注) RealSense SDK 1.0と互換性なし
・C, C++, Python, .NET(C#), JavaScript(Node.js)などに対応
・「人物や手, 顔などの姿勢推定」「3次元形状復元」などの応用機能なし

1.1 ダウンロード
オープンソースなので, Githubから取得できる.
 https://github.com/IntelRealSense/librealsense

1.2 インストール[1]
Pythonから使用するには, ソースからのビルドが必要.
ポイントは1つ
 $ cmake ../ -DBUILD_EXAMPLES=true \
   -DBUILD_GRAPHICAL_EXAMPLES=true \
   -DBUILD_PYTHON_BINDINGS=bool:true
あとは, make&installするだけ.


2. 基本的な使い方[1]
2.1 Depth画像の表示
3Dカメラの距離データを取り込み, まずは表示してみる.
この処理の流れが, 以降の他の処理においてもベースとなる.

[コード]

# -*- coding: utf-8 -*-

#############################################
##      D415 Depth画像の表示
#############################################
import pyrealsense2 as rs
import numpy as np
import cv2

# ストリーム(Color/Depth)の設定
config = rs.config()
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

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

try:
    while True:
        # フレーム待ち(Color & Depth)
        frames = pipeline.wait_for_frames()
        color_frame = frames.get_color_frame()
        depth_frame = frames.get_depth_frame()
        if not depth_frame or not color_frame:
            continue
        color_image = np.asanyarray(color_frame.get_data())
        # Depth画像
        depth_color_frame = rs.colorizer().colorize(depth_frame)
        depth_color_image = np.asanyarray(depth_color_frame.get_data())

        # 表示
        images = np.hstack((color_image, depth_color_image))
        cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
        cv2.imshow('RealSense', images)
        if cv2.waitKey(1) & 0xff == 27:
            break

finally:
    # ストリーミング停止
    pipeline.stop()
    cv2.destroyAllWindows()

[実行結果]
f:id:moonlight-aska:20180729131305p:plain

2.2 ファイルへの保存
3Dカメラのデータを用いてあれこれ実験するのに, 毎回データを取り込みならがやるのは大変.
そこで, データを保存し再生できると, 実験もやりやすい.
まずは保存だが, configに保存する際のファイル名を設定してやるだけでよい.

[コード]

import pyrealsense2 as rs
import numpy as np
import cv2

# ストリーム(Color/Depth/Infrared)の設定
config = rs.config()
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.infrared, 640, 480, rs.format.y8, 30)
# ↓ ここでファイル名設定
config.enable_record_to_file('./data/d415data.bag')

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

try:
    while True:
         :   
      (省略)

2.3 ファイルの再生
次は再生だが, こちらもconfigに読み出すデータのファイル名を設定してやるだけでよい.
注) ファイルは最後まで再生すると, リピートされる.

[コード]

# ストリーム(Color/Depth/Infrared)の設定
config = rs.config()
# ↓ ここでファイル名設定
config.enable_device_from_file('./data/d415data.bag')
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

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

try:
    while True:
        # フレーム待ち(Color & Depth)
        frames = pipeline.wait_for_frames()
        color_frame = frames.get_color_frame()
        depth_frame = frames.get_depth_frame()
              :   
           (省略)

2.4 距離情報の利用
最後に距離データの扱いだが, 実際のカメラからの距離は,
 距離[m] = depth * depth_scale
で, 計算できる.
RGB画像とDepth画像を重ねる場合, カメラ位置のずれを補正するために, Alignオブジェクトを使用するのがポイント.

[コード]

# -*- coding: utf-8 -*-

#############################################
##      D415 Depth画像の表示
#############################################
import pyrealsense2 as rs
import numpy as np
import cv2

# ストリーム(Depth/Color)の設定
config = rs.config()
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
config.enable_stream(rs.stream.depth, 640, 480, 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 = 1.0 # meter
clipping_distance = clipping_distance_in_meters / depth_scale

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

try:
    while True:
        # フレーム待ち(Color & Depth)
        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画像前処理(1m以内を画像化)  
        grey_color = 153
        depth_image_3d = np.dstack((depth_image,depth_image,depth_image))
        bg_removed = np.where((depth_image_3d > clipping_distance) | (depth_image_3d <= 0), grey_color, color_image)
        
        # レンダリング
        depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)
        images = np.hstack((bg_removed, depth_colormap))
        cv2.namedWindow('Align Example', cv2.WINDOW_AUTOSIZE)
        cv2.imshow('RealSense', images)
        if cv2.waitKey(1) & 0xff == 27:
            break

finally:
    # ストリーミング停止
    pipeline.stop()
    cv2.destroyAllWindows()

[実行結果]
f:id:moonlight-aska:20180729133416p:plain

Inel RealSense SDK 2.xのPythonドキュメントはまだまだ少ないが, Depth画像の取り込みなど基本的な使い方はとても簡単なので, まずは触ってみよう!!
また, 今回Githubpython wrapper[1]を参考にしているので, こちらも見てね.

----
参照URL:
[1] librealsense/wrappers/python at master・IntelRealSense/librealsense




Python 3.6 による 画像処理 第1巻: 画像入出力と表示

Python 3.6 による 画像処理 第1巻: 画像入出力と表示


オリジナルの画像認識AIを簡単に作ろう!

オリジナルの画像認識AIを簡単に作ろう!


Pythonで学ぶ実践画像・音声処理入門

Pythonで学ぶ実践画像・音声処理入門


実践OpenCV 2.4 for Python―映像処理&解析

実践OpenCV 2.4 for Python―映像処理&解析