56 const std::map<int, Transform> & poses,
57 const std::multimap<int, Link> & edgeConstraints,
58 cv::Mat & outputCovariance,
59 std::list<std::map<int, Transform> > * intermediateGraphes,
63 outputCovariance = cv::Mat::eye(6,6,CV_64FC1);
64 std::map<int, Transform> optimizedPoses;
66 UDEBUG(
"Optimizing graph (pose=%d constraints=%d)...", (
int)poses.size(), (int)edgeConstraints.size());
67 if(edgeConstraints.size()>=1 && poses.size()>=2 &&
iterations() > 0)
75 UDEBUG(
"fill poses to TORO...");
78 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
80 UASSERT(!iter->second.isNull());
82 AISNavigation::TreePoseGraph2::Vertex* v = pg2.
addVertex(iter->first, p);
88 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
90 UASSERT(!iter->second.isNull());
92 iter->second.getTranslationAndEulerAngles(x,y,z, roll,pitch,yaw);
94 AISNavigation::TreePoseGraph3::Vertex* v = pg3.
addVertex(iter->first, p);
101 UDEBUG(
"fill edges to TORO...");
104 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
106 UASSERT(!iter->second.transform().isNull());
112 inf.
values[0][0] = 1.0; inf.values[0][1] = 0.0; inf.values[0][2] = 0.0;
113 inf.values[1][0] = 0.0; inf.values[1][1] = 1.0; inf.values[1][2] = 0.0;
114 inf.values[2][0] = 0.0; inf.values[2][1] = 0.0; inf.values[2][2] = 1.0;
118 inf.values[0][0] = iter->second.infMatrix().at<
double>(0,0);
119 inf.values[0][1] = iter->second.infMatrix().at<
double>(0,1);
120 inf.values[0][2] = iter->second.infMatrix().at<
double>(0,5);
121 inf.values[1][0] = iter->second.infMatrix().at<
double>(1,0);
122 inf.values[1][1] = iter->second.infMatrix().at<
double>(1,1);
123 inf.values[1][2] = iter->second.infMatrix().at<
double>(1,5);
124 inf.values[2][0] = iter->second.infMatrix().at<
double>(5,0);
125 inf.values[2][1] = iter->second.infMatrix().at<
double>(5,1);
126 inf.values[2][2] = iter->second.infMatrix().at<
double>(5,5);
129 int id1 = iter->second.from();
130 int id2 = iter->second.to();
133 AISNavigation::TreePoseGraph2::Vertex* v1=pg2.
vertex(id1);
134 AISNavigation::TreePoseGraph2::Vertex* v2=pg2.
vertex(id2);
138 if (!pg2.
addEdge(v1, v2, t, inf))
140 UERROR(
"Map: Edge already exits between nodes %d and %d, skipping", id1, id2);
148 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
150 UASSERT(!iter->second.transform().isNull());
152 iter->second.transform().getTranslationAndEulerAngles(x,y,z, roll,pitch,yaw);
158 memcpy(inf[0], iter->second.infMatrix().data, iter->second.infMatrix().total()*
sizeof(double));
161 int id1 = iter->second.from();
162 int id2 = iter->second.to();
165 AISNavigation::TreePoseGraph3::Vertex* v1=pg3.
vertex(id1);
166 AISNavigation::TreePoseGraph3::Vertex* v2=pg3.
vertex(id2);
170 if (!pg3.
addEdge(v1, v2, t, inf))
172 UERROR(
"Map: Edge already exits between nodes %d and %d, skipping", id1, id2);
178 UDEBUG(
"buildMST... root=%d", rootId);
185 UDEBUG(
"initializeTreeParameters()");
187 UDEBUG(
"Building TORO tree... (if a crash happens just after this msg, " 188 "TORO is not able to find the root of the graph!)");
196 UDEBUG(
"initializeTreeParameters()");
198 UDEBUG(
"Building TORO tree... (if a crash happens just after this msg, " 199 "TORO is not able to find the root of the graph!)");
205 double lastError = 0;
210 if(intermediateGraphes && i>0)
212 std::map<int, Transform> tmpPoses;
215 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
217 AISNavigation::TreePoseGraph2::Vertex* v=pg2.
vertex(iter->first);
219 iter->second.getEulerAngles(roll, pitch, yaw);
220 Transform newPose(v->pose.x(), v->pose.y(), iter->second.z(),
roll,
pitch, v->pose.theta());
222 UASSERT_MSG(!newPose.isNull(),
uFormat(
"Optimized pose %d is null!?!?", iter->first).c_str());
223 tmpPoses.insert(std::pair<int, Transform>(iter->first, newPose));
228 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
230 AISNavigation::TreePoseGraph3::Vertex* v=pg3.
vertex(iter->first);
234 UASSERT_MSG(!newPose.isNull(),
uFormat(
"Optimized pose %d is null!?!?", iter->first).c_str());
235 tmpPoses.insert(std::pair<int, Transform>(iter->first, newPose));
238 intermediateGraphes->push_back(tmpPoses);
248 UDEBUG(
"iteration %d global error=%f error/constraint=%f", i, error, error/pg2.
edges.size());
255 double mte, mre, are, ate;
256 error=pg3.
error(&mre, &mte, &are, &ate);
257 UDEBUG(
"i %d RotGain=%f global error=%f error/constraint=%f",
262 double errorDelta = lastError - error;
263 if(i>0 && errorDelta < this->
epsilon())
267 UDEBUG(
"Negative improvement?! Ignore and continue optimizing... (%f < %f)", errorDelta, this->
epsilon());
271 UINFO(
"Stop optimizing, not enough improvement (%f < %f)", errorDelta, this->
epsilon());
275 else if(i==0 && error < this->
epsilon())
277 UINFO(
"Stop optimizing, error is already under epsilon (%f < %f)", error, this->
epsilon());
284 *finalError = lastError;
290 UINFO(
"TORO optimizing end (%d iterations done, error=%f, time = %f s)", i, lastError, timer.
ticks());
294 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
296 AISNavigation::TreePoseGraph2::Vertex* v=pg2.
vertex(iter->first);
298 iter->second.getEulerAngles(roll, pitch, yaw);
299 Transform newPose(v->pose.x(), v->pose.y(), iter->second.z(),
roll,
pitch, v->pose.theta());
301 UASSERT_MSG(!newPose.isNull(),
uFormat(
"Optimized pose %d is null!?!?", iter->first).c_str());
302 optimizedPoses.insert(std::pair<int, Transform>(iter->first, newPose));
307 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
309 AISNavigation::TreePoseGraph3::Vertex* v=pg3.
vertex(iter->first);
313 UASSERT_MSG(!newPose.isNull(),
uFormat(
"Optimized pose %d is null!?!?", iter->first).c_str());
314 optimizedPoses.insert(std::pair<int, Transform>(iter->first, newPose));
320 else if(poses.size() == 1 ||
iterations() <= 0)
322 optimizedPoses = poses;
326 UWARN(
"This method should be called at least with 1 pose!");
328 UDEBUG(
"Optimizing graph...end!");
330 UERROR(
"Not built with TORO support!");
332 return optimizedPoses;
336 const std::string & fileName,
337 const std::map<int, Transform> & poses,
338 const std::multimap<int, Link> & edgeConstraints)
343 fopen_s(&file, fileName.c_str(),
"w");
345 file = fopen(fileName.c_str(),
"w");
351 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
354 iter->second.getTranslationAndEulerAngles(x,y,z, roll, pitch, yaw);
355 fprintf(file,
"VERTEX3 %d %f %f %f %f %f %f\n",
366 for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
369 iter->second.transform().getTranslationAndEulerAngles(x,y,z, roll, pitch, yaw);
370 fprintf(file,
"EDGE3 %d %d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
379 iter->second.infMatrix().at<
double>(0,0),
380 iter->second.infMatrix().at<
double>(0,1),
381 iter->second.infMatrix().at<
double>(0,2),
382 iter->second.infMatrix().at<
double>(0,3),
383 iter->second.infMatrix().at<
double>(0,4),
384 iter->second.infMatrix().at<
double>(0,5),
385 iter->second.infMatrix().at<
double>(1,1),
386 iter->second.infMatrix().at<
double>(1,2),
387 iter->second.infMatrix().at<
double>(1,3),
388 iter->second.infMatrix().at<
double>(1,4),
389 iter->second.infMatrix().at<
double>(1,5),
390 iter->second.infMatrix().at<
double>(2,2),
391 iter->second.infMatrix().at<
double>(2,3),
392 iter->second.infMatrix().at<
double>(2,4),
393 iter->second.infMatrix().at<
double>(2,5),
394 iter->second.infMatrix().at<
double>(3,3),
395 iter->second.infMatrix().at<
double>(3,4),
396 iter->second.infMatrix().at<
double>(3,5),
397 iter->second.infMatrix().at<
double>(4,4),
398 iter->second.infMatrix().at<
double>(4,5),
399 iter->second.infMatrix().at<
double>(5,5));
401 UINFO(
"Graph saved to %s", fileName.c_str());
406 UERROR(
"Cannot save to file %s", fileName.c_str());
413 const std::string & fileName,
414 std::map<int, Transform> & poses,
415 std::multimap<int, Link> & edgeConstraints)
419 fopen_s(&file, fileName.c_str(),
"r");
421 file = fopen(fileName.c_str(),
"r");
427 while ( fgets (line , 400 , file) !=
NULL )
430 if(strList.size() == 8)
433 int id = atoi(strList[1].c_str());
440 Transform pose(x, y, z, roll, pitch, yaw);
441 if(poses.find(
id) == poses.end())
443 poses.insert(std::make_pair(
id, pose));
447 UFATAL(
"Pose %d already added",
id);
450 else if(strList.size() == 30)
453 int idFrom = atoi(strList[1].c_str());
454 int idTo = atoi(strList[2].c_str());
461 cv::Mat informationMatrix(6,6,CV_64FC1);
462 informationMatrix.at<
double>(3,3) =
uStr2Float(strList[9]);
463 informationMatrix.at<
double>(4,4) =
uStr2Float(strList[15]);
464 informationMatrix.at<
double>(5,5) =
uStr2Float(strList[20]);
465 UASSERT_MSG(informationMatrix.at<
double>(3,3) > 0.0 && informationMatrix.at<
double>(4,4) > 0.0 && informationMatrix.at<
double>(5,5) > 0.0,
uFormat(
"Information matrix should not be null! line=\"%s\"", line).c_str());
466 informationMatrix.at<
double>(0,0) =
uStr2Float(strList[24]);
467 informationMatrix.at<
double>(1,1) =
uStr2Float(strList[27]);
468 informationMatrix.at<
double>(2,2) =
uStr2Float(strList[29]);
469 UASSERT_MSG(informationMatrix.at<
double>(0,0) > 0.0 && informationMatrix.at<
double>(1,1) > 0.0 && informationMatrix.at<
double>(2,2) > 0.0,
uFormat(
"Information matrix should not be null! line=\"%s\"", line).c_str());
470 Transform transform(x, y, z, roll, pitch, yaw);
471 if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end())
475 edgeConstraints.insert(std::pair<int, Link>(idFrom, link));
479 UFATAL(
"Referred poses from the link not exist!");
482 else if(strList.size())
484 UFATAL(
"Error parsing graph file %s on line \"%s\" (strList.size()=%d)", fileName.c_str(), line, (int)strList.size());
488 UINFO(
"Graph loaded from %s", fileName.c_str());
493 UERROR(
"Cannot open file %s", fileName.c_str());
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
void iterate(TreePoseGraph2::EdgeSet *eset=0)
void initializeTreeParameters()
Defines the core optimizer class for 2D graphs which is a subclass of TreePoseGraph2.
double getRotGain() const
Class that contains the core optimization algorithm.
A class to represent symmetric 3x3 matrices.
float UTILITE_EXP uStr2Float(const std::string &str)
Class that contains the core optimization algorithm.
bool isCovarianceIgnored() const
Basic mathematics functions.
Defines the core optimizer class for 3D graphs which is a subclass of TreePoseGraph3.
Some conversion functions.
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
double error(double *mre=0, double *mte=0, double *are=0, double *ate=0, TreePoseGraph3::EdgeSet *eset=0) const
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
#define UASSERT(condition)
Wrappers of STL for convenient functions.
#define UASSERT_MSG(condition, msg_str)
void initializeTreeParameters()
std::string UTILITE_EXP uReplaceChar(const std::string &str, char before, char after)
bool uContains(const std::list< V > &list, const V &value)
Vertex * addVertex(int id, const Pose &pose)
Edge * addEdge(Vertex *v1, Vertex *v2, const Transformation &t, const Information &i)
std::vector< V > uListToVector(const std::list< V > &list)
virtual std::map< int, Transform > optimize(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &edgeConstraints, cv::Mat &outputCovariance, std::list< std::map< int, Transform > > *intermediateGraphes=0, double *finalError=0, int *iterationsDone=0)
ULogger class and convenient macros.
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
void iterate(TreePoseGraph3::EdgeSet *eset=0, bool noPreconditioner=false)
void initializeOptimization(EdgeCompareMode mode=EVComparator< Edge * >::CompareLevel)
static bool saveGraph(const std::string &fileName, const std::map< int, Transform > &poses, const std::multimap< int, Link > &edgeConstraints)
static bool loadGraph(const std::string &fileName, std::map< int, Transform > &poses, std::multimap< int, Link > &edgeConstraints)
void initializeOptimization()
Ops::TransformationType Transformation
std::string UTILITE_EXP uFormat(const char *fmt,...)
2D Point (x,y) with orientation (theta)