1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
#include <pcl/console/parse.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/point_representation.h>
#include <pcl/io/pcd_io.h>
#include <pcl/conversions.h>
#include <pcl/filters/uniform_sampling.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/fpfh.h>
#include <pcl/registration/correspondence_estimation.h>
#include <pcl/registration/correspondence_rejection_distance.h>
#include <pcl/registration/transformation_estimation_svd.h>
using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;
using namespace pcl::registration;
PointCloud<PointXYZ>::Ptr src, tgt;
////////////////////////////////////////////////////////////////////////////////
void
estimateKeypoints (const PointCloud<PointXYZ>::Ptr &src,
const PointCloud<PointXYZ>::Ptr &tgt,
PointCloud<PointXYZ> &keypoints_src,
PointCloud<PointXYZ> &keypoints_tgt)
{
// Get an uniform grid of keypoints
UniformSampling<PointXYZ> uniform;
uniform.setRadiusSearch (1); // 1m
uniform.setInputCloud (src);
uniform.filter (keypoints_src);
uniform.setInputCloud (tgt);
uniform.filter (keypoints_tgt);
// For debugging purposes only: uncomment the lines below and use pcl_viewer to view the results, i.e.:
// pcl_viewer source_pcd keypoints_src.pcd -ps 1 -ps 10
savePCDFileBinary ("keypoints_src.pcd", keypoints_src);
savePCDFileBinary ("keypoints_tgt.pcd", keypoints_tgt);
}
////////////////////////////////////////////////////////////////////////////////
void
estimateNormals (const PointCloud<PointXYZ>::Ptr &src,
const PointCloud<PointXYZ>::Ptr &tgt,
PointCloud<Normal> &normals_src,
PointCloud<Normal> &normals_tgt)
{
NormalEstimation<PointXYZ, Normal> normal_est;
normal_est.setInputCloud (src);
normal_est.setRadiusSearch (0.5); // 50cm
normal_est.compute (normals_src);
normal_est.setInputCloud (tgt);
normal_est.compute (normals_tgt);
// For debugging purposes only: uncomment the lines below and use pcl_viewer to view the results, i.e.:
// pcl_viewer normals_src.pcd
PointCloud<PointNormal> s, t;
copyPointCloud (*src, s);
copyPointCloud (normals_src, s);
copyPointCloud (*tgt, t);
copyPointCloud (normals_tgt, t);
savePCDFileBinary ("normals_src.pcd", s);
savePCDFileBinary ("normals_tgt.pcd", t);
}
////////////////////////////////////////////////////////////////////////////////
void
estimateFPFH (const PointCloud<PointXYZ>::Ptr &src,
const PointCloud<PointXYZ>::Ptr &tgt,
const PointCloud<Normal>::Ptr &normals_src,
const PointCloud<Normal>::Ptr &normals_tgt,
const PointCloud<PointXYZ>::Ptr &keypoints_src,
const PointCloud<PointXYZ>::Ptr &keypoints_tgt,
PointCloud<FPFHSignature33> &fpfhs_src,
PointCloud<FPFHSignature33> &fpfhs_tgt)
{
FPFHEstimation<PointXYZ, Normal, FPFHSignature33> fpfh_est;
fpfh_est.setInputCloud (keypoints_src);
fpfh_est.setInputNormals (normals_src);
fpfh_est.setRadiusSearch (1); // 1m
fpfh_est.setSearchSurface (src);
fpfh_est.compute (fpfhs_src);
fpfh_est.setInputCloud (keypoints_tgt);
fpfh_est.setInputNormals (normals_tgt);
fpfh_est.setSearchSurface (tgt);
fpfh_est.compute (fpfhs_tgt);
// For debugging purposes only: uncomment the lines below and use pcl_viewer to view the results, i.e.:
// pcl_viewer fpfhs_src.pcd
PCLPointCloud2 s, t, out;
toPCLPointCloud2 (*keypoints_src, s); toPCLPointCloud2 (fpfhs_src, t); concatenateFields (s, t, out);
savePCDFile ("fpfhs_src.pcd", out);
toPCLPointCloud2 (*keypoints_tgt, s); toPCLPointCloud2 (fpfhs_tgt, t); concatenateFields (s, t, out);
savePCDFile ("fpfhs_tgt.pcd", out);
}
////////////////////////////////////////////////////////////////////////////////
void
findCorrespondences (const PointCloud<FPFHSignature33>::Ptr &fpfhs_src,
const PointCloud<FPFHSignature33>::Ptr &fpfhs_tgt,
Correspondences &all_correspondences)
{
CorrespondenceEstimation<FPFHSignature33, FPFHSignature33> est;
est.setInputCloud (fpfhs_src);
est.setInputTarget (fpfhs_tgt);
est.determineReciprocalCorrespondences (all_correspondences);
}
////////////////////////////////////////////////////////////////////////////////
void
rejectBadCorrespondences (const CorrespondencesPtr &all_correspondences,
const PointCloud<PointXYZ>::Ptr &keypoints_src,
const PointCloud<PointXYZ>::Ptr &keypoints_tgt,
Correspondences &remaining_correspondences)
{
CorrespondenceRejectorDistance rej;
rej.setInputSource<PointXYZ> (keypoints_src);
rej.setInputTarget<PointXYZ> (keypoints_tgt);
rej.setMaximumDistance (1); // 1m
rej.setInputCorrespondences (all_correspondences);
rej.getCorrespondences (remaining_correspondences);
}
////////////////////////////////////////////////////////////////////////////////
void
computeTransformation (const PointCloud<PointXYZ>::Ptr &src,
const PointCloud<PointXYZ>::Ptr &tgt,
Eigen::Matrix4f &transform)
{
// Get an uniform grid of keypoints
PointCloud<PointXYZ>::Ptr keypoints_src (new PointCloud<PointXYZ>),
keypoints_tgt (new PointCloud<PointXYZ>);
estimateKeypoints (src, tgt, *keypoints_src, *keypoints_tgt);
print_info ("Found %zu and %zu keypoints for the source and target datasets.\n", static_cast<std::size_t>(keypoints_src->size ()), static_cast<std::size_t>(keypoints_tgt->size ()));
// Compute normals for all points keypoint
PointCloud<Normal>::Ptr normals_src (new PointCloud<Normal>),
normals_tgt (new PointCloud<Normal>);
estimateNormals (src, tgt, *normals_src, *normals_tgt);
print_info ("Estimated %zu and %zu normals for the source and target datasets.\n", static_cast<std::size_t>(normals_src->size ()), static_cast<std::size_t>(normals_tgt->size ()));
// Compute FPFH features at each keypoint
PointCloud<FPFHSignature33>::Ptr fpfhs_src (new PointCloud<FPFHSignature33>),
fpfhs_tgt (new PointCloud<FPFHSignature33>);
estimateFPFH (src, tgt, normals_src, normals_tgt, keypoints_src, keypoints_tgt, *fpfhs_src, *fpfhs_tgt);
// Copy the data and save it to disk
/* PointCloud<PointNormal> s, t;
copyPointCloud (*keypoints_src, s);
copyPointCloud (normals_src, s);
copyPointCloud (*keypoints_tgt, t);
copyPointCloud (normals_tgt, t);*/
// Find correspondences between keypoints in FPFH space
CorrespondencesPtr all_correspondences (new Correspondences),
good_correspondences (new Correspondences);
findCorrespondences (fpfhs_src, fpfhs_tgt, *all_correspondences);
// Reject correspondences based on their XYZ distance
rejectBadCorrespondences (all_correspondences, keypoints_src, keypoints_tgt, *good_correspondences);
for (int i = 0; i < good_correspondences->size (); ++i)
std::cerr << good_correspondences->at (i) << std::endl;
// Obtain the best transformation between the two sets of keypoints given the remaining correspondences
TransformationEstimationSVD<PointXYZ, PointXYZ> trans_est;
trans_est.estimateRigidTransformation (*keypoints_src, *keypoints_tgt, *good_correspondences, transform);
}
/* ---[ */
int
main (int argc, char** argv)
{
// Parse the command line arguments for .pcd files
std::vector<int> p_file_indices;
p_file_indices = parse_file_extension_argument (argc, argv, ".pcd");
if (p_file_indices.size () != 2)
{
print_error ("Need one input source PCD file and one input target PCD file to continue.\n");
print_error ("Example: %s source.pcd target.pcd\n", argv[0]);
return (-1);
}
// Load the files
print_info ("Loading %s as source and %s as target...\n", argv[p_file_indices[0]], argv[p_file_indices[1]]);
src.reset (new PointCloud<PointXYZ>);
tgt.reset (new PointCloud<PointXYZ>);
if (loadPCDFile (argv[p_file_indices[0]], *src) == -1 || loadPCDFile (argv[p_file_indices[1]], *tgt) == -1)
{
print_error ("Error reading the input files!\n");
return (-1);
}
// Compute the best transformtion
Eigen::Matrix4f transform;
computeTransformation (src, tgt, transform);
std::cerr << transform << std::endl;
// Transform the data and write it to disk
PointCloud<PointXYZ> output;
transformPointCloud (*src, output, transform);
savePCDFileBinary ("source_transformed.pcd", output);
}
/* ]--- */
|