Drawing Point Cloud retrieve from Kinect v2 using OpenCV Viz module

What is OpenCV Viz module?

OpenCV 2.4.9以降には3次元データの可視化のためのVizモジュール(opencv_viz)が提供されています。
このモジュールはVTK(Visualization Toolkit)をベースに実装されています。

How to Build OpenCV Viz module?

Vizモジュール(opencv_viz)はビルド済みパッケージには含まれていません。
そのため、Vizモジュールを利用するにはOpenCVをビルドする必要があります。

Vizモジュールを有効にするためのCMakeの設定は以下の通りです。

  • VTK_DIR C:\Program Files\VTK\lib\cmake\vtk-7.1
  • BUILD_opencv_viz ☑(check)
  • WITH_VTK ☑(check)

Drawing Point Cloud retrieve from Kinect v2 using OpenCV Viz module

サンプルプログラムは以下で公開しています。
Kinect SDK v2とOpenCVが必要です。

Vizモジュールを使用するにはopencv2/opencv.hppの他にopencv2/viz.hppをインクルードします。

app.h#L6-L7

#include <opencv2/opencv.hpp>
#include <opencv2/viz.hpp>

Initialize

cv::viz::Viz3dとPoint Cloudデータを格納するためのcv::Matを用意します。

cv::viz::Viz3dは3次元データを可視化するためのビューワーです。
ウィンドウの名前を与えてビューワーを作成します。

app.h#L41-L42

cv::viz::Viz3d viewer;
cv::Mat cloudMat;

app.cpp#L121-L131

inline void Kinect::initializePointCloud()
{
    // Create Window
    viewer = cv::viz::Viz3d( "Point Cloud" );
}

Draw

Point Cloudデータはfloat型の3チャンネル(cv::Vec3f)のバッファを用意します。
このバッファにKinect SDK v2のICoordinateMapper::MapDepthFrameToCameraSpace()でCamera座標系に変換したDepthデータを格納していきます。
Pointが存在しない場所には、NaN(Not a Number)を設定します。

データを格納したバッファからcv::Matを作成します。
Point Cloudデータを格納するcv::Matはfloat型の3チャンネル(CV_32FC3)の行列で作成します。

ここではfloat型を使用しましたが、必要な場合はdouble型を使用を検討してください。

app.cpp#L233-L256

inline void Kinect::drawPointCloud()
{
    // Retrieve Mapped Coordinates
    std::vector<CameraSpacePoint> cameraSpacePoints( depthWidth * depthHeight );
    ERROR_CHECK( coordinateMapper->MapDepthFrameToCameraSpace( depthBuffer.size(), &depthBuffer[0], cameraSpacePoints.size(), &cameraSpacePoints[0] ) );

    // Mapping Color to Depth Resolution
    std::vector<cv::Vec3f> buffer( depthWidth * depthHeight, cv::Vec3f::all( std::numeric_limits<float>::quiet_NaN() ) );

    Concurrency::parallel_for( 0, depthHeight, [&]( const int depthY ){
        const unsigned int depthOffset = depthY * depthWidth;
        for( int depthX = 0; depthX < depthWidth; depthX++ ){
            unsigned int depthIndex = depthOffset + depthX;
            UINT16 depth = depthBuffer[depthIndex];
            if( 500 <= depth && depth < 8000 ){
                CameraSpacePoint cameraSpacePoint = cameraSpacePoints[depthIndex];
                buffer[depthIndex] = cv::Vec3f( cameraSpacePoint.X, cameraSpacePoint.Y, cameraSpacePoint.Z );
            }
        }
    } );

    // Create cv::Mat from Coordinate Buffer
    cloudMat = cv::Mat( depthHeight, depthWidth, CV_32FC3, &buffer[0] ).clone();
}

Show

Point Cloudデータのウィジェットのcv::viz::WCloudを作成します。
Point Cloudデータを格納したcv::MatとColorデータを格納したcv::Matを与えます。

Colorデータは、Point Cloudデータと同じサイズ(width, height)である必要があります。
あらかじめ、Kinect SDK v2のICoordinateMapper::MapDepthFrameToColorSpace()で解像度を合わせたColorデータをcv::Matに格納しておきます。
(単色で着色する場合はcv::Viz::Colorを指定します。)

cv::viz::Viz3d::showWidget()にウィジェットの名前と表示するcv::viz::WCloudを設定します。
cv::viz::Viz3d::spinOnce()でシーンを描画します。

app.cpp#L266-L282

inline void Kinect::showPointCloud()
{
    if( colorMat.empty() ){
        return;
    }

    if( cloudMat.empty() ){
        return;
    }

    // Create Point Cloud
    cv::viz::WCloud cloud( cloudMat, colorMat );
    //cv::viz::WCloud cloud( cloudMat, cv::viz::Color::white() );

    // Show Point Cloud
    viewer.showWidget( "Cloud", cloud );
    viewer.spinOnce();
}

Execution Result

このサンプルプログラムを実行するとKinect v2から取得したPoint Cloudがリアルタイムで表示されます。

Reference

 


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です