最近想做机器人平台上的kinect fusion,在网上找了各种ROS下面kinfu相关的资料,大多残缺不全,唯一给了我灵感的这个网址:http://wiki.ros.org/pcl17,本以为自己找到了完美的解决方案,结果我却奇迹般地发现pcl17中kinfu相关的代码已经不存在。无奈,既然不能用ros下pcl17相关的代码,那我们就使用并改写https://github.com/PointCloudLibrary/pcl中的代码吧,既然pcl已经开源了kinfu的相关代码,那么把它移到ros下也不会是一件非常困难的事。
在开始之前,向大家介绍一下我的软件平台,我的PC机上的OS版本为Ubuntu 12.04 LTS 64bit,ROS的版本为groovy。虽然没在其他平台上测试,不过理论上不会有太大差别。
编译PCL/kinfu
创建ros_kinfu package
创建一个package
编辑package.xml文件
kinfu
0.0.0
The kinfu package
hao
TODO
catkin
roscpp
pcl
std_msgs
sensor_msgs
tf
image_transport
dynamic_reconfigure
message_runtime
roscpp
pcl
std_msgs
sensor_msgs
tf
image_transport
dynamic_reconfigure
roscpp
cmake_minimum_required(VERSION 2.8.3)
project(kinfu)
find_package(catkin REQUIRED
COMPONENTS message_generation roscpp std_srvs std_msgs sensor_msgs dynamic_reconfigure tf image_transport)
#include_directories(${PCL_INCLUDE_DIRS})
find_package(Eigen REQUIRED)
include_directories(${EIGEN_INCLUDE_DIRS})
add_definitions(${EIGEN_DEFINITIONS})
find_package(VTK REQUIRED)
include_directories(${VTK_INCLUDE_DIRS})
#find_package(PCL REQUIRED)
#include_directories(${PCL_INCLUDE_DIRS})
#link_directories(${PCL_LIBRARY_DIRS})
#add_definitions(${PCL_DEFINITIONS})
set(PCL_INCLUDE_DIRS "/usr/local/include/pcl-1.7")
set(PCL_LIBRARY_DIRS "/usr/local/lib")
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
include_directories("/usr/include/ni/")
#add dynamic reconfigure api
#generate_dynamic_reconfigure_options(cfg/dyn_config.cfg)
#include_directories(include cfg/cpp)
#### Cuda
find_package(CUDA)
if (CUDA_FOUND)
message(" * CUDA ${CUDA_VERSION} was found")
include(FindCUDA)
include_directories(${CUDA_INCLUDE_DIRS})
else(CUDA_FOUND)
message(" * CUDA is not found")
message(FATAL_ERROR "Not all CUDA libraries are found")
endif(CUDA_FOUND)
catkin_package(
CATKIN_DEPENDS message_runtime std_msgs sensor_msgs dynamic_reconfigure
)
add_executable(kinfuLS src/kinfuLS_app.cpp src/evaluation.cpp)
#add_dependencies(kinfuLS ${PROJECT_NAME}_gencfg)
#target_link_libraries(kinfuLS boost_system boost_signals)
target_link_libraries(kinfuLS ${catkin_LIBRARIES})
target_link_libraries(kinfuLS ${CUDA_LIBRARIES})
#target_link_libraries(kinfuLS ${PCL_LIBRARY_DIRS})
target_link_libraries(kinfuLS pcl_gpu_kinfu_large_scale pcl_common pcl_io pcl_visualization pcl_octree pcl_gpu_containers vtkCommon vtkFiltering OpenNI vtkRendering)
#define _CRT_SECURE_NO_DEPRECATE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "color_handler.h"
#include "evaluation.h"
#include
#include
#include
#include
#include "sensor_msgs/fill_image.h"
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_OPENCV
#include
#include
#endif
typedef pcl::ScopeTime ScopeTimeT;
#include
using namespace sensor_msgs;
using namespace message_filters;
using namespace std;
using namespace pcl;
using namespace Eigen;
using namespace pcl::gpu::kinfuLS;
using pcl::gpu::DeviceArray;
using pcl::gpu::DeviceArray2D;
using pcl::gpu::PtrStepSz;
namespace pc = pcl::console;
namespace pcl
{
namespace gpu
{
namespace kinfuLS
{
void paint3DView (const KinfuTracker::View& rgb24, KinfuTracker::View& view, float colors_weight = 0.5f);
void mergePointNormal (const DeviceArray& cloud, const DeviceArray& normals, DeviceArray& output);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
vector getPcdFilesInDir(const string& directory)
{
namespace fs = boost::filesystem;
fs::path dir(directory);
std::cout << "path: " << directory << std::endl;
if (directory.empty() || !fs::exists(dir) || !fs::is_directory(dir))
PCL_THROW_EXCEPTION (pcl::IOException, "No valid PCD directory given!\n");
vector result;
fs::directory_iterator pos(dir);
fs::directory_iterator end;
for(; pos != end ; ++pos)
if (fs::is_regular_file(pos->status()) )
if (fs::extension(*pos) == ".pcd")
{
#if BOOST_FILESYSTEM_VERSION == 3
result.push_back (pos->path ().string ());
#else
result.push_back (pos->path ());
#endif
cout << "added: " << result.back() << endl;
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SampledScopeTime : public StopWatch
{
enum { EACH = 33 };
SampledScopeTime(int& time_ms) : time_ms_(time_ms) {}
~SampledScopeTime()
{
static int i_ = 0;
static boost::posix_time::ptime starttime_ = boost::posix_time::microsec_clock::local_time();
time_ms_ += getTime ();
if (i_ % EACH == 0 && i_)
{
boost::posix_time::ptime endtime_ = boost::posix_time::microsec_clock::local_time();
cout << "Average frame time = " << time_ms_ / EACH << "ms ( " << 1000.f * EACH / time_ms_ << "fps )"
<< "( real: " << 1000.f * EACH / (endtime_-starttime_).total_milliseconds() << "fps )" << endl;
time_ms_ = 0;
starttime_ = endtime_;
}
++i_;
}
private:
int& time_ms_;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
setViewerPose (visualization::PCLVisualizer& viewer, const Eigen::Affine3f& viewer_pose)
{
Eigen::Vector3f pos_vector = viewer_pose * Eigen::Vector3f (0, 0, 0);
Eigen::Vector3f look_at_vector = viewer_pose.rotation () * Eigen::Vector3f (0, 0, 1) + pos_vector;
Eigen::Vector3f up_vector = viewer_pose.rotation () * Eigen::Vector3f (0, -1, 0);
viewer.setCameraPosition (pos_vector[0], pos_vector[1], pos_vector[2],
look_at_vector[0], look_at_vector[1], look_at_vector[2],
up_vector[0], up_vector[1], up_vector[2]);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Eigen::Affine3f
getViewerPose (visualization::PCLVisualizer& viewer)
{
Eigen::Affine3f pose = viewer.getViewerPose();
Eigen::Matrix3f rotation = pose.linear();
Matrix3f axis_reorder;
axis_reorder << 0, 0, 1,
-1, 0, 0,
0, -1, 0;
rotation = rotation * axis_reorder;
pose.linear() = rotation;
return pose;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template void
writeCloudFile (int format, const CloudT& cloud);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
writePolygonMeshFile (int format, const pcl::PolygonMesh& mesh);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template
typename PointCloud::Ptr merge(const PointCloud& points, const PointCloud& colors)
{
typename PointCloud::Ptr merged_ptr(new PointCloud());
pcl::copyPointCloud (points, *merged_ptr);
for (size_t i = 0; i < colors.size (); ++i)
merged_ptr->points[i].rgba = colors.points[i].rgba;
return merged_ptr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
boost::shared_ptr convertToMesh(const DeviceArray& triangles)
{
if (triangles.empty())
return boost::shared_ptr();
pcl::PointCloud cloud;
cloud.width = (int)triangles.size();
cloud.height = 1;
triangles.download(cloud.points);
boost::shared_ptr mesh_ptr( new pcl::PolygonMesh() );
pcl::toPCLPointCloud2(cloud, mesh_ptr->cloud);
mesh_ptr->polygons.resize (triangles.size() / 3);
for (size_t i = 0; i < mesh_ptr->polygons.size (); ++i)
{
pcl::Vertices v;
v.vertices.push_back(i*3+0);
v.vertices.push_back(i*3+2);
v.vertices.push_back(i*3+1);
mesh_ptr->polygons[i] = v;
}
return mesh_ptr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct CurrentFrameCloudView
{
CurrentFrameCloudView() : cloud_device_ (480, 640), cloud_viewer_ ("Frame Cloud Viewer")
{
cloud_ptr_ = PointCloud::Ptr (new PointCloud);
cloud_viewer_.setBackgroundColor (0, 0, 0.15);
cloud_viewer_.setPointCloudRenderingProperties (visualization::PCL_VISUALIZER_POINT_SIZE, 1);
cloud_viewer_.addCoordinateSystem (1.0, "global");
cloud_viewer_.initCameraParameters ();
cloud_viewer_.setPosition (0, 500);
cloud_viewer_.setSize (640, 480);
cloud_viewer_.setCameraClipDistances (0.01, 10.01);
}
void
show (const KinfuTracker& kinfu)
{
kinfu.getLastFrameCloud (cloud_device_);
int c;
cloud_device_.download (cloud_ptr_->points, c);
cloud_ptr_->width = cloud_device_.cols ();
cloud_ptr_->height = cloud_device_.rows ();
cloud_ptr_->is_dense = false;
cloud_viewer_.removeAllPointClouds ();
cloud_viewer_.addPointCloud(cloud_ptr_);
cloud_viewer_.spinOnce ();
}
void
setViewerPose (const Eigen::Affine3f& viewer_pose) {
::setViewerPose (cloud_viewer_, viewer_pose);
}
PointCloud::Ptr cloud_ptr_;
DeviceArray2D cloud_device_;
visualization::PCLVisualizer cloud_viewer_;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ImageView
{
ImageView() : paint_image_ (false), accumulate_views_ (false)
{
viewerScene_.setWindowTitle ("View3D from ray tracing");
viewerScene_.setPosition (0, 0);
//viewerDepth_.setWindowTitle ("Kinect Depth stream");
//viewerDepth_.setPosition (640, 0);
//viewerColor_.setWindowTitle ("Kinect RGB stream");
}
void
showScene (KinfuTracker& kinfu, const PtrStepSz& rgb24, bool registration, Eigen::Affine3f* pose_ptr = 0)
{
if (pose_ptr)
{
raycaster_ptr_->run ( kinfu.volume (), *pose_ptr, kinfu.getCyclicalBufferStructure () ); //says in cmake it does not know it
raycaster_ptr_->generateSceneView(view_device_);
}
else
{
kinfu.getImage (view_device_);
}
if (paint_image_ && registration && !pose_ptr)
{
colors_device_.upload (rgb24.data, rgb24.step, rgb24.rows, rgb24.cols);
paint3DView (colors_device_, view_device_);