Open3D+ROS+Pythonで3次元画像処理を楽々プロトタイピング

f:id:karaage:20170817152149j:plain:w640

3次元画像処理ライブラリ「Open3D」の紹介

 いつも読んでいる、「空飛ぶロボットのつくりかた」というブログで、Open3DというIntel製の3次元画像処理のライブラリが紹介されていました。

 「Open3D」の公式サイトは以下です。 Open3D

 個人的に、3次元画像処理には興味あって、以前Point Cloud Library(以下PCL)を使った、簡単な3次元画像処理を紹介したことがあります(以下記事参照)。

 ただ、PCLには以下のような不満がありました。

  • C++しか使えない(C++苦手…)
  • ちょっとした修正にもいちいちビルドしないといけない
  • たくさん行数書く必要がある

 Open3Dがつくられたのも、上記のような不満を解消するのが目標だったようで、Open3Dを紹介する論文によると、Open3DのPCLに比べた利点は以下とのことです。

  • Pythonが使える
  • 少ない行数でかける(PCLの1/5とのこと)
  • Jupyter Notebookでデバッグできる

 そしてPCLはかなりディスられてました。よっぽど嫌な思いをしたのでしょう(PCLに親を殺されたとか)。

Open3DはROSと連携させると良さそう

 Open3D、ちょっと触ってみて。確かにPythonでサクサク書けるのは便利で、プロトタイピング(試行錯誤)には使いやすそうだなと感じました。

 ただ、3次元画像処理って自分としては3次元センサと組み合わせてリアルタイムで処理したいのですよね。PCLの場合は、ROS(Robot Operation System)と組み合わせることで、ROSに対応した多種多様な3次元センサと、ROSの強力な可視化機能(Rviz)やログ機能(rosbag)が使えたのが非常に便利でした。

 Open3Dは、自分が調べた感じROSには対応していなさそうでした。「対応していないのだったら、自分でROSに対応させちゃえ!」ということで、「open3d_ros」というOpen3DとROSを連携させるちょっとしたツールを作ってみました。

 この記事では、「open3d_ros」の使い方と、どんなことができるかを簡単に紹介いたします。

「open3d_ros」によるOpen3DとROS連携のセットアップ方法

 Open3DとROSを連携させるためのセットアップ手順を説明していきます。ここからの想定は、ネイティブのLinux(Ubuntu 16.04)がインストールされたPC、もしくは仮想環境上でのLinux環境を想定しています。

 Macの仮想環境(Parallels Desktop Lite)に関しては以下記事参照下さい。WindowsでもVirtual Boxなどの環境で同様にできると思います(未確認)。

 仮想環境上で、Open3Dのビルドに失敗する場合は、仮想環境のメモリ設定を最大限確保し、何度かビルドをしてみて下さい。

ROSと3次元センサのセットアップ

 ROSと3次元センサのセットアップに関しては、以下記事参照下さい。

 3次元センサはKinectを想定していますが、もし3Dセンサを持っていなくても、ログデータ(rosbag)で試すことできますので、Kinectのセットアップをスキップして次に進んで下さい。

Open3Dインストール

 Open3Dのインストールは、公式サイトのドキュメントこちらの記事に従いました。具体的にはLinux(Ubuntu)のターミナル上で以下コマンドを実行します。

$ git clone https://github.com/IntelVCL/Open3D
$ cd Open3D
$ ./scripts/install-deps-ubuntu.sh
$ mkdir build && cd build
$ cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python ../src
$ make -j

 参考までに、以下コマンド実行すれば、ネイティブのMacにインストールすることもできました。ネイティブのMacにROSを入れるのは至難の技ですが…

$ git clone https://github.com/IntelVCL/Open3D
$ cd Open3D
$ ./scripts/install-deps-osx.sh
$ mkdir build && cd build
$ cmake ../src
$ make -j

 これで py3d が Open3d/build/lib/以下に生成されるのですが、このままだと py3d をimport するのに Open3d/build/lib/に移動したり、パスを指定しないといけないので不便です。

 以下で Pythonのパスが通っているディレクトリが分かるので、 py3dをコピーしてやり、簡単にインポートできるようにしましょう。

$ python
>> import sys
>> sys.path

 Ubuntuの場合は、/usr/lib/python2.7/dist-packages/だったので以下のようにコピーしました。

$ sudo cp lib/py3d.so /usr/lib/python2.7/dist-packages/

 ネイティブのMacの場合は、pyenvを使っていたので/Users/denso/.pyenv/versions/anaconda3-4.4.0/envs/ml/lib/となり、以下のようにコピーしました。

$ sudo cp lib/py3d.cpython-36m-darwin.so /Users/denso/.pyenv/versions/anaconda3-4.4.0/envs/ml/lib/

 ここらへんは、ご自分の流儀に合わせて適宜変更下さい。pipで一発で入ってくると嬉しいのですけどね。

 これ以降の内容は、上記の通りpy3dがパスの通ったディレクトリにコピーしてある前提で説明いたします。

 続いて、以下コマンド実行してテストします。

$ cd lib/Tutorial/Basic
$ python rgbd_redwood.py

 以下のような画像が表示されればOKです。 f:id:karaage:20180227181440p:plain:w480

Open3D+ROS連携

 ここからいよいよ「open3d_ros」を使っていきます。ここからは以下のリポジトリを使用します。

 あらかじめ、好きな場所に以下のコマンドで「open3d_ros」をcloneしておいて下さい。

$ git clone https://github.com/karaage0703/open3d_ros

 次に、ターミナルのウィンドウを4つ立ち上げて、それぞれのターミナルでopen3d_rosディレクトリ内で以下コマンドを実行します。

 1つ目でroscore立ち上げ

$ roscore

 2つ目で、ログデータ(rosbag)再生

$ rosbag play -l rosbag_data/kinect_room.bag

 3つ目でOpen3D使用

$ python down_sampling.py input:=/camera/depth_registered/points

 4つ目でRviz立ち上げて3次元情報を可視化

$ rosrun rviz rviz -d kinect.rviz

   以下のようにRviz上にダウンサンプリングされた点群が表示されます。 f:id:karaage:20180308003053g:plain:w640

 ダウンサンプリング前 f:id:karaage:20180308004256p:plain:w640

 ちなみに、down_sampling.pyは、以下のような30行にも満たないスクリプトです。面倒臭いROSとの連携部分はutil.pyというファイルに詰め込んでインポートしています(興味ある方はutil.pyの方も見てみて下さい)。

#! /usr/bin/env python

import rospy
from sensor_msgs.msg import PointCloud2

import util
import py3d

def down_sampling(pcl_data):
    downpcd = py3d.voxel_down_sample(pcl_data, voxel_size = 0.05)

    return downpcd


def callback(data):
    pcl_data = util.convert_pcl(data)

    result_pcl = down_sampling(pcl_data)

    util.publish_pointcloud(result_pcl, data)

if __name__ == "__main__":
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber('input',
                     PointCloud2, callback)

    rospy.spin()

 上記コードのdown_samplingという関数を書き換えると、好きなように3次元処理ができます。これみると、なんとなく簡単に3次元画像処理ができそうな気がしてきますね(してきますよね?)。

 今回はあらかじめ用意したログデータでテストしましたが、3次元センサを使っても、簡単に同様の画像処理ができます。具体的には、以下記事参考にKinectをセットアップして。

 上記のログの再生のコマンドの代わりに以下コマンドを実行するだけです。

$ roslaunch freenect_launch freenect.launch

 もちろん、Kinect以外も、ROSに対応している3次元カメラであれば、同じ要領で3次元画像処理が可能です。今だとRealsenseあたりがお手頃でしょうか。これもOpen3Dと同じくIntel製ですね。

まとめ

 Open3D+ROS+Pythonで3次元画像処理のプロトタイピングができる「open3d_ros」というツールを自作して紹介しました。「Open3D」Python使えるのは、ビルドしなくてよいし、簡単にかけて良いですね(C++難しい…)。

 Pythonで書くときは、Numpyが使えるのも魅力的です。3次元画像処理って、2次元画像処理と基本的な部分は共通するところが多いので、2次元画像と同じ要領で直接画素を弄って好きなフィルタを作ったりできるはずです。2次元画像の例ですが、Numpyで画像処理フィルタを作る方法は下記記事参照ください。

 あとは、Pythonなので3次元のディープラーニングというのも中々面白いかもしれませんね。3次元でディープラーニングやっている例って、2次元に比べるとまだまだかなり少ない印象です。私が知っているのは、Appleの自動運転の研究くらいでしょうか(End-to-Endで物体検出しています)。

[1711.06396] VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection

 Open3Dによって、3次元のディープラーニングの研究も進んで行く可能性あるかもしれませんね。

 そして何より、Open3DとROSの強力な可視化ソフトやツール群との組み合わせというのは、なかなかパワフルじゃないかなと思います。これ使って、色々試してみたいなと思います。それこそロボット作ってみたいですね。

参考リンク

Open3Dのお勉強(一回目) - 空飛ぶロボットのつくりかた

ROSのPointCloud2で独自のフィールドを定義 - Yura YuLife

関連記事