Added "Vis/UseDepthAsMask" parameter (don't detect features where depth is not available or it is over "Vis/MaxDepth")

This commit is contained in:
matlabbe
2016-01-13 09:20:15 -05:00
parent f6924ba48b
commit 136867253d
10 changed files with 179 additions and 58 deletions

View File

@@ -141,8 +141,12 @@ public:
public: public:
virtual ~Feature2D(); virtual ~Feature2D();
std::vector<cv::KeyPoint> generateKeypoints(const cv::Mat & image) const; std::vector<cv::KeyPoint> generateKeypoints(
cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const; const cv::Mat & image,
const cv::Mat & mask = cv::Mat()) const;
cv::Mat generateDescriptors(
const cv::Mat & image,
std::vector<cv::KeyPoint> & keypoints) const;
std::vector<cv::Point3f> generateKeypoints3D( std::vector<cv::Point3f> generateKeypoints3D(
const SensorData & data, const SensorData & data,
const std::vector<cv::KeyPoint> & keypoints) const; const std::vector<cv::KeyPoint> & keypoints) const;
@@ -155,14 +159,14 @@ protected:
Feature2D(const ParametersMap & parameters = ParametersMap()); Feature2D(const ParametersMap & parameters = ParametersMap());
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const = 0; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const = 0;
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const = 0; virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const = 0;
private: private:
ParametersMap parameters_; ParametersMap parameters_;
int maxFeatures_; int maxFeatures_;
float _wordsMaxDepth; // 0=inf float _maxDepth; // 0=inf
float _wordsMinDepth; float _minDepth;
std::vector<float> _roiRatios; // size 4 std::vector<float> _roiRatios; // size 4
int _subPixWinSize; int _subPixWinSize;
int _subPixIterations; int _subPixIterations;
@@ -182,7 +186,7 @@ public:
virtual Feature2D::Type getType() const {return kFeatureSurf;} virtual Feature2D::Type getType() const {return kFeatureSurf;}
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const; virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private: private:
@@ -209,7 +213,7 @@ public:
virtual Feature2D::Type getType() const {return kFeatureSift;} virtual Feature2D::Type getType() const {return kFeatureSift;}
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const; virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private: private:
@@ -232,7 +236,7 @@ public:
virtual Feature2D::Type getType() const {return kFeatureOrb;} virtual Feature2D::Type getType() const {return kFeatureOrb;}
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const; virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private: private:
@@ -262,7 +266,7 @@ public:
virtual void parseParameters(const ParametersMap & parameters); virtual void parseParameters(const ParametersMap & parameters);
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
private: private:
int threshold_; int threshold_;
@@ -346,7 +350,7 @@ public:
virtual void parseParameters(const ParametersMap & parameters); virtual void parseParameters(const ParametersMap & parameters);
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
private: private:
double _qualityLevel; double _qualityLevel;
@@ -427,7 +431,7 @@ public:
virtual Feature2D::Type getType() const {return kFeatureBrisk;} virtual Feature2D::Type getType() const {return kFeatureBrisk;}
private: private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const; virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const; virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private: private:

View File

@@ -245,6 +245,7 @@ private:
float _rehearsalMaxDistance; float _rehearsalMaxDistance;
float _rehearsalMaxAngle; float _rehearsalMaxAngle;
bool _rehearsalWeightIgnoredWhileMoving; bool _rehearsalWeightIgnoredWhileMoving;
bool _useDepthAsMask;
int _idCount; int _idCount;
int _idMapCount; int _idMapCount;

View File

@@ -207,6 +207,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Mem, InitWMWithAllNodes, bool, false, "Initialize the Working Memory with all nodes in Long-Term Memory. When false, it is initialized with nodes of the previous session."); RTABMAP_PARAM(Mem, InitWMWithAllNodes, bool, false, "Initialize the Working Memory with all nodes in Long-Term Memory. When false, it is initialized with nodes of the previous session.");
RTABMAP_PARAM(Mem, ImageDecimation, int, 1, "Image decimation (>=1) when creating a signature."); RTABMAP_PARAM(Mem, ImageDecimation, int, 1, "Image decimation (>=1) when creating a signature.");
RTABMAP_PARAM(Mem, LaserScanDownsampleStepSize, int, 1, "If > 1, downsample the laser scans when creating a signature."); RTABMAP_PARAM(Mem, LaserScanDownsampleStepSize, int, 1, "If > 1, downsample the laser scans when creating a signature.");
RTABMAP_PARAM(Mem, UseDepthAsMask, bool, false, "Use depth image as mask for features detection.");
// KeypointMemory (Keypoint-based) // KeypointMemory (Keypoint-based)
RTABMAP_PARAM_COND(Kp, NNStrategy, int, RTABMAP_NONFREE, 1, 3, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4"); RTABMAP_PARAM_COND(Kp, NNStrategy, int, RTABMAP_NONFREE, 1, 3, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4");
@@ -389,7 +390,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Vis, CorFlowIterations, int, 30, "[Vis/CorrespondenceType=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach."); RTABMAP_PARAM(Vis, CorFlowIterations, int, 30, "[Vis/CorrespondenceType=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.");
RTABMAP_PARAM(Vis, CorFlowEps, float, 0.01, "[Vis/CorrespondenceType=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach."); RTABMAP_PARAM(Vis, CorFlowEps, float, 0.01, "[Vis/CorrespondenceType=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.");
RTABMAP_PARAM(Vis, CorFlowMaxLevel, int, 3, "[Vis/CorrespondenceType=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach."); RTABMAP_PARAM(Vis, CorFlowMaxLevel, int, 3, "[Vis/CorrespondenceType=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.");
RTABMAP_PARAM(Vis, UseDepthAsMask, bool, true, "Use depth image as mask for features detection.");
// ICP registration parameters // ICP registration parameters
RTABMAP_PARAM(Icp, MaxTranslation, float, 0.2, "Maximum ICP translation correction accepted (m)."); RTABMAP_PARAM(Icp, MaxTranslation, float, 0.2, "Maximum ICP translation correction accepted (m).");

View File

@@ -75,6 +75,7 @@ private:
int _flowIterations; int _flowIterations;
float _flowEps; float _flowEps;
int _flowMaxLevel; int _flowMaxLevel;
bool _useDepthAsMask;
ParametersMap _featureParameters; ParametersMap _featureParameters;
}; };

View File

@@ -338,8 +338,8 @@ cv::Rect Feature2D::computeRoi(const cv::Mat & image, const std::vector<float> &
///////////////////// /////////////////////
Feature2D::Feature2D(const ParametersMap & parameters) : Feature2D::Feature2D(const ParametersMap & parameters) :
maxFeatures_(Parameters::defaultKpMaxFeatures()), maxFeatures_(Parameters::defaultKpMaxFeatures()),
_wordsMaxDepth(Parameters::defaultKpMaxDepth()), _maxDepth(Parameters::defaultKpMaxDepth()),
_wordsMinDepth(Parameters::defaultKpMinDepth()), _minDepth(Parameters::defaultKpMinDepth()),
_roiRatios(std::vector<float>(4, 0.0f)), _roiRatios(std::vector<float>(4, 0.0f)),
_subPixWinSize(Parameters::defaultKpSubPixWinSize()), _subPixWinSize(Parameters::defaultKpSubPixWinSize()),
_subPixIterations(Parameters::defaultKpSubPixIterations()), _subPixIterations(Parameters::defaultKpSubPixIterations()),
@@ -357,8 +357,8 @@ void Feature2D::parseParameters(const ParametersMap & parameters)
uInsert(parameters_, parameters); uInsert(parameters_, parameters);
Parameters::parse(parameters, Parameters::kKpMaxFeatures(), maxFeatures_); Parameters::parse(parameters, Parameters::kKpMaxFeatures(), maxFeatures_);
Parameters::parse(parameters, Parameters::kKpMaxDepth(), _wordsMaxDepth); Parameters::parse(parameters, Parameters::kKpMaxDepth(), _maxDepth);
Parameters::parse(parameters, Parameters::kKpMinDepth(), _wordsMinDepth); Parameters::parse(parameters, Parameters::kKpMinDepth(), _minDepth);
Parameters::parse(parameters, Parameters::kKpSubPixWinSize(), _subPixWinSize); Parameters::parse(parameters, Parameters::kKpSubPixWinSize(), _subPixWinSize);
Parameters::parse(parameters, Parameters::kKpSubPixIterations(), _subPixIterations); Parameters::parse(parameters, Parameters::kKpSubPixIterations(), _subPixIterations);
Parameters::parse(parameters, Parameters::kKpSubPixEps(), _subPixEps); Parameters::parse(parameters, Parameters::kKpSubPixEps(), _subPixEps);
@@ -488,17 +488,34 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
return feature2D; return feature2D;
} }
std::vector<cv::KeyPoint> Feature2D::generateKeypoints(const cv::Mat & image) const std::vector<cv::KeyPoint> Feature2D::generateKeypoints(const cv::Mat & image, const cv::Mat & maskIn) const
{ {
UASSERT(!image.empty()); UASSERT(!image.empty());
UASSERT(image.type() == CV_8UC1); UASSERT(image.type() == CV_8UC1);
cv::Mat mask;
if(maskIn.type()==CV_16UC1 || maskIn.type() == CV_32FC1)
{
mask = cv::Mat::zeros(maskIn.rows, maskIn.cols, CV_8UC1);
for(int i=0; i<(int)mask.total(); ++i)
{
float value = maskIn.type()==CV_16UC1?float(((unsigned short*)maskIn.data)[i])/1000.0f:((float*)maskIn.data)[i];
if(value>_minDepth &&
(_maxDepth == 0.0f || value <= _maxDepth))
{
((unsigned char*)mask.data)[i] = 1;
}
}
}
UASSERT(mask.empty() || (mask.cols == image.cols && mask.rows == image.rows));
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
UTimer timer; UTimer timer;
// Get keypoints // Get keypoints
cv::Rect roi = Feature2D::computeRoi(image, _roiRatios); cv::Rect roi = Feature2D::computeRoi(image, _roiRatios);
keypoints = this->generateKeypointsImpl(image, roi.width && roi.height?roi:cv::Rect(0,0,image.cols, image.rows)); keypoints = this->generateKeypointsImpl(image, roi.width && roi.height?roi:cv::Rect(0,0,image.cols, image.rows), mask);
UDEBUG("Keypoints extraction time = %f s, keypoints extracted = %d", timer.ticks(), keypoints.size()); UDEBUG("Keypoints extraction time = %f s, keypoints extracted = %d", timer.ticks(), keypoints.size());
limitKeypoints(keypoints, maxFeatures_); limitKeypoints(keypoints, maxFeatures_);
@@ -574,7 +591,7 @@ std::vector<cv::Point3f> Feature2D::generateKeypoints3D(
leftCorners, leftCorners,
status); status);
if(_wordsMaxDepth > 0.0f || _wordsMinDepth > 0.0f) if(_maxDepth > 0.0f || _minDepth > 0.0f)
{ {
UASSERT(status.size() == leftCorners.size() && status.size() == rightCorners.size()); UASSERT(status.size() == leftCorners.size() && status.size() == rightCorners.size());
for(unsigned int i=0; i<status.size(); ++i) for(unsigned int i=0; i<status.size(); ++i)
@@ -582,8 +599,8 @@ std::vector<cv::Point3f> Feature2D::generateKeypoints3D(
if(status[i] != 0) if(status[i] != 0)
{ {
float d = data.stereoCameraModel().computeDepth(leftCorners[i].x - rightCorners[i].x); float d = data.stereoCameraModel().computeDepth(leftCorners[i].x - rightCorners[i].x);
if((_wordsMinDepth > 0.0f && d < _wordsMinDepth) || if((_minDepth > 0.0f && d < _minDepth) ||
(_wordsMaxDepth > 0.0f && d > _wordsMaxDepth)) (_maxDepth > 0.0f && d > _maxDepth))
{ {
status[i] = 0; status[i] = 0;
} }
@@ -604,7 +621,7 @@ std::vector<cv::Point3f> Feature2D::generateKeypoints3D(
data.depthOrRightRaw(), data.depthOrRightRaw(),
data.cameraModels()); data.cameraModels());
if(_wordsMaxDepth > 0.0f || _wordsMinDepth > 0.0f) if(_maxDepth > 0.0f || _minDepth > 0.0f)
{ {
UASSERT(keypoints3D.size() == keypoints.size()); UASSERT(keypoints3D.size() == keypoints.size());
bool isInMM = data.depthRaw().type() == CV_16UC1; bool isInMM = data.depthRaw().type() == CV_16UC1;
@@ -617,7 +634,7 @@ std::vector<cv::Point3f> Feature2D::generateKeypoints3D(
if(u >=0 && u<data.depthRaw().cols && v >=0 && v<data.depthRaw().rows) if(u >=0 && u<data.depthRaw().cols && v >=0 && v<data.depthRaw().rows)
{ {
float d = isInMM?(float)data.depthRaw().at<uint16_t>(v,u)*0.001f:data.depthRaw().at<float>(v,u); float d = isInMM?(float)data.depthRaw().at<uint16_t>(v,u)*0.001f:data.depthRaw().at<float>(v,u);
if(uIsFinite(d) && d>_wordsMinDepth && (_wordsMaxDepth <= 0.0f || d < _wordsMaxDepth)) if(uIsFinite(d) && d>_minDepth && (_maxDepth <= 0.0f || d < _maxDepth))
{ {
reject = false; reject = false;
} }
@@ -697,26 +714,33 @@ void SURF::parseParameters(const ParametersMap & parameters)
#endif #endif
} }
std::vector<cv::KeyPoint> SURF::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const std::vector<cv::KeyPoint> SURF::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask) const
{ {
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
#if RTABMAP_NONFREE == 1 #if RTABMAP_NONFREE == 1
cv::Mat imgRoi(image, roi); cv::Mat imgRoi(image, roi);
cv::Mat maskRoi;
if(!mask.empty())
{
maskRoi = cv::Mat(mask, roi);
}
if(gpuVersion_) if(gpuVersion_)
{ {
#if CV_MAJOR_VERSION < 3 #if CV_MAJOR_VERSION < 3
cv::gpu::GpuMat imgGpu(imgRoi); cv::gpu::GpuMat imgGpu(imgRoi);
(*_gpuSurf.obj)(imgGpu, cv::gpu::GpuMat(), keypoints); cv::gpu::GpuMat maskGpu(maskRoi);
(*_gpuSurf.obj)(imgGpu, maskGpu, keypoints);
#else #else
cv::cuda::GpuMat imgGpu(imgRoi); cv::cuda::GpuMat imgGpu(imgRoi);
(*_gpuSurf.get())(imgGpu, cv::cuda::GpuMat(), keypoints); cv::cuda::GpuMat maskGpu(maskRoi);
(*_gpuSurf.get())(imgGpu, maskGpu, keypoints);
#endif #endif
} }
else else
{ {
_surf->detect(imgRoi, keypoints); _surf->detect(imgRoi, keypoints, maskRoi);
} }
#else #else
UWARN("RTAB-Map is not built with OpenCV nonfree module so SURF cannot be used!"); UWARN("RTAB-Map is not built with OpenCV nonfree module so SURF cannot be used!");
@@ -798,13 +822,18 @@ void SIFT::parseParameters(const ParametersMap & parameters)
#endif #endif
} }
std::vector<cv::KeyPoint> SIFT::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const std::vector<cv::KeyPoint> SIFT::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask) const
{ {
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
#if RTABMAP_NONFREE == 1 #if RTABMAP_NONFREE == 1
cv::Mat imgRoi(image, roi); cv::Mat imgRoi(image, roi);
_sift->detect(imgRoi, keypoints); // Opencv keypoints cv::Mat maskRoi;
if(!mask.empty())
{
maskRoi = cv::Mat(mask, roi);
}
_sift->detect(imgRoi, keypoints, maskRoi); // Opencv keypoints
#else #else
UWARN("RTAB-Map is not built with OpenCV nonfree module so SIFT cannot be used!"); UWARN("RTAB-Map is not built with OpenCV nonfree module so SIFT cannot be used!");
#endif #endif
@@ -902,17 +931,23 @@ void ORB::parseParameters(const ParametersMap & parameters)
} }
} }
std::vector<cv::KeyPoint> ORB::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const std::vector<cv::KeyPoint> ORB::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask) const
{ {
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
cv::Mat imgRoi(image, roi); cv::Mat imgRoi(image, roi);
cv::Mat maskRoi;
if(!mask.empty())
{
maskRoi = cv::Mat(mask, roi);
}
if(gpu_) if(gpu_)
{ {
#if CV_MAJOR_VERSION < 3 #if CV_MAJOR_VERSION < 3
cv::gpu::GpuMat imgGpu(imgRoi); cv::gpu::GpuMat imgGpu(imgRoi);
(*_gpuOrb.obj)(imgGpu, cv::gpu::GpuMat(), keypoints); cv::gpu::GpuMat maskGpu(maskRoi);
(*_gpuOrb.obj)(imgGpu, maskGpu, keypoints);
#else #else
#ifdef HAVE_OPENCV_CUDAFEATURES2D #ifdef HAVE_OPENCV_CUDAFEATURES2D
UFATAL("not implemented"); UFATAL("not implemented");
@@ -921,7 +956,7 @@ std::vector<cv::KeyPoint> ORB::generateKeypointsImpl(const cv::Mat & image, cons
} }
else else
{ {
_orb->detect(imgRoi, keypoints); _orb->detect(imgRoi, keypoints, maskRoi);
} }
return keypoints; return keypoints;
@@ -1068,16 +1103,22 @@ void FAST::parseParameters(const ParametersMap & parameters)
} }
} }
std::vector<cv::KeyPoint> FAST::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const std::vector<cv::KeyPoint> FAST::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask) const
{ {
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
cv::Mat imgRoi(image, roi); cv::Mat imgRoi(image, roi);
cv::Mat maskRoi;
if(!mask.empty())
{
maskRoi = cv::Mat(mask, roi);
}
if(gpu_) if(gpu_)
{ {
#if CV_MAJOR_VERSION < 3 #if CV_MAJOR_VERSION < 3
cv::gpu::GpuMat imgGpu(imgRoi); cv::gpu::GpuMat imgGpu(imgRoi);
(*_gpuFast.obj)(imgGpu, cv::gpu::GpuMat(), keypoints); cv::gpu::GpuMat maskGpu(maskRoi);
(*_gpuFast.obj)(imgGpu, maskGpu, keypoints);
#else #else
#ifdef HAVE_OPENCV_CUDAFEATURES2D #ifdef HAVE_OPENCV_CUDAFEATURES2D
UFATAL("not implemented"); UFATAL("not implemented");
@@ -1086,7 +1127,7 @@ std::vector<cv::KeyPoint> FAST::generateKeypointsImpl(const cv::Mat & image, con
} }
else else
{ {
_fast->detect(imgRoi, keypoints); // Opencv keypoints _fast->detect(imgRoi, keypoints, maskRoi); // Opencv keypoints
} }
return keypoints; return keypoints;
} }
@@ -1250,12 +1291,17 @@ void GFTT::parseParameters(const ParametersMap & parameters)
#endif #endif
} }
std::vector<cv::KeyPoint> GFTT::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const std::vector<cv::KeyPoint> GFTT::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask) const
{ {
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
cv::Mat imgRoi(image, roi); cv::Mat imgRoi(image, roi);
_gftt->detect(imgRoi, keypoints); // Opencv keypoints cv::Mat maskRoi;
if(!mask.empty())
{
maskRoi = cv::Mat(mask, roi);
}
_gftt->detect(imgRoi, keypoints, maskRoi); // Opencv keypoints
return keypoints; return keypoints;
} }
@@ -1414,12 +1460,17 @@ void BRISK::parseParameters(const ParametersMap & parameters)
#endif #endif
} }
std::vector<cv::KeyPoint> BRISK::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi) const std::vector<cv::KeyPoint> BRISK::generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask) const
{ {
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
std::vector<cv::KeyPoint> keypoints; std::vector<cv::KeyPoint> keypoints;
cv::Mat imgRoi(image, roi); cv::Mat imgRoi(image, roi);
brisk_->detect(imgRoi, keypoints); // Opencv keypoints cv::Mat maskRoi;
if(!mask.empty())
{
maskRoi = cv::Mat(mask, roi);
}
brisk_->detect(imgRoi, keypoints, maskRoi); // Opencv keypoints
return keypoints; return keypoints;
} }

View File

@@ -89,6 +89,7 @@ Memory::Memory(const ParametersMap & parameters) :
_rehearsalMaxDistance(Parameters::defaultRGBDLinearUpdate()), _rehearsalMaxDistance(Parameters::defaultRGBDLinearUpdate()),
_rehearsalMaxAngle(Parameters::defaultRGBDAngularUpdate()), _rehearsalMaxAngle(Parameters::defaultRGBDAngularUpdate()),
_rehearsalWeightIgnoredWhileMoving(Parameters::defaultMemRehearsalWeightIgnoredWhileMoving()), _rehearsalWeightIgnoredWhileMoving(Parameters::defaultMemRehearsalWeightIgnoredWhileMoving()),
_useDepthAsMask(Parameters::defaultMemUseDepthAsMask()),
_idCount(kIdStart), _idCount(kIdStart),
_idMapCount(kIdStart), _idMapCount(kIdStart),
_lastSignature(0), _lastSignature(0),
@@ -402,6 +403,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance); Parameters::parse(parameters, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance);
Parameters::parse(parameters, Parameters::kRGBDAngularUpdate(), _rehearsalMaxAngle); Parameters::parse(parameters, Parameters::kRGBDAngularUpdate(), _rehearsalMaxAngle);
Parameters::parse(parameters, Parameters::kMemRehearsalWeightIgnoredWhileMoving(), _rehearsalWeightIgnoredWhileMoving); Parameters::parse(parameters, Parameters::kMemRehearsalWeightIgnoredWhileMoving(), _rehearsalWeightIgnoredWhileMoving);
Parameters::parse(parameters, Parameters::kMemUseDepthAsMask(), _useDepthAsMask);
UASSERT_MSG(_maxStMemSize >= 0, uFormat("value=%d", _maxStMemSize).c_str()); UASSERT_MSG(_maxStMemSize >= 0, uFormat("value=%d", _maxStMemSize).c_str());
UASSERT_MSG(_similarityThreshold >= 0.0f && _similarityThreshold <= 1.0f, uFormat("value=%f", _similarityThreshold).c_str()); UASSERT_MSG(_similarityThreshold >= 0.0f && _similarityThreshold <= 1.0f, uFormat("value=%f", _similarityThreshold).c_str());
@@ -3091,7 +3093,9 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
imageMono = data.imageRaw(); imageMono = data.imageRaw();
} }
keypoints = _feature2D->generateKeypoints(imageMono); keypoints = _feature2D->generateKeypoints(
imageMono,
_useDepthAsMask&&!data.depthRaw().empty()?data.depthRaw():cv::Mat());
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_detection(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_detection(), t*1000.0f);
UDEBUG("time keypoints (%d) = %fs", (int)keypoints.size(), t); UDEBUG("time keypoints (%d) = %fs", (int)keypoints.size(), t);

View File

@@ -65,12 +65,15 @@ OdometryLocalMap::OdometryLocalMap(const ParametersMap & parameters) :
float minDepth = Parameters::defaultVisMinDepth(); float minDepth = Parameters::defaultVisMinDepth();
float maxDepth = Parameters::defaultVisMaxDepth(); float maxDepth = Parameters::defaultVisMaxDepth();
std::string roi = Parameters::defaultVisRoiRatios(); std::string roi = Parameters::defaultVisRoiRatios();
bool useDepthAsMask = Parameters::defaultVisUseDepthAsMask();
Parameters::parse(parameters, Parameters::kVisMinDepth(), minDepth); Parameters::parse(parameters, Parameters::kVisMinDepth(), minDepth);
Parameters::parse(parameters, Parameters::kVisMaxDepth(), maxDepth); Parameters::parse(parameters, Parameters::kVisMaxDepth(), maxDepth);
Parameters::parse(parameters, Parameters::kVisRoiRatios(), roi); Parameters::parse(parameters, Parameters::kVisRoiRatios(), roi);
Parameters::parse(parameters, Parameters::kVisUseDepthAsMask(), useDepthAsMask);
customParameters.insert(ParametersPair(Parameters::kKpMinDepth(), uNumber2Str(minDepth))); customParameters.insert(ParametersPair(Parameters::kKpMinDepth(), uNumber2Str(minDepth)));
customParameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(maxDepth))); customParameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(maxDepth)));
customParameters.insert(ParametersPair(Parameters::kKpRoiRatios(), roi)); customParameters.insert(ParametersPair(Parameters::kKpRoiRatios(), roi));
customParameters.insert(ParametersPair(Parameters::kMemUseDepthAsMask(), uBool2Str(useDepthAsMask)));
customParameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0")); // desactivate rehearsal customParameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0")); // desactivate rehearsal
customParameters.insert(ParametersPair(Parameters::kMemBinDataKept(), "false")); customParameters.insert(ParametersPair(Parameters::kMemBinDataKept(), "false"));
customParameters.insert(ParametersPair(Parameters::kMemSTMSize(), "0")); customParameters.insert(ParametersPair(Parameters::kMemSTMSize(), "0"));

View File

@@ -57,7 +57,8 @@ RegistrationVis::RegistrationVis(const ParametersMap & parameters, Registration
_flowWinSize(Parameters::defaultVisCorFlowWinSize()), _flowWinSize(Parameters::defaultVisCorFlowWinSize()),
_flowIterations(Parameters::defaultVisCorFlowIterations()), _flowIterations(Parameters::defaultVisCorFlowIterations()),
_flowEps(Parameters::defaultVisCorFlowEps()), _flowEps(Parameters::defaultVisCorFlowEps()),
_flowMaxLevel(Parameters::defaultVisCorFlowMaxLevel()) _flowMaxLevel(Parameters::defaultVisCorFlowMaxLevel()),
_useDepthAsMask(Parameters::defaultVisUseDepthAsMask())
{ {
_featureParameters = Parameters::getDefaultParameters(); _featureParameters = Parameters::getDefaultParameters();
uInsert(_featureParameters, ParametersPair(Parameters::kKpNNStrategy(), _featureParameters.at(Parameters::kVisCorNNType()))); uInsert(_featureParameters, ParametersPair(Parameters::kKpNNStrategy(), _featureParameters.at(Parameters::kVisCorNNType())));
@@ -92,6 +93,7 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kVisCorFlowIterations(), _flowIterations); Parameters::parse(parameters, Parameters::kVisCorFlowIterations(), _flowIterations);
Parameters::parse(parameters, Parameters::kVisCorFlowEps(), _flowEps); Parameters::parse(parameters, Parameters::kVisCorFlowEps(), _flowEps);
Parameters::parse(parameters, Parameters::kVisCorFlowMaxLevel(), _flowMaxLevel); Parameters::parse(parameters, Parameters::kVisCorFlowMaxLevel(), _flowMaxLevel);
Parameters::parse(parameters, Parameters::kVisUseDepthAsMask(), _useDepthAsMask);
UASSERT_MSG(_minInliers >= 1, uFormat("value=%d", _minInliers).c_str()); UASSERT_MSG(_minInliers >= 1, uFormat("value=%d", _minInliers).c_str());
UASSERT_MSG(_inlierDistance > 0.0f, uFormat("value=%f", _inlierDistance).c_str()); UASSERT_MSG(_inlierDistance > 0.0f, uFormat("value=%f", _inlierDistance).c_str());
@@ -230,7 +232,9 @@ Transform RegistrationVis::computeTransformationImpl(
fromSignature.sensorData().setImageRaw(tmp); fromSignature.sensorData().setImageRaw(tmp);
} }
kptsFrom = detector->generateKeypoints(fromSignature.sensorData().imageRaw()); kptsFrom = detector->generateKeypoints(
fromSignature.sensorData().imageRaw(),
_useDepthAsMask&&!fromSignature.sensorData().depthRaw().empty()?fromSignature.sensorData().depthRaw():cv::Mat());
} }
else else
{ {
@@ -385,7 +389,9 @@ Transform RegistrationVis::computeTransformationImpl(
cv::cvtColor(toSignature.sensorData().imageRaw(), tmp, cv::COLOR_BGR2GRAY); cv::cvtColor(toSignature.sensorData().imageRaw(), tmp, cv::COLOR_BGR2GRAY);
toSignature.sensorData().setImageRaw(tmp); toSignature.sensorData().setImageRaw(tmp);
} }
kptsTo = detector->generateKeypoints(toSignature.sensorData().imageRaw()); kptsTo = detector->generateKeypoints(
toSignature.sensorData().imageRaw(),
_useDepthAsMask&&!toSignature.sensorData().depthRaw().empty()?toSignature.sensorData().depthRaw():cv::Mat());
} }
else else
{ {

View File

@@ -494,7 +494,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->checkBox_localSpaceScanMatchingIDsSaved->setObjectName(Parameters::kRGBDScanMatchingIdsSavedInLinks().c_str()); _ui->checkBox_localSpaceScanMatchingIDsSaved->setObjectName(Parameters::kRGBDScanMatchingIdsSavedInLinks().c_str());
_ui->spinBox_imageDecimation->setObjectName(Parameters::kMemImageDecimation().c_str()); _ui->spinBox_imageDecimation->setObjectName(Parameters::kMemImageDecimation().c_str());
_ui->general_spinBox_laserScanDownsample->setObjectName(Parameters::kMemLaserScanDownsampleStepSize().c_str()); _ui->general_spinBox_laserScanDownsample->setObjectName(Parameters::kMemLaserScanDownsampleStepSize().c_str());
_ui->checkBox_useDepthAsMask->setObjectName(Parameters::kMemUseDepthAsMask().c_str());
// Database // Database
_ui->checkBox_dbInMemory->setObjectName(Parameters::kDbSqlite3InMemory().c_str()); _ui->checkBox_dbInMemory->setObjectName(Parameters::kDbSqlite3InMemory().c_str());
@@ -646,6 +646,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->loopClosure_pnpReprojError->setObjectName(Parameters::kVisPnPReprojError().c_str()); _ui->loopClosure_pnpReprojError->setObjectName(Parameters::kVisPnPReprojError().c_str());
_ui->loopClosure_pnpFlags->setObjectName(Parameters::kVisPnPFlags().c_str()); _ui->loopClosure_pnpFlags->setObjectName(Parameters::kVisPnPFlags().c_str());
_ui->loopClosure_pnpRefineIterations->setObjectName(Parameters::kVisPnPRefineIterations().c_str()); _ui->loopClosure_pnpRefineIterations->setObjectName(Parameters::kVisPnPRefineIterations().c_str());
_ui->loopClosure_useDepthAsMask->setObjectName(Parameters::kVisUseDepthAsMask().c_str());
_ui->loopClosure_bowVarianceFromInliersCount->setObjectName(Parameters::kRegVarianceFromInliersCount().c_str()); _ui->loopClosure_bowVarianceFromInliersCount->setObjectName(Parameters::kRegVarianceFromInliersCount().c_str());
_ui->comboBox_registrationStrategy->setObjectName(Parameters::kRegStrategy().c_str()); _ui->comboBox_registrationStrategy->setObjectName(Parameters::kRegStrategy().c_str());

View File

@@ -63,7 +63,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>-139</y>
<width>681</width> <width>681</width>
<height>1888</height> <height>1888</height>
</rect> </rect>
@@ -86,7 +86,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>10</number> <number>7</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1"> <layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -4976,7 +4976,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_101"> <widget class="QLabel" name="label_101">
<property name="text"> <property name="text">
<string>ROI ratios [left, right, top, bottom] between 0 and 1.</string> <string>ROI ratios [left, right, top, bottom] between 0 and 1.</string>
@@ -4989,7 +4989,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="8" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi1"> <widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi1">
<property name="suffix"> <property name="suffix">
<string> %</string> <string> %</string>
@@ -4999,7 +4999,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="9" column="1">
<widget class="QLabel" name="label_99"> <widget class="QLabel" name="label_99">
<property name="text"> <property name="text">
<string>Top ROI ratio (0 = no change).</string> <string>Top ROI ratio (0 = no change).</string>
@@ -5098,14 +5098,14 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="6" column="0">
<widget class="QLineEdit" name="lineEdit_kp_roi"> <widget class="QLineEdit" name="lineEdit_kp_roi">
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0"> <item row="7" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi0"> <widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi0">
<property name="suffix"> <property name="suffix">
<string> %</string> <string> %</string>
@@ -5115,7 +5115,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_97"> <widget class="QLabel" name="label_97">
<property name="text"> <property name="text">
<string>Left ROI ratio (0 = no change).</string> <string>Left ROI ratio (0 = no change).</string>
@@ -5128,7 +5128,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="8" column="1">
<widget class="QLabel" name="label_98"> <widget class="QLabel" name="label_98">
<property name="text"> <property name="text">
<string>Right ROI ratio (0 = no change).</string> <string>Right ROI ratio (0 = no change).</string>
@@ -5141,7 +5141,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="9" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi2"> <widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi2">
<property name="suffix"> <property name="suffix">
<string> %</string> <string> %</string>
@@ -5151,7 +5151,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0"> <item row="10" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi3"> <widget class="QDoubleSpinBox" name="doubleSpinBox_kp_roi3">
<property name="suffix"> <property name="suffix">
<string> %</string> <string> %</string>
@@ -5161,7 +5161,7 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="10" column="1">
<widget class="QLabel" name="label_100"> <widget class="QLabel" name="label_100">
<property name="text"> <property name="text">
<string>Bottom ROI ratio (0 = no change).</string> <string>Bottom ROI ratio (0 = no change).</string>
@@ -5215,6 +5215,35 @@ generate the number of words requested.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1">
<widget class="QLabel" name="label_123">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Use depth image as mask for feature detection.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_useDepthAsMask">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@@ -8739,7 +8768,7 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_261"> <widget class="QLabel" name="label_261">
<property name="text"> <property name="text">
<string>ROI ratios [left, right, top, bottom] between 0 and 1.</string> <string>ROI ratios [left, right, top, bottom] between 0 and 1.</string>
@@ -8752,7 +8781,7 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="6" column="0">
<widget class="QLineEdit" name="loopClosure_roi"/> <widget class="QLineEdit" name="loopClosure_roi"/>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
@@ -8811,6 +8840,26 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1">
<widget class="QLabel" name="label_290">
<property name="text">
<string>Use depth image as mask for feature detection.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="loopClosure_useDepthAsMask">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>