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 <DataStructures/KdTree/KdTree.h>
28 #include <Tracking/ICP.h>
29 
30 #include <cmath>
31 
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 ICP::SetScenePointcloud(const std::vector<Eigen::Vector3f>& aScenePoints)
58 {
59  // clean up
60  m_aScenePoints.clear();
61 
62  for (int i = 0; i < m_nNumScenePoints; i++)
63  {
64  delete[] m_pValues[i];
65  }
66 
67  delete[] m_pValues;
68  delete m_pKdTree;
69 
70  // copy points
71  const int nSize = aScenePoints.size();
72 
73  for (int i = 0; i < nSize; i++)
74  {
75  m_aScenePoints.push_back(aScenePoints.at(i));
76  }
77 
78  m_pKdTree = new CKdTree(nSize);
79 
80  m_pValues = new float*[nSize];
81  m_nNumScenePoints = nSize;
82 
83  for (int i = 0; i < nSize; i++)
84  {
85  m_pValues[i] = new float[3];
86  m_pValues[i][0] = aScenePoints.at(i)[0];
87  m_pValues[i][1] = aScenePoints.at(i)[1];
88  m_pValues[i][2] = aScenePoints.at(i)[2];
89  }
90 
91  m_pKdTree->Build(m_pValues, 0, nSize - 1, m_nKdTreeBucketSize, 3, 0);
92 }
93 
94 void ICP::SetObjectPointcloud(const std::vector<Eigen::Vector3f>& aObjectPoints)
95 {
96  m_aObjectPoints.clear();
97 
98  for (size_t i = 0; i < aObjectPoints.size(); i++)
99  {
100  m_aObjectPoints.push_back(aObjectPoints.at(i));
101  }
102 }
103 float ICP::SearchObject(Mat3d& mRotation, Vec3d& vTranslation, const float fBestDistanceUntilNow)
104 {
105  Math3d::SetMat(mRotation, Math3d::unit_mat);
106  Math3d::SetVec(vTranslation, 0, 0, 0);
107 
108  if (m_aObjectPoints.size() < 3)
109  {
110  ARMARX_WARNING_S << "CColorICP::SearchObject: not enough object points!";
111  return -1;
112  }
113 
114  if (m_aScenePoints.size() < 3)
115  {
116  ARMARX_WARNING_S << "CColorICP::SearchObject: not enough scene points!";
117  return -1;
118  }
119 
120  float fLastDistance = FLT_MAX;
121  float fDistance = 0, fPointDistance;
122  Vec3d vPoint, vPointTransformed;
123  float* pPointData = new float[3];
124  float* pNearestNeighbor;
125  Vec3d* pPointPositions = new Vec3d[m_aObjectPoints.size()];
126  Vec3d* pCorrespondingPointPositions = new Vec3d[m_aObjectPoints.size()];
127  int nNumPointCorrespondences;
128 
129  // iterations of the ICP algorithm
130  for (int n = 0; n < m_nMaxIterations; n++)
131  {
132  fDistance = 0;
133  nNumPointCorrespondences = 0;
134 
135  // find nearest neighbor for each point in XYZRGB space
136  for (size_t i = 0; i < m_aObjectPoints.size(); i++)
137  {
138  Math3d::SetVec(vPoint, m_aObjectPoints.at(i)[0], m_aObjectPoints.at(i)[1], m_aObjectPoints.at(i)[2]);
139  Math3d::MulMatVec(mRotation, vPoint, vTranslation, vPointTransformed);
140 
141  pPointData[0] = vPointTransformed.x;
142  pPointData[1] = vPointTransformed.y;
143  pPointData[2] = vPointTransformed.z;
144 
145  m_pKdTree->NearestNeighborBBF(pPointData, fPointDistance, pNearestNeighbor);
146 
147  fPointDistance = sqrtf(fPointDistance);
148 
149  // if the correspondence is too far away, we ignore it in the estimation of the transformation
150  if (fPointDistance > m_fCutoffDistance)
151  {
152  fDistance += m_fCutoffDistance;
153  }
154  else
155  {
156  fDistance += fPointDistance;
157  Math3d::SetVec(pPointPositions[nNumPointCorrespondences], vPoint);
158  Math3d::SetVec(pCorrespondingPointPositions[nNumPointCorrespondences], pNearestNeighbor[0], pNearestNeighbor[1], pNearestNeighbor[2]);
159  nNumPointCorrespondences++;
160  }
161  }
162 
163  if (nNumPointCorrespondences < 3)
164  {
165  ARMARX_WARNING_S << "CColorICP::SearchObject: not enough correspondences found!";
166  return -1;
167  }
168 
169  // re-estimate the transformation between the two pointclouds using the correspondences
170  CICP::CalculateOptimalTransformation(pPointPositions, pCorrespondingPointPositions, nNumPointCorrespondences, mRotation, vTranslation);
171 
172 
173  // if the improvement is very small, finish
174 
175  if (0.8f * fDistance < fBestDistanceUntilNow)
176  {
177  // if it seems we might get a new best result, quit only if improvement is very very small
178  if (1.0f - fDistance / fLastDistance < 0.01f * m_fConvergenceDelta)
179  {
180  break;
181  }
182  }
183  else if ((1.0f - fDistance / fLastDistance < m_fConvergenceDelta) || (2 * n > m_nMaxIterations))
184  {
185  // otherwise quit if improvement is below threshold or already many iterations
186  break;
187  }
188  else if ((0.5f * fDistance > fBestDistanceUntilNow) && (3 * n > m_nMaxIterations))
189  {
190  // if we dont seem to get close to the best result, quit earlier
191  break;
192  }
193 
194  fLastDistance = fDistance;
195 
196  //ARMARX_WARNING_S << "%.1f ", fDistance/m_aObjectPoints.size());
197  }
198 
199  delete[] pPointData;
200  delete[] pPointPositions;
201  delete[] pCorrespondingPointPositions;
202 
203  return fDistance / m_aObjectPoints.size();
204 }
205 
206 void ICP::SetParameters(float fCutoffDistance, float fConvergenceDelta, int nMaxIterations, int nKdTreeBucketSize)
207 {
208  m_fCutoffDistance = fCutoffDistance;
209  m_fConvergenceDelta = fConvergenceDelta;
210  m_nMaxIterations = nMaxIterations;
211  m_nKdTreeBucketSize = nKdTreeBucketSize;
212 }
213 
214 void ICP::GetPointMatchDistances(std::vector<float>& aPointMatchDistances)
215 {
216  float* pPointData = new float[3];
217  float* pNearestNeighbor;
218  float fDistance;
219 
220  for (size_t i = 0; i < m_aObjectPoints.size(); i++)
221  {
222  pPointData[0] = m_aObjectPoints.at(i)[0];
223  pPointData[1] = m_aObjectPoints.at(i)[1];
224  pPointData[2] = m_aObjectPoints.at(i)[2];
225 
226  m_pKdTree->NearestNeighborBBF(pPointData, fDistance, pNearestNeighbor);
227 
228  aPointMatchDistances.push_back(fDistance);
229  }
230 
231  delete[] pPointData;
232 }
233 
234 void ICP::GetNearestNeighbors(std::vector<Eigen::Vector3f>& aNeighbors, std::vector<float>& aPointMatchDistances)
235 {
236  float* pPointData = new float[3];
237  float* pNearestNeighbor;
238  Eigen::Vector3f pNearestNeighborPoint;
239  float fDistance;
240 
241  for (size_t i = 0; i < m_aObjectPoints.size(); i++)
242  {
243  pPointData[0] = m_aObjectPoints.at(i)[0];
244  pPointData[1] = m_aObjectPoints.at(i)[1];
245  pPointData[2] = m_aObjectPoints.at(i)[2];
246 
247  m_pKdTree->NearestNeighborBBF(pPointData, fDistance, pNearestNeighbor);
248 
249  pNearestNeighborPoint[0] = pNearestNeighbor[0];
250  pNearestNeighborPoint[1] = pNearestNeighbor[1];
251  pNearestNeighborPoint[2] = pNearestNeighbor[2];
252 
253  aNeighbors.push_back(pNearestNeighborPoint);
254  aPointMatchDistances.push_back(fDistance);
255  }
256 
257  delete[] pPointData;
258 }
ICP.h
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:234
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:103
visionx::ICP::SetScenePointcloud
void SetScenePointcloud(const std::vector< Eigen::Vector3f > &aScenePoints)
Definition: ICP.cpp:57
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:695
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:206
visionx::ICP::SetParameters
void SetParameters(float fCutoffDistance=FLT_MAX, float fConvergenceDelta=0.001f, int nMaxIterations=40, int nKdTreeBucketSize=50)
Definition: ICP.cpp:206
Logging.h
visionx::ICP::GetPointMatchDistances
void GetPointMatchDistances(std::vector< float > &aPointMatchDistances)
Definition: ICP.cpp:214
visionx::ICP::SetObjectPointcloud
void SetObjectPointcloud(const std::vector< Eigen::Vector3f > &aObjectPoints)
Definition: ICP.cpp:94