インテル Realsence D435iで、近くに来た物体だけを撮影してみました

2020.10.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

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

前回、「カメラの前に商品をかざしたタイミングで、商品を推論したい」という事で、超音波距離センサーで試してみました。

今回は、別のアプローチとして、depthカメラを試してみました。

使用させて頂いたのは、インテル Realsence LiDARカメラ D435iは、深度計測が可能なステレオビジョンの深度カメラです。

2 動作確認

以下の動画は、動作確認している様子です。

画像の右側は、RBGのオリジナル画像です。そして、左側は、深度カメラで一定の距離以下を検出し、それ以外の部分を白色で塗り潰した画像です。また、背景色が一定値以下になると、コンソールに「検出」と表示しています。

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_EXAMPLES=true -DBUILD_WITH_OPENMP=false -DHWM_OVER_XU=false -DBUILD_PYTHON_BINDINGS=true -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -G "Unix Makefiles"
% make
% sudo make install

作成されたモジュールは、以下のようになっています。

% ls /usr/local/lib/pyrealsense*
/usr/local/lib/pyrealsense2.2.34.0.cpython-37m-darwin.so    /usr/local/lib/pyrealsense2.cpython-37m-darwin.so
/usr/local/lib/pyrealsense2.2.34.cpython-37m-darwin.so

Pythonから利用可能なように、site-packagesにリンクを置きました。

% cd /Users/hirauchi.shinichi/.local/lib/python3.7/site-packages
% sudo ln -s /usr/local/lib/pyrealsense2.cpython-37m-darwin.so pyrealsense2.so
% sudo ln -s /usr/local/lib/pybackend2.cpython-37m-darwin.so pybackend2.so
% ls -la
lrwxr-xr-x  1 root               staff   47 10  6 13:02 pybackend2.so -> /usr/local/lib/pybackend2.cpython-37m-darwin.so
lrwxr-xr-x  1 root               staff   49 10  6 13:02 pyrealsense2.so -> /usr/local/lib/pyrealsense2.cpython-37m-darwin.so

Python3からimportで確認しています。

% python3
>>> import pyrealsense2
>>> print(pyrealsense2.__version__)
2.34.0

4 コード

作成したコードは、以下の通りです。

一定の距離で背景を取り除く処理は、Pythonラッパーのサンプルコードで提供されている、Stream Alignmentを参考にさせて頂きました。
IntelRealSense/librealsense/wrappers/python/examples/align-depth2color.py

# -*- coding: utf-8 -*-
import 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)

threshold = (WIDTH * HEIGHT * 3) * 0.95

try:
    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())

        # clipping_distance_in_metersm以内を画像化
        white_color = 255 # 背景色
        depth_image_3d = np.dstack((depth_image, depth_image, depth_image))
        bg_removed = np.where((depth_image_3d > clipping_distance) | (depth_image_3d <= 0), white_color, color_image)
        # 背景色となっているピクセル数をカウント
        white_pic = np.sum(bg_removed == 255)
        # 背景色が一定値以下になった時に、「検出」を表示する
        if(threshold > white_pic):
            print("検出 {}".format(white_pic))
        else:
            print("{}".format(white_pic))

        images = np.hstack((bg_removed, color_image))
        cv2.imshow('Frames', images)

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

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

5 最後に

今回は、D435iで近くに来た物体だけを抽出してみました。こちらの方法だと、不要な背景を取り除けるのがメリットかも知れません。