Python OpenNI2 - eiichiromomma/CVMLAB GitHub Wiki

(Python) OpenNI2

PythonでOpenNI 2とNiTE 2を使う

※Xtion Proでテスト

OpenNI2およびNiTe2の導入

各サイトに説明されているので省略

Mac OS Xの場合

どちらもinstall.shを実行後に生成されるOpenNIDevEnvironmentおよびNiTEDevEnvironmentを実行し、環境変数が指定されていることを意味する。 一々打つのが面倒な場合には .profile 等に以下のように記述しておく。

source /InstalledDir/OpenNI-MacOSX-x64-2.x/OpenNIDevEnvironment
source /InstalledDir/NiTE-MacOSX-x64-2.x/NiTEDevEnvironment

primesense package の導入

conda等のパッケージマネージャでインストールできる。

自力でインストールする場合はhttps://pypi.python.org/pypi/primesense/からzipなりtar.gzを入手し、適当な場所へ展開する。 コマンドラインから python setup.py install で導入完了。

テスト

サンプルで載っているソース

下記ファイルを実行すると一瞬投光部が光る

from primesense import openni2
openni2.initialize()     # can also accept the path of the OpenNI redistribution

dev = openni2.Device.open_any()
print dev.get_sensor_info(openni2.SENSOR_DEPTH)

depth_stream = dev.create_depth_stream()
depth_stream.start()
frame = depth_stream.read_frame()
frame_data = frame.get_buffer_as_uint16()
depth_stream.stop()

openni2.unload()

frameデータからの変換

frame_dataはuint16のバッファになっていて、numpyのndarrayへdtypeの指定無しで入れるとおかしな事になるので

import numpy as np
import matplotlib.pyplot as plt
depth_array = np.ndarray((frame.height,frame.width),dtype=np.uint16,buffer=frame_data) 

とする。 あとは

plt.imshow(depth_array)
plt.show()

で表示できる。

通しだと下記の通り。

import numpy as np
import matplotlib.pyplot as plt
from primesense import openni2
openni2.initialize()     # can also accept the path of the OpenNI redistribution
dev = openni2.Device.open_any()
print dev.get_sensor_info(openni2.SENSOR_DEPTH)
depth_stream = dev.create_depth_stream()
depth_stream.start()
frame = depth_stream.read_frame()
frame_data = frame.get_buffer_as_uint16()
depth_stream.stop()
openni2.unload()

depth_array = np.ndarray((frame.height,frame.width),dtype=np.uint16,buffer=frame_data) 
plt.imshow(depth_array)
plt.show()

OpenCV との連携

特に大した事はしていないが、それなりの速さで取り込み可能

# encoding: utf-8
# oni_ocv_sample.py
# 2013-9-13
# Eiichiro Momma
__author__ = 'momma'
import numpy as np
import matplotlib.pyplot as plt
from primesense import openni2

import cv2

openni2.initialize()     # can also accept the path of the OpenNI redistribution
dev = openni2.Device.open_any()
print dev.get_sensor_info(openni2.SENSOR_DEPTH)
depth_stream = dev.create_depth_stream()
depth_stream.start()

shot_idx = 0
while True:
    frame = depth_stream.read_frame()
    frame_data = frame.get_buffer_as_uint16()
    depth_array = np.ndarray((frame.height, frame.width),dtype=np.uint16,buffer=frame_data)/10000. #0-10000mm to 0.-1.
    cv2.imshow('Depth',depth_array)
    ch = 0xFF & cv2.waitKey(1)
    if ch == 27:
          break
    if ch == ord(' '):
        fn = 'shot_%03d.png)' % shot_idx
        cv2.imwrite(fn, (depth_array*255).astype(np.uint8))
        print fn, ' saved'
        shot_idx += 1        
depth_stream.stop()
openni2.unload()
cv2.destroyAllWindows()

IRセンサも追加

C I/F同様にストリームを指定するだけでIR画像が得られる。但し16bitで1000程度の値にしかならないので,ここでは最大値で正規化している。

# encoding: utf-8
# oni_ocv_sample.py
# 2013-9-13
# Eiichiro Momma
__author__ = 'momma'
import numpy as np
import matplotlib.pyplot as plt
from primesense import openni2

import cv2

openni2.initialize()     # can also accept the path of the OpenNI redistribution
dev = openni2.Device.open_any()
print dev.get_sensor_info(openni2.SENSOR_DEPTH)
depth_stream = dev.create_depth_stream()
depth_stream.start()

ir_stream = dev.create_ir_stream()
ir_stream.start()

shot_idx = 0
while True:
    frame = depth_stream.read_frame()
    frame_data = frame.get_buffer_as_uint16()
    depth_array = np.ndarray((frame.height, frame.width),dtype=np.uint16,buffer=frame_data)/10000. #0-10000mm to 0.-1.
    cv2.imshow('Depth',depth_array)
    ir_frame = ir_stream.read_frame()
    ir_frame_data = ir_frame.get_buffer_as_uint16()
    ir_array = np.ndarray((ir_frame.height, ir_frame.width),dtype=np.uint16, buffer = ir_frame_data).astype(np.float32)
    cv2.imshow('IR',ir_array/ir_array.max())

    ch = 0xFF & cv2.waitKey(1)
    if ch == 27:
          break
    if ch == ord(' '):
        fn = 'depth_shot_%03d.png)' % shot_idx
        cv2.imwrite(fn, (depth_array*255).astype(np.uint8))
        print fn, ' saved'
        fn = 'ir_shot_%03d.png)' % shot_idx
        cv2.imwrite(fn, (ir_array/ir_array.max()*255).astype(np.uint8))
        print fn, ' saved'
        shot_idx += 1
depth_stream.stop()
openni2.unload()
cv2.destroyAllWindows()

depthをCSVに書き出し+フレームサイズを640x480に

要望があったので追加

# encoding: utf-8
# oni_ocv_sample2.py
# 2014-10-29
# Eiichiro Momma
__author__ = 'momma'
import numpy as np
import matplotlib.pyplot as plt
from primesense import openni2

import cv2

openni2.initialize()     # can also accept the path of the OpenNI redistribution
dev = openni2.Device.open_any()
print dev.get_sensor_info(openni2.SENSOR_DEPTH)
depth_stream = dev.create_depth_stream()

depth_stream.set_video_mode(openni2.c_api.OniVideoMode(pixelFormat = openni2.c_api.OniPixelFormat.ONI_PIXEL_FORMAT_DEPTH_1_MM, resolutionX = 640, resolutionY = 480, fps = 30))

depth_stream.start()

ir_stream = dev.create_ir_stream()
ir_stream.set_video_mode(openni2.c_api.OniVideoMode(pixelFormat = openni2.c_api.OniPixelFormat.ONI_PIXEL_FORMAT_GRAY16, resolutionX = 640, resolutionY = 480, fps = 30))
ir_stream.set_video_mode(vmode)

ir_stream.start()

shot_idx = 0
while True:
    frame = depth_stream.read_frame()
    frame_data = frame.get_buffer_as_uint16()
    depth_array = np.ndarray((frame.height,frame.width),dtype=np.uint16,buffer=frame_data)/10000. #0-10000mm to 0.-1.
    depth_array_mm = np.ndarray((frame.height,frame.width),dtype=np.uint16,buffer=frame_data) #0-10000mm
    cv2.imshow('Depth',depth_array)
    
    ir_frame = ir_stream.read_frame()
#Kinect
#    ir_frame_data = ir_frame.get_buffer_as_uint8()
#    ir_array = np.ndarray((ir_frame.height,ir_frame.width),dtype=np.uint8, buffer = ir_frame_data).astype(np.float32)
#Xtion Pro
    ir_frame_data = ir_frame.get_buffer_as_uint16()
    ir_array = np.ndarray((ir_frame.height,ir_frame.width),dtype=np.uint16, buffer = ir_frame_data).astype(np.float32)

    cv2.imshow('IR',ir_array/ir_array.max())

    ch = 0xFF & cv2.waitKey(500)
    if ch == 27:
        break
    if ch == ord(' '):
#    if True:
        fn = 'depth_shot_%03d.png' % shot_idx
        cv2.imwrite(fn, (depth_array*255).astype(np.uint8))
        print fn, 'depth saved'
        fn = 'ir_shot_%03d.png' % shot_idx
        cv2.imwrite(fn, (ir_array/ir_array.max()*255).astype(np.uint8))
        print fn, 'ir saved'
        fn = 'depth_mm_%03d.csv' % shot_idx
        np.savetxt(fn,depth_array_mm,'%d',delimiter=',')
        shot_idx += 1
depth_stream.stop()
ir_stream.stop()
openni2.unload()
cv2.destroyAllWindows()

NiTE2の利用

普通にinitializeするとエラーが発生する。site-packages内にインストールされた_nite2.pyからniteDumpUserTrackerCalibrationDataToFile関連をコメントアウトするとinitializeに成功するが、使い方が不明。