@@ -15,7 +15,6 @@ namespace cv
15
15
{
16
16
namespace kinfu
17
17
{
18
-
19
18
bool PoseGraph::isValid () const
20
19
{
21
20
int numNodes = int (nodes.size ());
@@ -34,7 +33,7 @@ bool PoseGraph::isValid() const
34
33
{
35
34
int currNodeId = nodesToVisit.back ();
36
35
nodesToVisit.pop_back ();
37
-
36
+ std::cout << " Visiting node: " << currNodeId << " \n " ;
38
37
// Since each node does not maintain its neighbor list
39
38
for (int i = 0 ; i < numEdges; i++)
40
39
{
@@ -49,20 +48,20 @@ bool PoseGraph::isValid() const
49
48
{
50
49
nextNodeId = potentialEdge.getSourceNodeId ();
51
50
}
52
-
51
+ std::cout << " Next node: " << nextNodeId << std::endl;
53
52
if (nextNodeId != -1 )
54
53
{
55
- if (nodesVisited.count (currNodeId) == 0 )
54
+ if (nodesVisited.count (currNodeId) == 0 )
56
55
{
57
56
nodesVisited.insert (currNodeId);
57
+ nodesToVisit.push_back (nextNodeId);
58
58
}
59
- nodesToVisit.push_back (nextNodeId);
60
59
}
61
60
}
62
61
}
63
62
64
63
isGraphConnected = (int (nodesVisited.size ()) == numNodes);
65
-
64
+ std::cout << " IsGraphConnected: " << isGraphConnected << std::endl;
66
65
bool invalidEdgeNode = false ;
67
66
for (int i = 0 ; i < numEdges; i++)
68
67
{
@@ -81,26 +80,37 @@ float PoseGraph::createLinearSystem(BlockSparseMat<float, 6, 6>& H, Mat& B)
81
80
{
82
81
int numEdges = int (edges.size ());
83
82
84
- float residual = 0 ;
83
+ float residual = 0 . 0f ;
85
84
86
- // ! Lmabda to calculate error jacobian for a particular constraint
85
+ // Lambda to calculate the error Jacobians w.r.t source and target poses
87
86
auto calcErrorJacobian = [](Matx66f& jacSource, Matx66f& jacTarget, const Affine3f& relativePoseMeas,
88
- const Affine3f& sourcePose, const Affine3f& targetPose) -> void {
87
+ const Affine3f& sourcePose, const Affine3f& targetPose) -> void
88
+ {
89
89
const Affine3f relativePoseMeas_inv = relativePoseMeas.inv ();
90
90
const Affine3f targetPose_inv = targetPose.inv ();
91
91
for (int i = 0 ; i < 6 ; i++)
92
92
{
93
93
Affine3f dError_dSource = relativePoseMeas_inv * targetPose_inv * cv::Affine3f (generatorJacobian[i]) * sourcePose;
94
- Vec3f rot = dError_dSource.rvec ();
95
- Vec3f trans = dError_dSource.translation ();
96
- jacSource.col (i) = Vec6f (rot (0 ), rot (1 ), rot (2 ), trans (0 ), trans (1 ), trans (2 ));
94
+ Vec3f rot = dError_dSource.rvec ();
95
+ Vec3f trans = dError_dSource.translation ();
96
+ jacSource.val [i + 6 *0 ] = rot (0 );
97
+ jacSource.val [i + 6 *1 ] = rot (1 );
98
+ jacSource.val [i + 6 *2 ] = rot (2 );
99
+ jacSource.val [i + 6 *3 ] = trans (0 );
100
+ jacSource.val [i + 6 *4 ] = trans (1 );
101
+ jacSource.val [i + 6 *5 ] = trans (2 );
97
102
}
98
103
for (int i = 0 ; i < 6 ; i++)
99
104
{
100
105
Affine3f dError_dSource = relativePoseMeas_inv * targetPose_inv * cv::Affine3f (-generatorJacobian[i]) * sourcePose;
101
- Vec3f rot = dError_dSource.rvec ();
102
- Vec3f trans = dError_dSource.translation ();
103
- jacTarget.col (i) = Vec6f (rot (0 ), rot (1 ), rot (2 ), trans (0 ), trans (1 ), trans (2 ));
106
+ Vec3f rot = dError_dSource.rvec ();
107
+ Vec3f trans = dError_dSource.translation ();
108
+ jacTarget.val [i + 6 *0 ] = rot (0 );
109
+ jacTarget.val [i + 6 *1 ] = rot (1 );
110
+ jacTarget.val [i + 6 *2 ] = rot (2 );
111
+ jacTarget.val [i + 6 *3 ] = trans (0 );
112
+ jacTarget.val [i + 6 *4 ] = trans (1 );
113
+ jacTarget.val [i + 6 *5 ] = trans (2 );
104
114
}
105
115
};
106
116
@@ -117,35 +127,51 @@ float PoseGraph::createLinearSystem(BlockSparseMat<float, 6, 6>& H, Mat& B)
117
127
// ! Edge transformation is source to target. (relativeConstraint should be identity if no error)
118
128
Affine3f poseConstraint = currEdge.transformation .inv () * relativeSourceToTarget;
119
129
120
- Vec6f error;
130
+ std::cout << " RelativeSourceToTarget: \n " << relativeSourceToTarget.matrix << " \n " ;
131
+ std::cout << " Edge estimated transformation: \n " << currEdge.transformation .matrix << " \n " ;
132
+ std::cout << " PoseConstraint: \n " << poseConstraint.matrix << " \n " ;
133
+
134
+ Matx61f error;
121
135
Vec3f rot = poseConstraint.rvec ();
122
136
Vec3f trans = poseConstraint.translation ();
123
137
124
- error[0 ] = rot[0 ];
125
- error[1 ] = rot[1 ];
126
- error[2 ] = rot[2 ];
127
- error[3 ] = trans[0 ];
128
- error[4 ] = trans[1 ];
129
- error[5 ] = trans[2 ];
138
+ error.val [0 ] = rot[0 ];
139
+ error.val [1 ] = rot[1 ];
140
+ error.val [2 ] = rot[2 ];
141
+ error.val [3 ] = trans[0 ];
142
+ error.val [4 ] = trans[1 ];
143
+ error.val [5 ] = trans[2 ];
144
+
145
+ std::cout << " Error vector: \n " << error << std::endl;
130
146
131
147
Matx66f jacSource, jacTarget;
132
148
calcErrorJacobian (jacSource, jacTarget, currEdge.transformation , sourcePose, targetPose);
149
+ std::cout << " Source Jacobian: \n " << jacSource << std::endl;
150
+ std::cout << " Target Jacobian: \n " << jacTarget << std::endl;
133
151
134
152
Matx16f errorTransposeInfo = error.t () * currEdge.information ;
135
153
Matx66f jacSourceTransposeInfo = jacSource.t () * currEdge.information ;
136
154
Matx66f jacTargetTransposeInfo = jacTarget.t () * currEdge.information ;
137
155
138
- residual += (errorTransposeInfo * error)[0 ];
156
+ /* std::cout << "errorTransposeInfo: " << errorTransposeInfo << "\n"; */
157
+ /* std::cout << "jacSourceTransposeInfo: " << jacSourceTransposeInfo << "\n"; */
158
+ /* std::cout << "jacTargetTransposeInfo: " << jacTargetTransposeInfo << "\n"; */
159
+
160
+ float res = std::sqrt ((errorTransposeInfo * error).val [0 ]);
161
+ residual += res;
139
162
163
+ std::cout << " sourceNodeId: " << sourceNodeId << " targetNodeId: " << targetNodeId << std::endl;
140
164
H.refBlock (sourceNodeId, sourceNodeId) += jacSourceTransposeInfo * jacSource;
141
165
H.refBlock (targetNodeId, targetNodeId) += jacTargetTransposeInfo * jacTarget;
142
166
H.refBlock (sourceNodeId, targetNodeId) += jacSourceTransposeInfo * jacTarget;
143
167
H.refBlock (targetNodeId, sourceNodeId) += jacTargetTransposeInfo * jacSource;
144
168
145
- B.rowRange (6 * sourceNodeId, 6 * (sourceNodeId + 1 )) += errorTransposeInfo * jacSource;
146
- B.rowRange (6 * targetNodeId, 6 * (targetNodeId + 1 )) += errorTransposeInfo * jacTarget;
169
+
170
+ B.rowRange (6 * sourceNodeId, 6 * (sourceNodeId + 1 )) += (errorTransposeInfo * jacSource).reshape <6 , 1 >();
171
+ B.rowRange (6 * targetNodeId, 6 * (targetNodeId + 1 )) += (errorTransposeInfo * jacTarget).reshape <6 , 1 >();
147
172
}
148
173
174
+ std::cout << " Residual value: " << residual << std::endl;
149
175
return residual;
150
176
}
151
177
@@ -161,6 +187,7 @@ PoseGraph PoseGraph::update(const Mat& deltaVec)
161
187
Vec6f delta = deltaVec.rowRange (6 * currentNodeId, 6 * (currentNodeId + 1 ));
162
188
Affine3f pose = nodes.at (currentNodeId).getPose ();
163
189
Affine3f currDelta = Affine3f (Vec3f (delta.val ), Vec3f (delta.val + 3 ));
190
+ std::cout << " Current Delta for node ID: " << currentNodeId << " \n " << currDelta.matrix << std::endl;
164
191
Affine3f updatedPose = currDelta * pose;
165
192
166
193
updatedPoseGraph.nodes .at (currentNodeId).setPose (updatedPose);
@@ -169,6 +196,20 @@ PoseGraph PoseGraph::update(const Mat& deltaVec)
169
196
return updatedPoseGraph;
170
197
}
171
198
199
+ Mat PoseGraph::getVector ()
200
+ {
201
+ int numNodes = int (nodes.size ());
202
+ Mat vector (6 * numNodes, 1 , CV_32F, Scalar (0 ));
203
+ for (int currentNodeId = 0 ; currentNodeId < numNodes; currentNodeId++)
204
+ {
205
+ Affine3f pose = nodes.at (currentNodeId).getPose ();
206
+ Vec3f rot = pose.rvec ();
207
+ Vec3f trans = pose.translation ();
208
+ vector.rowRange (6 * currentNodeId, 6 * (currentNodeId+1 )) = Vec6f (rot.val [0 ], rot.val [1 ], rot.val [2 ], trans.val [0 ], trans.val [1 ], trans.val [2 ]);
209
+ }
210
+ return vector;
211
+ }
212
+
172
213
// ! NOTE: We follow left-composition for the infinitesimal pose update
173
214
void Optimizer::optimizeGaussNewton (const Optimizer::Params& params, PoseGraph& poseGraph)
174
215
{
@@ -187,38 +228,49 @@ void Optimizer::optimizeGaussNewton(const Optimizer::Params& params, PoseGraph&
187
228
std::cout << " Optimizing posegraph with nodes: " << numNodes << " edges: " << numEdges << std::endl;
188
229
189
230
int iter = 0 ;
190
- // ! converged is set to true when error/residual is within some limit
191
- bool converged = false ;
192
231
float prevResidual = std::numeric_limits<float >::max ();
193
232
do
194
233
{
234
+ std::cout << " Current iteration: " << iter << std::endl;
195
235
// ! ApproxH = Approximate Hessian = J^T * information * J
196
236
BlockSparseMat<float , 6 , 6 > ApproxH (numNodes);
197
- Mat B (6 * numNodes, 1 , CV_32F);
237
+ Mat B = cv::Mat::zeros (6 * numNodes, 1 , CV_32F);
198
238
199
239
float currentResidual = poseGraph.createLinearSystem (ApproxH, B);
200
-
240
+ std::cout << " Number of non-zero blocks in H: " << ApproxH. nonZeroBlocks () << " \n " ;
201
241
Mat delta (6 * numNodes, 1 , CV_32F);
242
+ Mat X = poseGraph.getVector ();
202
243
bool success = sparseSolve (ApproxH, B, delta);
203
244
if (!success)
204
245
{
205
246
CV_Error (Error::StsNoConv, " Sparse solve failed" );
206
247
return ;
207
248
}
249
+ std::cout << " delta update: " << delta << " \n delta norm: " << cv::norm (delta) << " X norm: " << cv::norm (X) << std::endl;
250
+
208
251
// ! Check delta
252
+ if (cv::norm (delta) < 1e-6f * (cv::norm (X) + 1e-6f ))
253
+ {
254
+ std::cout << " Delta norm[" << cv::norm (delta) << " ] < 1e-6f * X norm[" << cv::norm (X) <<" ] + 1e-6f\n " ;
255
+ break ;
256
+ }
257
+ std::cout << " Current residual: " << currentResidual << " Prev residual: " << prevResidual << " \n " ;
209
258
210
259
// ! TODO: Improve criterion and allow small increments in residual
211
- if ((currentResidual - prevResidual) > params.maxAcceptableResIncre )
260
+ if ((currentResidual - prevResidual) > params.maxAcceptableResIncre )
261
+ {
262
+ std::cout << " Current residual increased from prevResidual by at least " << params.maxAcceptableResIncre << std::endl;
212
263
break ;
213
- if ((currentResidual - params.minResidual ) < 0 .00001f )
214
- converged = true ;
215
-
264
+ }
265
+ // ! If updates don't improve a lot means loss function basin has been reached
266
+ if ((currentResidual - params.minResidual ) < 1e-5f )
267
+ {
268
+ std::cout << " Gauss newton converged \n " ;
269
+ break ;
270
+ }
216
271
poseGraph = poseGraph.update (delta);
217
- std::cout << " Current residual: " << currentResidual << " Prev residual: " << prevResidual << " \n " ;
218
-
219
272
prevResidual = currentResidual;
220
-
221
- } while (iter < params.maxNumIters && !converged);
273
+ } while (iter < params.maxNumIters );
222
274
}
223
275
} // namespace kinfu
224
276
} // namespace cv
0 commit comments