diff --git a/corelib/include/rtabmap/core/Features2d.h b/corelib/include/rtabmap/core/Features2d.h index 81ac630d72..ff27600094 100644 --- a/corelib/include/rtabmap/core/Features2d.h +++ b/corelib/include/rtabmap/core/Features2d.h @@ -192,16 +192,17 @@ class RTABMAP_CORE_EXPORT Feature2D { const cv::Mat & disparity, float minDisparity); - static void limitKeypoints(std::vector & keypoints, int maxKeypoints); - static void limitKeypoints(std::vector & keypoints, cv::Mat & descriptors, int maxKeypoints); - static void limitKeypoints(std::vector & keypoints, std::vector & keypoints3D, cv::Mat & descriptors, int maxKeypoints); - static void limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints); - static void limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols); + static void limitKeypoints(std::vector & keypoints, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false); + static void limitKeypoints(std::vector & keypoints, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false); + static void limitKeypoints(std::vector & keypoints, std::vector & keypoints3D, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false); + static void limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false); + static void limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols, bool ssc = false); static cv::Rect computeRoi(const cv::Mat & image, const std::string & roiRatios); static cv::Rect computeRoi(const cv::Mat & image, const std::vector & roiRatios); int getMaxFeatures() const {return maxFeatures_;} + bool getSSC() const {return SSC_;} float getMinDepth() const {return _minDepth;} float getMaxDepth() const {return _maxDepth;} int getGridRows() const {return gridRows_;} @@ -234,6 +235,7 @@ class RTABMAP_CORE_EXPORT Feature2D { private: ParametersMap parameters_; int maxFeatures_; + bool SSC_; float _maxDepth; // 0=inf float _minDepth; std::vector _roiRatios; // size 4 diff --git a/corelib/include/rtabmap/core/Memory.h b/corelib/include/rtabmap/core/Memory.h index aa11fe6dd7..145aeb1936 100644 --- a/corelib/include/rtabmap/core/Memory.h +++ b/corelib/include/rtabmap/core/Memory.h @@ -334,6 +334,7 @@ class RTABMAP_CORE_EXPORT Memory bool _rotateImagesUpsideUp; bool _createOccupancyGrid; int _visMaxFeatures; + bool _visSSC; bool _imagesAlreadyRectified; bool _rectifyOnlyFeatures; bool _covOffDiagonalIgnored; diff --git a/corelib/include/rtabmap/core/Parameters.h b/corelib/include/rtabmap/core/Parameters.h index 59d2b537c7..847f9cc145 100644 --- a/corelib/include/rtabmap/core/Parameters.h +++ b/corelib/include/rtabmap/core/Parameters.h @@ -244,6 +244,7 @@ class RTABMAP_CORE_EXPORT Parameters RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf)."); RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth."); RTABMAP_PARAM(Kp, MaxFeatures, int, 500, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction)."); + RTABMAP_PARAM(Kp, SSC, bool, false, "If true, SSC (Suppression via Square Covering) is applied to limit keypoints."); RTABMAP_PARAM(Kp, BadSignRatio, float, 0.5, "Bad signature ratio (less than Ratio x AverageWordsPerImage = bad)."); RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)"); #if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D) @@ -693,6 +694,7 @@ class RTABMAP_CORE_EXPORT Parameters RTABMAP_PARAM(Vis, FeatureType, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint 12=SURF/FREAK 13=GFTT/DAISY 14=SURF/DAISY 15=PyDetector"); #endif RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits."); + RTABMAP_PARAM(Vis, SSC, bool, false, "If true, SSC (Suppression via Square Covering) is applied to limit keypoints."); RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit)."); RTABMAP_PARAM(Vis, MinDepth, float, 0, "Min depth of the features (0 means no limit)."); RTABMAP_PARAM(Vis, DepthAsMask, bool, true, "Use depth image as mask when extracting features."); diff --git a/corelib/include/rtabmap/core/util2d.h b/corelib/include/rtabmap/core/util2d.h index 3565921386..602768e20c 100644 --- a/corelib/include/rtabmap/core/util2d.h +++ b/corelib/include/rtabmap/core/util2d.h @@ -164,6 +164,9 @@ void RTABMAP_CORE_EXPORT NMS( cv::Mat & descriptorsOut, int border, int dist_thresh, int img_width, int img_height); +std::vector RTABMAP_CORE_EXPORT SSC( + const std::vector & keypoints, int maxKeypoints, float tolerance, int cols, int rows); + /** * @brief Rotate images and camera model so that the top of the image is up. * diff --git a/corelib/src/Features2d.cpp b/corelib/src/Features2d.cpp index add45c75cc..c306b5fd61 100644 --- a/corelib/src/Features2d.cpp +++ b/corelib/src/Features2d.cpp @@ -268,70 +268,111 @@ void Feature2D::filterKeypointsByDisparity( } } -void Feature2D::limitKeypoints(std::vector & keypoints, int maxKeypoints) +void Feature2D::limitKeypoints(std::vector & keypoints, int maxKeypoints, const cv::Size & imageSize, bool ssc) { cv::Mat descriptors; - limitKeypoints(keypoints, descriptors, maxKeypoints); + limitKeypoints(keypoints, descriptors, maxKeypoints, imageSize, ssc); } -void Feature2D::limitKeypoints(std::vector & keypoints, cv::Mat & descriptors, int maxKeypoints) +void Feature2D::limitKeypoints(std::vector & keypoints, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize, bool ssc) { std::vector keypoints3D; - limitKeypoints(keypoints, keypoints3D, descriptors, maxKeypoints); + limitKeypoints(keypoints, keypoints3D, descriptors, maxKeypoints, imageSize, ssc); } -void Feature2D::limitKeypoints(std::vector & keypoints, std::vector & keypoints3D, cv::Mat & descriptors, int maxKeypoints) +void Feature2D::limitKeypoints(std::vector & keypoints, std::vector & keypoints3D, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize, bool ssc) { UASSERT_MSG((int)keypoints.size() == descriptors.rows || descriptors.rows == 0, uFormat("keypoints=%d descriptors=%d", (int)keypoints.size(), descriptors.rows).c_str()); UASSERT_MSG(keypoints.size() == keypoints3D.size() || keypoints3D.size() == 0, uFormat("keypoints=%d keypoints3D=%d", (int)keypoints.size(), (int)keypoints3D.size()).c_str()); if(maxKeypoints > 0 && (int)keypoints.size() > maxKeypoints) { UTimer timer; - ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", keypoints.size()); - // Remove words under the new hessian threshold - - // Sort words by hessian - std::multimap hessianMap; // - for(unsigned int i = 0; i (fabs(keypoints[i].response), i)); - } - - // Remove them from the signature - int removed = (int)hessianMap.size()-maxKeypoints; - std::multimap::reverse_iterator iter = hessianMap.rbegin(); - std::vector kptsTmp(maxKeypoints); + int removed; + std::vector kptsTmp; std::vector kpts3DTmp; - if(!keypoints3D.empty()) - { - kpts3DTmp.resize(maxKeypoints); - } cv::Mat descriptorsTmp; - if(descriptors.rows) + if(ssc) { - descriptorsTmp = cv::Mat(maxKeypoints, descriptors.cols, descriptors.type()); + ULOGGER_DEBUG("too much words (%d), removing words with SSC", keypoints.size()); + static constexpr float tolerance = 0.1; + auto ResultVec = util2d::SSC(keypoints, maxKeypoints, tolerance, imageSize.width, imageSize.height); + removed = keypoints.size()-ResultVec.size(); + // retrieve final keypoints + kptsTmp.resize(ResultVec.size()); + if(!keypoints3D.empty()) + { + kpts3DTmp.resize(ResultVec.size()); + } + if(descriptors.rows) + { + descriptorsTmp = cv::Mat(ResultVec.size(), descriptors.cols, descriptors.type()); + } + for(unsigned int k=0; k(k), descriptors.ptr(ResultVec[k]), descriptors.cols*sizeof(float)); + } + else + { + memcpy(descriptorsTmp.ptr(k), descriptors.ptr(ResultVec[k]), descriptors.cols*sizeof(char)); + } + } + } } - for(unsigned int k=0; k < kptsTmp.size() && iter!=hessianMap.rend(); ++k, ++iter) + else { - kptsTmp[k] = keypoints[iter->second]; - if(keypoints3D.size()) + ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", keypoints.size()); + // Remove words under the new hessian threshold + + // Sort words by hessian + std::multimap hessianMap; // + for(unsigned int i = 0; i second]; + //Keep track of the data, to be easier to manage the data in the next step + hessianMap.insert(std::pair(fabs(keypoints[i].response), i)); + } + + // Remove them from the signature + removed = (int)hessianMap.size()-maxKeypoints; + std::multimap::reverse_iterator iter = hessianMap.rbegin(); + kptsTmp.resize(maxKeypoints); + if(!keypoints3D.empty()) + { + kpts3DTmp.resize(maxKeypoints); } if(descriptors.rows) { - if(descriptors.type() == CV_32FC1) + descriptorsTmp = cv::Mat(maxKeypoints, descriptors.cols, descriptors.type()); + } + for(unsigned int k=0; ksecond]; + if(keypoints3D.size()) { - memcpy(descriptorsTmp.ptr(k), descriptors.ptr(iter->second), descriptors.cols*sizeof(float)); + kpts3DTmp[k] = keypoints3D[iter->second]; } - else + if(descriptors.rows) { - memcpy(descriptorsTmp.ptr(k), descriptors.ptr(iter->second), descriptors.cols*sizeof(char)); + if(descriptors.type() == CV_32FC1) + { + memcpy(descriptorsTmp.ptr(k), descriptors.ptr(iter->second), descriptors.cols*sizeof(float)); + } + else + { + memcpy(descriptorsTmp.ptr(k), descriptors.ptr(iter->second), descriptors.cols*sizeof(char)); + } } } } - ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, (int)kptsTmp.size(), kptsTmp.size()?kptsTmp.back().response:0.0f); + ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, (int)kptsTmp.size(), !ssc&&kptsTmp.size()?kptsTmp.back().response:0.0f); ULOGGER_DEBUG("removing words time = %f s", timer.ticks()); keypoints = kptsTmp; keypoints3D = kpts3DTmp; @@ -342,31 +383,46 @@ void Feature2D::limitKeypoints(std::vector & keypoints, std::vecto } } -void Feature2D::limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints) +void Feature2D::limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints, const cv::Size & imageSize, bool ssc) { if(maxKeypoints > 0 && (int)keypoints.size() > maxKeypoints) { UTimer timer; - ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", (int)keypoints.size()); - // Remove words under the new hessian threshold - - // Sort words by hessian - std::multimap hessianMap; // - for(unsigned int i = 0; i (fabs(keypoints[i].response), i)); + ULOGGER_DEBUG("too much words (%d), removing words with SSC", keypoints.size()); + static constexpr float tolerance = 0.1; + auto ResultVec = util2d::SSC(keypoints, maxKeypoints, tolerance, imageSize.width, imageSize.height); + removed = keypoints.size()-ResultVec.size(); + for(unsigned int k=0; k::reverse_iterator iter = hessianMap.rbegin(); - inliers.resize(keypoints.size(), false); - float minimumHessian = 0.0f; - for(int k=0; k < maxKeypoints && iter!=hessianMap.rend(); ++k, ++iter) + else { - inliers[iter->second] = true; - minimumHessian = iter->first; + ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", keypoints.size()); + // Remove words under the new hessian threshold + + // Sort words by hessian + std::multimap hessianMap; // + for(unsigned int i = 0; i(fabs(keypoints[i].response), i)); + } + + // Keep keypoints with highest response + removed = (int)hessianMap.size()-maxKeypoints; + std::multimap::reverse_iterator iter = hessianMap.rbegin(); + for(int k=0; ksecond] = true; + minimumHessian = iter->first; + } } ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, maxKeypoints, minimumHessian); ULOGGER_DEBUG("filter keypoints time = %f s", timer.ticks()); @@ -378,7 +434,7 @@ void Feature2D::limitKeypoints(const std::vector & keypoints, std: } } -void Feature2D::limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols) +void Feature2D::limitKeypoints(const std::vector & keypoints, std::vector & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols, bool ssc) { if(maxKeypoints <= 0 || (int)keypoints.size() <= maxKeypoints) { @@ -406,7 +462,7 @@ void Feature2D::limitKeypoints(const std::vector & keypoints, std: for(size_t i=0; i inliersCell; - limitKeypoints(keypointsPerCell[i], inliersCell, maxKeypointsPerCell); + limitKeypoints(keypointsPerCell[i], inliersCell, maxKeypointsPerCell, cv::Size(colSize, rowSize), ssc); for(size_t j=0; j & ///////////////////// Feature2D::Feature2D(const ParametersMap & parameters) : maxFeatures_(Parameters::defaultKpMaxFeatures()), + SSC_(Parameters::defaultKpSSC()), _maxDepth(Parameters::defaultKpMaxDepth()), _minDepth(Parameters::defaultKpMinDepth()), _roiRatios(std::vector(4, 0.0f)), @@ -453,6 +510,7 @@ void Feature2D::parseParameters(const ParametersMap & parameters) uInsert(parameters_, parameters); Parameters::parse(parameters, Parameters::kKpMaxFeatures(), maxFeatures_); + Parameters::parse(parameters, Parameters::kKpSSC(), SSC_); Parameters::parse(parameters, Parameters::kKpMaxDepth(), _maxDepth); Parameters::parse(parameters, Parameters::kKpMinDepth(), _minDepth); Parameters::parse(parameters, Parameters::kKpSubPixWinSize(), _subPixWinSize); @@ -736,7 +794,7 @@ std::vector Feature2D::generateKeypoints(const cv::Mat & image, co subKeypoints = this->generateKeypointsImpl(image, roi, mask); if (this->getType() != Feature2D::Type::kFeaturePyDetector) { - limitKeypoints(subKeypoints, maxFeatures); + limitKeypoints(subKeypoints, maxFeatures, roi.size(), this->getSSC()); } if(roi.x || roi.y) { @@ -2142,7 +2200,7 @@ std::vector ORBOctree::generateKeypointsImpl(const cv::Mat & image if((int)keypoints.size() > this->getMaxFeatures()) { - limitKeypoints(keypoints, descriptors_, this->getMaxFeatures()); + limitKeypoints(keypoints, descriptors_, this->getMaxFeatures(), roi.size(), this->getSSC()); } #else UWARN("RTAB-Map is not built with ORB OcTree option enabled so ORB OcTree feature cannot be used!"); diff --git a/corelib/src/Memory.cpp b/corelib/src/Memory.cpp index 4e70acad47..57784aca84 100644 --- a/corelib/src/Memory.cpp +++ b/corelib/src/Memory.cpp @@ -111,6 +111,7 @@ Memory::Memory(const ParametersMap & parameters) : _rotateImagesUpsideUp(Parameters::defaultMemRotateImagesUpsideUp()), _createOccupancyGrid(Parameters::defaultRGBDCreateOccupancyGrid()), _visMaxFeatures(Parameters::defaultVisMaxFeatures()), + _visSSC(Parameters::defaultVisSSC()), _imagesAlreadyRectified(Parameters::defaultRtabmapImagesAlreadyRectified()), _rectifyOnlyFeatures(Parameters::defaultRtabmapRectifyOnlyFeatures()), _covOffDiagonalIgnored(Parameters::defaultMemCovOffDiagIgnored()), @@ -603,6 +604,7 @@ void Memory::parseParameters(const ParametersMap & parameters) Parameters::parse(params, Parameters::kMemRotateImagesUpsideUp(), _rotateImagesUpsideUp); Parameters::parse(params, Parameters::kRGBDCreateOccupancyGrid(), _createOccupancyGrid); Parameters::parse(params, Parameters::kVisMaxFeatures(), _visMaxFeatures); + Parameters::parse(params, Parameters::kVisSSC(), _visSSC); Parameters::parse(params, Parameters::kRtabmapImagesAlreadyRectified(), _imagesAlreadyRectified); Parameters::parse(params, Parameters::kRtabmapRectifyOnlyFeatures(), _rectifyOnlyFeatures); Parameters::parse(params, Parameters::kMemCovOffDiagIgnored(), _covOffDiagonalIgnored); @@ -5131,9 +5133,13 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor UASSERT(keypoints3D.empty() || keypoints3D.size() == keypoints.size()); int maxFeatures = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visMaxFeatures:_feature2D->getMaxFeatures(); + bool ssc = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visSSC:_feature2D->getSSC(); if((int)keypoints.size() > maxFeatures) { - _feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures); + if(data.cameraModels().size()==1 || data.stereoCameraModels().size()==1) + _feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures, data.cameraModels().size()?data.cameraModels()[0].imageSize():data.stereoCameraModels()[0].left().imageSize(), ssc); + else + _feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures); } t = timer.ticks(); if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_detection(), t*1000.0f); @@ -5349,22 +5355,13 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor int inliersCount = 0; if((_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1) && (decimatedData.cameraModels().size()==1 || decimatedData.stereoCameraModels().size()==1 || - data.cameraModels().size()==1 || data.stereoCameraModels().size()==1)) + data.cameraModels().size()==1 || data.stereoCameraModels().size()==1)) { - Feature2D::limitKeypoints(keypoints, - inliers, - _feature2D->getMaxFeatures(), - decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize(): - decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize(): - data.cameraModels().size()?data.cameraModels()[0].imageSize():data.stereoCameraModels()[0].left().imageSize(), - _feature2D->getGridRows(), _feature2D->getGridCols()); - for(size_t i=0; igetMaxFeatures(), + decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize(): + decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize(): + data.cameraModels().size()?data.cameraModels()[0].imageSize():data.stereoCameraModels()[0].left().imageSize(), + _feature2D->getGridRows(), _feature2D->getGridCols(), _feature2D->getSSC()); } else { @@ -5373,8 +5370,24 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor UWARN("Ignored %s and %s parameters as they cannot be used for multi-cameras setup or uncalibrated camera.", Parameters::kKpGridCols().c_str(), Parameters::kKpGridRows().c_str()); } - Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures()); - inliersCount = _feature2D->getMaxFeatures(); + if(decimatedData.cameraModels().size()==1 || decimatedData.stereoCameraModels().size()==1 || + data.cameraModels().size()==1 || data.stereoCameraModels().size()==1) + { + Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures(), + decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize(): + decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize(): + data.cameraModels().size()?data.cameraModels()[0].imageSize():data.stereoCameraModels()[0].left().imageSize(), + _feature2D->getSSC()); + } + else + { + Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures()); + } + } + for(size_t i=0; i SSC( + const std::vector & keypoints, int maxKeypoints, float tolerance, int cols, int rows) +{ + // several temp expression variables to simplify solution equation + int exp1 = rows + cols + 2*maxKeypoints; + long long exp2 = ((long long)4*cols + (long long)4*maxKeypoints + (long long)4*rows*maxKeypoints + (long long)rows*rows + (long long)cols*cols - (long long)2*rows*cols + (long long)4*rows*cols*maxKeypoints); + double exp3 = sqrt(exp2); + double exp4 = maxKeypoints - 1; + + double sol1 = -round((exp1 + exp3) / exp4); // first solution + double sol2 = -round((exp1 - exp3) / exp4); // second solution + + // binary search range initialization with positive solution + int high = (sol1 > sol2) ? sol1 : sol2; + int low = floor(sqrt((double)keypoints.size() / maxKeypoints)); + low = std::max(1, low); + + int width; + int prevWidth = -1; + + unsigned int Kmin = round(maxKeypoints - (maxKeypoints * tolerance)); + unsigned int Kmax = round(maxKeypoints + (maxKeypoints * tolerance)); + + std::vector ResultVec, result; + result.reserve(keypoints.size()); + + bool complete = false; + while(!complete) + { + width = low + (high - low) / 2; + if(width==prevWidth || low>high) // needed to reassure the same radius is not repeated again + { + ResultVec = result; // return the keypoints from the previous iteration + break; + } + result.clear(); + double c = (double)width / 2.0; // initializing Grid + int numCellCols = floor(cols / c); + int numCellRows = floor(rows / c); + std::vector> coveredVec(numCellRows+1, std::vector(numCellCols+1, false)); + + for(unsigned int i=0; i= 0) ? (row - floor(width / c)) : 0; // get range which current radius is covering + int rowMax = ((row + floor(width / c)) <= numCellRows) ? (row + floor(width / c)) : numCellRows; + int colMin = ((col - floor(width / c)) >= 0) ? (col - floor(width / c)) : 0; + int colMax = ((col + floor(width / c)) <= numCellCols) ? (col + floor(width / c)) : numCellCols; + for(int rowToCov=rowMin; rowToCov<=rowMax; ++rowToCov) + { + for(int colToCov=colMin; colToCov<=colMax; ++colToCov) + { + if(!coveredVec[rowToCov][colToCov]) + coveredVec[rowToCov][colToCov] = true; // cover cells within the square bounding box with width + } + } + } + } + + if(result.size() >= Kmin && result.size() <= Kmax) // solution found + { + ResultVec = result; + complete = true; + } + else if(result.size() < Kmin) + high = width - 1; // update binary search range + else + low = width + 1; + prevWidth = width; + } + return ResultVec; +} + void rotateImagesUpsideUpIfNecessary( CameraModel & model, cv::Mat & rgb, diff --git a/guilib/src/DatabaseViewer.cpp b/guilib/src/DatabaseViewer.cpp index 0e48a7acbd..64c0f10a65 100644 --- a/guilib/src/DatabaseViewer.cpp +++ b/guilib/src/DatabaseViewer.cpp @@ -5732,6 +5732,7 @@ void DatabaseViewer::updateStereo(const SensorData * data) // generate kpts std::vector kpts; uInsert(parameters, ParametersPair(Parameters::kKpMaxFeatures(), parameters.at(Parameters::kVisMaxFeatures()))); + uInsert(parameters, ParametersPair(Parameters::kKpSSC(), parameters.at(Parameters::kVisSSC()))); uInsert(parameters, ParametersPair(Parameters::kKpMinDepth(), parameters.at(Parameters::kVisMinDepth()))); uInsert(parameters, ParametersPair(Parameters::kKpMaxDepth(), parameters.at(Parameters::kVisMaxDepth()))); uInsert(parameters, ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType()))); diff --git a/guilib/src/PreferencesDialog.cpp b/guilib/src/PreferencesDialog.cpp index 21763cfd15..4b7de1c94d 100644 --- a/guilib/src/PreferencesDialog.cpp +++ b/guilib/src/PreferencesDialog.cpp @@ -1029,6 +1029,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : _ui->checkBox_memDepthAsMask->setObjectName(Parameters::kMemDepthAsMask().c_str()); _ui->checkBox_memStereoFromMotion->setObjectName(Parameters::kMemStereoFromMotion().c_str()); _ui->surf_spinBox_wordsPerImageTarget->setObjectName(Parameters::kKpMaxFeatures().c_str()); + _ui->checkBox_kp_ssc->setObjectName(Parameters::kKpSSC().c_str()); _ui->spinBox_KPGridRows->setObjectName(Parameters::kKpGridRows().c_str()); _ui->spinBox_KPGridCols->setObjectName(Parameters::kKpGridCols().c_str()); _ui->surf_doubleSpinBox_ratioBadSign->setObjectName(Parameters::kKpBadSignRatio().c_str()); @@ -1245,9 +1246,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : connect(_ui->reextract_nn, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFeatureMatchingVisibility())); _ui->reextract_nndrRatio->setObjectName(Parameters::kVisCorNNDR().c_str()); _ui->spinBox_visCorGuessWinSize->setObjectName(Parameters::kVisCorGuessWinSize().c_str()); - _ui->checkBox__visCorGuessMatchToProjection->setObjectName(Parameters::kVisCorGuessMatchToProjection().c_str()); + _ui->checkBox_visCorGuessMatchToProjection->setObjectName(Parameters::kVisCorGuessMatchToProjection().c_str()); _ui->vis_feature_detector->setObjectName(Parameters::kVisFeatureType().c_str()); _ui->reextract_maxFeatures->setObjectName(Parameters::kVisMaxFeatures().c_str()); + _ui->checkBox_visSSC->setObjectName(Parameters::kVisSSC().c_str()); _ui->reextract_gridrows->setObjectName(Parameters::kVisGridRows().c_str()); _ui->reextract_gridcols->setObjectName(Parameters::kVisGridCols().c_str()); _ui->loopClosure_bowMaxDepth->setObjectName(Parameters::kVisMaxDepth().c_str()); @@ -4180,7 +4182,7 @@ void PreferencesDialog::selectSourceDriver(Src src, int variant) { Src previousCameraSrc = getSourceDriver(); Src previousLidarSrc = getLidarSourceDriver(); - + if(_ui->comboBox_imuFilter_strategy->currentIndex()==0) { _ui->comboBox_imuFilter_strategy->setCurrentIndex(2); @@ -5376,6 +5378,7 @@ void PreferencesDialog::useOdomFeatures() _ui->surf_doubleSpinBox_maxDepth->setValue(_ui->loopClosure_bowMaxDepth->value()); _ui->surf_doubleSpinBox_minDepth->setValue(_ui->loopClosure_bowMinDepth->value()); _ui->surf_spinBox_wordsPerImageTarget->setValue(_ui->reextract_maxFeatures->value()); + _ui->checkBox_kp_ssc->setChecked(_ui->checkBox_visSSC->isChecked()); _ui->spinBox_KPGridRows->setValue(_ui->reextract_gridrows->value()); _ui->spinBox_KPGridCols->setValue(_ui->reextract_gridcols->value()); _ui->lineEdit_kp_roi->setText(_ui->loopClosure_roi->text()); diff --git a/guilib/src/ui/preferencesDialog.ui b/guilib/src/ui/preferencesDialog.ui index fce6e5ec33..c4556e2814 100644 --- a/guilib/src/ui/preferencesDialog.ui +++ b/guilib/src/ui/preferencesDialog.ui @@ -10587,14 +10587,8 @@ generate the number of words requested. - + - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Bad signature ratio (less than Ratio x AverageWordsPerImage = bad). @@ -10606,7 +10600,7 @@ generate the number of words requested. - + Top ROI ratio (0 = no change). @@ -10619,7 +10613,7 @@ generate the number of words requested. - + 2 @@ -10640,12 +10634,6 @@ generate the number of words requested. - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Minimum words depth. Only used when a depth image is provided. Applied before "Maximum words per image". @@ -10741,14 +10729,14 @@ generate the number of words requested. - + true - + ROI ratios [left, right, top, bottom] between 0 and 1. @@ -10763,12 +10751,6 @@ generate the number of words requested. - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Maximum words depth (0 means inf). Only used when a depth image is provided. Applied before "Maximum words per image". @@ -10780,7 +10762,7 @@ generate the number of words requested. - + % @@ -10834,11 +10816,31 @@ generate the number of words requested. 2000 - 150 + 500 - + + + + + + + + + + + If true, SSC (Suppression via Square Covering) is applied to limit keypoints. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + % @@ -10848,7 +10850,7 @@ generate the number of words requested. - + Left ROI ratio (0 = no change). @@ -10861,7 +10863,7 @@ generate the number of words requested. - + Right ROI ratio (0 = no change). @@ -10874,7 +10876,7 @@ generate the number of words requested. - + % @@ -10884,7 +10886,7 @@ generate the number of words requested. - + % @@ -10894,7 +10896,7 @@ generate the number of words requested. - + Bottom ROI ratio (0 = no change). @@ -10929,14 +10931,8 @@ generate the number of words requested. - + - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Number of rows of the grid used to extract uniformly "max words / grid cells" features from each cell. @@ -10948,7 +10944,7 @@ generate the number of words requested. - + 1 @@ -10961,7 +10957,7 @@ generate the number of words requested. - + 1 @@ -10974,14 +10970,8 @@ generate the number of words requested. - + - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Number of columns of the grid used to extract uniformly "max words / grid cells" features from each cell. @@ -10995,12 +10985,6 @@ generate the number of words requested. - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Use depth image as mask when extracting features. @@ -11021,12 +11005,6 @@ generate the number of words requested. - - 0 means that the response (hessian) threshold -used for the detector will not be adapted. -Otherwise, the threshold is modified to -generate the number of words requested. - Triangulate features without depth using stereo from motion (odometry). It would be ignored if depth as mask is checked and the feature detector used supports masking. @@ -21684,7 +21662,7 @@ Lower the ratio -> higher the precision. - + @@ -22461,7 +22439,7 @@ Lower the ratio -> higher the precision. - + Maximum feature depth. @@ -22474,7 +22452,7 @@ Lower the ratio -> higher the precision. - + ROI ratios [left right top bottom] between 0 and 1. @@ -22487,7 +22465,7 @@ Lower the ratio -> higher the precision. - + @@ -22510,7 +22488,27 @@ Lower the ratio -> higher the precision. - + + + + + + + + + + + If true, SSC (Suppression via Square Covering) is applied to limit keypoints. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + Minimum feature depth. @@ -22613,7 +22611,7 @@ Lower the ratio -> higher the precision. - + m @@ -22636,7 +22634,7 @@ Lower the ratio -> higher the precision. - + m @@ -22649,7 +22647,7 @@ Lower the ratio -> higher the precision. - + 1 @@ -22662,7 +22660,7 @@ Lower the ratio -> higher the precision. - + Number of rows of the grid used to extract uniformly "max features / grid cells" features from each cell. @@ -22675,7 +22673,7 @@ Lower the ratio -> higher the precision. - + Number of columns of the grid used to extract uniformly "max features / grid cells" features from each cell. @@ -22688,7 +22686,7 @@ Lower the ratio -> higher the precision. - + 1 @@ -22701,7 +22699,7 @@ Lower the ratio -> higher the precision. - + Use depth image as mask when extracting features. @@ -22714,7 +22712,7 @@ Lower the ratio -> higher the precision. - +