/* * go.h * * Created on: Jun 4, 2012 * Author: aitor */ #pragma once #include #include #include //includes required by mets.hh #include #include #include #include #include #include #include #include namespace pcl { /** \brief A hypothesis verification method proposed in * "A Global Hypotheses Verification Method for 3D Object Recognition", A. Aldoma and F. Tombari and L. Di Stefano and Markus Vincze, ECCV 2012 * \author Aitor Aldoma * \ingroup recognition */ template class PCL_EXPORTS GlobalHypothesesVerification: public HypothesisVerification { private: //Helper classes struct RecognitionModel { public: std::vector explained_; //indices vector referencing explained_by_RM_ std::vector explained_distances_; //closest distances to the scene for point i std::vector unexplained_in_neighborhood; //indices vector referencing unexplained_by_RM_neighboorhods std::vector unexplained_in_neighborhood_weights; //weights for the points not being explained in the neighborhood of a hypothesis std::vector outlier_indices_; //outlier indices of this model std::vector complete_cloud_occupancy_indices_; typename pcl::PointCloud::Ptr cloud_; typename pcl::PointCloud::Ptr complete_cloud_; int bad_information_; float outliers_weight_; pcl::PointCloud::Ptr normals_; int id_; }; using RecognitionModelPtr = std::shared_ptr; using SAOptimizerT = GlobalHypothesesVerification; class SAModel: public mets::evaluable_solution { public: std::vector solution_; SAOptimizerT * opt_; mets::gol_type cost_; //Evaluates the current solution mets::gol_type cost_function() const override { return cost_; } void copy_from(const mets::copyable& o) override { const auto& s = dynamic_cast (o); solution_ = s.solution_; opt_ = s.opt_; cost_ = s.cost_; } mets::gol_type what_if(int /*index*/, bool /*val*/) const { /*std::vector tmp (solution_); tmp[index] = val; mets::gol_type sol = opt_->evaluateSolution (solution_, index); //evaluate without updating status return sol;*/ return static_cast(0); } mets::gol_type apply_and_evaluate(int index, bool val) { solution_[index] = val; mets::gol_type sol = opt_->evaluateSolution (solution_, index); //this will update the state of the solution cost_ = sol; return sol; } void apply(int /*index*/, bool /*val*/) { } void unapply(int index, bool val) { solution_[index] = val; //update optimizer solution cost_ = opt_->evaluateSolution (solution_, index); //this will update the cost function in opt_ } void setSolution(std::vector & sol) { solution_ = sol; } void setOptimizer(SAOptimizerT * opt) { opt_ = opt; } }; /* * Represents a move, deactivate a hypothesis */ class move: public mets::move { int index_; public: move(int i) : index_ (i) { } mets::gol_type evaluate(const mets::feasible_solution& /*cs*/) const override { return static_cast(0); } mets::gol_type apply_and_evaluate(mets::feasible_solution& cs) { auto& model = dynamic_cast (cs); return model.apply_and_evaluate (index_, !model.solution_[index_]); } void apply(mets::feasible_solution& /*s*/) const override { } void unapply(mets::feasible_solution& s) const { auto& model = dynamic_cast (s); model.unapply (index_, !model.solution_[index_]); } }; class move_manager { public: std::vector moves_m; using iterator = typename std::vector::iterator; iterator begin() { return moves_m.begin (); } iterator end() { return moves_m.end (); } move_manager(int problem_size) { for (int ii = 0; ii != problem_size; ++ii) moves_m.push_back (new move (ii)); } ~move_manager() { // delete all moves for (auto ii = begin (); ii != end (); ++ii) delete (*ii); } void refresh(mets::feasible_solution& /*s*/) { std::shuffle (moves_m.begin (), moves_m.end (), std::mt19937(std::random_device()())); } }; //inherited class attributes using HypothesisVerification::mask_; using HypothesisVerification::scene_cloud_downsampled_; using HypothesisVerification::scene_downsampled_tree_; using HypothesisVerification::visible_models_; using HypothesisVerification::complete_models_; using HypothesisVerification::resolution_; using HypothesisVerification::inliers_threshold_; //class attributes using NormalEstimator_ = pcl::NormalEstimation; pcl::PointCloud::Ptr scene_normals_; pcl::PointCloud::Ptr clusters_cloud_; std::vector complete_cloud_occupancy_by_RM_; float res_occupancy_grid_; float w_occupied_multiple_cm_; std::vector explained_by_RM_; //represents the points of scene_cloud_ that are explained by the recognition models std::vector explained_by_RM_distance_weighted; //represents the points of scene_cloud_ that are explained by the recognition models std::vector unexplained_by_RM_neighboorhods; //represents the points of scene_cloud_ that are not explained by the active hypotheses in the neighboorhod of the recognition models std::vector recognition_models_; std::vector indices_; float regularizer_; float clutter_regularizer_; bool detect_clutter_; float radius_neighborhood_GO_; float radius_normals_; float previous_explained_value; int previous_duplicity_; int previous_duplicity_complete_models_; float previous_bad_info_; float previous_unexplained_; int max_iterations_; //max iterations without improvement SAModel best_seen_; float initial_temp_; int n_cc_; std::vector > cc_; void setPreviousBadInfo(float f) { previous_bad_info_ = f; } float getPreviousBadInfo() { return previous_bad_info_; } void setPreviousExplainedValue(float v) { previous_explained_value = v; } void setPreviousDuplicity(int v) { previous_duplicity_ = v; } void setPreviousDuplicityCM(int v) { previous_duplicity_complete_models_ = v; } void setPreviousUnexplainedValue(float v) { previous_unexplained_ = v; } float getPreviousUnexplainedValue() { return previous_unexplained_; } float getExplainedValue() { return previous_explained_value; } int getDuplicity() { return previous_duplicity_; } int getDuplicityCM() { return previous_duplicity_complete_models_; } void updateUnexplainedVector(std::vector & unexplained_, std::vector & unexplained_distances, std::vector & unexplained_by_RM, std::vector & explained, std::vector & explained_by_RM, float val) { { float add_to_unexplained = 0.f; for (std::size_t i = 0; i < unexplained_.size (); i++) { bool prev_unexplained = (unexplained_by_RM[unexplained_[i]] > 0) && (explained_by_RM[unexplained_[i]] == 0); unexplained_by_RM[unexplained_[i]] += val * unexplained_distances[i]; if (val < 0) //the hypothesis is being removed { if (prev_unexplained) { //decrease by 1 add_to_unexplained -= unexplained_distances[i]; } } else //the hypothesis is being added and unexplains unexplained_[i], so increase by 1 unless its explained by another hypothesis { if (explained_by_RM[unexplained_[i]] == 0) add_to_unexplained += unexplained_distances[i]; } } for (const int &i : explained) { if (val < 0) { //the hypothesis is being removed, check that there are no points that become unexplained and have clutter unexplained hypotheses if ((explained_by_RM[i] == 0) && (unexplained_by_RM[i] > 0)) { add_to_unexplained += unexplained_by_RM[i]; //the points become unexplained } } else { //std::cout << "being added..." << add_to_unexplained << " " << unexplained_by_RM[explained[i]] << std::endl; if ((explained_by_RM[i] == 1) && (unexplained_by_RM[i] > 0)) { //the only hypothesis explaining that point add_to_unexplained -= unexplained_by_RM[i]; //the points are not unexplained any longer because this hypothesis explains them } } } //std::cout << add_to_unexplained << std::endl; previous_unexplained_ += add_to_unexplained; } } void updateExplainedVector(std::vector & vec, std::vector & vec_float, std::vector & explained_, std::vector & explained_by_RM_distance_weighted, float sign) { float add_to_explained = 0.f; int add_to_duplicity_ = 0; for (std::size_t i = 0; i < vec.size (); i++) { bool prev_dup = explained_[vec[i]] > 1; explained_[vec[i]] += static_cast (sign); explained_by_RM_distance_weighted[vec[i]] += vec_float[i] * sign; add_to_explained += vec_float[i] * sign; if ((explained_[vec[i]] > 1) && prev_dup) { //its still a duplicate, we are adding add_to_duplicity_ += static_cast (sign); //so, just add or remove one } else if ((explained_[vec[i]] == 1) && prev_dup) { //if was duplicate before, now its not, remove 2, we are removing the hypothesis add_to_duplicity_ -= 2; } else if ((explained_[vec[i]] > 1) && !prev_dup) { //it was not a duplicate but it is now, add 2, we are adding a conflicting hypothesis for the point add_to_duplicity_ += 2; } } //update explained and duplicity values... previous_explained_value += add_to_explained; previous_duplicity_ += add_to_duplicity_; } void updateCMDuplicity(std::vector & vec, std::vector & occupancy_vec, float sign) { int add_to_duplicity_ = 0; for (const int &i : vec) { bool prev_dup = occupancy_vec[i] > 1; occupancy_vec[i] += static_cast (sign); if ((occupancy_vec[i] > 1) && prev_dup) { //its still a duplicate, we are adding add_to_duplicity_ += static_cast (sign); //so, just add or remove one } else if ((occupancy_vec[i] == 1) && prev_dup) { //if was duplicate before, now its not, remove 2, we are removing the hypothesis add_to_duplicity_ -= 2; } else if ((occupancy_vec[i] > 1) && !prev_dup) { //it was not a duplicate but it is now, add 2, we are adding a conflicting hypothesis for the point add_to_duplicity_ += 2; } } previous_duplicity_complete_models_ += add_to_duplicity_; } float getTotalExplainedInformation(std::vector & explained_, std::vector & explained_by_RM_distance_weighted, int * duplicity_) { float explained_info = 0; int duplicity = 0; for (std::size_t i = 0; i < explained_.size (); i++) { if (explained_[i] > 0) explained_info += explained_by_RM_distance_weighted[i]; if (explained_[i] > 1) duplicity += explained_[i]; } *duplicity_ = duplicity; return explained_info; } float getTotalBadInformation(std::vector & recog_models) { float bad_info = 0; for (std::size_t i = 0; i < recog_models.size (); i++) bad_info += recog_models[i]->outliers_weight_ * static_cast (recog_models[i]->bad_information_); return bad_info; } float getUnexplainedInformationInNeighborhood(std::vector & unexplained, std::vector & explained) { float unexplained_sum = 0.f; for (std::size_t i = 0; i < unexplained.size (); i++) { if (unexplained[i] > 0 && explained[i] == 0) unexplained_sum += unexplained[i]; } return unexplained_sum; } //Performs smooth segmentation of the scene cloud and compute the model cues void initialize(); mets::gol_type evaluateSolution(const std::vector & active, int changed); bool addModel(typename pcl::PointCloud::ConstPtr & model, typename pcl::PointCloud::ConstPtr & complete_model, RecognitionModelPtr & recog_model); void computeClutterCue(RecognitionModelPtr & recog_model); void SAOptimize(std::vector & cc_indices, std::vector & sub_solution); public: GlobalHypothesesVerification() : HypothesisVerification() { resolution_ = 0.005f; max_iterations_ = 5000; regularizer_ = 1.f; radius_normals_ = 0.01f; initial_temp_ = 1000; detect_clutter_ = true; radius_neighborhood_GO_ = 0.03f; clutter_regularizer_ = 5.f; res_occupancy_grid_ = 0.01f; w_occupied_multiple_cm_ = 4.f; } void verify() override; void setResolutionOccupancyGrid(float r) { res_occupancy_grid_ = r; } void setRadiusNormals(float r) { radius_normals_ = r; } void setMaxIterations(int i) { max_iterations_ = i; } void setInitialTemp(float t) { initial_temp_ = t; } void setRegularizer(float r) { regularizer_ = r; } void setRadiusClutter(float r) { radius_neighborhood_GO_ = r; } void setClutterRegularizer(float cr) { clutter_regularizer_ = cr; } void setDetectClutter(bool d) { detect_clutter_ = d; } }; } #ifdef PCL_NO_PRECOMPILE #include #endif