00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef _FRAME_EXTENDED_H_
00039 #define _FRAME_EXTENDED_H_
00040
00041 #include "frame_common/frame.h"
00042
00043 #include <pcl/point_types.h>
00044 #include <pcl/point_cloud.h>
00045 #include <pcl/PointIndices.h>
00046 #include <pcl/features/normal_3d.h>
00047 #include <pcl/kdtree/kdtree_flann.h>
00048 #include <pcl/filters/passthrough.h>
00049 #include <pcl/filters/voxel_grid.h>
00050 #include <pcl/filters/filter.h>
00051 #include <pcl/filters/extract_indices.h>
00052 #include <pcl/common/transforms.h>
00053 #include <pcl/registration/transforms.h>
00054 #include <pcl/registration/icp.h>
00055 #include <pcl/registration/icp_nl.h>
00056
00057 #include <pcl/io/pcd_io.h>
00058
00059 using namespace pcl;
00060 using namespace Eigen;
00061
00062 namespace frame_common
00063 {
00065 class FrameExtended : public Frame
00066 {
00067 public:
00069 pcl::PointCloud<pcl::PointXYZRGBNormal> cloud;
00071 pcl::PointIndices indices;
00072
00074 template <typename PointT, typename PointNT> void
00075 estimateNormals (const pcl::PointCloud<PointT> &input, const pcl::PointIndices &indices, pcl::PointCloud<PointNT> &output)
00076 {
00077
00078 pcl::search::OrganizedNeighbor<PointT> tree;
00079
00080
00081 pcl::NormalEstimation<PointT, PointNT> ne;
00082 ne.setInputCloud (boost::make_shared<const pcl::PointCloud<PointT> > (input));
00083 ne.setIndices (boost::make_shared<std::vector<int> > (indices.indices));
00084 ne.setSearchMethod (tree);
00085
00086 ne.setKSearch (10);
00087
00088 ne.compute (output);
00089 }
00090
00092 void match(frame_common::FrameExtended& frame, const Eigen::Vector3d& trans, const Eigen::Quaterniond& rot, std::vector<cv::DMatch>& matches)
00093 {
00094 PointCloud<PointXYZRGBNormal> transformed_cloud;
00095
00096
00097 transformPointCloudWithNormals<PointXYZRGBNormal>(frame.cloud, transformed_cloud, -trans.cast<float>(), rot.cast<float>().conjugate());
00098
00099 Matrix3d rotmat = rot.toRotationMatrix();
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 std::vector<int> other_indices, this_indices;
00114 getMatchingIndices(transformed_cloud, cloud, other_indices, this_indices);
00115
00116
00117
00118
00119
00120 matches.clear();
00121
00122 for (unsigned int i=1; i < other_indices.size(); i++)
00123 {
00124 PointXYZRGBNormal &pt0 = transformed_cloud.points[other_indices[i]];
00125 PointXYZRGBNormal &pt1 = cloud.points[this_indices[i]];
00126
00127
00128 Quaterniond normalquat;
00129 Vector3d norm0(pt0.normal[0], pt0.normal[1], pt0.normal[2]), norm1(pt1.normal[0], pt1.normal[1], pt1.normal[2]);
00130 normalquat.setFromTwoVectors(norm0, norm1);
00131 double angledist = normalquat.angularDistance(normalquat.Identity());
00132 double dist = (Vector3d(pt0.x, pt0.y, pt0.z)-Vector3d(pt1.x, pt1.y, pt1.z)).norm();
00133
00134 Vector4d p0_pt = Vector4d(pt0.x, pt0.y, pt0.z, 1.0);
00135 Vector3d expected_proj = projectPoint(p0_pt);
00136
00137 Vector3d diff = expected_proj - pl_kpts[this_indices[i]].head<3>();
00138 diff(2) = diff(2) - diff(0);
00139
00140 if ((norm0 - norm1).norm() < 0.5)
00141 matches.push_back(cv::DMatch(other_indices[i], this_indices[i], dist));
00142 }
00143
00144 printf("[FrameExtended] Found %d matches, then converted %d matches.\n", (int)other_indices.size(), (int)matches.size());
00145 }
00146
00149 void setPointcloud(const pcl::PointCloud<pcl::PointXYZRGB>& input_cloud)
00150 {
00151 reduceCloud(input_cloud, cloud);
00152
00153
00154
00155
00156 pl_pts.clear();
00157 pl_kpts.clear();
00158 pl_normals.clear();
00159 pl_ipts.clear();
00160
00161 unsigned int ptcloudsize = cloud.points.size();
00162 pl_pts.resize(ptcloudsize);
00163 pl_kpts.resize(ptcloudsize);
00164 pl_normals.resize(ptcloudsize);
00165 pl_ipts.resize(ptcloudsize);
00166
00167 for (unsigned int i=0; i < cloud.points.size(); i++)
00168 {
00169 PointXYZRGBNormal &pt = cloud.points[i];
00170
00171 pl_pts[i] = Eigen::Vector4d(pt.x, pt.y, pt.z, 1.0);
00172 pl_normals[i] = Eigen::Vector4d(pt.normal[0], pt.normal[1], pt.normal[2], 1.0);
00173 pl_kpts[i] = projectPoint(pl_pts[i]);
00174 pl_ipts[i] = -1;
00175 }
00176 }
00177
00178 private:
00179 void reduceCloud(const PointCloud<PointXYZRGB>& input, PointCloud<PointXYZRGBNormal>& output)
00180 {
00181 PointCloud<PointXYZRGB> cloud_nan_filtered, cloud_box_filtered, cloud_voxel_reduced;
00182 PointCloud<Normal> normals;
00183 PointCloud<PointXYZRGBNormal> cloud_normals;
00184
00185 std::vector<int> indices;
00186
00187
00188 removeNaNFromPointCloud(input, cloud_nan_filtered, indices);
00189 indices.clear();
00190
00191
00192 Eigen::Vector4f min_pt(-100, -100, -100, -100);
00193 Eigen::Vector4f max_pt(100, 100, 100, 100);
00194 getPointsInBox(cloud_nan_filtered, min_pt, max_pt, indices);
00195
00196 ExtractIndices<PointXYZRGB> boxfilter;
00197 boxfilter.setInputCloud(boost::make_shared<const PointCloud<PointXYZRGB> >(cloud_nan_filtered));
00198 boxfilter.setIndices (boost::make_shared<std::vector<int> > (indices));
00199 boxfilter.filter(cloud_box_filtered);
00200
00201
00202 VoxelGrid<PointXYZRGB> voxelfilter;
00203 voxelfilter.setInputCloud (boost::make_shared<const PointCloud<PointXYZRGB> > (cloud_box_filtered));
00204 voxelfilter.setLeafSize (0.05, 0.05, 0.05);
00205 voxelfilter.filter (cloud_voxel_reduced);
00206
00207
00208 NormalEstimation<PointXYZRGB, Normal> normalest;
00209 normalest.setViewPoint(0, 0, 0);
00210 normalest.setSearchMethod (boost::make_shared<search::KdTree<PointXYZRGB> > ());
00211
00212 normalest.setRadiusSearch (0.25);
00213 normalest.setInputCloud(boost::make_shared<const PointCloud<PointXYZRGB> >(cloud_voxel_reduced));
00214 normalest.compute(normals);
00215
00216 pcl::concatenateFields (cloud_voxel_reduced, normals, cloud_normals);
00217
00218
00219 PassThrough<PointXYZRGBNormal> normalfilter;
00220 normalfilter.setFilterFieldName("curvature");
00221 normalfilter.setFilterLimits(0.0, 0.1);
00222 normalfilter.setInputCloud(boost::make_shared<const PointCloud<PointXYZRGBNormal> >(cloud_normals));
00223 normalfilter.filter(output);
00224 }
00225
00226 void getMatchingIndices(PointCloud<PointXYZRGBNormal>& input, PointCloud<PointXYZRGBNormal>& output,
00227 std::vector<int>& input_indices, std::vector<int>& output_indices)
00228 {
00229
00230 KdTreeFLANN<PointXYZRGBNormal> input_tree, output_tree;
00231
00232 input_tree.setInputCloud(boost::make_shared<const PointCloud<PointXYZRGBNormal> >(input));
00233 output_tree.setInputCloud(boost::make_shared<const PointCloud<PointXYZRGBNormal> >(output));
00234
00235
00236
00237 for (unsigned int i = 0; i < input.points.size(); i++)
00238 {
00239 PointXYZRGBNormal input_pt = input.points[i];
00240 std::vector<int> input_indexvect(1), output_indexvect(1);
00241 std::vector<float> input_distvect(1), output_distvect(1);
00242
00243
00244 output_tree.nearestKSearch(input_pt, 1, input_indexvect, input_distvect);
00245
00246 PointXYZRGBNormal output_pt = output.points[input_indexvect[0]];
00247
00248
00249 input_tree.nearestKSearch(output_pt, 1, output_indexvect, output_distvect);
00250
00251
00252 if (output_indexvect[0] == (int)i)
00253 {
00254 input_indices.push_back(i);
00255 output_indices.push_back(input_indexvect[0]);
00256 }
00257 }
00258 }
00259
00260 Eigen::Vector3d projectPoint(Eigen::Vector4d& point)
00261 {
00262 Eigen::Vector3d keypoint;
00263
00264 keypoint(0) = (cam.fx*point.x()) / point.z() + cam.cx;
00265 keypoint(1) = (cam.fy*point.y()) / point.z() + cam.cy;
00266 keypoint(2) = (cam.fx*(point.x()-cam.tx)/point.z() + cam.cx);
00267
00268 return keypoint;
00269 }
00270 };
00271
00272 void drawVOtracks(const cv::Mat &image,
00273 const std::vector<FrameExtended, Eigen::aligned_allocator<FrameExtended> > &frames,
00274 cv::Mat &display);
00275
00276 }
00277 #endif // _FRAME_EXTENDED_H_
00278