Added Daisy descriptor. ORB: updated default parameters. Making ORBOctree using ORB parameters. Updated Vis/CorNNDR default from 0.6 to 0.8 (increase number of matches with binary descriptors, increase slightly feature matching time with float descriptors). Note that jfr2018 scripts have been updated to use old value 0.6. rtabmap-info: show descriptor dimension and type.

This commit is contained in:
matlabbe
2020-11-01 11:28:59 -05:00
parent 25c2a51ee3
commit 99275fba1d
13 changed files with 326 additions and 73 deletions

View File

@@ -509,55 +509,69 @@ Feature2D * Feature2D::create(const ParametersMap & parameters)
Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parameters)
{
// NONFREE checks
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11)))
#ifndef RTABMAP_NONFREE
if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSift || type == Feature2D::kFeatureSurfFreak)
#ifndef RTABMAP_NONFREE
if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSift || type == Feature2D::kFeatureSurfFreak || type == Feature2D::kFeatureSurfDaisy)
{
#if CV_MAJOR_VERSION < 3
#if CV_MAJOR_VERSION < 3
UWARN("SURF and SIFT features cannot be used because OpenCV was not built with nonfree module. GFTT/ORB is used instead.");
#else
#else
UWARN("SURF and SIFT features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
#endif
#endif
type = Feature2D::kFeatureGfttOrb;
}
#if CV_MAJOR_VERSION == 3
if(type == Feature2D::kFeatureFastBrief ||
type == Feature2D::kFeatureFastFreak ||
type == Feature2D::kFeatureGfttBrief ||
type == Feature2D::kFeatureGfttFreak ||
type == Feature2D::kFeatureSurfFreak)
{
UWARN("BRIEF and FREAK features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
type = Feature2D::kFeatureGfttOrb;
}
#endif
#endif
#endif
#else // >= 4.4.0 >= 3.4.11
#ifndef RTABMAP_NONFREE
if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSurfFreak)
#ifndef RTABMAP_NONFREE
if(type == Feature2D::kFeatureSurf)
{
UWARN("SURF features cannot be used because OpenCV was not built with nonfree module. SIFT is used instead.");
type = Feature2D::kFeatureSift;
}
#endif
else if(type == Feature2D::kFeatureSurfFreak || type == Feature2D::kFeatureSurfDaisy)
{
UWARN("SURF detector cannot be used because OpenCV was not built with nonfree module. GFTT/ORB is used instead.");
type = Feature2D::kFeatureGfttOrb;
}
#endif
#endif // >= 4.4.0 >= 3.4.11
#if CV_MAJOR_VERSION < 3
#if !defined(HAVE_OPENCV_XFEATURES2D) && CV_MAJOR_VERSION >= 3
if(type == Feature2D::kFeatureFastBrief ||
type == Feature2D::kFeatureFastFreak ||
type == Feature2D::kFeatureGfttBrief ||
type == Feature2D::kFeatureGfttFreak ||
type == Feature2D::kFeatureSurfFreak ||
type == Feature2D::kFeatureGfttDaisy ||
type == Feature2D::kFeatureSurfDaisy)
{
UWARN("BRIEF, FREAK and DAISY features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
type = Feature2D::kFeatureGfttOrb;
}
#elif CV_MAJOR_VERSION < 3
if(type == Feature2D::kFeatureKaze)
{
#ifdef RTABMAP_NONFREE
#ifdef RTABMAP_NONFREE
UWARN("KAZE detector/descriptor can be used only with OpenCV3. SURF is used instead.");
type = Feature2D::kFeatureSurf;
#else
#else
UWARN("KAZE detector/descriptor can be used only with OpenCV3. GFTT/ORB is used instead.");
type = Feature2D::kFeatureGfttOrb;
#endif
#endif
}
if(type == Feature2D::kFeatureGfttDaisy || type == Feature2D::kFeatureSurfDaisy)
{
UWARN("DAISY detector/descriptor can be used only with OpenCV3. GFTT/BRIEF is used instead.");
type = Feature2D::kFeatureGfttBrief;
}
#endif
#ifndef RTABMAP_ORB_OCTREE
if(type == Feature2D::kFeatureOrbOctree)
{
@@ -618,6 +632,12 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
case Feature2D::kFeatureSurfFreak:
feature2D = new SURF_FREAK(parameters);
break;
case Feature2D::kFeatureGfttDaisy:
feature2D = new GFTT_DAISY(parameters);
break;
case Feature2D::kFeatureSurfDaisy:
feature2D = new SURF_DAISY(parameters);
break;
#ifdef RTABMAP_NONFREE
default:
feature2D = new SURF(parameters);
@@ -626,7 +646,7 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
#else
default:
feature2D = new ORB(parameters);
type = Feature2D::kFeatureOrb;
type = Feature2D::kFeatureGfttOrb;
break;
#endif
@@ -1939,7 +1959,10 @@ cv::Mat KAZE::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::Key
ORBOctree::ORBOctree(const ParametersMap & parameters) :
scaleFactor_(Parameters::defaultORBScaleFactor()),
nLevels_(Parameters::defaultORBNLevels()),
fastThreshold_(Parameters::defaultFASTThreshold())
patchSize_(Parameters::defaultORBPatchSize()),
edgeThreshold_(Parameters::defaultORBEdgeThreshold()),
fastThreshold_(Parameters::defaultFASTThreshold()),
fastMinThreshold_(Parameters::defaultFASTMinThreshold())
{
parseParameters(parameters);
}
@@ -1954,12 +1977,14 @@ void ORBOctree::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kORBScaleFactor(), scaleFactor_);
Parameters::parse(parameters, Parameters::kORBNLevels(), nLevels_);
Parameters::parse(parameters, Parameters::kORBPatchSize(), patchSize_);
Parameters::parse(parameters, Parameters::kORBEdgeThreshold(), edgeThreshold_);
Parameters::parse(parameters, Parameters::kFASTThreshold(), fastThreshold_);
Parameters::parse(parameters, Parameters::kFASTMinThreshold(), fastMinThreshold_);
#ifdef RTABMAP_ORB_OCTREE
_orb = cv::Ptr<ORBextractor>(new ORBextractor(this->getMaxFeatures(), scaleFactor_, nLevels_, fastThreshold_, fastMinThreshold_));
_orb = cv::Ptr<ORBextractor>(new ORBextractor(this->getMaxFeatures(), scaleFactor_, nLevels_, fastThreshold_, fastMinThreshold_, patchSize_, edgeThreshold_));
#else
UWARN("RTAB-Map is not built with ORB OcTree option enabled so ORB OcTree feature cannot be used!");
#endif
@@ -2070,4 +2095,103 @@ cv::Mat SuperPointTorch::generateDescriptorsImpl(const cv::Mat & image, std::vec
#endif
}
//////////////////////////
//GFTT-DAISY
//////////////////////////
GFTT_DAISY::GFTT_DAISY(const ParametersMap & parameters) :
GFTT(parameters),
orientationNormalized_(Parameters::defaultFREAKOrientationNormalized()),
scaleNormalized_(Parameters::defaultFREAKScaleNormalized()),
patternScale_(Parameters::defaultFREAKPatternScale()),
nOctaves_(Parameters::defaultFREAKNOctaves())
{
parseParameters(parameters);
}
GFTT_DAISY::~GFTT_DAISY()
{
}
void GFTT_DAISY::parseParameters(const ParametersMap & parameters)
{
GFTT::parseParameters(parameters);
Parameters::parse(parameters, Parameters::kFREAKOrientationNormalized(), orientationNormalized_);
Parameters::parse(parameters, Parameters::kFREAKScaleNormalized(), scaleNormalized_);
Parameters::parse(parameters, Parameters::kFREAKPatternScale(), patternScale_);
Parameters::parse(parameters, Parameters::kFREAKNOctaves(), nOctaves_);
#if CV_MAJOR_VERSION < 3
_daisy = cv::Ptr<CV_DAISY>(new CV_DAISY());
#else
#ifdef HAVE_OPENCV_XFEATURES2D
_daisy = CV_DAISY::create();
#else
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
#endif
#endif
}
cv::Mat GFTT_DAISY::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
cv::Mat descriptors;
#if CV_MAJOR_VERSION < 3
_daisy->compute(image, keypoints, descriptors);
#else
#ifdef HAVE_OPENCV_XFEATURES2D
_daisy->compute(image, keypoints, descriptors);
#else
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
#endif
#endif
return descriptors;
}
//////////////////////////
//SURF-DAISY
//////////////////////////
SURF_DAISY::SURF_DAISY(const ParametersMap & parameters) :
SURF(parameters),
orientationNormalized_(Parameters::defaultFREAKOrientationNormalized()),
scaleNormalized_(Parameters::defaultFREAKScaleNormalized()),
patternScale_(Parameters::defaultFREAKPatternScale()),
nOctaves_(Parameters::defaultFREAKNOctaves())
{
parseParameters(parameters);
}
SURF_DAISY::~SURF_DAISY()
{
}
void SURF_DAISY::parseParameters(const ParametersMap & parameters)
{
SURF::parseParameters(parameters);
Parameters::parse(parameters, Parameters::kFREAKOrientationNormalized(), orientationNormalized_);
Parameters::parse(parameters, Parameters::kFREAKScaleNormalized(), scaleNormalized_);
Parameters::parse(parameters, Parameters::kFREAKPatternScale(), patternScale_);
Parameters::parse(parameters, Parameters::kFREAKNOctaves(), nOctaves_);
#ifdef HAVE_OPENCV_XFEATURES2D
_daisy = CV_DAISY::create();
#else
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
#endif
}
cv::Mat SURF_DAISY::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
cv::Mat descriptors;
#ifdef HAVE_OPENCV_XFEATURES2D
_daisy->compute(image, keypoints, descriptors);
#else
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
#endif
return descriptors;
}
}

View File

@@ -80,24 +80,19 @@ using namespace std;
namespace rtabmap
{
const int PATCH_SIZE = 31;
const int HALF_PATCH_SIZE = 15;
const int EDGE_THRESHOLD = 19;
static float IC_Angle(const Mat& image, Point2f pt, const vector<int> & u_max)
static float IC_Angle(const Mat& image, Point2f pt, const vector<int> & u_max, int halfPatchSize)
{
int m_01 = 0, m_10 = 0;
const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));
// Treat the center line differently, v=0
for (int u = -HALF_PATCH_SIZE; u <= HALF_PATCH_SIZE; ++u)
for (int u = -halfPatchSize; u <= halfPatchSize; ++u)
m_10 += u * center[u];
// Go line by line in the circuI853lar patch
int step = (int)image.step1();
for (int v = 1; v <= HALF_PATCH_SIZE; ++v)
for (int v = 1; v <= halfPatchSize; ++v)
{
// Proceed over the two lines
int v_sum = 0;
@@ -419,10 +414,11 @@ static int bit_pattern_31_[256*4] =
};
ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
int _iniThFAST, int _minThFAST):
int _iniThFAST, int _minThFAST, int _patchSize, int _edgeThreshold):
nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels),
iniThFAST(_iniThFAST), minThFAST(_minThFAST)
iniThFAST(_iniThFAST), minThFAST(_minThFAST), patchSize(_patchSize), edgeThreshold(_edgeThreshold)
{
halfPatchSize = patchSize/2;
mvScaleFactor.resize(nlevels);
mvLevelSigma2.resize(nlevels);
mvScaleFactor[0]=1.0f;
@@ -462,16 +458,16 @@ ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
//This is for orientation
// pre-compute the end of a row in a circular patch
umax.resize(HALF_PATCH_SIZE + 1);
umax.resize(halfPatchSize + 1);
int v, v0, vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1);
int vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);
const double hp2 = HALF_PATCH_SIZE*HALF_PATCH_SIZE;
int v, v0, vmax = cvFloor(float(halfPatchSize) * sqrt(2.f) / 2 + 1);
int vmin = cvCeil(float(halfPatchSize) * sqrt(2.f) / 2);
const double hp2 = halfPatchSize*halfPatchSize;
for (v = 0; v <= vmax; ++v)
umax[v] = cvRound(sqrt(hp2 - v * v));
// Make sure we are symmetric
for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
for (v = halfPatchSize, v0 = 0; v >= vmin; --v)
{
while (umax[v0] == umax[v0 + 1])
++v0;
@@ -480,12 +476,12 @@ ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
}
}
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax)
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax, int halfPatchSize)
{
for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
{
keypoint->angle = IC_Angle(image, keypoint->pt, umax);
keypoint->angle = IC_Angle(image, keypoint->pt, umax, halfPatchSize);
}
}
@@ -781,10 +777,10 @@ void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoin
for (int level = 0; level < nlevels; ++level)
{
const int minBorderX = EDGE_THRESHOLD-3;
const int minBorderX = edgeThreshold-3;
const int minBorderY = minBorderX;
const int maxBorderX = mvImagePyramid[level].cols-EDGE_THRESHOLD+3;
const int maxBorderY = mvImagePyramid[level].rows-EDGE_THRESHOLD+3;
const int maxBorderX = mvImagePyramid[level].cols-edgeThreshold+3;
const int maxBorderY = mvImagePyramid[level].rows-edgeThreshold+3;
vector<cv::KeyPoint> vToDistributeKeys;
vToDistributeKeys.reserve(nfeatures*10);
@@ -845,7 +841,7 @@ void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoin
keypoints = DistributeOctTree(vToDistributeKeys, minBorderX, maxBorderX,
minBorderY, maxBorderY,mnFeaturesPerLevel[level], level);
const int scaledPatchSize = PATCH_SIZE*mvScaleFactor[level];
const int scaledPatchSize = patchSize*mvScaleFactor[level];
// Add border to coordinates and scale information
const int nkps = keypoints.size();
@@ -860,7 +856,7 @@ void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoin
// compute orientations
for (int level = 0; level < nlevels; ++level)
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax);
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax, halfPatchSize);
}
void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allKeypoints)
@@ -876,10 +872,10 @@ void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allK
const int levelCols = sqrt((float)nDesiredFeatures/(5*imageRatio));
const int levelRows = imageRatio*levelCols;
const int minBorderX = EDGE_THRESHOLD;
const int minBorderX = edgeThreshold;
const int minBorderY = minBorderX;
const int maxBorderX = mvImagePyramid[level].cols-EDGE_THRESHOLD;
const int maxBorderY = mvImagePyramid[level].rows-EDGE_THRESHOLD;
const int maxBorderX = mvImagePyramid[level].cols-edgeThreshold;
const int maxBorderY = mvImagePyramid[level].rows-edgeThreshold;
const int W = maxBorderX - minBorderX;
const int H = maxBorderY - minBorderY;
@@ -1006,7 +1002,7 @@ void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allK
vector<KeyPoint> & keypoints = allKeypoints[level];
keypoints.reserve(nDesiredFeatures*2);
const int scaledPatchSize = PATCH_SIZE*mvScaleFactor[level];
const int scaledPatchSize = patchSize*mvScaleFactor[level];
// Retain by score and transform coordinates
for(int i=0; i<levelRows; i++)
@@ -1039,7 +1035,7 @@ void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allK
// and compute orientations
for (int level = 0; level < nlevels; ++level)
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax);
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax, halfPatchSize);
}
static void computeDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors,
@@ -1121,21 +1117,21 @@ void ORBextractor::ComputePyramid(cv::Mat image)
{
float scale = mvInvScaleFactor[level];
Size sz(cvRound((float)image.cols*scale), cvRound((float)image.rows*scale));
Size wholeSize(sz.width + EDGE_THRESHOLD*2, sz.height + EDGE_THRESHOLD*2);
Size wholeSize(sz.width + edgeThreshold*2, sz.height + edgeThreshold*2);
Mat temp(wholeSize, image.type()), masktemp;
mvImagePyramid[level] = temp(Rect(EDGE_THRESHOLD, EDGE_THRESHOLD, sz.width, sz.height));
mvImagePyramid[level] = temp(Rect(edgeThreshold, edgeThreshold, sz.width, sz.height));
// Compute the resized image
if( level != 0 )
{
resize(mvImagePyramid[level-1], mvImagePyramid[level], sz, 0, 0, INTER_LINEAR);
copyMakeBorder(mvImagePyramid[level], temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
copyMakeBorder(mvImagePyramid[level], temp, edgeThreshold, edgeThreshold, edgeThreshold, edgeThreshold,
BORDER_REFLECT_101+BORDER_ISOLATED);
}
else
{
copyMakeBorder(image, temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
copyMakeBorder(image, temp, edgeThreshold, edgeThreshold, edgeThreshold, edgeThreshold,
BORDER_REFLECT_101);
}
}

View File

@@ -57,7 +57,7 @@ public:
enum {HARRIS_SCORE=0, FAST_SCORE=1 };
ORBextractor(int nfeatures, float scaleFactor, int nlevels,
int iniThFAST, int minThFAST);
int iniThFAST, int minThFAST, int patchSize, int edgeThreshold);
~ORBextractor(){}
@@ -107,6 +107,10 @@ protected:
int nlevels;
int iniThFAST;
int minThFAST;
int patchSize;
int edgeThreshold;
int halfPatchSize;
std::vector<int> mnFeaturesPerLevel;