diff --git a/CMakeLists.txt b/CMakeLists.txt index b4a40c33cf8d2573b7999f6411b064558b96d0db..b6d381755addeead6f60c35b42fe1526eda0af4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -319,6 +319,7 @@ SET(HDRS_PROCESSOR include/core/processor/processor_frame_nearest_neighbor_filter.h include/core/processor/processor_logging.h include/core/processor/processor_loopclosure_base.h + include/core/processor/processor_loopclosure_base2.h include/core/processor/processor_motion.h include/core/processor/processor_odom_2D.h include/core/processor/processor_odom_3D.h @@ -414,6 +415,7 @@ SET(SRCS_PROCESSOR src/processor/processor_diff_drive.cpp src/processor/processor_frame_nearest_neighbor_filter.cpp src/processor/processor_loopclosure_base.cpp + src/processor/processor_loopclosure_base2.cpp src/processor/processor_motion.cpp src/processor/processor_odom_2D.cpp src/processor/processor_odom_3D.cpp diff --git a/include/core/processor/processor_loopclosure_base2.h b/include/core/processor/processor_loopclosure_base2.h new file mode 100644 index 0000000000000000000000000000000000000000..8d91689f9eea4da29a9c6057384ec65bbb3b9cfc --- /dev/null +++ b/include/core/processor/processor_loopclosure_base2.h @@ -0,0 +1,155 @@ +#ifndef _WOLF_PROCESSOR_LOOPCLOSURE_BASE_H +#define _WOLF_PROCESSOR_LOOPCLOSURE_BASE_H + +// Wolf related headers +#include "core/processor/processor_base.h" + +namespace wolf{ + +WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsLoopClosure2); + +struct ProcessorParamsLoopClosure2 : public ProcessorParamsBase +{ + using ProcessorParamsBase::ProcessorParamsBase; + // virtual ~ProcessorParamsLoopClosure2() = default; + + // add neccesery parameters for loop closure initialisation here and initialize + // them in constructor +}; + +/** \brief General loop closure processor + * + * This is an abstract class. + * + You must define the following classes : + * - doProcessLoopClosure() + * - findLoopCandidate() + * - createFactors() + * + You can override the following classes : + * - selectPairKC() + * - validateLoop() + * - processLoopClosure() + * + * It establishes factors XXX + * + * Should you need extra functionality for your derived types, + * you can overload these two methods, + * + * - preProcess() { } + * - postProcess() { } + * + * which are called at the beginning and at the end of process() respectively. + */ + +class ProcessorLoopClosureBase2 : public ProcessorBase +{ +protected: + + ProcessorParamsLoopClosure2Ptr params_loop_closure_; + +public: + + ProcessorLoopClosureBase2(const std::string& _type, ProcessorParamsLoopClosure2Ptr _params_loop_closure); + + virtual ~ProcessorLoopClosureBase2() = default; + virtual void configure(SensorBasePtr _sensor) override { }; + + /** \brief Full processing of an incoming Capture. + * + * Usually you do not need to overload this method in derived classes. + * Overload it only if you want to alter this algorithm. + */ + virtual void process(CaptureBasePtr _incoming_ptr) override; + +protected: + + /** \brief Called by process(). Tells if processLoopClosure will be called + */ + virtual bool doProcessLoopClosure(CaptureBasePtr _incoming_ptr) = 0; + + /** \brief Tries to close a loop + * + * this method is called in process() if doProcessLoopClosure retruns true + * this method uses : + * - selectPairKC() + * - addCapture() + * - findLoopCandidate() + * - validateLoop() + * - createFactors() + */ + void processLoopClosure(void); + + /** \brief returns a KeyFrame-Capture pair compatible together (selected from the buffers) + * + * Should clear elements before the ones selected in buffers. + * In the default implementation, we select the KF with the most recent TimeStamp + * and that is compatible with at least a Capture + */ + std::pair<FrameBasePtr,CaptureBasePtr> selectPairKC(void); + + /** \brief add the Capture and all features needed to the corresponding KF + * + * If the loop closure process requires features associated to each capture, + * the computations to create thies featrues must be done here + */ + virtual void addCapture(std::pair<FrameBasePtr,CaptureBasePtr>) = 0; + + /** \brief Find a KF that would be a good candidate to close a loop + * if validateLoop is not overwritten, a loop will be closed with the returned candidate + * if no good candidate is found, return nullptr + */ + virtual FrameBasePtr findLoopCandidate(FrameBasePtr _key_frame) = 0; + + /** \brief validate/discard a loop closure + * + * overwrite it if you want an additional test after findLoopCandidate() + */ + bool validateLoop(FrameBasePtr _key_frame_1, FrameBasePtr _key_frame_2) {return true;}; + + /** \brief create the factor(s) + * + * overwrite it if needed + */ + virtual void createFactors(FrameBasePtr _key_frame_1, FrameBasePtr _key_frame_2) = 0; + + + /** Pre-process incoming Capture + * + * This is called by process() just after assigning incoming_ptr_ to a valid Capture. + * + * Overload this function to prepare stuff on derived classes. + * + * Typical uses of prePrecess() are: + * - casting base types to derived types + * - initializing counters, flags, or any derived variables + * - initializing algorithms needed for processing the derived data + */ + virtual void preProcess() { } + + /** Post-process + * + * This is called by process() after finishing the processing algorithm. + * + * Overload this function to post-process stuff on derived classes. + * + * Typical uses of postPrecess() are: + * - resetting and/or clearing variables and/or algorithms at the end of processing + * - drawing / printing / logging the results of the processing + */ + virtual void postProcess() { } + + /** \brief Vote for KeyFrame generation + * + * If a KeyFrame criterion is validated, this function returns true, + * meaning that it wants to create a KeyFrame at the \b last Capture. + * + * WARNING! This function only votes! It does not create KeyFrames! + */ + bool voteForKeyFrame() + { + return false; + }; +}; + +} // namespace wolf + +#endif /* _WOLF_PROCESSOR_LOOPCLOSURE_BASE_H */ diff --git a/src/processor/processor_loopclosure_base2.cpp b/src/processor/processor_loopclosure_base2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7114b2c0e2fde68df59f5e0835a418a25269061c --- /dev/null +++ b/src/processor/processor_loopclosure_base2.cpp @@ -0,0 +1,80 @@ +/** + * \file processor_loop_closure2.h + * + * Created on: Mai 31, 2019 + * \author: Pierre Guetschel + */ + +#include "core/processor/processor_loopclosure_base2.h" + + +namespace wolf +{ + +ProcessorLoopClosureBase2::ProcessorLoopClosureBase2(const std::string& _type, ProcessorParamsLoopClosure2Ptr _params_loop_closure): + ProcessorBase(_type, _params_loop_closure), + params_loop_closure_(_params_loop_closure) +{ + // +} + +//############################################################################## +void ProcessorLoopClosureBase2::process(CaptureBasePtr _incoming_ptr) +{ + // the pre-process, if necessary, is implemented in the derived classes + preProcess(); + + if (doProcessLoopClosure(_incoming_ptr)) + { + //CREAT_THREAD(function=processLoopClosure); + processLoopClosure(); + }; + // the post-process, if necessary, is implemented in the derived classes + postProcess(); +} + +void ProcessorLoopClosureBase2::processLoopClosure() +{ + std::pair<FrameBasePtr,CaptureBasePtr> pairKC = selectPairKC(); + if (pairKC.first==nullptr || pairKC.second==nullptr) + return; + addCapture(pairKC); + FrameBasePtr key_frame_1 = pairKC.first; + FrameBasePtr key_frame_2 = findLoopCandidate(key_frame_1); + if (key_frame_2==nullptr) + return; + if (validateLoop(key_frame_1, key_frame_2)==false) + return; + createFactors(key_frame_1, key_frame_2); +} + +/** + * In the default implementation, we select the KF with the most recent TimeStamp + * and that is compatible with at least a Capture + */ +std::pair<FrameBasePtr,CaptureBasePtr> ProcessorLoopClosureBase2::selectPairKC() +{ + std::map<TimeStamp,PackKeyFramePtr> kf_container = kf_pack_buffer_.getContainer(); + if (kf_container.empty()){ + return std::make_pair(nullptr, nullptr);}; + PackKeyFrameBuffer::Iterator kf_it; + for (kf_it=kf_container.begin(); kf_it!=kf_container.end(); ++kf_it) + { + CaptureBasePtr cap_ptr = buffer_capture_.select(kf_it->first, kf_it->second->time_tolerance); + if (cap_ptr != nullptr) + { + // clear the buffers : + buffer_capture_.removeUpTo(cap_ptr->getTimeStamp()); + kf_pack_buffer_.removeUpTo(kf_it->first); + // return the KF-Cap pair : + return std::make_pair(kf_it->second->key_frame, cap_ptr); + }; + } + return std::make_pair(nullptr, nullptr); +} + + +//############################################################################## + + +}// namespace wolf