ColorICP.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 "ColorICP.h"
25
27
28// IVT
29#include <cmath>
30
32
33#include <DataStructures/KdTree/KdTree.h>
34#include <Tracking/ICP.h>
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
58CColorICP::SetScenePointcloud(std::vector<CColorICP::CPointXYZRGBI> 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[7];
87 m_pValues[i][0] = aScenePoints.at(i).x;
88 m_pValues[i][1] = aScenePoints.at(i).y;
89 m_pValues[i][2] = aScenePoints.at(i).z;
90 m_pValues[i][3] = m_fColorWeight * aScenePoints.at(i).r;
91 m_pValues[i][4] = m_fColorWeight * aScenePoints.at(i).g;
92 m_pValues[i][5] = m_fColorWeight * aScenePoints.at(i).b;
93 m_pValues[i][6] = m_fColorWeight * aScenePoints.at(i).i;
94 }
95
96 bool bUseIntensity = OLP_EFFORT_POINTCLOUD_MATCHING > 0;
97
98 if (bUseIntensity)
99 {
100 m_pKdTree->Build(m_pValues, 0, nSize - 1, m_nKdTreeBucketSize, 7, 0);
101 }
102 else
103 {
104 m_pKdTree->Build(m_pValues, 0, nSize - 1, m_nKdTreeBucketSize, 6, 1);
105 }
106}
107
108float
109CColorICP::SearchObject(const std::vector<CPointXYZRGBI>& aObjectPoints,
110 Mat3d& mRotation,
111 Vec3d& vTranslation,
112 const float fBestDistanceUntilNow)
113{
114 Math3d::SetMat(mRotation, Math3d::unit_mat);
115 Math3d::SetVec(vTranslation, 0, 0, 0);
116
117 if (aObjectPoints.size() < 3)
118 {
119 ARMARX_VERBOSE_S << "CColorICP::SearchObject: not enough object points!";
120 return FLT_MAX;
121 }
122
123 if (m_aScenePoints.size() < 3)
124 {
125 ARMARX_WARNING_S << "CColorICP::SearchObject: not enough scene points!";
126 return FLT_MAX;
127 }
128
129 float fLastDistance = FLT_MAX;
130 float fDistance = 0, fPointDistance;
131 Vec3d vPoint, vPointTransformed;
132 float* pPointData = new float[7];
133 float* pNearestNeighbor;
134 Vec3d* pPointPositions = new Vec3d[aObjectPoints.size()];
135 Vec3d* pCorrespondingPointPositions = new Vec3d[aObjectPoints.size()];
136 int nNumPointCorrespondences;
137
138 // iterations of the ICP algorithm
139 for (int n = 0; n < m_nMaxIterations; n++)
140 {
141 fDistance = 0;
142 nNumPointCorrespondences = 0;
143
144 // find nearest neighbor for each point in XYZRGB space
145 for (size_t i = 0; i < aObjectPoints.size(); i++)
146 {
147 Math3d::SetVec(
148 vPoint, aObjectPoints.at(i).x, aObjectPoints.at(i).y, aObjectPoints.at(i).z);
149 Math3d::MulMatVec(mRotation, vPoint, vTranslation, vPointTransformed);
150
151 pPointData[0] = vPointTransformed.x;
152 pPointData[1] = vPointTransformed.y;
153 pPointData[2] = vPointTransformed.z;
154 pPointData[3] = m_fColorWeight * aObjectPoints.at(i).r;
155 pPointData[4] = m_fColorWeight * aObjectPoints.at(i).g;
156 pPointData[5] = m_fColorWeight * aObjectPoints.at(i).b;
157 pPointData[6] = m_fColorWeight * aObjectPoints.at(i).i;
158
159 m_pKdTree->NearestNeighborBBF(pPointData, fPointDistance, pNearestNeighbor);
160 //FindNNBruteForce(pPointData, fPointDistance, pNearestNeighbor);
161
162 fPointDistance = sqrtf(fPointDistance);
163
164 // if (i%10==0)
165 // {
166 // ARMARX_WARNING_S << "(%.1f %.1f %.1f %.1f %.1f %.1f) , (%.1f %.1f %.1f %.1f %.1f %.1f) : %.1f\n",
167 // pPointData[0], pPointData[1], pPointData[2], pPointData[3], pPointData[4], pPointData[5],
168 // pNearestNeighbor[0], pNearestNeighbor[1], pNearestNeighbor[2], pNearestNeighbor[3], pNearestNeighbor[4], pNearestNeighbor[5], fPointDistance);
169 // }
170
171 // if the correspondence is too far away, we ignore it in the estimation of the transformation
172 if (fPointDistance > m_fCutoffDistance)
173 {
174 fDistance += m_fCutoffDistance;
175 }
176 else
177 {
178 fDistance += fPointDistance;
179 Math3d::SetVec(pPointPositions[nNumPointCorrespondences], vPoint);
180 Math3d::SetVec(pCorrespondingPointPositions[nNumPointCorrespondences],
181 pNearestNeighbor[0],
182 pNearestNeighbor[1],
183 pNearestNeighbor[2]);
184 nNumPointCorrespondences++;
185 }
186 }
187
188 if (nNumPointCorrespondences < 3)
189 {
190 ARMARX_IMPORTANT_S << "CColorICP::SearchObject: less than 3 correspondences found - no "
191 "transformation determined";
192 return FLT_MAX;
193 }
194
195 // re-estimate the transformation between the two pointclouds using the correspondences
196 CICP::CalculateOptimalTransformation(pPointPositions,
197 pCorrespondingPointPositions,
198 nNumPointCorrespondences,
199 mRotation,
200 vTranslation);
201
202
203 // if the improvement is very small, finish
204
205 if (0.8f * fDistance < fBestDistanceUntilNow)
206 {
207 // if it seems we might get a new best result, quit only if improvement is very very small
208 if (1.0f - fDistance / fLastDistance < 0.01f * m_fConvergenceDelta)
209 {
210 break;
211 }
212 }
213 else if ((1.0f - fDistance / fLastDistance < m_fConvergenceDelta) ||
214 (2 * n > m_nMaxIterations))
215 {
216 // otherwise quit if improvement is below threshold or already many iterations
217 break;
218 }
219 else if ((0.5f * fDistance > fBestDistanceUntilNow) && (3 * n > m_nMaxIterations))
220 {
221 // if we dont seem to get close to the best result, quit earlier
222 break;
223 }
224
225 fLastDistance = fDistance;
226
227 //ARMARX_WARNING_S << "%.1f ", fDistance/aObjectPoints.size());
228 }
229
230 delete[] pPointData;
231 delete[] pPointPositions;
232 delete[] pCorrespondingPointPositions;
233
234 return fDistance / aObjectPoints.size();
235}
236
237void
238CColorICP::SetParameters(float fColorWeight,
239 float fCutoffDistance,
240 float fConvergenceDelta,
241 int nMaxIterations,
242 int nKdTreeBucketSize)
243{
244 m_fColorWeight = fColorWeight;
245 m_fCutoffDistance = fCutoffDistance;
246 m_fConvergenceDelta = fConvergenceDelta;
247 m_nMaxIterations = nMaxIterations;
248 m_nKdTreeBucketSize = nKdTreeBucketSize;
249}
250
251void
252CColorICP::FindNNBruteForce(const float* pPoint, float& fSquaredDistance, float*& pNeighbor)
253{
254 float fMinDist = FLT_MAX;
255 float fDist;
256 int nBestIndex = -1;
257
258 for (int i = 0; i < m_nNumScenePoints; i++)
259 {
260 fDist = 0;
261
262 for (int j = 0; j < 6; j++)
263 {
264 fDist += (pPoint[j] - m_pValues[i][j]) * (pPoint[j] - m_pValues[i][j]);
265 }
266
267 if (fDist < fMinDist)
268 {
269 fMinDist = fDist;
270 nBestIndex = i;
271 }
272 }
273
274 fSquaredDistance = fMinDist;
275 pNeighbor = m_pValues[nBestIndex];
276}
277
278void
279CColorICP::GetPointMatchDistances(const std::vector<CPointXYZRGBI>& aObjectPoints,
280 std::vector<float>& aPointMatchDistances)
281{
282 float* pPointData = new float[7];
283 float* pNearestNeighbor;
284 float fDistance;
285
286 for (size_t i = 0; i < aObjectPoints.size(); i++)
287 {
288 pPointData[0] = aObjectPoints.at(i).x;
289 pPointData[1] = aObjectPoints.at(i).y;
290 pPointData[2] = aObjectPoints.at(i).z;
291 pPointData[3] = m_fColorWeight * aObjectPoints.at(i).r;
292 pPointData[4] = m_fColorWeight * aObjectPoints.at(i).g;
293 pPointData[5] = m_fColorWeight * aObjectPoints.at(i).b;
294 pPointData[6] = m_fColorWeight * aObjectPoints.at(i).i;
295
296 m_pKdTree->NearestNeighborBBF(pPointData, fDistance, pNearestNeighbor);
297
298 aPointMatchDistances.push_back(fDistance);
299 }
300
301 delete[] pPointData;
302}
303
304void
305CColorICP::GetNearestNeighbors(const std::vector<CPointXYZRGBI>& aObjectPoints,
306 std::vector<CColorICP::CPointXYZRGBI>& aNeighbors,
307 std::vector<float>& aPointMatchDistances)
308{
309 float* pPointData = new float[7];
310 float* pNearestNeighbor;
311 CColorICP::CPointXYZRGBI pNearestNeighborPoint;
312 float fDistance;
313 const float fColorWeightFactor = 1.0f / m_fColorWeight;
314
315 for (size_t i = 0; i < aObjectPoints.size(); i++)
316 {
317 pPointData[0] = aObjectPoints.at(i).x;
318 pPointData[1] = aObjectPoints.at(i).y;
319 pPointData[2] = aObjectPoints.at(i).z;
320 pPointData[3] = m_fColorWeight * aObjectPoints.at(i).r;
321 pPointData[4] = m_fColorWeight * aObjectPoints.at(i).g;
322 pPointData[5] = m_fColorWeight * aObjectPoints.at(i).b;
323 pPointData[6] = m_fColorWeight * aObjectPoints.at(i).i;
324
325 m_pKdTree->NearestNeighborBBF(pPointData, fDistance, pNearestNeighbor);
326
327 pNearestNeighborPoint.x = pNearestNeighbor[0];
328 pNearestNeighborPoint.y = pNearestNeighbor[1];
329 pNearestNeighborPoint.z = pNearestNeighbor[2];
330 pNearestNeighborPoint.r = fColorWeightFactor * pNearestNeighbor[3];
331 pNearestNeighborPoint.g = fColorWeightFactor * pNearestNeighbor[4];
332 pNearestNeighborPoint.b = fColorWeightFactor * pNearestNeighbor[5];
333 pNearestNeighborPoint.i = fColorWeightFactor * pNearestNeighbor[6];
334
335 aNeighbors.push_back(pNearestNeighborPoint);
336 aPointMatchDistances.push_back(fDistance);
337 }
338
339 delete[] pPointData;
340}
341
344{
346 ret.x = pPoint->vPosition.x;
347 ret.y = pPoint->vPosition.y;
348 ret.z = pPoint->vPosition.z;
349 ret.r = pPoint->fColorR;
350 ret.g = pPoint->fColorG;
351 ret.b = pPoint->fColorB;
352 ret.i = pPoint->fIntensity;
353
354 return ret;
355}
356
359{
362 Math3d::SetVec(pRet->vPosition, pPoint.x, pPoint.y, pPoint.z);
363 pRet->fColorR = pPoint.r;
364 pRet->fColorG = pPoint.g;
365 pRet->fColorB = pPoint.b;
366 pRet->fIntensity = pPoint.i;
367 pRet->fMembershipProbability = 0.8f;
368 return pRet;
369}
370
371void
372CColorICP::TransformPointXYZRGBI(CPointXYZRGBI& pPoint, Mat3d mRotation, Vec3d vTranslation)
373{
374 const float x = pPoint.x;
375 const float y = pPoint.y;
376 const float z = pPoint.z;
377 pPoint.x = mRotation.r1 * x + mRotation.r2 * y + mRotation.r3 * z + vTranslation.x;
378 pPoint.y = mRotation.r4 * x + mRotation.r5 * y + mRotation.r6 * z + vTranslation.y;
379 pPoint.z = mRotation.r7 * x + mRotation.r8 * y + mRotation.r9 * z + vTranslation.z;
380}
#define OLP_EFFORT_POINTCLOUD_MATCHING
void SetScenePointcloud(std::vector< CPointXYZRGBI > aScenePoints)
Definition ColorICP.cpp:58
void GetPointMatchDistances(const std::vector< CPointXYZRGBI > &aObjectPoints, std::vector< float > &aPointMatchDistances)
Definition ColorICP.cpp:279
static CHypothesisPoint * ConvertFromXYZRGBI(CPointXYZRGBI pPoint)
Definition ColorICP.cpp:358
void GetNearestNeighbors(const std::vector< CPointXYZRGBI > &aObjectPoints, std::vector< CColorICP::CPointXYZRGBI > &aNeighbors, std::vector< float > &aPointMatchDistances)
Definition ColorICP.cpp:305
static void TransformPointXYZRGBI(CPointXYZRGBI &pPoint, Mat3d mRotation, Vec3d vTranslation)
Definition ColorICP.cpp:372
static CPointXYZRGBI ConvertToXYZRGBI(CHypothesisPoint *pPoint)
Definition ColorICP.cpp:343
float SearchObject(const std::vector< CPointXYZRGBI > &aObjectPoints, Mat3d &mRotation, Vec3d &vTranslation, const float fBestDistanceUntilNow=FLT_MAX)
Definition ColorICP.cpp:109
void SetParameters(float fColorWeight=OLP_ICP_COLOR_DISTANCE_WEIGHT, float fCutoffDistance=FLT_MAX, float fConvergenceDelta=0.01f, int nMaxIterations=30, int nKdTreeBucketSize=50)
Definition ColorICP.cpp:238
#define ARMARX_VERBOSE_S
Definition Logging.h:207
#define ARMARX_IMPORTANT_S
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:210
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
This file offers overloads of toIce() and fromIce() functions for STL container types.