10 #ifndef CLEVMARQGSO_IMPL_H 11 #define CLEVMARQGSO_IMPL_H 18 template <
class GRAPH_T>
20 : m_first_time_call(false),
21 m_has_read_config(false),
22 m_autozoom_active(true),
23 m_last_total_num_of_nodes(5),
24 m_optimization_policy(FOP_USE_LC),
25 m_curr_used_consec_lcs(0),
26 m_curr_ignored_consec_lcs(0),
27 m_just_fully_optimized_graph(false),
28 m_min_nodes_for_optimization(3)
35 template <
class GRAPH_T>
44 template <
class GRAPH_T>
53 if (this->m_graph->nodeCount() > m_last_total_num_of_nodes)
55 m_last_total_num_of_nodes = this->m_graph->nodeCount();
56 registered_new_node =
true;
58 if (m_first_time_call)
60 opt_params.last_pair_nodes_to_edge = this->m_graph->edges;
61 m_first_time_call =
true;
64 if (opt_params.optimization_on_second_thread)
67 m_thread_optimize.join();
74 bool is_full_update = this->checkForFullOptimization();
75 this->_optimizeGraph(is_full_update);
83 template <
class GRAPH_T>
88 parent::initializeVisuals();
90 this->initGraphVisualization();
91 this->initOptDistanceVisualization();
96 template <
class GRAPH_T>
100 parent::updateVisuals();
102 if (opt_params.optimization_distance > 0)
104 this->updateOptDistanceVisualization();
107 this->updateGraphVisualization();
112 template <
class GRAPH_T>
114 const std::map<std::string, bool>& events_occurred)
118 parent::notifyOfWindowEvents(events_occurred);
123 if (opt_params.optimization_distance > 0)
125 if (events_occurred.find(opt_params.keystroke_optimization_distance)
128 this->toggleOptDistanceVisualization();
131 if (events_occurred.find(opt_params.keystroke_optimize_graph)->second)
133 this->_optimizeGraph(
true);
138 if (events_occurred.find(viz_params.keystroke_graph_toggle)->second)
140 this->toggleGraphVisualization();
144 if (events_occurred.find(
"mouse_clicked")->second)
147 m_autozoom_active =
false;
151 if (events_occurred.find(viz_params.keystroke_graph_autofit)->second)
154 this->fitGraphInView();
160 template <
class GRAPH_T>
164 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* is given");
166 if (viz_params.visualize_optimized_graph)
168 this->m_win_observer->registerKeystroke(
169 viz_params.keystroke_graph_toggle,
"Toggle Graph visualization");
170 this->m_win_observer->registerKeystroke(
171 viz_params.keystroke_graph_autofit,
"Fit Graph in view");
173 this->m_win_manager->assignTextMessageParameters(
174 &viz_params.offset_y_graph,
175 &viz_params.text_index_graph);
180 template <
class GRAPH_T>
184 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* is given");
196 bool prev_visibility =
true;
199 prev_visibility = prev_object->isVisible();
201 scene->removeObject(prev_object);
206 this->m_graph->getAs3DObject(graph_obj, viz_params.cfg);
208 graph_obj->setName(
"optimized_graph");
209 graph_obj->setVisibility(prev_visibility);
210 scene->insert(graph_obj);
211 this->m_win->unlockAccess3DScene();
213 this->m_win_manager->addTextMessage(
214 5, -viz_params.offset_y_graph,
216 "Optimized Graph: #nodes %d",
217 static_cast<int>(this->m_graph->nodeCount())),
219 viz_params.text_index_graph);
221 this->m_win->forceRepaint();
223 if (m_autozoom_active)
225 this->fitGraphInView();
231 template <
class GRAPH_T>
240 graph_obj->setVisibility(!graph_obj->isVisible());
242 this->m_win->unlockAccess3DScene();
243 this->m_win->forceRepaint();
248 template <
class GRAPH_T>
256 "\nVisualization of data was requested but no CDisplayWindow3D pointer " 264 this->m_win->unlockAccess3DScene();
265 this->m_win->forceRepaint();
272 float x_min, x_max, y_min, y_max;
273 obj_grid->getPlaneLimits(x_min, x_max, y_min, y_max);
274 const float z_min = obj_grid->getPlaneZcoord();
275 this->m_win->setCameraPointingToPoint(
276 0.5 * (x_min + x_max), 0.5 * (y_min + y_max), z_min);
277 this->m_win->setCameraZoom(
278 2.0f * std::max(10.0f, std::max(x_max - x_min, y_max - y_min)));
280 this->m_win->setCameraAzimuthDeg(60);
281 this->m_win->setCameraElevationDeg(75);
282 this->m_win->setCameraProjective(
true);
287 template <
class GRAPH_T>
293 if (opt_params.optimization_distance > 0)
295 this->m_win_observer->registerKeystroke(
296 opt_params.keystroke_optimization_distance,
297 "Toggle optimization distance on/off");
299 this->m_win_observer->registerKeystroke(
300 opt_params.keystroke_optimize_graph,
301 "Manually trigger a full graph optimization");
307 obj->setPose(initial_pose);
308 obj->setName(
"optimization_distance_obj");
312 this->m_win->unlockAccess3DScene();
313 this->m_win->forceRepaint();
316 this->m_win_manager->assignTextMessageParameters(
317 &opt_params.offset_y_optimization_distance,
318 &opt_params.text_index_optimization_distance);
320 this->m_win_manager->addTextMessage(
321 5, -opt_params.offset_y_optimization_distance,
322 format(
"Radius for graph optimization"),
324 opt_params.text_index_optimization_distance);
328 template <
class GRAPH_T>
337 opt_params.optimization_distance,
338 opt_params.optimization_distance - 0.1);
339 obj->setColor_u8(opt_params.optimization_distance_color);
343 template <
class GRAPH_T>
351 obj->setRadius(opt_params.optimization_distance);
353 opt_params.optimization_distance_color.R,
354 opt_params.optimization_distance_color.G,
355 opt_params.optimization_distance_color.B,
361 template <
class GRAPH_T>
365 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* is given");
372 obj->setPose(this->m_graph->nodes.rbegin()->second);
374 this->m_win->unlockAccess3DScene();
375 this->m_win->forceRepaint();
380 template <
class GRAPH_T>
389 obj->setVisibility(!
obj->isVisible());
391 this->m_win->unlockAccess3DScene();
392 this->m_win->forceRepaint();
397 template <
class GRAPH_T>
404 "optimizeGraph:: ThreadID:" << endl
405 <<
"\t" << std::this_thread::get_id()
408 <<
"Trying to grab lock... ");
410 std::lock_guard<std::mutex> graph_lock(*this->m_graph_section);
411 this->_optimizeGraph();
418 template <
class GRAPH_T>
422 this->m_time_logger.enter(
"CLevMarqGSO::_optimizeGraph");
425 if (m_min_nodes_for_optimization > this->m_graph->nodes.size())
431 optimization_timer.
Tic();
434 std::set<mrpt::graphs::TNodeID>* nodes_to_optimize;
443 nodes_to_optimize = NULL;
447 nodes_to_optimize =
new std::set<mrpt::graphs::TNodeID>;
453 this->getNearbyNodesOf(
454 nodes_to_optimize, this->m_graph->nodeCount() - 1,
455 opt_params.optimization_distance);
456 nodes_to_optimize->insert(this->m_graph->nodeCount() - 1);
463 *(this->m_graph), levmarq_info, nodes_to_optimize, opt_params.cfg,
468 m_just_fully_optimized_graph =
true;
472 m_just_fully_optimized_graph =
false;
475 double elapsed_time = optimization_timer.
Tac();
481 delete nodes_to_optimize;
482 nodes_to_optimize =
nullptr;
484 this->m_time_logger.leave(
"CLevMarqGSO::_optimizeGraph");
489 template <
class GRAPH_T>
494 bool is_loop_closure =
false;
495 auto curr_pair_nodes_to_edge = this->m_graph->edges;
505 curr_pair_nodes_to_edge.begin();
506 it != curr_pair_nodes_to_edge.end(); ++it)
508 search = opt_params.last_pair_nodes_to_edge.find(it->first);
510 if (search == opt_params.last_pair_nodes_to_edge.end())
512 curr_pair = it->first;
515 static_cast<int>(curr_pair.first) -
516 static_cast<int>(curr_pair.second)) >
517 opt_params.LC_min_nodeid_diff)
521 is_loop_closure =
true;
528 opt_params.last_pair_nodes_to_edge = curr_pair_nodes_to_edge;
529 return is_loop_closure;
534 template <
class GRAPH_T>
537 bool is_full_update =
false;
539 if (opt_params.optimization_distance == -1)
544 bool added_lc = this->checkForLoopClosures();
549 if (m_curr_used_consec_lcs != 0 || m_curr_ignored_consec_lcs != 0)
554 m_curr_used_consec_lcs = 0;
555 m_curr_ignored_consec_lcs = 0;
556 m_optimization_policy = FOP_USE_LC;
558 return is_full_update;
563 bool use_limit_reached =
564 m_curr_used_consec_lcs == m_max_used_consec_lcs;
566 bool ignore_limit_reached =
567 m_curr_ignored_consec_lcs == m_max_ignored_consec_lcs;
570 if (ignore_limit_reached || use_limit_reached)
572 m_curr_ignored_consec_lcs = 0;
573 m_curr_used_consec_lcs = 0;
576 if (ignore_limit_reached)
578 m_optimization_policy = FOP_USE_LC;
580 if (use_limit_reached)
582 m_optimization_policy = FOP_IGNORE_LC;
587 if (m_optimization_policy == FOP_USE_LC)
589 m_curr_used_consec_lcs += 1;
593 m_curr_ignored_consec_lcs += 1;
599 if (m_optimization_policy == FOP_IGNORE_LC)
601 is_full_update =
false;
603 "*PARTIAL* graph optimization.. ignoring new loop closure");
607 is_full_update =
true;
610 return is_full_update;
614 template <
class GRAPH_T>
617 return m_just_fully_optimized_graph;
620 template <
class GRAPH_T>
622 const GRAPH_T& graph,
const size_t iter,
const size_t max_iter,
623 const double cur_sq_error)
627 template <
class GRAPH_T>
629 std::set<mrpt::graphs::TNodeID>* nodes_set,
638 nodeID < this->m_graph->nodeCount() - 1; ++nodeID)
640 double curr_distance = this->m_graph->nodes[nodeID].distanceTo(
641 this->m_graph->nodes[cur_nodeID]);
644 nodes_set->insert(nodeID);
650 this->m_graph->getAllNodes(*nodes_set);
656 template <
class GRAPH_T>
659 parent::printParams();
661 opt_params.dumpToConsole();
662 viz_params.dumpToConsole();
664 template <
class GRAPH_T>
668 parent::loadParams(source_fname);
670 opt_params.loadFromConfigFileName(source_fname,
"OptimizerParameters");
671 viz_params.loadFromConfigFileName(source_fname,
"VisualizationParameters");
676 m_max_used_consec_lcs =
source.read_int(
677 "OptimizerParameters",
"max_used_consecutive_loop_closures", 2,
false);
679 m_max_ignored_consec_lcs =
source.read_int(
680 "OptimizerParameters",
"max_ignored_consecutive_loop_closures", 15,
685 int min_verbosity_level =
686 source.read_int(
"OptimizerParameters",
"class_verbosity", 1,
false);
690 m_has_read_config =
true;
695 template <
class GRAPH_T>
705 stringstream class_props_ss;
706 class_props_ss <<
"Levenberg Marquardt Optimization Summary: " << std::endl;
707 class_props_ss << header_sep << std::endl;
710 const std::string time_res = this->m_time_logger.getStatsAsText();
711 const std::string output_res = this->getLogAsString();
715 parent::getDescriptiveReport(report_str);
717 *report_str += class_props_ss.str();
718 *report_str += report_sep;
720 *report_str += time_res;
721 *report_str += report_sep;
723 *report_str += output_res;
724 *report_str += report_sep;
731 template <
class GRAPH_T>
733 : optimization_distance_color(0, 201, 87),
734 keystroke_optimization_distance(
"u"),
735 keystroke_optimize_graph(
"w")
738 template <
class GRAPH_T>
742 template <
class GRAPH_T>
744 std::ostream& out)
const 747 out <<
"-----------[ Levenberg-Marquardt Optimization ] -------\n";
748 out <<
"Optimization on second thread = " 749 << (optimization_on_second_thread ?
"TRUE" :
"FALSE") << std::endl;
750 out <<
"Optimize nodes in distance = " << optimization_distance <<
"\n";
751 out <<
"Min. node difference for LC = " << LC_min_nodeid_diff <<
"\n";
752 out << cfg.getAsString() << std::endl;
755 template <
class GRAPH_T>
760 optimization_on_second_thread =
source.read_bool(
761 section,
"optimization_on_second_thread",
false,
false);
762 LC_min_nodeid_diff =
source.read_int(
763 "GeneralConfiguration",
"LC_min_nodeid_diff", 30,
false);
764 optimization_distance =
765 source.read_double(section,
"optimization_distance", 5,
false);
768 optimization_distance == 1 || optimization_distance > 0,
770 "Invalid value for optimization distance: %.2f",
771 optimization_distance));
774 cfg[
"verbose"] =
source.read_bool(section,
"verbose", 0,
false);
775 cfg[
"profiler"] =
source.read_bool(section,
"profiler", 0,
false);
776 cfg[
"max_iterations"] =
777 source.read_double(section,
"max_iterations", 100,
false);
778 cfg[
"scale_hessian"] =
779 source.read_double(
"Optimization",
"scale_hessian", 0.2,
false);
780 cfg[
"tau"] =
source.read_double(section,
"tau", 1e-3,
false);
787 template <
class GRAPH_T>
789 : keystroke_graph_toggle(
"s"), keystroke_graph_autofit(
"a")
792 template <
class GRAPH_T>
796 template <
class GRAPH_T>
798 std::ostream& out)
const 803 "-----------[ Graph Visualization Parameters ]-----------\n");
805 "Visualize optimized graph = %s\n",
806 visualize_optimized_graph ?
"TRUE" :
"FALSE");
810 std::cout << std::endl;
814 template <
class GRAPH_T>
820 visualize_optimized_graph =
821 source.read_bool(section,
"visualize_optimized_graph", 1,
false);
823 cfg[
"show_ID_labels"] =
824 source.read_bool(section,
"optimized_show_ID_labels", 0,
false);
825 cfg[
"show_ground_grid"] =
826 source.read_double(section,
"optimized_show_ground_grid", 1,
false);
828 source.read_bool(section,
"optimized_show_edges", 1,
false);
830 source.read_int(section,
"optimized_edge_color", 4286611456,
false);
832 source.read_double(section,
"optimized_edge_width", 1.5,
false);
833 cfg[
"show_node_corners"] =
834 source.read_bool(section,
"optimized_show_node_corners", 1,
false);
835 cfg[
"show_edge_rel_poses"] =
836 source.read_bool(section,
"optimized_show_edge_rel_poses", 1,
false);
837 cfg[
"edge_rel_poses_color"] =
source.read_int(
838 section,
"optimized_edge_rel_poses_color", 1090486272,
false);
839 cfg[
"nodes_edges_corner_scale"] =
source.read_double(
840 section,
"optimized_nodes_edges_corner_scale", 0.4,
false);
841 cfg[
"nodes_corner_scale"] =
842 source.read_double(section,
"optimized_nodes_corner_scale", 0.7,
false);
843 cfg[
"nodes_point_size"] =
844 source.read_int(section,
"optimized_nodes_point_size", 5,
false);
845 cfg[
"nodes_point_color"] =
source.read_int(
846 section,
"optimized_nodes_point_color", 10526880,
false);
void initGraphVisualization()
Initialize objects relateed to the Graph Visualization.
double Tac() noexcept
Stops the stopwatch.
void dumpToTextStream(std::ostream &out) const
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
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.
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(), typename graphslam_traits< GRAPH_T >::TFunctorFeedback functor_feedback=typename graphslam_traits< GRAPH_T >::TFunctorFeedback())
Optimize a graph of pose constraints using the Sparse Pose Adjustment (SPA) sparse representation and...
bool checkForFullOptimization()
Decide whether to issue a full graph optimization.
#define MRPT_LOG_DEBUG(_STRING)
Use: MRPT_LOG_DEBUG("message");
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.
void toggleGraphVisualization()
Toggle the graph visualization on and off.
A set of object, which are referenced to the coordinates framework established in this object...
void optimizeGraph()
Wrapper around _optimizeGraph which first locks the section and then calls the _optimizeGraph method...
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.
bool justFullyOptimizedGraph() const
Used by the caller to query for possible full graph optimization on the latest optimizer run...
GLsizei GLsizei GLuint * obj
~GraphVisualizationParams()
#define MRPT_LOG_WARN_STREAM(__CONTENTS)
void printParams() const
Print the problem parameters - relevant to the decider/optimizer to the screen in a unified/compact w...
void toggleOptDistanceVisualization()
toggle the optimization distance object on and off
void initOptDistanceVisualization()
Initialize the Disk/Sphere used for visualizing the optimization distance.
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion)
This method load the options from a ".ini"-like file or memory-stored string list.
This class allows loading and storing values and vectors of different types from a configuration text...
void initializeVisuals()
Initialize visual objects in CDisplayWindow (e.g.
void loadParams(const std::string &source_fname)
Load the necessary for the decider/optimizer configuration parameters.
void notifyOfWindowEvents(const std::map< std::string, bool > &events_occurred)
Get a list of the window events that happened since the last call.
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()
void dumpToTextStream(std::ostream &out) const
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
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.
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.
bool updateState(mrpt::obs::CActionCollection::Ptr action, mrpt::obs::CSensoryFrame::Ptr observations, mrpt::obs::CObservation::Ptr observation)
Generic method for fetching the incremental action/observation readings from the calling function...
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)
This method load the options from a ".ini"-like file or memory-stored string list.
const Scalar * const_iterator
void getDescriptiveReport(std::string *report_str) const
Fill the provided string with a detailed report of the decider/optimizer state.
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
void updateVisuals()
Update the relevant visual features in CDisplayWindow.
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.