RealSense D455 4

PCL本家のexamplesをやります。

SIFTやります。
PCL本家のexamplesそのままではなくてRealSenseからの入力を使うように変更します。

RealSense + PCL

git cloneして、implして、buildして、runします。

準備

少し先の未来のことも考えながら整理します。


$ cd ~/develop
$ git clone https://github.com/PointCloudLibrary/pcl.git
$ mkdir 100_sift
$ (mv 001.cpp compile_test.cpp)
$ cp pcl/examples/keypoints/example_sift_keypoint_estimation.cpp 100_sift/sift.cpp
$ cd 100_sift
$ vi sift.cpp ../wrap/pcl-color/rs-pcl-color.cpp -O

impl

RealSenseのソースコードをPCLのSIFTへ移植したソースコードです。

移植のわかりやすさの為に、#includeの重複を許容しています。
インクルードガードで大丈夫のはずです。

PCLのexamplesの方でPCDからXYZRGBを取ってきている部分をコメントアウトして、RealSenseからの入力に置き換えています。
パラメーターの設定は「これだ !!」という設定にできているわけではありません。試している途中です。

sift.cpp

/*
 * Software License Agreement (BSD License)
 *
 * Point Cloud Library (PCL) - www.pointclouds.org
 * Copyright (c) 2009-2011, Willow Garage, Inc.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 * * Neither the name of Willow Garage, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 *
 */

#include <iostream>

#include <pcl/io/pcd_io.h>
#include <pcl/keypoints/sift_keypoint.h>

// -----------------------------------------------------------------------------

#include <iostream>
#include <algorithm>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
#include <string>

// Intel Realsense Headers
#include <librealsense2/rs.hpp> // Include RealSense Cross Platform API

// PCL Headers
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/common/common_headers.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>
#include <boost/thread/thread.hpp>
#include <pcl/io/io.h>
#include <pcl/visualization/cloud_viewer.h>

using namespace std;

typedef pcl::PointXYZRGB RGB_Cloud;
typedef pcl::PointCloud<RGB_Cloud> point_cloud;
typedef point_cloud::Ptr cloud_pointer;
typedef point_cloud::Ptr prevCloud;

// -----------------------------------------------------------------------------

std::tuple<int, int, int> RGB_Texture(rs2::video_frame texture, rs2::texture_coordinate Texture_XY)
{
    // Get Width and Height coordinates of texture
    int width  = texture.get_width();  // Frame width in pixels
    int height = texture.get_height(); // Frame height in pixels

    // Normals to Texture Coordinates conversion
    int x_value = min(max(int(Texture_XY.u * width  + .5f), 0), width - 1);
    int y_value = min(max(int(Texture_XY.v * height + .5f), 0), height - 1);

    int bytes = x_value * texture.get_bytes_per_pixel();   // Get # of bytes per pixel
    int strides = y_value * texture.get_stride_in_bytes(); // Get line width in bytes
    int Text_Index =  (bytes + strides);

    const auto New_Texture = reinterpret_cast<const uint8_t*>(texture.get_data());

    // RGB components to save in tuple
    int NT1 = New_Texture[Text_Index];
    int NT2 = New_Texture[Text_Index + 1];
    int NT3 = New_Texture[Text_Index + 2];

    return std::tuple<int, int, int>(NT1, NT2, NT3);
}

// -----------------------------------------------------------------------------

cloud_pointer PCL_Conversion(const rs2::points& points, const rs2::video_frame& color){

    // Object Declaration (Point Cloud)
    cloud_pointer cloud(new point_cloud);

    // Declare Tuple for RGB value Storage (<t0>, <t1>, <t2>)
    std::tuple<uint8_t, uint8_t, uint8_t> RGB_Color;

    //================================
    // PCL Cloud Object Configuration
    //================================
    // Convert data captured from Realsense camera to Point Cloud
    auto sp = points.get_profile().as<rs2::video_stream_profile>();

    cloud->width  = static_cast<uint32_t>( sp.width()  );
    cloud->height = static_cast<uint32_t>( sp.height() );
    cloud->is_dense = false;
    cloud->points.resize( points.size() );

    auto Texture_Coord = points.get_texture_coordinates();
    auto Vertex = points.get_vertices();

    // Iterating through all points and setting XYZ coordinates
    // and RGB values
    for (int i = 0; i < points.size(); i++)
    {
        //===================================
        // Mapping Depth Coordinates
        // - Depth data stored as XYZ values
        //===================================
        cloud->points[i].x = Vertex[i].x;
        cloud->points[i].y = Vertex[i].y;
        cloud->points[i].z = Vertex[i].z;

        // Obtain color texture for specific point
        RGB_Color = RGB_Texture(color, Texture_Coord[i]);

        // Mapping Color (BGR due to Camera Model)
        cloud->points[i].r = get<2>(RGB_Color); // Reference tuple<2>
        cloud->points[i].g = get<1>(RGB_Color); // Reference tuple<1>
        cloud->points[i].b = get<0>(RGB_Color); // Reference tuple<0>
    }

   return cloud; // PCL RGB Point Cloud generated
}

// -----------------------------------------------------------------------------

int
main(int, char** argv)
{
    // std::string filename = argv[1];
    // std::cout << "Reading " << filename << std::endl;

    // pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);

    rs2::pointcloud pc;
    rs2::pipeline pipe;
    rs2::config cfg;
    cfg.enable_stream(RS2_STREAM_COLOR);
    cfg.enable_stream(RS2_STREAM_INFRARED);
    cfg.enable_stream(RS2_STREAM_DEPTH);
    rs2::pipeline_profile selection = pipe.start(cfg);
    rs2::device selected_device = selection.get_device();
    auto depth_sensor = selected_device.first<rs2::depth_sensor>();
    if (depth_sensor.supports(RS2_OPTION_EMITTER_ENABLED))
    {
        depth_sensor.set_option(RS2_OPTION_EMITTER_ENABLED, 1.f); // Enable emitter
        pipe.wait_for_frames();
        depth_sensor.set_option(RS2_OPTION_EMITTER_ENABLED, 0.f); // Disable emitter
    }
    if (depth_sensor.supports(RS2_OPTION_LASER_POWER))
    {
        // Query min and max values:
        auto range = depth_sensor.get_option_range(RS2_OPTION_LASER_POWER);
        depth_sensor.set_option(RS2_OPTION_LASER_POWER, range.max); // Set max power
        sleep(1);
        depth_sensor.set_option(RS2_OPTION_LASER_POWER, 0.f); // Disable laser
    }

    // Visualization of keypoints along with the original cloud
    pcl::visualization::PCLVisualizer viewer("PCL Viewer");
    viewer.setBackgroundColor( 0.0, 0.0, 0.0 );
    viewer.initCameraParameters();  // Camera Parameters for ease of viewing

    for (;;)
    {
        auto frames = pipe.wait_for_frames();
        auto depth = frames.get_depth_frame();
        auto RGB = frames.get_color_frame();
        pc.map_to(RGB);
        auto points = pc.calculate(depth);
        cloud_pointer cloud = PCL_Conversion(points, RGB);

        // if(pcl::io::loadPCDFile<pcl::PointXYZRGB> (filename, *cloud) == -1) // load the file
        // {
        //     PCL_ERROR ("Couldn't read file\n");
        //     return -1;
        // }
        std::cout << "points: " << cloud->size () <<std::endl;

        // Parameters for sift computation
        const float min_scale = 0.1f;
        // const int n_octaves = 6;
        const int n_octaves = 4;
        // const int n_scales_per_octave = 10;
        const int n_scales_per_octave = 5;
        // const float min_contrast = 0.5f;
        const float min_contrast = 0.2f;

        // Estimate the sift interest points using Intensity values from RGB values
        pcl::SIFTKeypoint<pcl::PointXYZRGB, pcl::PointWithScale> sift;
        pcl::PointCloud<pcl::PointWithScale> result;
        pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB> ());
        sift.setSearchMethod(tree);
        sift.setScales(min_scale, n_octaves, n_scales_per_octave);
        sift.setMinimumContrast(min_contrast);
        sift.setInputCloud(cloud);
        sift.compute(result);

        // Copying the pointwithscale to pointxyz so as visualize the cloud
        pcl::PointCloud<pcl::PointXYZ>::Ptr result_cloud (new pcl::PointCloud<pcl::PointXYZ>);
        copyPointCloud(result, *result_cloud);

        // Saving the resultant cloud
        std::cout << "Resulting sift points are of size: " << result_cloud->size () <<std::endl;
        pcl::io::savePCDFileASCII("sift_points.pcd", *result_cloud);

        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color_handler (result_cloud, 0, 255, 0);
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> cloud_color_handler (cloud, 255, 255, 0);
        viewer.addPointCloud(cloud, "cloud");
        viewer.addPointCloud(result_cloud, keypoints_color_handler, "keypoints");
        viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "keypoints");

        viewer.spinOnce();
        viewer.removePointCloud ("cloud");
        viewer.removePointCloud ("keypoints");
    }

    return 0;

}

build

Makefileを取ってきて、変更します。

LIBGLの行は無くてもOKと思いますが、削除はしません。
-I ../pcl/common/include -I ../pcl/surface/includeも要らないですね。
-l pcl_outofcore -l pcl_octreeも要らない。


$ cp ../wrap/pcl/pcl-color/Makefile .
$ vi Makefile

Makefile

CC = g++
CFLAGS = -O2
BIN = sift
OBJS = ${BIN}.o
INC = -I /usr/include/pcl-1.10 -I /usr/include/eigen3 -I /usr/include/vtk-7.1 -I ../pcl/common/include -I ../pcl/surface/include
LIB = -l realsense2 -l fw -l realsense-file -l usb-1.0 -l pthread -l udev -l boost_filesystem
LIBGL = -l GL -l glfw -l GLU
LIBPCL = -l pcl_common -l pcl_filters -l pcl_io -l pcl_visualization -l pcl_search -l pcl_outofcore -l pcl_octree
LIBVTK = -l vtkCommonCore-7.1 -l vtkCommonDataModel-7.1 -l vtkCommonMath-7.1 -l vtkRenderingCore-7.1

all : ${BIN}.o
	${CC} ${CFLAGS} ${OBJS} ${LIB} ${LIBGL} ${LIBPCL} ${LIBVTK} -o ${BIN}

${BIN}.o : ${BIN}.cpp
	${CC} ${CFLAGS} ${INC} -c $?

clean :
	\rm sift sift.o

run


$ make
$ ./sift

これはsudoが不要でした。

きちんと特徴を把握できているかわからないですが、目的がRealSenseから入力を得てPCLに変換することなので、これでOKとします。
角は取得できているように見えます。

まとめ

これだけ情報を取れていれば色々とできそうです。

PCLのexamplesに見栄えのするのは少ないです。すぐにRealSenseとつなげられて見栄えがするのはSIFTくらい ?

広告

IT開発関連書とビジネス書が豊富な翔泳社の通販『SEshop』
さくらのレンタルサーバ
ムームードメイン
Oisix(おいしっくす)
らでぃっしゅぼーや
珈琲きゃろっと
エプソムソルト




«       »