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 
34 using namespace visionx;
35 
37 {
38  SetParameters();
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 
57 void
58 ICP::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 
95 void
96 ICP::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 
106 float
107 ICP::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 
221 void
222 ICP::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 
233 void
234 ICP::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 
254 void
255 ICP::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 }
ICP.h
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:737
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
visionx::ICP::~ICP
~ICP()
Definition: ICP.cpp:45
visionx::ICP::GetNearestNeighbors
void GetNearestNeighbors(std::vector< Eigen::Vector3f > &aNeighbors, std::vector< float > &aPointMatchDistances)
Definition: ICP.cpp:255
visionx::ICP::ICP
ICP()
Definition: ICP.cpp:36
visionx::ICP::SearchObject
float SearchObject(Mat3d &mRotation, Vec3d &vTranslation, const float fBestDistanceUntilNow=FLT_MAX)
Definition: ICP.cpp:107
visionx::ICP::SetScenePointcloud
void SetScenePointcloud(const std::vector< Eigen::Vector3f > &aScenePoints)
Definition: ICP.cpp:58
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:213
visionx::ICP::SetParameters
void SetParameters(float fCutoffDistance=FLT_MAX, float fConvergenceDelta=0.001f, int nMaxIterations=40, int nKdTreeBucketSize=50)
Definition: ICP.cpp:222
Logging.h
visionx::ICP::GetPointMatchDistances
void GetPointMatchDistances(std::vector< float > &aPointMatchDistances)
Definition: ICP.cpp:234
visionx::ICP::SetObjectPointcloud
void SetObjectPointcloud(const std::vector< Eigen::Vector3f > &aObjectPoints)
Definition: ICP.cpp:96