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 format(
"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");
465 template <
class GRAPH_T>
470 bool is_loop_closure =
false;
471 auto curr_pair_nodes_to_edge = this->m_graph->edges;
477 typename GRAPH_T::edges_map_t::const_iterator search;
480 for (
auto it = curr_pair_nodes_to_edge.begin();
481 it != curr_pair_nodes_to_edge.end(); ++it)
483 search = opt_params.last_pair_nodes_to_edge.find(it->first);
485 if (search == opt_params.last_pair_nodes_to_edge.end())
487 curr_pair = it->first;
490 static_cast<int>(curr_pair.first) -
491 static_cast<int>(curr_pair.second)) >
492 opt_params.LC_min_nodeid_diff)
496 is_loop_closure =
true;
503 opt_params.last_pair_nodes_to_edge = curr_pair_nodes_to_edge;
504 return is_loop_closure;
509 template <
class GRAPH_T>
512 bool is_full_update =
false;
514 if (opt_params.optimization_distance == -1)
519 bool added_lc = this->checkForLoopClosures();
524 if (m_curr_used_consec_lcs != 0 || m_curr_ignored_consec_lcs != 0)
529 m_curr_used_consec_lcs = 0;
530 m_curr_ignored_consec_lcs = 0;
531 m_optimization_policy = OptimizationPolicy::UseLoopClosures;
533 return is_full_update;
538 bool use_limit_reached =
539 m_curr_used_consec_lcs == m_max_used_consec_lcs;
541 bool ignore_limit_reached =
542 m_curr_ignored_consec_lcs == m_max_ignored_consec_lcs;
545 if (ignore_limit_reached || use_limit_reached)
547 m_curr_ignored_consec_lcs = 0;
548 m_curr_used_consec_lcs = 0;
551 if (ignore_limit_reached)
553 m_optimization_policy = OptimizationPolicy::UseLoopClosures;
555 if (use_limit_reached)
557 m_optimization_policy = OptimizationPolicy::IgnoreLoopClosures;
562 if (m_optimization_policy == OptimizationPolicy::UseLoopClosures)
564 m_curr_used_consec_lcs += 1;
568 m_curr_ignored_consec_lcs += 1;
574 if (m_optimization_policy == OptimizationPolicy::IgnoreLoopClosures)
576 is_full_update =
false;
578 "*PARTIAL* graph optimization.. ignoring new loop closure");
582 is_full_update =
true;
585 return is_full_update;
589 template <
class GRAPH_T>
592 return m_just_fully_optimized_graph;
595 template <
class GRAPH_T>
597 const GRAPH_T& graph,
const size_t iter,
const size_t max_iter,
598 const double cur_sq_error)
602 template <
class GRAPH_T>
604 std::set<mrpt::graphs::TNodeID>* nodes_set,
613 nodeID < this->m_graph->nodeCount() - 1; ++nodeID)
615 double curr_distance = this->m_graph->nodes[nodeID].distanceTo(
616 this->m_graph->nodes[cur_nodeID]);
619 nodes_set->insert(nodeID);
625 this->m_graph->getAllNodes(*nodes_set);
631 template <
class GRAPH_T>
634 parent::printParams();
636 opt_params.dumpToConsole();
637 viz_params.dumpToConsole();
639 template <
class GRAPH_T>
643 parent::loadParams(source_fname);
645 opt_params.loadFromConfigFileName(source_fname,
"OptimizerParameters");
646 viz_params.loadFromConfigFileName(source_fname,
"VisualizationParameters");
651 m_max_used_consec_lcs =
source.read_int(
652 "OptimizerParameters",
"max_used_consecutive_loop_closures", 2,
false);
654 m_max_ignored_consec_lcs =
source.read_int(
655 "OptimizerParameters",
"max_ignored_consecutive_loop_closures", 15,
660 int min_verbosity_level =
661 source.read_int(
"OptimizerParameters",
"class_verbosity", 1,
false);
665 m_has_read_config =
true;
670 template <
class GRAPH_T>
680 stringstream class_props_ss;
681 class_props_ss <<
"Levenberg Marquardt Optimization Summary: " << std::endl;
682 class_props_ss << header_sep << std::endl;
685 const std::string time_res = this->m_time_logger.getStatsAsText();
686 const std::string output_res = this->getLogAsString();
690 parent::getDescriptiveReport(report_str);
692 *report_str += class_props_ss.str();
693 *report_str += report_sep;
695 *report_str += time_res;
696 *report_str += report_sep;
698 *report_str += output_res;
699 *report_str += report_sep;
704 template <
class GRAPH_T>
706 : optimization_distance_color(0, 201, 87),
707 keystroke_optimization_distance(
"u"),
708 keystroke_optimize_graph(
"w")
711 template <
class GRAPH_T>
713 template <
class GRAPH_T>
715 std::ostream& out)
const 718 out <<
"-----------[ Levenberg-Marquardt Optimization ] -------\n";
719 out <<
"Optimization on second thread = " 720 << (optimization_on_second_thread ?
"TRUE" :
"FALSE") << std::endl;
721 out <<
"Optimize nodes in distance = " << optimization_distance <<
"\n";
722 out <<
"Min. node difference for LC = " << LC_min_nodeid_diff <<
"\n";
723 out << cfg.getAsString() << std::endl;
726 template <
class GRAPH_T>
731 optimization_on_second_thread =
source.read_bool(
732 section,
"optimization_on_second_thread",
false,
false);
733 LC_min_nodeid_diff =
source.read_int(
734 "GeneralConfiguration",
"LC_min_nodeid_diff", 30,
false);
735 optimization_distance =
736 source.read_double(section,
"optimization_distance", 5,
false);
739 optimization_distance == 1 || optimization_distance > 0,
741 "Invalid value for optimization distance: %.2f",
742 optimization_distance));
745 cfg[
"verbose"] =
source.read_bool(section,
"verbose",
false,
false);
746 cfg[
"profiler"] =
source.read_bool(section,
"profiler",
false,
false);
747 cfg[
"max_iterations"] =
748 source.read_double(section,
"max_iterations", 100,
false);
749 cfg[
"scale_hessian"] =
750 source.read_double(
"Optimization",
"scale_hessian", 0.2,
false);
751 cfg[
"tau"] =
source.read_double(section,
"tau", 1e-3,
false);
756 template <
class GRAPH_T>
758 : keystroke_graph_toggle(
"s"), keystroke_graph_autofit(
"a")
761 template <
class GRAPH_T>
764 template <
class GRAPH_T>
766 std::ostream& out)
const 771 "-----------[ Graph Visualization Parameters ]-----------\n");
773 "Visualize optimized graph = %s\n",
774 visualize_optimized_graph ?
"TRUE" :
"FALSE");
778 std::cout << std::endl;
782 template <
class GRAPH_T>
788 visualize_optimized_graph =
789 source.read_bool(section,
"visualize_optimized_graph",
true,
false);
791 cfg[
"show_ID_labels"] =
792 source.read_bool(section,
"optimized_show_ID_labels",
false,
false);
793 cfg[
"show_ground_grid"] =
794 source.read_double(section,
"optimized_show_ground_grid", 1,
false);
796 source.read_bool(section,
"optimized_show_edges",
true,
false);
798 source.read_int(section,
"optimized_edge_color", 1500,
false);
800 source.read_double(section,
"optimized_edge_width", 1.5,
false);
801 cfg[
"show_node_corners"] =
802 source.read_bool(section,
"optimized_show_node_corners",
true,
false);
803 cfg[
"show_edge_rel_poses"] =
804 source.read_bool(section,
"optimized_show_edge_rel_poses",
true,
false);
805 cfg[
"edge_rel_poses_color"] =
806 source.read_int(section,
"optimized_edge_rel_poses_color", 2000,
false);
807 cfg[
"nodes_edges_corner_scale"] =
source.read_double(
808 section,
"optimized_nodes_edges_corner_scale", 0.4,
false);
809 cfg[
"nodes_corner_scale"] =
810 source.read_double(section,
"optimized_nodes_corner_scale", 0.7,
false);
811 cfg[
"nodes_point_size"] =
812 source.read_int(section,
"optimized_nodes_point_size", 5,
false);
813 cfg[
"nodes_point_color"] =
814 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...
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...
GLsizei GLsizei GLuint * obj
#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
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...
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);
GLsizei const GLchar ** string
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).
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
A RGB color - floats in the range [0,1].
Output information for mrpt::graphslam::optimize_graph_spa_levmarq()
The namespace for 3D scene representation and rendering.
GLsizei GLsizei GLchar * source
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.
GLenum GLsizei GLenum format
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.
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.