diff --git a/cpp/deplex/src/deplex/cell_grid.cpp b/cpp/deplex/src/deplex/cell_grid.cpp index 3950b29..c775398 100644 --- a/cpp/deplex/src/deplex/cell_grid.cpp +++ b/cpp/deplex/src/deplex/cell_grid.cpp @@ -22,25 +22,40 @@ CellGrid::CellGrid(Eigen::MatrixXf const& points, config::Config const& config, cell_height_(config.getInt("patchSize")), number_horizontal_cells_(number_horizontal_cells), number_vertical_cells_(number_vertical_cells), - cell_grid_(number_vertical_cells), - planar_mask_(number_horizontal_cells_ * number_vertical_cells_) { + parent_(number_vertical_cells * number_horizontal_cells), + component_size_(number_vertical_cells * number_horizontal_cells, 1), + planar_mask_(number_vertical_cells * number_horizontal_cells) { + cell_grid_.reserve(planar_mask_.size()); int32_t stacked_cell_id = 0; for (Eigen::Index cell_row = 0; cell_row < number_vertical_cells; ++cell_row) { - cell_grid_[cell_row].reserve(number_horizontal_cells); for (Eigen::Index cell_col = 0; cell_col < number_horizontal_cells; ++cell_col) { Eigen::Index offset = stacked_cell_id * cell_width_ * cell_height_; Eigen::MatrixXf cell_points = points.block(offset, 0, cell_width_ * cell_height_, 3); - cell_grid_[cell_row].emplace_back(cell_points, config); - planar_mask_[stacked_cell_id] = cell_grid_[cell_row][cell_col].isPlanar(); + parent_[stacked_cell_id] = stacked_cell_id; + cell_grid_.emplace_back(cell_points, config); + planar_mask_[stacked_cell_id] = cell_grid_[stacked_cell_id].isPlanar(); ++stacked_cell_id; } } } -CellSegment const& CellGrid::getByCoordinates(size_t x, size_t y) const { return cell_grid_[x][y]; } +CellSegment const& CellGrid::operator[](size_t cell_id) const { return cell_grid_[cell_id]; } -CellSegment const& CellGrid::operator[](size_t cell_id) const { - return cell_grid_[cell_id / number_horizontal_cells_][cell_id % number_horizontal_cells_]; +size_t CellGrid::findLabel(size_t cell_id) { + return (parent_[cell_id] == cell_id) ? cell_id : parent_[cell_id] = findLabel(parent_[cell_id]); +} + +void CellGrid::uniteLabels(size_t a, size_t b) { + a = findLabel(a); + b = findLabel(b); + if (component_size_[a] > component_size_[b]) std::swap(a, b); + component_size_[b] += component_size_[a]; + parent_[a] = b; +} + +void CellGrid::updateCell(size_t cell_id, CellSegment new_cell) { + planar_mask_[cell_id] = new_cell.isPlanar(); + cell_grid_[cell_id] = std::move(new_cell); } std::vector const& CellGrid::getPlanarMask() const { return planar_mask_; } @@ -49,9 +64,9 @@ std::vector CellGrid::getNeighbours(size_t cell_id) const { std::vector neighbours; size_t x = cell_id / number_horizontal_cells_; size_t y = cell_id % number_horizontal_cells_; - if (x - 1 >= 0) neighbours.push_back(cell_id - number_horizontal_cells_); + if (x >= 1) neighbours.push_back(cell_id - number_horizontal_cells_); if (x + 1 < number_vertical_cells_) neighbours.push_back(cell_id + number_horizontal_cells_); - if (y - 1 >= 0) neighbours.push_back(cell_id - 1); + if (y >= 1) neighbours.push_back(cell_id - 1); if (y + 1 < number_horizontal_cells_) neighbours.push_back(cell_id + 1); return neighbours; diff --git a/cpp/deplex/src/deplex/cell_grid.h b/cpp/deplex/src/deplex/cell_grid.h index d713758..7d5e9f4 100644 --- a/cpp/deplex/src/deplex/cell_grid.h +++ b/cpp/deplex/src/deplex/cell_grid.h @@ -25,7 +25,11 @@ class CellGrid { CellGrid(Eigen::MatrixXf const& points, config::Config const& config, int32_t number_horizontal_cells, int32_t number_vertical_cells); - CellSegment const& getByCoordinates(size_t x, size_t y) const; + size_t findLabel(size_t v); + + void uniteLabels(size_t a, size_t b); + + void updateCell(size_t cell_id, CellSegment new_cell); CellSegment const& operator[](size_t cell_id) const; @@ -40,7 +44,9 @@ class CellGrid { int32_t cell_height_; int32_t number_horizontal_cells_; int32_t number_vertical_cells_; - std::vector> cell_grid_; + std::vector parent_; + std::vector component_size_; + std::vector cell_grid_; std::vector planar_mask_; }; } // namespace deplex \ No newline at end of file diff --git a/cpp/deplex/src/deplex/cell_segment.cpp b/cpp/deplex/src/deplex/cell_segment.cpp index 590ccd2..e4e2e2c 100644 --- a/cpp/deplex/src/deplex/cell_segment.cpp +++ b/cpp/deplex/src/deplex/cell_segment.cpp @@ -16,7 +16,12 @@ #include "cell_segment.h" namespace deplex { -CellSegment::CellSegment(Eigen::MatrixXf const& cell_points, config::Config const& config) : is_planar_(false) { +CellSegment::CellSegment() : stats_(), is_planar_(false), merge_tolerance_(), min_merge_cos_(), max_merge_dist_() {} + +CellSegment::CellSegment(Eigen::MatrixXf const& cell_points, config::Config const& config) + : is_planar_(false), + min_merge_cos_(config.getFloat("minCosAngleForMerge")), + max_merge_dist_(config.getFloat("maxMergeDist")) { size_t valid_pts_threshold = cell_points.size() / config.getInt("minPtsPerCell"); int32_t cell_width = config.getInt("patchSize"); int32_t cell_height = config.getInt("patchSize"); @@ -38,6 +43,13 @@ CellSegment& CellSegment::operator+=(CellSegment const& other) { return *this; } +bool CellSegment::areNeighbours3D(CellSegment const& other) const { + if (!this->is_planar_ || !other.is_planar_) return false; + auto cos_angle = this->getStat().getNormal().dot(other.getStat().getNormal()); + auto distance = pow(this->getStat().getNormal().dot(other.getStat().getMean()) + this->getStat().getD(), 2); + return cos_angle >= min_merge_cos_ && distance <= max_merge_dist_; +} + CellSegmentStat const& CellSegment::getStat() const { return stats_; }; bool CellSegment::isPlanar() const { return is_planar_; } diff --git a/cpp/deplex/src/deplex/cell_segment.h b/cpp/deplex/src/deplex/cell_segment.h index 76b5958..6912a66 100644 --- a/cpp/deplex/src/deplex/cell_segment.h +++ b/cpp/deplex/src/deplex/cell_segment.h @@ -23,6 +23,8 @@ namespace deplex { class CellSegment { public: + CellSegment(); + CellSegment(Eigen::MatrixXf const& cell_points, config::Config const& config); CellSegment& operator+=(CellSegment const& other); @@ -33,12 +35,16 @@ class CellSegment { bool isPlanar() const; + bool areNeighbours3D(CellSegment const& other) const; + float getMergeTolerance() const; private: CellSegmentStat stats_; bool is_planar_; float merge_tolerance_; + float min_merge_cos_; + float max_merge_dist_; bool hasValidPoints(Eigen::MatrixXf const& cell_points, size_t valid_pts_threshold) const; diff --git a/cpp/deplex/src/deplex/plane_extractor.cpp b/cpp/deplex/src/deplex/plane_extractor.cpp index c75b5c8..b4f05e1 100644 --- a/cpp/deplex/src/deplex/plane_extractor.cpp +++ b/cpp/deplex/src/deplex/plane_extractor.cpp @@ -16,7 +16,8 @@ #include "deplex/plane_extractor.h" #include -#include +#include +#include #ifdef DEBUG_DEPLEX #include @@ -40,8 +41,6 @@ class PlaneExtractor::Impl { config::Config config_; int32_t nr_horizontal_cells_; int32_t nr_vertical_cells_; - int32_t nr_total_cells_; - int32_t nr_pts_per_cell_; int32_t image_height_; int32_t image_width_; Eigen::MatrixXi labels_map_; @@ -49,19 +48,20 @@ class PlaneExtractor::Impl { NormalsHistogram initializeHistogram(CellGrid const& cell_grid); - std::vector createPlaneSegments(CellGrid const& cell_grid, NormalsHistogram hist); + std::set createPlaneSegments(CellGrid* cell_grid, NormalsHistogram* hist); - std::vector findMergedLabels(std::vector* plane_segments); + void mergePlanes(std::set* plane_labels, CellGrid* cell_Grid); - Eigen::VectorXi toImageLabels(std::vector const& merge_labels); + std::unordered_map> findPlaneNeighbours(std::set const& plane_labels, + CellGrid* cell_grid); + + Eigen::VectorXi toImageLabels(std::set const& plane_labels, CellGrid* cell_grid); void cleanArtifacts(); void growSeed(Eigen::Index seed_id, std::vector const& unassigned, std::vector* activation_map, CellGrid const& cell_grid) const; - std::vector> getConnectedComponents(size_t nr_planes) const; - #ifdef DEBUG_DEPLEX void planarCellsToLabels(std::vector const& planar_flags, std::string const& save_path); #endif @@ -86,8 +86,6 @@ PlaneExtractor::Impl::Impl(int32_t image_height, int32_t image_width, config::Co : config_(config), nr_horizontal_cells_(image_width / config.getInt("patchSize")), nr_vertical_cells_(image_height / config.getInt("patchSize")), - nr_total_cells_(nr_horizontal_cells_ * nr_vertical_cells_), - nr_pts_per_cell_(pow(config.getInt("patchSize"), 2)), image_height_(image_height), image_width_(image_width), labels_map_(Eigen::MatrixXi::Zero(nr_vertical_cells_, nr_horizontal_cells_)) {} @@ -107,35 +105,22 @@ Eigen::VectorXi PlaneExtractor::Impl::process(Eigen::MatrixXf const& pcd_array) organizeByCell(pcd_array, &organized_array); // 1. Initialize cell grid (Planarity estimation) CellGrid cell_grid(organized_array, config_, nr_horizontal_cells_, nr_vertical_cells_); -#ifdef DEBUG_DEPLEX - planarCellsToLabels(cell_grid.getPlanarMask(), "dbg_1_planar_cells.csv"); - std::clog << "[DebugInfo] Planar cell found: " - << std::count(cell_grid.getPlanarMask().begin(), cell_grid.getPlanarMask().end(), true) << '\n'; -#endif - // 2. Histogram initialization + // 2. Find dominant cell normals NormalsHistogram hist = initializeHistogram(cell_grid); - // 3. Region growing - auto plane_segments = createPlaneSegments(cell_grid, hist); -#ifdef DEBUG_DEPLEX - std::clog << "[DebugInfo] Plane segments found: " << (plane_segments.empty() ? 0 : plane_segments.size() - 1) << '\n'; -#endif - if (plane_segments.empty()) { + auto plane_labels = createPlaneSegments(&cell_grid, &hist); + if (plane_labels.empty()) { return Eigen::VectorXi::Zero(pcd_array.rows()); } - // 5. Merge planes - std::vector merge_labels = findMergedLabels(&plane_segments); #ifdef DEBUG_DEPLEX - std::vector sorted_labels(merge_labels); - std::sort(sorted_labels.begin(), sorted_labels.end()); - - std::clog << "[DebugInfo] Planes number after merge: " - << std::distance(sorted_labels.begin(), std::unique(sorted_labels.begin(), sorted_labels.end())) - 1 - << '\n'; + std::clog << "Plane found: " << plane_labels.size() << '\n'; #endif - Eigen::VectorXi labels = toImageLabels(merge_labels); + // 4. Merge planes + mergePlanes(&plane_labels, &cell_grid); + // 5. Get labels map + Eigen::VectorXi labels = toImageLabels(plane_labels, &cell_grid); #ifdef DEBUG_DEPLEX - std::ofstream of("dbg_3_labels.csv"); + std::ofstream of("dbg_labels.csv"); of << labels.reshaped(image_height_, image_width_) .format(Eigen::IOFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, ",", "\n")); #endif @@ -178,36 +163,36 @@ NormalsHistogram PlaneExtractor::Impl::initializeHistogram(CellGrid const& cell_ return NormalsHistogram{nr_bins_per_coord, normals}; } -std::vector PlaneExtractor::Impl::createPlaneSegments(CellGrid const& cell_grid, NormalsHistogram hist) { - std::vector plane_segments; - std::vector unassigned_mask(cell_grid.getPlanarMask()); +std::set PlaneExtractor::Impl::createPlaneSegments(CellGrid* cell_grid, NormalsHistogram* hist) { + std::set plane_labels; + std::vector unassigned_mask(cell_grid->getPlanarMask()); auto remaining_planar_cells = static_cast(std::count(unassigned_mask.begin(), unassigned_mask.end(), true)); while (remaining_planar_cells > 0) { // 1. Seeding - std::vector seed_candidates = hist.getPointsFromMostFrequentBin(); + std::vector seed_candidates = hist->getPointsFromMostFrequentBin(); if (seed_candidates.size() < config_.getInt("minRegionGrowingCandidateSize")) { - return plane_segments; + return plane_labels; } // 2. Select seed with minimum MSE int32_t seed_id; double min_mse = INT_MAX; for (int32_t seed_candidate : seed_candidates) { - if (cell_grid[seed_candidate].getStat().getMSE() < min_mse) { + if ((*cell_grid)[seed_candidate].getStat().getMSE() < min_mse) { seed_id = seed_candidate; - min_mse = cell_grid[seed_candidate].getStat().getMSE(); + min_mse = (*cell_grid)[seed_candidate].getStat().getMSE(); } } // 3. Grow seed - CellSegment plane_candidate(cell_grid[seed_id]); + CellSegment plane_candidate((*cell_grid)[seed_id]); std::vector activation_map(unassigned_mask.size()); - growSeed(seed_id, unassigned_mask, &activation_map, cell_grid); + growSeed(seed_id, unassigned_mask, &activation_map, *cell_grid); // 4. Merge activated cells & remove from hist for (size_t i = 0; i < activation_map.size(); ++i) { if (activation_map[i]) { - plane_candidate += cell_grid[i]; - hist.removePoint(static_cast(i)); + plane_candidate += (*cell_grid)[i]; + hist->removePoint(static_cast(i)); unassigned_mask[i] = false; --remaining_planar_cells; } @@ -222,23 +207,18 @@ std::vector PlaneExtractor::Impl::createPlaneSegments(CellGrid cons // 5. Model fitting if (plane_candidate.getStat().getScore() > config_.getFloat("minRegionPlanarityScore")) { - plane_segments.push_back(plane_candidate); - auto nr_curr_planes = static_cast(plane_segments.size()); + plane_labels.insert(seed_id); // Mark cells - // TODO: Effective assigning by mask? - int stacked_cell_id = 0; - for (int32_t row_id = 0; row_id < nr_vertical_cells_; ++row_id) { - for (int32_t col_id = 0; col_id < nr_horizontal_cells_; ++col_id) { - if (activation_map[stacked_cell_id]) { - labels_map_.row(row_id)[col_id] = nr_curr_planes; - } - ++stacked_cell_id; + for (size_t i = 0; i < activation_map.size(); ++i) { + if (activation_map[i]) { + cell_grid->uniteLabels(i, seed_id); } } + cell_grid->updateCell(seed_id, std::move(plane_candidate)); } } - return plane_segments; + return plane_labels; } void PlaneExtractor::Impl::growSeed(Eigen::Index seed_id, std::vector const& unassigned, @@ -276,85 +256,109 @@ void PlaneExtractor::Impl::growSeed(Eigen::Index seed_id, std::vector cons } } -std::vector PlaneExtractor::Impl::findMergedLabels(std::vector* plane_segments) { - size_t nr_planes = plane_segments->size(); - // Boolean matrix [nr_planes X nr_planes] - auto planes_association_mx = getConnectedComponents(nr_planes); - std::vector plane_merge_labels(nr_planes); - std::iota(plane_merge_labels.begin(), plane_merge_labels.end(), 0); - - // Connect compatible planes - for (size_t row_id = 0; row_id < nr_planes; ++row_id) { - int32_t plane_id = plane_merge_labels[row_id]; - bool plane_expanded = false; - for (size_t col_id = row_id + 1; col_id != planes_association_mx[row_id].size(); ++col_id) { - if (planes_association_mx[row_id][col_id]) { - double cos_angle = - plane_segments->at(plane_id).getStat().getNormal().dot(plane_segments->at(col_id).getStat().getNormal()); - double distance = - pow(plane_segments->at(plane_id).getStat().getNormal().dot(plane_segments->at(col_id).getStat().getMean()) + - plane_segments->at(plane_id).getStat().getD(), - 2); - if (cos_angle > config_.getFloat("minCosAngleForMerge") && distance < config_.getFloat("maxMergeDist")) { - plane_segments->at(plane_id) += plane_segments->at(col_id); - plane_merge_labels[col_id] = plane_id; - plane_expanded = true; - } else { - planes_association_mx[row_id][col_id] = false; - } +void PlaneExtractor::Impl::mergePlanes(std::set* plane_labels, CellGrid* cell_grid) { + // 1. Find neighbours + // Map> - set of neighbouring labels (planes) + auto neighbour_labels = findPlaneNeighbours(*plane_labels, cell_grid); + // 2. Initialize min-MSE priority queue + auto mse_cmp = [&cell_grid](size_t a, size_t b) { + return (*cell_grid)[cell_grid->findLabel(a)].getStat().getMSE() < + (*cell_grid)[cell_grid->findLabel(b)].getStat().getMSE(); + }; + std::set min_mse_queue(mse_cmp); + for (auto label : *plane_labels) { + min_mse_queue.insert(label); + } + + while (!min_mse_queue.empty()) { + auto min_plane_label = *min_mse_queue.begin(); + min_mse_queue.erase(min_mse_queue.begin()); + auto min_mse = std::numeric_limits::max(); + CellSegment min_mse_candidate; + size_t min_mse_candidate_label = min_plane_label; + // Find neighbour : merge(neighbour, min_plane).MSE() -> min + // TODO: Or merge with all neighbours? + for (auto neighbour : neighbour_labels[min_plane_label]) { + CellSegment merge_candidate = (*cell_grid)[min_plane_label]; + merge_candidate += (*cell_grid)[neighbour]; + merge_candidate.calculateStats(); + auto candidate_mse = merge_candidate.getStat().getMSE(); + auto candidate_score = merge_candidate.getStat().getScore(); + // TODO: Replace Const * minRegionPlanarityScore with mergeScore parameter + if (candidate_mse < min_mse && candidate_score < 1.4 * config_.getFloat("minRegionPlanarityScore")) { + min_mse = candidate_mse; + min_mse_candidate = std::move(merge_candidate); + min_mse_candidate_label = neighbour; } } - if (plane_expanded) plane_segments->at(plane_id).calculateStats(); + if (min_mse_candidate_label != min_plane_label) { + cell_grid->uniteLabels(min_mse_candidate_label, min_plane_label); + // If plane(a) merged with plane(b), then neighbours(a) = neighbours(b) \ a + // TODO: (?) Assuming isNeighbour(x, z) <- isNeighbour(x, y) && isNeighbour(y, z) + for (auto const& candidate_neighbour : neighbour_labels[min_mse_candidate_label]) { + neighbour_labels[min_plane_label].insert(cell_grid->findLabel(candidate_neighbour)); + } + neighbour_labels[min_plane_label].erase(min_plane_label); + neighbour_labels[min_plane_label].erase(min_mse_candidate_label); + neighbour_labels.erase(min_mse_candidate_label); + // Put merged plane to plane_labels and back to Queue + cell_grid->updateCell(min_plane_label, min_mse_candidate); + plane_labels->insert(min_plane_label); + min_mse_queue.insert(min_plane_label); +#ifdef DEBUG_DEPLEX + std::clog << "- Merged " << min_mse_candidate_label << " and " << min_plane_label << '\n'; +#endif + } } - - return plane_merge_labels; } -void PlaneExtractor::Impl::cleanArtifacts() { labels_map_.setZero(); } - -std::vector> PlaneExtractor::Impl::getConnectedComponents(size_t nr_planes) const { - std::vector> planes_assoc_matrix(nr_planes, std::vector(nr_planes, false)); - - for (int32_t row_id = 0; row_id < labels_map_.rows() - 1; ++row_id) { - auto row = labels_map_.row(row_id); - auto next_row = labels_map_.row(row_id + 1); - for (int32_t col_id = 0; col_id < labels_map_.cols() - 1; ++col_id) { - auto plane_id = row[col_id]; - if (plane_id > 0) { - if (row[col_id + 1] > 0 && plane_id != row[col_id + 1]) - planes_assoc_matrix[plane_id - 1][row[col_id + 1] - 1] = true; - if (next_row[col_id] > 0 && plane_id != next_row[col_id]) - planes_assoc_matrix[plane_id - 1][next_row[col_id] - 1] = true; +std::unordered_map> PlaneExtractor::Impl::findPlaneNeighbours( + std::set const& plane_labels, CellGrid* cell_grid) { + std::unordered_map> neighbours; + // Iterate over each grown planar segments and find its DSU-neighbours + // TODO: Iterate over each planar segment? (Not every planar segment is present in plane_labels) + for (size_t cell_id = 0; cell_id < cell_grid->size(); ++cell_id) { + auto plane_segment_label = cell_grid->findLabel(cell_id); + auto plane_segment_it = plane_labels.find(plane_segment_label); + // If cell_id is part of one of plane_labels components + if (plane_segment_it != plane_labels.end()) { + for (auto neighbour_id : cell_grid->getNeighbours(cell_id)) { + auto neighbour_label = cell_grid->findLabel(neighbour_id); + // If cell-neighbour is not within the same component && cell-neighbour is mergeable + if (neighbour_label != plane_segment_label && + (*cell_grid)[plane_segment_label].areNeighbours3D((*cell_grid)[neighbour_label])) { + neighbours[plane_segment_label].insert(neighbour_label); + neighbours[neighbour_label].insert(plane_segment_label); + } } } } - for (int32_t row_id = 0; row_id < planes_assoc_matrix.size(); ++row_id) { - for (int32_t col_id = 0; col_id < planes_assoc_matrix.size(); ++col_id) { - planes_assoc_matrix[row_id][col_id] = planes_assoc_matrix[row_id][col_id] || planes_assoc_matrix[col_id][row_id]; - } - } - return planes_assoc_matrix; + return neighbours; } -Eigen::VectorXi PlaneExtractor::Impl::toImageLabels(std::vector const& merge_labels) { +void PlaneExtractor::Impl::cleanArtifacts() { labels_map_.setZero(); } + +Eigen::VectorXi PlaneExtractor::Impl::toImageLabels(std::set const& plane_labels, CellGrid* cell_grid) { Eigen::MatrixXi labels(Eigen::MatrixXi::Zero(image_height_, image_width_)); int32_t cell_width = config_.getInt("patchSize"); int32_t cell_height = config_.getInt("patchSize"); int32_t stacked_cell_id = 0; - for (auto row = 0; row < labels_map_.rows(); ++row) { - for (auto col = 0; col < labels_map_.cols(); ++col) { - auto cell_row = stacked_cell_id / nr_horizontal_cells_; - auto cell_col = stacked_cell_id % nr_horizontal_cells_; - // Fill cell with label - auto label_row = cell_row * cell_height; - auto label_col = cell_col * cell_width; - for (auto i = label_row; i < label_row + cell_height; ++i) { - for (auto j = label_col; j < label_col + cell_width; ++j) { - auto label = labels_map_.row(row)[col]; - labels.row(i)[j] = (label == 0 ? 0 : merge_labels[label - 1] + 1); + for (auto row = 0; row < nr_vertical_cells_; ++row) { + for (auto col = 0; col < nr_horizontal_cells_; ++col) { + auto cell_label = cell_grid->findLabel(stacked_cell_id); + if (plane_labels.find(cell_label) != plane_labels.end()) { + auto cell_row = stacked_cell_id / nr_horizontal_cells_; + auto cell_col = stacked_cell_id % nr_horizontal_cells_; + // Fill cell with label + auto label_row = cell_row * cell_height; + auto label_col = cell_col * cell_width; + for (auto i = label_row; i < label_row + cell_height; ++i) { + for (auto j = label_col; j < label_col + cell_width; ++j) { + labels.row(i)[j] = cell_label; + } } } ++stacked_cell_id; diff --git a/data/configs/newTUM_fr3_long_val.ini b/data/configs/newTUM_fr3_long_val.ini new file mode 100644 index 0000000..17d7ab5 --- /dev/null +++ b/data/configs/newTUM_fr3_long_val.ini @@ -0,0 +1,28 @@ +[Common] +# used in depth-dependent thresholds, unit: mm^-1 +depthSigma=0.7e-6 +[Initialization] +patchSize=10 +# depth-dependent threshold for depth-discontinuity evaluation +depthAlpha=0.15 +depthTolerance=0.25 +# maximum depth disc. occurrences inside one cell +maxNumberDepthDiscontinuity=3 +# for seed selection, bigger value detects dominant normal direction more precisely +histogramBinsPerCoord=20 +# minimum number of cells to consider a dominant direction valid +minRegionGrowingCandidateSize=2 +# сell's MSE tolerance (depthSigma * z^2 + initMSETol), unit: mm +initMSETolerance=5 +[RegionGrowing] +# closest/farthest z to be considered, unit: mm +z_near=5000 +z_far=9000 +# dynamic normal deviation angle threshold, unit: degree +angleDegree_near=15 +angleDegree_far=30 +# Minimum number of cells considered to be a planar region +minRegionGrowingCellsActivated=4 +[Merging] +# normal deviation angle threshold for merge, unit: degree +angleDegree_merge=40 \ No newline at end of file