ICP.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "ICP.h"
25
26// IVT
27#include <cmath>
28
30
31#include <DataStructures/KdTree/KdTree.h>
32#include <Tracking/ICP.h>
33
34using namespace visionx;
35
37{
39 m_pKdTree = new CKdTree();
40
41 m_nNumScenePoints = 0;
42 m_pValues = new float*[1];
43}
44
46{
47 delete m_pKdTree;
48
49 for (int i = 0; i < m_nNumScenePoints; i++)
50 {
51 delete[] m_pValues[i];
52 }
53
54 delete[] m_pValues;
55}
56
57void
58ICP::SetScenePointcloud(const std::vector<Eigen::Vector3f>& aScenePoints)
59{
60 // clean up
61 m_aScenePoints.clear();
62
63 for (int i = 0; i < m_nNumScenePoints; i++)
64 {
65 delete[] m_pValues[i];
66 }
67
68 delete[] m_pValues;
69 delete m_pKdTree;
70
71 // copy points
72 const int nSize = aScenePoints.size();
73
74 for (int i = 0; i < nSize; i++)
75 {
76 m_aScenePoints.push_back(aScenePoints.at(i));
77 }
78
79 m_pKdTree = new CKdTree(nSize);
80
81 m_pValues = new float*[nSize];
82 m_nNumScenePoints = nSize;
83
84 for (int i = 0; i < nSize; i++)
85 {
86 m_pValues[i] = new float[3];
87 m_pValues[i][0] = aScenePoints.at(i)[0];
88 m_pValues[i][1] = aScenePoints.at(i)[1];
89 m_pValues[i][2] = aScenePoints.at(i)[2];
90 }
91
92 m_pKdTree->Build(m_pValues, 0, nSize - 1, m_nKdTreeBucketSize, 3, 0);
93}
94
95void
96ICP::SetObjectPointcloud(const std::vector<Eigen::Vector3f>& aObjectPoints)
97{
98 m_aObjectPoints.clear();
99
100 for (size_t i = 0; i < aObjectPoints.size(); i++)
101 {
102 m_aObjectPoints.push_back(aObjectPoints.at(i));
103 }
104}
105
106float
107ICP::SearchObject(Mat3d& mRotation, Vec3d& vTranslation, const float fBestDistanceUntilNow)
108{
109 Math3d::SetMat(mRotation, Math3d::unit_mat);
110 Math3d::SetVec(vTranslation, 0, 0, 0);
111
112 if (m_aObjectPoints.size() < 3)
113 {
114 ARMARX_WARNING_S << "CColorICP::SearchObject: not enough object points!";
115 return -1;
116 }
117
118 if (m_aScenePoints.size() < 3)
119 {
120 ARMARX_WARNING_S << "CColorICP::SearchObject: not enough scene points!";
121 return -1;
122 }
123
124 float fLastDistance = FLT_MAX;
125 float fDistance = 0, fPointDistance;
126 Vec3d vPoint, vPointTransformed;
127 float* pPointData = new float[3];
128 float* pNearestNeighbor;
129 Vec3d* pPointPositions = new Vec3d[m_aObjectPoints.size()];
130 Vec3d* pCorrespondingPointPositions = new Vec3d[m_aObjectPoints.size()];
131 int nNumPointCorrespondences;
132
133 // iterations of the ICP algorithm
134 for (int n = 0; n < m_nMaxIterations; n++)
135 {
136 fDistance = 0;
137 nNumPointCorrespondences = 0;
138
139 // find nearest neighbor for each point in XYZRGB space
140 for (size_t i = 0; i < m_aObjectPoints.size(); i++)
141 {
142 Math3d::SetVec(vPoint,
143 m_aObjectPoints.at(i)[0],
144 m_aObjectPoints.at(i)[1],
145 m_aObjectPoints.at(i)[2]);
146 Math3d::MulMatVec(mRotation, vPoint, vTranslation, vPointTransformed);
147
148 pPointData[0] = vPointTransformed.x;
149 pPointData[1] = vPointTransformed.y;
150 pPointData[2] = vPointTransformed.z;
151
152 m_pKdTree->NearestNeighborBBF(pPointData, fPointDistance, pNearestNeighbor);
153
154 fPointDistance = sqrtf(fPointDistance);
155
156 // if the correspondence is too far away, we ignore it in the estimation of the transformation
157 if (fPointDistance > m_fCutoffDistance)
158 {
159 fDistance += m_fCutoffDistance;
160 }
161 else
162 {
163 fDistance += fPointDistance;
164 Math3d::SetVec(pPointPositions[nNumPointCorrespondences], vPoint);
165 Math3d::SetVec(pCorrespondingPointPositions[nNumPointCorrespondences],
166 pNearestNeighbor[0],
167 pNearestNeighbor[1],
168 pNearestNeighbor[2]);
169 nNumPointCorrespondences++;
170 }
171 }
172
173 if (nNumPointCorrespondences < 3)
174 {
175 ARMARX_WARNING_S << "CColorICP::SearchObject: not enough correspondences found!";
176 return -1;
177 }
178
179 // re-estimate the transformation between the two pointclouds using the correspondences
180 CICP::CalculateOptimalTransformation(pPointPositions,
181 pCorrespondingPointPositions,
182 nNumPointCorrespondences,
183 mRotation,
184 vTranslation);
185
186
187 // if the improvement is very small, finish
188
189 if (0.8f * fDistance < fBestDistanceUntilNow)
190 {
191 // if it seems we might get a new best result, quit only if improvement is very very small
192 if (1.0f - fDistance / fLastDistance < 0.01f * m_fConvergenceDelta)
193 {
194 break;
195 }
196 }
197 else if ((1.0f - fDistance / fLastDistance < m_fConvergenceDelta) ||
198 (2 * n > m_nMaxIterations))
199 {
200 // otherwise quit if improvement is below threshold or already many iterations
201 break;
202 }
203 else if ((0.5f * fDistance > fBestDistanceUntilNow) && (3 * n > m_nMaxIterations))
204 {
205 // if we dont seem to get close to the best result, quit earlier
206 break;
207 }
208
209 fLastDistance = fDistance;
210
211 //ARMARX_WARNING_S << "%.1f ", fDistance/m_aObjectPoints.size());
212 }
213
214 delete[] pPointData;
215 delete[] pPointPositions;
216 delete[] pCorrespondingPointPositions;
217
218 return fDistance / m_aObjectPoints.size();
219}
220
221void
222ICP::SetParameters(float fCutoffDistance,
223 float fConvergenceDelta,
224 int nMaxIterations,
225 int nKdTreeBucketSize)
226{
227 m_fCutoffDistance = fCutoffDistance;
228 m_fConvergenceDelta = fConvergenceDelta;
229 m_nMaxIterations = nMaxIterations;
230 m_nKdTreeBucketSize = nKdTreeBucketSize;
231}
232
233void
234ICP::GetPointMatchDistances(std::vector<float>& aPointMatchDistances)
235{
236 float* pPointData = new float[3];
237 float* pNearestNeighbor;
238 float fDistance;
239
240 for (size_t i = 0; i < m_aObjectPoints.size(); i++)
241 {
242 pPointData[0] = m_aObjectPoints.at(i)[0];
243 pPointData[1] = m_aObjectPoints.at(i)[1];
244 pPointData[2] = m_aObjectPoints.at(i)[2];
245
246 m_pKdTree->NearestNeighborBBF(pPointData, fDistance, pNearestNeighbor);
247
248 aPointMatchDistances.push_back(fDistance);
249 }
250
251 delete[] pPointData;
252}
253
254void
255ICP::GetNearestNeighbors(std::vector<Eigen::Vector3f>& aNeighbors,
256 std::vector<float>& aPointMatchDistances)
257{
258 float* pPointData = new float[3];
259 float* pNearestNeighbor;
260 Eigen::Vector3f pNearestNeighborPoint;
261 float fDistance;
262
263 for (size_t i = 0; i < m_aObjectPoints.size(); i++)
264 {
265 pPointData[0] = m_aObjectPoints.at(i)[0];
266 pPointData[1] = m_aObjectPoints.at(i)[1];
267 pPointData[2] = m_aObjectPoints.at(i)[2];
268
269 m_pKdTree->NearestNeighborBBF(pPointData, fDistance, pNearestNeighbor);
270
271 pNearestNeighborPoint[0] = pNearestNeighbor[0];
272 pNearestNeighborPoint[1] = pNearestNeighbor[1];
273 pNearestNeighborPoint[2] = pNearestNeighbor[2];
274
275 aNeighbors.push_back(pNearestNeighborPoint);
276 aPointMatchDistances.push_back(fDistance);
277 }
278
279 delete[] pPointData;
280}
void GetNearestNeighbors(std::vector< Eigen::Vector3f > &aNeighbors, std::vector< float > &aPointMatchDistances)
Definition ICP.cpp:255
void SetScenePointcloud(const std::vector< Eigen::Vector3f > &aScenePoints)
Definition ICP.cpp:58
void GetPointMatchDistances(std::vector< float > &aPointMatchDistances)
Definition ICP.cpp:234
void SetParameters(float fCutoffDistance=FLT_MAX, float fConvergenceDelta=0.001f, int nMaxIterations=40, int nKdTreeBucketSize=50)
Definition ICP.cpp:222
void SetObjectPointcloud(const std::vector< Eigen::Vector3f > &aObjectPoints)
Definition ICP.cpp:96
float SearchObject(Mat3d &mRotation, Vec3d &vTranslation, const float fBestDistanceUntilNow=FLT_MAX)
Definition ICP.cpp:107
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
ArmarX headers.