14 template <
class GRAPH_T>
22 template <
class GRAPH_T>
29 if (this->m_graph->nodeCount() > m_last_total_num_of_nodes)
31 m_last_total_num_of_nodes = this->m_graph->nodeCount();
32 registered_new_node =
true;
34 if (m_first_time_call)
36 opt_params.last_pair_nodes_to_edge = this->m_graph->edges;
37 m_first_time_call =
true;
40 if (opt_params.optimization_on_second_thread)
43 m_thread_optimize.join();
50 bool is_full_update = this->checkForFullOptimization();
51 this->_optimizeGraph(is_full_update);
59 template <
class GRAPH_T>
64 parent::initializeVisuals();
66 this->initGraphVisualization();
67 this->initOptDistanceVisualization();
72 template <
class GRAPH_T>
76 parent::updateVisuals();
78 if (opt_params.optimization_distance > 0)
80 this->updateOptDistanceVisualization();
83 this->updateGraphVisualization();
88 template <
class GRAPH_T>
90 const std::map<std::string, bool>& events_occurred)
94 parent::notifyOfWindowEvents(events_occurred);
99 if (opt_params.optimization_distance > 0)
101 if (events_occurred.find(opt_params.keystroke_optimization_distance)
104 this->toggleOptDistanceVisualization();
107 if (events_occurred.find(opt_params.keystroke_optimize_graph)->second)
109 this->_optimizeGraph(
true);
114 if (events_occurred.find(viz_params.keystroke_graph_toggle)->second)
116 this->toggleGraphVisualization();
120 if (events_occurred.find(
"mouse_clicked")->second)
123 m_autozoom_active =
false;
127 if (events_occurred.find(viz_params.keystroke_graph_autofit)->second)
130 this->fitGraphInView();
136 template <
class GRAPH_T>
140 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* is given");
142 if (viz_params.visualize_optimized_graph)
144 this->m_win_observer->registerKeystroke(
145 viz_params.keystroke_graph_toggle,
"Toggle Graph visualization");
146 this->m_win_observer->registerKeystroke(
147 viz_params.keystroke_graph_autofit,
"Fit Graph in view");
149 this->m_win_manager->assignTextMessageParameters(
150 &viz_params.offset_y_graph,
151 &viz_params.text_index_graph);
156 template <
class GRAPH_T>
160 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* is given");
172 bool prev_visibility =
true;
175 prev_visibility = prev_object->isVisible();
177 scene->removeObject(prev_object);
182 this->m_graph->getAs3DObject(graph_obj, viz_params.cfg);
184 graph_obj->setName(
"optimized_graph");
185 graph_obj->setVisibility(prev_visibility);
186 scene->insert(graph_obj);
187 this->m_win->unlockAccess3DScene();
189 this->m_win_manager->addTextMessage(
190 5, -viz_params.offset_y_graph,
192 "Optimized Graph: #nodes %d",
193 static_cast<int>(this->m_graph->nodeCount())),
195 viz_params.text_index_graph);
197 this->m_win->forceRepaint();
199 if (m_autozoom_active)
201 this->fitGraphInView();
207 template <
class GRAPH_T>
216 graph_obj->setVisibility(!graph_obj->isVisible());
218 this->m_win->unlockAccess3DScene();
219 this->m_win->forceRepaint();
224 template <
class GRAPH_T>
232 "\nVisualization of data was requested but no CDisplayWindow3D pointer " 240 this->m_win->unlockAccess3DScene();
241 this->m_win->forceRepaint();
248 float x_min, x_max, y_min, y_max;
249 obj_grid->getPlaneLimits(x_min, x_max, y_min, y_max);
250 const float z_min = obj_grid->getPlaneZcoord();
251 this->m_win->setCameraPointingToPoint(
252 0.5 * (x_min + x_max), 0.5 * (y_min + y_max), z_min);
253 this->m_win->setCameraZoom(
254 2.0f * std::max(10.0f, std::max(x_max - x_min, y_max - y_min)));
256 this->m_win->setCameraAzimuthDeg(60);
257 this->m_win->setCameraElevationDeg(75);
258 this->m_win->setCameraProjective(
true);
263 template <
class GRAPH_T>
269 if (opt_params.optimization_distance > 0)
271 this->m_win_observer->registerKeystroke(
272 opt_params.keystroke_optimization_distance,
273 "Toggle optimization distance on/off");
275 this->m_win_observer->registerKeystroke(
276 opt_params.keystroke_optimize_graph,
277 "Manually trigger a full graph optimization");
283 obj->setPose(initial_pose);
284 obj->setName(
"optimization_distance_obj");
288 this->m_win->unlockAccess3DScene();
289 this->m_win->forceRepaint();
292 this->m_win_manager->assignTextMessageParameters(
293 &opt_params.offset_y_optimization_distance,
294 &opt_params.text_index_optimization_distance);
296 this->m_win_manager->addTextMessage(
297 5, -opt_params.offset_y_optimization_distance,
298 "Radius for graph optimization",
300 opt_params.text_index_optimization_distance);
304 template <
class GRAPH_T>
313 opt_params.optimization_distance,
314 opt_params.optimization_distance - 0.1);
315 obj->setColor_u8(opt_params.optimization_distance_color);
319 template <
class GRAPH_T>
327 obj->setRadius(opt_params.optimization_distance);
329 opt_params.optimization_distance_color.R,
330 opt_params.optimization_distance_color.G,
331 opt_params.optimization_distance_color.B,
337 template <
class GRAPH_T>
341 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* is given");
348 obj->setPose(this->m_graph->nodes.rbegin()->second);
350 this->m_win->unlockAccess3DScene();
351 this->m_win->forceRepaint();
356 template <
class GRAPH_T>
365 obj->setVisibility(!obj->isVisible());
367 this->m_win->unlockAccess3DScene();
368 this->m_win->forceRepaint();
373 template <
class GRAPH_T>
380 "optimizeGraph:: ThreadID:" << endl
381 <<
"\t" << std::this_thread::get_id()
384 <<
"Trying to grab lock... ");
386 std::lock_guard<std::mutex> graph_lock(*this->m_graph_section);
387 this->_optimizeGraph();
394 template <
class GRAPH_T>
398 this->m_time_logger.enter(
"CLevMarqGSO::_optimizeGraph");
401 if (m_min_nodes_for_optimization > this->m_graph->nodes.size())
407 optimization_timer.
Tic();
410 std::set<mrpt::graphs::TNodeID>* nodes_to_optimize;
419 nodes_to_optimize =
nullptr;
423 nodes_to_optimize =
new std::set<mrpt::graphs::TNodeID>;
429 this->getNearbyNodesOf(
430 nodes_to_optimize, this->m_graph->nodeCount() - 1,
431 opt_params.optimization_distance);
432 nodes_to_optimize->insert(this->m_graph->nodeCount() - 1);
439 *(this->m_graph), levmarq_info, nodes_to_optimize, opt_params.cfg,
444 m_just_fully_optimized_graph =
true;
448 m_just_fully_optimized_graph =
false;
451 double elapsed_time = optimization_timer.
Tac();
457 delete nodes_to_optimize;
458 nodes_to_optimize =
nullptr;
460 this->m_time_logger.leave(
"CLevMarqGSO::_optimizeGraph");
464 template <
class GRAPH_T>
469 bool is_loop_closure =
false;
470 auto curr_pair_nodes_to_edge = this->m_graph->edges;
476 typename GRAPH_T::edges_map_t::const_iterator search;
479 for (
auto it = curr_pair_nodes_to_edge.begin();
480 it != curr_pair_nodes_to_edge.end(); ++it)
482 search = opt_params.last_pair_nodes_to_edge.find(it->first);
484 if (search == opt_params.last_pair_nodes_to_edge.end())
486 curr_pair = it->first;
489 static_cast<int>(curr_pair.first) -
490 static_cast<int>(curr_pair.second)) >
491 opt_params.LC_min_nodeid_diff)
495 is_loop_closure =
true;
502 opt_params.last_pair_nodes_to_edge = curr_pair_nodes_to_edge;
503 return is_loop_closure;
508 template <
class GRAPH_T>
511 bool is_full_update =
false;
513 if (opt_params.optimization_distance == -1)
518 bool added_lc = this->checkForLoopClosures();
523 if (m_curr_used_consec_lcs != 0 || m_curr_ignored_consec_lcs != 0)
528 m_curr_used_consec_lcs = 0;
529 m_curr_ignored_consec_lcs = 0;
530 m_optimization_policy = OptimizationPolicy::UseLoopClosures;
532 return is_full_update;
537 bool use_limit_reached =
538 m_curr_used_consec_lcs == m_max_used_consec_lcs;
540 bool ignore_limit_reached =
541 m_curr_ignored_consec_lcs == m_max_ignored_consec_lcs;
544 if (ignore_limit_reached || use_limit_reached)
546 m_curr_ignored_consec_lcs = 0;
547 m_curr_used_consec_lcs = 0;
550 if (ignore_limit_reached)
552 m_optimization_policy = OptimizationPolicy::UseLoopClosures;
554 if (use_limit_reached)
556 m_optimization_policy = OptimizationPolicy::IgnoreLoopClosures;
561 if (m_optimization_policy == OptimizationPolicy::UseLoopClosures)
563 m_curr_used_consec_lcs += 1;
567 m_curr_ignored_consec_lcs += 1;
573 if (m_optimization_policy == OptimizationPolicy::IgnoreLoopClosures)
575 is_full_update =
false;
577 "*PARTIAL* graph optimization.. ignoring new loop closure");
581 is_full_update =
true;
584 return is_full_update;
588 template <
class GRAPH_T>
591 return m_just_fully_optimized_graph;
594 template <
class GRAPH_T>
596 const GRAPH_T& graph,
const size_t iter,
const size_t max_iter,
597 const double cur_sq_error)
601 template <
class GRAPH_T>
603 std::set<mrpt::graphs::TNodeID>* nodes_set,
612 nodeID < this->m_graph->nodeCount() - 1; ++nodeID)
614 double curr_distance = this->m_graph->nodes[nodeID].distanceTo(
615 this->m_graph->nodes[cur_nodeID]);
618 nodes_set->insert(nodeID);
624 this->m_graph->getAllNodes(*nodes_set);
630 template <
class GRAPH_T>
633 parent::printParams();
635 opt_params.dumpToConsole();
636 viz_params.dumpToConsole();
638 template <
class GRAPH_T>
642 parent::loadParams(source_fname);
644 opt_params.loadFromConfigFileName(source_fname,
"OptimizerParameters");
645 viz_params.loadFromConfigFileName(source_fname,
"VisualizationParameters");
650 m_max_used_consec_lcs = source.
read_int(
651 "OptimizerParameters",
"max_used_consecutive_loop_closures", 2,
false);
653 m_max_ignored_consec_lcs = source.
read_int(
654 "OptimizerParameters",
"max_ignored_consecutive_loop_closures", 15,
659 int min_verbosity_level =
660 source.
read_int(
"OptimizerParameters",
"class_verbosity", 1,
false);
664 m_has_read_config =
true;
669 template <
class GRAPH_T>
675 const std::string report_sep(2,
'\n');
676 const std::string header_sep(80,
'#');
679 stringstream class_props_ss;
680 class_props_ss <<
"Levenberg Marquardt Optimization Summary: " << std::endl;
681 class_props_ss << header_sep << std::endl;
684 const std::string time_res = this->m_time_logger.getStatsAsText();
685 const std::string output_res = this->getLogAsString();
689 parent::getDescriptiveReport(report_str);
691 *report_str += class_props_ss.str();
692 *report_str += report_sep;
694 *report_str += time_res;
695 *report_str += report_sep;
697 *report_str += output_res;
698 *report_str += report_sep;
703 template <
class GRAPH_T>
705 : optimization_distance_color(0, 201, 87),
706 keystroke_optimization_distance(
"u"),
707 keystroke_optimize_graph(
"w")
710 template <
class GRAPH_T>
712 template <
class GRAPH_T>
714 std::ostream&
out)
const 717 out <<
"-----------[ Levenberg-Marquardt Optimization ] -------\n";
718 out <<
"Optimization on second thread = " 719 << (optimization_on_second_thread ?
"TRUE" :
"FALSE") << std::endl;
720 out <<
"Optimize nodes in distance = " << optimization_distance <<
"\n";
721 out <<
"Min. node difference for LC = " << LC_min_nodeid_diff <<
"\n";
722 out << cfg.getAsString() << std::endl;
725 template <
class GRAPH_T>
730 optimization_on_second_thread = source.
read_bool(
731 section,
"optimization_on_second_thread",
false,
false);
732 LC_min_nodeid_diff = source.
read_int(
733 "GeneralConfiguration",
"LC_min_nodeid_diff", 30,
false);
734 optimization_distance =
735 source.
read_double(section,
"optimization_distance", 5,
false);
738 optimization_distance == 1 || optimization_distance > 0,
740 "Invalid value for optimization distance: %.2f",
741 optimization_distance));
744 cfg[
"verbose"] = source.
read_bool(section,
"verbose",
false,
false);
745 cfg[
"profiler"] = source.
read_bool(section,
"profiler",
false,
false);
746 cfg[
"max_iterations"] =
747 source.
read_double(section,
"max_iterations", 100,
false);
748 cfg[
"scale_hessian"] =
749 source.
read_double(
"Optimization",
"scale_hessian", 0.2,
false);
750 cfg[
"tau"] = source.
read_double(section,
"tau", 1e-3,
false);
755 template <
class GRAPH_T>
757 : keystroke_graph_toggle(
"s"), keystroke_graph_autofit(
"a")
760 template <
class GRAPH_T>
763 template <
class GRAPH_T>
765 std::ostream&
out)
const 769 out <<
"-----------[ Graph Visualization Parameters ]-----------\n";
771 "Visualize optimized graph = %s\n",
772 visualize_optimized_graph ?
"TRUE" :
"FALSE");
776 std::cout << std::endl;
780 template <
class GRAPH_T>
786 visualize_optimized_graph =
787 source.
read_bool(section,
"visualize_optimized_graph",
true,
false);
789 cfg[
"show_ID_labels"] =
790 source.
read_bool(section,
"optimized_show_ID_labels",
false,
false);
791 cfg[
"show_ground_grid"] =
792 source.
read_double(section,
"optimized_show_ground_grid", 1,
false);
794 source.
read_bool(section,
"optimized_show_edges",
true,
false);
796 source.
read_int(section,
"optimized_edge_color", 1500,
false);
798 source.
read_double(section,
"optimized_edge_width", 1.5,
false);
799 cfg[
"show_node_corners"] =
800 source.
read_bool(section,
"optimized_show_node_corners",
true,
false);
801 cfg[
"show_edge_rel_poses"] =
802 source.
read_bool(section,
"optimized_show_edge_rel_poses",
true,
false);
803 cfg[
"edge_rel_poses_color"] =
804 source.
read_int(section,
"optimized_edge_rel_poses_color", 2000,
false);
805 cfg[
"nodes_edges_corner_scale"] = source.
read_double(
806 section,
"optimized_nodes_edges_corner_scale", 0.4,
false);
807 cfg[
"nodes_corner_scale"] =
808 source.
read_double(section,
"optimized_nodes_corner_scale", 0.7,
false);
809 cfg[
"nodes_point_size"] =
810 source.
read_int(section,
"optimized_nodes_point_size", 5,
false);
811 cfg[
"nodes_point_color"] =
812 source.
read_int(section,
"optimized_nodes_point_color", 3000,
false);
void initGraphVisualization()
Initialize objects relateed to the Graph Visualization.
double Tac() noexcept
Stops the stopwatch.
static void levMarqFeedback(const GRAPH_T &graph, const size_t iter, const size_t max_iter, const double cur_sq_error)
Feedback of the Levenberg-Marquardt graph optimization procedure.
bool checkForFullOptimization()
Decide whether to issue a full graph optimization.
#define MRPT_LOG_DEBUG(_STRING)
Use: MRPT_LOG_DEBUG("message");
void updateVisuals() override
Update the relevant visual features in CDisplayWindow.
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini"-like file or memory-stored string list.
void getNearbyNodesOf(std::set< mrpt::graphs::TNodeID > *nodes_set, const mrpt::graphs::TNodeID &cur_nodeID, double distance)
Get a list of the nodeIDs whose position is within a certain distance to the specified nodeID...
VerbosityLevel
Enumeration of available verbosity levels.
GraphVisualizationParams()
A grid of lines over the XY plane.
mrpt::opengl::CRenderizable::Ptr initOptDistanceVisualizationInternal(const mrpt::poses::CPose2D &p_unused)
Setup the corresponding Disk/Sphere instance.
void updateGraphVisualization()
Called internally for updating the visualization scene for the graph building procedure.
bool justFullyOptimizedGraph() const override
Used by the caller to query for possible full graph optimization on the latest optimizer run...
void toggleGraphVisualization()
Toggle the graph visualization on and off.
void optimize_graph_spa_levmarq(GRAPH_T &graph, TResultInfoSpaLevMarq &out_info, const std::set< mrpt::graphs::TNodeID > *in_nodes_to_optimize=nullptr, const mrpt::system::TParametersDouble &extra_params=mrpt::system::TParametersDouble(), FEEDBACK_CALLABLE functor_feedback=FEEDBACK_CALLABLE())
Optimize a graph of pose constraints using the Sparse Pose Adjustment (SPA) sparse representation and...
A set of object, which are referenced to the coordinates framework established in this object...
std::string std::string format(std::string_view fmt, ARGS &&... args)
app setMinLoggingLevel(mrpt::system::LVL_ERROR)
This class allows loading and storing values and vectors of different types from ".ini" files easily.
typename GRAPH_T::constraint_t::type_value pose_t
type of underlying poses (2D/3D)
A high-performance stopwatch, with typical resolution of nanoseconds.
~OptimizationParams() override
void printParams() const override
Print the problem parameters - relevant to the decider/optimizer to the screen in a unified/compact w...
#define MRPT_LOG_WARN_STREAM(__CONTENTS)
void dumpToTextStream(std::ostream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
void toggleOptDistanceVisualization()
toggle the optimization distance object on and off
int read_int(const std::string §ion, const std::string &name, int defaultValue, bool failIfNotFound=false) const
void initOptDistanceVisualization()
Initialize the Disk/Sphere used for visualizing the optimization distance.
This class allows loading and storing values and vectors of different types from a configuration text...
~GraphVisualizationParams() override
bool updateState(mrpt::obs::CActionCollection::Ptr action, mrpt::obs::CSensoryFrame::Ptr observations, mrpt::obs::CObservation::Ptr observation) override
Generic method for fetching the incremental action-observations (or observation-only) measurements...
OptimizationPolicy
Enumeration that defines the behaviors towards using or ignoring a newly added loop closure to fully ...
void optimizeGraph() override
Wrapper around _optimizeGraph which first locks the section and then calls the _optimizeGraph method...
double read_double(const std::string §ion, const std::string &name, double defaultValue, bool failIfNotFound=false) const
virtual void initializeLoggers(const std::string &name)
Initialize the COutputLogger, CTimeLogger instances given the name of the decider/optimizer at hand...
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
Use: MRPT_LOG_DEBUG_STREAM("Var=" << value << " foo=" << foo_var);
bool checkForLoopClosures()
Check if a loop closure edge was added in the graph.
#define ASSERTDEBMSG_(f, __ERROR_MSG)
void updateOptDistanceVisualization()
Update the position of the disk indicating the distance in which Levenberg-Marquardt graph optimizati...
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
mrpt::vision::TStereoCalibResults out
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
bool read_bool(const std::string §ion, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
An RGBA color - floats in the range [0,1].
Output information for mrpt::graphslam::optimize_graph_spa_levmarq()
The namespace for 3D scene representation and rendering.
uint64_t TNodeID
A generic numeric type for unique IDs of nodes or entities.
void getDescriptiveReport(std::string *report_str) const override
Fill the provided string with a detailed report of the decider/optimizer state.
void loadParams(const std::string &source_fname) override
Load the necessary for the decider/optimizer configuration parameters.
std::pair< TNodeID, TNodeID > TPairNodeIDs
A pair of node IDs.
Levenberg-Marquardt non-linear graph slam optimization scheme.
void Tic() noexcept
Starts the stopwatch.
void initializeVisuals() override
Initialize visual objects in CDisplayWindow (e.g.
void fitGraphInView()
Set the camera parameters of the CDisplayWindow3D so that the whole graph is viewed in the window...
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini"-like file or memory-stored string list.
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
void dumpToTextStream(std::ostream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
void notifyOfWindowEvents(const std::map< std::string, bool > &events_occurred) override
Get a list of the window events that happened since the last call.
void _optimizeGraph(bool is_full_update=false)
Optimize the given graph.