Skip to content

Commit f543422

Browse files
committed
Implement posegraph update, Gauss newton is unstable
1 parent de7ba96 commit f543422

File tree

5 files changed

+142
-55
lines changed

5 files changed

+142
-55
lines changed

modules/rgbd/src/large_kinfu.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ bool LargeKinfuImpl<MatType>::updateT(const MatType& _depth)
227227
std::cout << "Current frameID: " << frameCounter << "\n";
228228
for (const auto& it : submapMgr->activeSubmaps)
229229
{
230-
//! Iterate over map?
231230
int currTrackingId = it.first;
232231
auto submapData = it.second;
233232
Ptr<Submap<MatType>> currTrackingSubmap = submapMgr->getSubmap(currTrackingId);
@@ -250,6 +249,7 @@ bool LargeKinfuImpl<MatType>::updateT(const MatType& _depth)
250249
else
251250
{
252251
std::cout << "Tracking failed" << std::endl;
252+
continue;
253253
}
254254

255255
//2. Integrate
@@ -272,7 +272,17 @@ bool LargeKinfuImpl<MatType>::updateT(const MatType& _depth)
272272

273273
}
274274
//4. Update map
275-
submapMgr->updateMap(frameCounter, newPoints, newNormals);
275+
bool isMapUpdated = submapMgr->updateMap(frameCounter, newPoints, newNormals);
276+
277+
if(isMapUpdated)
278+
{
279+
// TODO: Convert constraints to posegraph
280+
PoseGraph poseGraph = submapMgr->createPoseGraph();
281+
std::cout << "Created posegraph\n";
282+
Optimizer::optimizeGaussNewton(Optimizer::Params(), poseGraph);
283+
/* submapMgr->adjustMap(poseGraph); */
284+
285+
}
276286
std::cout << "Number of submaps: " << submapMgr->submapList.size() << "\n";
277287

278288
frameCounter++;

modules/rgbd/src/pose_graph.cpp

+61-29
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ namespace cv
1515
{
1616
namespace kinfu
1717
{
18-
1918
bool PoseGraph::isValid() const
2019
{
2120
int numNodes = int(nodes.size());
@@ -34,7 +33,7 @@ bool PoseGraph::isValid() const
3433
{
3534
int currNodeId = nodesToVisit.back();
3635
nodesToVisit.pop_back();
37-
36+
std::cout << "Visiting node: " << currNodeId << "\n";
3837
// Since each node does not maintain its neighbor list
3938
for (int i = 0; i < numEdges; i++)
4039
{
@@ -49,20 +48,20 @@ bool PoseGraph::isValid() const
4948
{
5049
nextNodeId = potentialEdge.getSourceNodeId();
5150
}
52-
51+
std::cout << "Next node: " << nextNodeId << std::endl;
5352
if (nextNodeId != -1)
5453
{
55-
if(nodesVisited.count(currNodeId) == 0)
54+
if (nodesVisited.count(currNodeId) == 0)
5655
{
5756
nodesVisited.insert(currNodeId);
57+
nodesToVisit.push_back(nextNodeId);
5858
}
59-
nodesToVisit.push_back(nextNodeId);
6059
}
6160
}
6261
}
6362

6463
isGraphConnected = (int(nodesVisited.size()) == numNodes);
65-
64+
std::cout << "IsGraphConnected: " << isGraphConnected << std::endl;
6665
bool invalidEdgeNode = false;
6766
for (int i = 0; i < numEdges; i++)
6867
{
@@ -81,26 +80,37 @@ float PoseGraph::createLinearSystem(BlockSparseMat<float, 6, 6>& H, Mat& B)
8180
{
8281
int numEdges = int(edges.size());
8382

84-
float residual = 0;
83+
float residual = 0.0f;
8584

86-
//! Lmabda to calculate error jacobian for a particular constraint
85+
// Lambda to calculate the error Jacobians w.r.t source and target poses
8786
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+
{
8989
const Affine3f relativePoseMeas_inv = relativePoseMeas.inv();
9090
const Affine3f targetPose_inv = targetPose.inv();
9191
for (int i = 0; i < 6; i++)
9292
{
9393
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);
97102
}
98103
for (int i = 0; i < 6; i++)
99104
{
100105
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);
104114
}
105115
};
106116

@@ -117,35 +127,50 @@ float PoseGraph::createLinearSystem(BlockSparseMat<float, 6, 6>& H, Mat& B)
117127
//! Edge transformation is source to target. (relativeConstraint should be identity if no error)
118128
Affine3f poseConstraint = currEdge.transformation.inv() * relativeSourceToTarget;
119129

120-
Vec6f error;
130+
std::cout << "RelativeSourceToTarget: \n" << relativeSourceToTarget.matrix << "\n";
131+
std::cout << "PoseConstraint: \n" << poseConstraint.matrix << "\n";
132+
133+
Matx61f error;
121134
Vec3f rot = poseConstraint.rvec();
122135
Vec3f trans = poseConstraint.translation();
123136

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];
137+
error.val[0] = rot[0];
138+
error.val[1] = rot[1];
139+
error.val[2] = rot[2];
140+
error.val[3] = trans[0];
141+
error.val[4] = trans[1];
142+
error.val[5] = trans[2];
143+
144+
std::cout << "Error vector: " << error << std::endl;
130145

131146
Matx66f jacSource, jacTarget;
132147
calcErrorJacobian(jacSource, jacTarget, currEdge.transformation, sourcePose, targetPose);
148+
std::cout << "Source Jacobian: \n" << jacSource << std::endl;
149+
std::cout << "Target Jacobian: \n" << jacTarget << std::endl;
133150

134151
Matx16f errorTransposeInfo = error.t() * currEdge.information;
135152
Matx66f jacSourceTransposeInfo = jacSource.t() * currEdge.information;
136153
Matx66f jacTargetTransposeInfo = jacTarget.t() * currEdge.information;
137154

138-
residual += (errorTransposeInfo * error)[0];
155+
std::cout << "errorTransposeInfo: " << errorTransposeInfo << "\n";
156+
std::cout << "jacSourceTransposeInfo: " << jacSourceTransposeInfo << "\n";
157+
std::cout << "jacTargetTransposeInfo: " << jacTargetTransposeInfo << "\n";
158+
159+
float res = (errorTransposeInfo * error).val[0];
160+
residual += res;
139161

162+
std::cout << "sourceNodeId: " << sourceNodeId << " targetNodeId: " << targetNodeId << std::endl;
140163
H.refBlock(sourceNodeId, sourceNodeId) += jacSourceTransposeInfo * jacSource;
141164
H.refBlock(targetNodeId, targetNodeId) += jacTargetTransposeInfo * jacTarget;
142165
H.refBlock(sourceNodeId, targetNodeId) += jacSourceTransposeInfo * jacTarget;
143166
H.refBlock(targetNodeId, sourceNodeId) += jacTargetTransposeInfo * jacSource;
144167

145-
B.rowRange(6 * sourceNodeId, 6 * (sourceNodeId + 1)) += errorTransposeInfo * jacSource;
146-
B.rowRange(6 * targetNodeId, 6 * (targetNodeId + 1)) += errorTransposeInfo * jacTarget;
168+
169+
B.rowRange(6 * sourceNodeId, 6 * (sourceNodeId + 1)) += (errorTransposeInfo * jacSource).reshape<6, 1>();
170+
B.rowRange(6 * targetNodeId, 6 * (targetNodeId + 1)) += (errorTransposeInfo * jacTarget).reshape<6, 1>();
147171
}
148172

173+
std::cout << "Residual value: " << residual << std::endl;
149174
return residual;
150175
}
151176

@@ -194,27 +219,34 @@ void Optimizer::optimizeGaussNewton(const Optimizer::Params& params, PoseGraph&
194219
{
195220
//! ApproxH = Approximate Hessian = J^T * information * J
196221
BlockSparseMat<float, 6, 6> ApproxH(numNodes);
197-
Mat B(6 * numNodes, 1, CV_32F);
222+
Mat B = cv::Mat::zeros(6 * numNodes, 1, CV_32F);
198223

199224
float currentResidual = poseGraph.createLinearSystem(ApproxH, B);
200-
225+
std::cout << "Number of non-zero blocks in H: " << ApproxH.nonZeroBlocks() << "\n";
201226
Mat delta(6 * numNodes, 1, CV_32F);
202227
bool success = sparseSolve(ApproxH, B, delta);
203228
if (!success)
204229
{
205230
CV_Error(Error::StsNoConv, "Sparse solve failed");
206231
return;
207232
}
233+
std::cout << "delta update: " << delta << "\n";
208234
//! Check delta
235+
std::cout << " Current residual: " << currentResidual << " Prev residual: " << prevResidual << "\n";
209236

210237
//! TODO: Improve criterion and allow small increments in residual
211-
if((currentResidual - prevResidual) > params.maxAcceptableResIncre)
238+
if ((currentResidual - prevResidual) > params.maxAcceptableResIncre)
239+
{
240+
std::cout << "Current residual increased from prevResidual by at least " << params.maxAcceptableResIncre << std::endl;
212241
break;
242+
}
213243
if ((currentResidual - params.minResidual) < 0.00001f)
244+
{
245+
std::cout << "Gauss newton converged \n";
214246
converged = true;
247+
}
215248

216249
poseGraph = poseGraph.update(delta);
217-
std::cout << " Current residual: " << currentResidual << " Prev residual: " << prevResidual << "\n";
218250

219251
prevResidual = currentResidual;
220252

modules/rgbd/src/pose_graph.hpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ namespace kinfu
1818
struct PoseGraphNode
1919
{
2020
public:
21-
explicit PoseGraphNode(int _nodeId, const Affine3f& _pose) : nodeId(_nodeId), isFixed(false), pose(_pose) {}
22-
virtual ~PoseGraphNode();
21+
explicit PoseGraphNode(int _nodeId, const Affine3f& _pose) : nodeId(_nodeId), isFixed(false), pose(_pose) {}
22+
virtual ~PoseGraphNode() = default;
2323

2424
int getId() const { return nodeId; }
2525
Affine3f getPose() const { return pose; }
@@ -130,7 +130,6 @@ class PoseGraph
130130
float createLinearSystem(BlockSparseMat<float, 6, 6>& H, Mat& B);
131131

132132
private:
133-
134133
NodeVector nodes;
135134
EdgeVector edges;
136135
};

modules/rgbd/src/sparse_block_matrix.hpp

+13-8
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ struct BlockSparseMat
5050
auto it = ijValue.find(p);
5151
if (it == ijValue.end())
5252
{
53-
it = ijValue.insert({ p, Matx<_Tp, blockM, blockN>() }).first;
53+
it = ijValue.insert({ p, Matx<_Tp, blockM, blockN>::zeros() }).first;
5454
}
5555
return it->second;
5656
}
@@ -65,25 +65,29 @@ struct BlockSparseMat
6565
Eigen::SparseMatrix<_Tp> toEigen() const
6666
{
6767
std::vector<Eigen::Triplet<double>> tripletList;
68-
tripletList.reserve(ijValue.size() * blockSize * blockSize);
69-
68+
tripletList.reserve(ijValue.size() * blockSize);
7069
for (auto ijv : ijValue)
7170
{
7271
int xb = ijv.first.x, yb = ijv.first.y;
72+
std::cout << "xb: " << xb << " yb: " << yb << "\n";
7373
MatType vblock = ijv.second;
74-
for (int i = 0; i < blockSize; i++)
74+
std::cout << "vblock: " << vblock << "\n";
75+
for (int i = 0; i < blockM; i++)
7576
{
76-
for (int j = 0; j < blockSize; j++)
77+
for (int j = 0; j < blockN; j++)
7778
{
7879
float val = vblock(i, j);
7980
if (abs(val) >= NON_ZERO_VAL_THRESHOLD)
8081
{
81-
tripletList.push_back(Eigen::Triplet<double>(blockSize * xb + i, blockSize * yb + j, val));
82+
std::cout << "Pushing back triplet: (" << i << ", " << j << ", " << val << ")\n";
83+
tripletList.push_back(Eigen::Triplet<double>(blockM * xb + i, blockN * yb + j, val));
8284
}
8385
}
8486
}
8587
}
86-
Eigen::SparseMatrix<_Tp> EigenMat(blockSize * nBlocks, blockSize * nBlocks);
88+
std::cout << "tripletListSize: " << tripletList.size() << "\n";
89+
std::cout << blockM << " " << nBlocks << " " << blockN << std::endl;
90+
Eigen::SparseMatrix<_Tp> EigenMat(blockM * nBlocks, blockN * nBlocks);
8791
EigenMat.setFromTriplets(tripletList.begin(), tripletList.end());
8892
EigenMat.makeCompressed();
8993

@@ -118,13 +122,14 @@ static bool sparseSolve(const BlockSparseMat<float, 6, 6>& H, const Mat& B, Mat&
118122
return result;
119123
}
120124

121-
122125
// TODO: try this, LLT and Cholesky
123126
Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>> solver;
124127

125128
std::cout << "starting eigen-compute..." << std::endl;
126129
solver.compute(bigA);
127130

131+
std::cout << "solver info: " << solver.info() << "\n";
132+
128133
if (solver.info() != Eigen::Success)
129134
{
130135
std::cout << "failed to eigen-decompose" << std::endl;

0 commit comments

Comments
 (0)