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