367 lines
14 KiB
HTML
367 lines
14 KiB
HTML
|
||
|
||
<!DOCTYPE html>
|
||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||
<head>
|
||
<meta charset="utf-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
||
<title>The PCL Registration API — Point Cloud Library 1.12.0 documentation</title>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script type="text/javascript" src="_static/js/modernizr.min.js"></script>
|
||
|
||
|
||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||
<script type="text/javascript" src="_static/underscore.js"></script>
|
||
<script type="text/javascript" src="_static/doctools.js"></script>
|
||
<script type="text/javascript" src="_static/language_data.js"></script>
|
||
|
||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
</head>
|
||
|
||
<body class="wy-body-for-nav">
|
||
|
||
|
||
<div class="wy-grid-for-nav">
|
||
|
||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||
<div class="wy-side-scroll">
|
||
<div class="wy-side-nav-search" >
|
||
|
||
|
||
|
||
<a href="index.html" class="icon icon-home"> Point Cloud Library
|
||
|
||
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
<div class="version">
|
||
1.12.0
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<div role="search">
|
||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||
<input type="text" name="q" placeholder="Search docs" />
|
||
<input type="hidden" name="check_keywords" value="yes" />
|
||
<input type="hidden" name="area" value="default" />
|
||
</form>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<!-- Local TOC -->
|
||
<div class="local-toc"><ul>
|
||
<li><a class="reference internal" href="#">The PCL Registration API</a></li>
|
||
<li><a class="reference internal" href="#an-overview-of-pairwise-registration">An overview of pairwise registration</a></li>
|
||
<li><a class="reference internal" href="#registration-modules">Registration modules</a><ul>
|
||
<li><a class="reference internal" href="#keypoints">Keypoints</a></li>
|
||
<li><a class="reference internal" href="#feature-descriptors">Feature descriptors</a></li>
|
||
<li><a class="reference internal" href="#correspondences-estimation">Correspondences estimation</a></li>
|
||
<li><a class="reference internal" href="#correspondences-rejection">Correspondences rejection</a></li>
|
||
<li><a class="reference internal" href="#transformation-estimation">Transformation estimation</a></li>
|
||
<li><a class="reference internal" href="#example-pipelines">Example pipelines</a><ul>
|
||
<li><a class="reference internal" href="#iterative-closest-point">Iterative Closest Point</a></li>
|
||
<li><a class="reference internal" href="#feature-based-registration">Feature based registration</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#example-1-office-scene-kinect-data">Example 1: Office scene, Kinect data</a></li>
|
||
<li><a class="reference internal" href="#example-2-outdoor-scene-laser-riegl-data">Example 2: Outdoor scene, Laser (Riegl) data</a></li>
|
||
<li><a class="reference internal" href="#example-3-indoor-scene-laser-sick-data">Example 3: Indoor scene, Laser (SICK) data</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||
|
||
|
||
<nav class="wy-nav-top" aria-label="top navigation">
|
||
|
||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||
<a href="index.html">Point Cloud Library</a>
|
||
|
||
</nav>
|
||
|
||
|
||
<div class="wy-nav-content">
|
||
|
||
<div class="rst-content">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||
|
||
<ul class="wy-breadcrumbs">
|
||
|
||
<li><a href="index.html">Docs</a> »</li>
|
||
|
||
<li>The PCL Registration API</li>
|
||
|
||
|
||
<li class="wy-breadcrumbs-aside">
|
||
|
||
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
<hr/>
|
||
</div>
|
||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||
<div itemprop="articleBody">
|
||
|
||
<div class="section" id="the-pcl-registration-api">
|
||
<span id="registration-api"></span><h1>The PCL Registration API</h1>
|
||
<p>The problem of consistently aligning various 3D point cloud data views into a
|
||
complete model is known as <strong>registration</strong>. Its goal is to find the relative
|
||
positions and orientations of the separately acquired views in a global
|
||
coordinate framework, such that the intersecting areas between them overlap
|
||
perfectly. For every set of point cloud datasets acquired from different views,
|
||
we therefore need a system that is able to align them together into a single
|
||
point cloud model, so that subsequent processing steps such as segmentation and
|
||
object reconstruction can be applied.</p>
|
||
<img alt="_images/scans.jpg" class="align-center" src="_images/scans.jpg" />
|
||
<p>A motivation example in this sense is given in the figure above, where a set of
|
||
six individual datasets has been acquired using a tilting 2D laser unit. Since
|
||
each individual scan represents only a small part of the surrounding world, it
|
||
is imperative to find ways to register them together, thus creating the complete
|
||
point cloud model as shown in the figure below.</p>
|
||
<img alt="_images/s1-6.jpg" class="align-center" src="_images/s1-6.jpg" />
|
||
<p>The algorithmic work in the PCL registration library is motivated by finding
|
||
correct point correspondences in the given input datasets, and estimating rigid
|
||
transformations that can rotate and translate each individual dataset into a
|
||
consistent global coordinate framework. This registration paradigm becomes
|
||
easily solvable if the point correspondences are perfectly known in the input
|
||
datasets. This means that a selected list of points in one dataset have to
|
||
“coincide” from a feature representation point of view with a list of points
|
||
from another dataset. Additionally, if the correspondences estimated are
|
||
“perfect”, then the registration problem has a closed form solution.</p>
|
||
<p>PCL contains a set of powerful algorithms that allow the estimation of multiple
|
||
sets of correspondences, as well as methods for rejecting bad correspondences,
|
||
and estimating transformations in a robust manner from them. The following
|
||
sections will describe each of them individually.</p>
|
||
</div>
|
||
<div class="section" id="an-overview-of-pairwise-registration">
|
||
<h1>An overview of pairwise registration</h1>
|
||
<p>We sometimes refer to the problem of registering a pair of point cloud datasets
|
||
together as <em>pairwise registration</em>, and its output is usually a rigid
|
||
transformation matrix (4x4) representing the rotation and translation that would
|
||
have to be applied on one of the datasets (let’s call it <em>source</em>) in order for
|
||
it to be perfectly aligned with the other dataset (let’s call it <em>target</em>, or
|
||
<em>model</em>).</p>
|
||
<p>The steps performed in a <em>pairwise registration</em> step are shown in the diagram
|
||
below. Please note that we are representing a single iteration of the algorithm.
|
||
The programmer can decide to loop over any or all of the steps.</p>
|
||
<img alt="_images/block_diagram_single_iteration.jpg" class="align-center" src="_images/block_diagram_single_iteration.jpg" />
|
||
<p>The computational steps for two datasets are straightforward:</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li>from a set of points, identify <strong>interest points</strong> (i.e., <strong>keypoints</strong>) that best represent the scene in both datasets;</li>
|
||
<li>at each keypoint, compute a <strong>feature descriptor</strong>;</li>
|
||
<li>from the set of <strong>feature descriptors</strong> together with their XYZ positions in the two datasets, estimate a set of <strong>correspondences</strong>, based on the similarities between features and positions;</li>
|
||
<li>given that the data is assumed to be noisy, not all correspondences are valid, so reject those bad correspondences that contribute negatively to the registration process;</li>
|
||
<li>from the remaining set of good correspondences, estimate a motion transformation.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
</div>
|
||
<div class="section" id="registration-modules">
|
||
<h1>Registration modules</h1>
|
||
<p>Let’s have a look at the single steps of the pipeline.</p>
|
||
<div class="section" id="keypoints">
|
||
<h2>Keypoints</h2>
|
||
<p>A keypoint is an interest point that has a “special property” in the scene,
|
||
like the corner of a book, or the letter “P” on a book that has written “PCL”
|
||
on it. There are a number of different keypoints available in PCL like NARF,
|
||
SIFT and FAST. Alternatively you can take every point, or a subset, as
|
||
keypoints as well. The problem with “feeding two kinect datasets into a correspondence estimation” directly is that you have 300k points in each frame, so there can be 300k^2 correspondences.</p>
|
||
</div>
|
||
<div class="section" id="feature-descriptors">
|
||
<h2>Feature descriptors</h2>
|
||
<p>Based on the keypoints found we have to extract [features](<a class="reference external" href="http://www.pointclouds.org/documentation/tutorials/how_features_work.php">http://www.pointclouds.org/documentation/tutorials/how_features_work.php</a>), where we assemble the information and generate vectors to compare them with each other. Again there
|
||
is a number of feature options to choose from, for example NARF, FPFH, BRIEF or
|
||
SIFT.</p>
|
||
</div>
|
||
<div class="section" id="correspondences-estimation">
|
||
<h2>Correspondences estimation</h2>
|
||
<p>Given two sets of feature vectors coming from two acquired scans we have to
|
||
find corresponding features to find overlapping parts in the data. Depending on
|
||
the feature type we can use different methods to find the correspondences.</p>
|
||
<p>For <em>point matching</em> (using the points’ xyz-coordinates as features) different
|
||
methods exist for organized and unorganized data:</p>
|
||
<ul class="simple">
|
||
<li>brute force matching,</li>
|
||
<li>kd-tree nearest neighbor search (FLANN),</li>
|
||
<li>searching in the image space of organized data, and</li>
|
||
<li>searching in the index space of organized data.</li>
|
||
</ul>
|
||
<p>For <em>feature matching</em> (not using the points’ coordinates, but certain features)
|
||
only the following methods exist:</p>
|
||
<ul class="simple">
|
||
<li>brute force matching and</li>
|
||
<li>kd-tree nearest neighbor search (FLANN).</li>
|
||
</ul>
|
||
<p>In addition to the search, two types of correspondence estimation are
|
||
distinguished:</p>
|
||
<ul class="simple">
|
||
<li>Direct correspondence estimation (default) searches for correspondences
|
||
in cloud B for every point in cloud A .</li>
|
||
<li>“Reciprocal” correspondence estimation searches for correspondences from
|
||
cloud A to cloud B, and from B to A and only use the intersection.</li>
|
||
</ul>
|
||
</div>
|
||
<div class="section" id="correspondences-rejection">
|
||
<h2>Correspondences rejection</h2>
|
||
<p>Naturally, not all estimated correspondences are correct.
|
||
Since wrong correspondences can negatively affect the estimation of the final
|
||
transformation, they need to be rejected.
|
||
This could be done using RANSAC or by trimming down the amount and using only a
|
||
certain percent of the found correspondences.</p>
|
||
<p>A special case are one to many correspondences where one point in the model
|
||
corresponds to a number of points in the source. These could be filtered by
|
||
using only the one with the smallest distance or by checking for other
|
||
matchings near by.</p>
|
||
</div>
|
||
<div class="section" id="transformation-estimation">
|
||
<h2>Transformation estimation</h2>
|
||
<p>The last step is to actually compute the transformation.</p>
|
||
<ul class="simple">
|
||
<li>evaluate some error metric based on correspondence</li>
|
||
<li>estimate a (rigid) transformation between camera poses (motion estimate) and minimize error metric</li>
|
||
<li>optimize the structure of the points</li>
|
||
<li>Examples:
|
||
- SVD for motion estimate;
|
||
- Levenberg-Marquardt with different kernels for motion estimate;</li>
|
||
<li>use the rigid transformation to rotate/translate the source onto the target,
|
||
and potentially run an internal ICP loop with either all points or a subset
|
||
of points or the keypoints</li>
|
||
<li>iterate until some convergence criterion is met</li>
|
||
</ul>
|
||
</div>
|
||
<div class="section" id="example-pipelines">
|
||
<h2>Example pipelines</h2>
|
||
<div class="section" id="iterative-closest-point">
|
||
<h3>Iterative Closest Point</h3>
|
||
<ol class="arabic simple">
|
||
<li>Search for correspondences.</li>
|
||
<li>Reject bad correspondences.</li>
|
||
<li>Estimate a transformation using the good correspondences.</li>
|
||
<li>Iterate.</li>
|
||
</ol>
|
||
</div>
|
||
<div class="section" id="feature-based-registration">
|
||
<h3>Feature based registration</h3>
|
||
<ol class="arabic simple">
|
||
<li>use SIFT Keypoints (pcl::SIFT…something)</li>
|
||
<li>use FPFH descriptors (pcl::FPFHEstimation) at the keypoints (see our tutorials for that, like http://www.pointclouds.org/media/rss2011.html)</li>
|
||
<li>get the FPFH descriptors and estimate correspondences using pcl::CorrespondenceEstimation</li>
|
||
<li>reject bad correspondences using one or many of the pcl::CorrespondenceRejectionXXX methods</li>
|
||
<li>finally get a transformation as mentioned above</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="example-1-office-scene-kinect-data">
|
||
<h1>Example 1: Office scene, Kinect data</h1>
|
||
</div>
|
||
<div class="section" id="example-2-outdoor-scene-laser-riegl-data">
|
||
<h1>Example 2: Outdoor scene, Laser (Riegl) data</h1>
|
||
</div>
|
||
<div class="section" id="example-3-indoor-scene-laser-sick-data">
|
||
<h1>Example 3: Indoor scene, Laser (SICK) data</h1>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<footer>
|
||
|
||
|
||
<hr/>
|
||
|
||
<div role="contentinfo">
|
||
<p>
|
||
© Copyright
|
||
|
||
</p>
|
||
</div>
|
||
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||
|
||
</footer>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</section>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script type="text/javascript">
|
||
jQuery(function () {
|
||
SphinxRtdTheme.Navigation.enable(true);
|
||
});
|
||
</script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</body>
|
||
</html> |