mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
Odometry and stereo: added parameter OdomStereo/MaxSlope to filter bad stereo pair matches from cvOpticalFlow
git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@1967 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
@@ -258,10 +258,11 @@ private:
|
|||||||
int _stereoFlowIterations;
|
int _stereoFlowIterations;
|
||||||
double _stereoFlowEpsilon;
|
double _stereoFlowEpsilon;
|
||||||
int _stereoFlowMaxLevel;
|
int _stereoFlowMaxLevel;
|
||||||
|
float _stereoMaxSlope;
|
||||||
|
|
||||||
int _stereoSubPixWinSize;
|
int _subPixWinSize;
|
||||||
int _stereoSubPixIterations;
|
int _subPixIterations;
|
||||||
double _stereoSubPixEps;
|
double _subPixEps;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rtabmap
|
} // namespace rtabmap
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ private:
|
|||||||
int flowIterations_;
|
int flowIterations_;
|
||||||
double flowEps_;
|
double flowEps_;
|
||||||
int flowMaxLevel_;
|
int flowMaxLevel_;
|
||||||
|
float stereoMaxSlope_;
|
||||||
|
|
||||||
int subPixWinSize_;
|
int subPixWinSize_;
|
||||||
int subPixIterations_;
|
int subPixIterations_;
|
||||||
|
|||||||
@@ -175,6 +175,10 @@ class RTABMAP_EXP Parameters
|
|||||||
RTABMAP_PARAM_STR(Kp, DictionaryPath, "", "Path of the pre-computed dictionary");
|
RTABMAP_PARAM_STR(Kp, DictionaryPath, "", "Path of the pre-computed dictionary");
|
||||||
RTABMAP_PARAM(Kp, NewWordsComparedTogether, bool, true, "When adding new words to dictionary, they are compared also with each other (to detect same words in the same signature).");
|
RTABMAP_PARAM(Kp, NewWordsComparedTogether, bool, true, "When adding new words to dictionary, they are compared also with each other (to detect same words in the same signature).");
|
||||||
|
|
||||||
|
RTABMAP_PARAM(Kp, SubPixWinSize, int, 3, "See cv::cornerSubPix().");
|
||||||
|
RTABMAP_PARAM(Kp, SubPixIterations, int, 0, "See cv::cornerSubPix(). 0 disables sub pixel refining.");
|
||||||
|
RTABMAP_PARAM(Kp, SubPixEps, double, 0.02, "See cv::cornerSubPix().");
|
||||||
|
|
||||||
//Database
|
//Database
|
||||||
RTABMAP_PARAM(DbSqlite3, InMemory, bool, false, "Using database in the memory instead of a file on the hard disk.");
|
RTABMAP_PARAM(DbSqlite3, InMemory, bool, false, "Using database in the memory instead of a file on the hard disk.");
|
||||||
RTABMAP_PARAM(DbSqlite3, CacheSize, unsigned int, 10000, "Sqlite cache size (default is 2000).");
|
RTABMAP_PARAM(DbSqlite3, CacheSize, unsigned int, 10000, "Sqlite cache size (default is 2000).");
|
||||||
@@ -276,14 +280,17 @@ class RTABMAP_EXP Parameters
|
|||||||
RTABMAP_PARAM(OdomBow, NNType, int, 3, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4");
|
RTABMAP_PARAM(OdomBow, NNType, int, 3, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4");
|
||||||
RTABMAP_PARAM(OdomBow, NNDR, float, 0.8, "NNDR: nearest neighbor distance ratio.");
|
RTABMAP_PARAM(OdomBow, NNDR, float, 0.8, "NNDR: nearest neighbor distance ratio.");
|
||||||
|
|
||||||
// Odometry Optical Flow
|
// Odometry common stuff between BOW and Optical Flow approaches
|
||||||
RTABMAP_PARAM(OdomFlow, WinSize, int, 9, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(OdomFlow, WinSize, int, 9, "Used for optical flow approach and for stereo matching. See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(OdomFlow, Iterations, int, 20, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(OdomFlow, Iterations, int, 20, "Used for optical flow approach and for stereo matching. See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(OdomFlow, Eps, double, 0.02, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(OdomFlow, Eps, double, 0.02, "Used for optical flow approach and for stereo matching. See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(OdomFlow, MaxLevel, int, 4, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(OdomFlow, MaxLevel, int, 4, "Used for optical flow approach and for stereo matching. See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(OdomFlow, SubPixWinSize, int, 3, "See cv::cornerSubPix().");
|
|
||||||
RTABMAP_PARAM(OdomFlow, SubPixIterations, int, 0, "See cv::cornerSubPix(). 0 disables sub pixel refining.");
|
RTABMAP_PARAM(OdomSubPix, WinSize, int, 3, "Can be used with BOW and optical flow approaches. See cv::cornerSubPix().");
|
||||||
RTABMAP_PARAM(OdomFlow, SubPixEps, double, 0.02, "See cv::cornerSubPix().");
|
RTABMAP_PARAM(OdomSubPix, Iterations, int, 0, "Can be used with BOW and optical flow approaches. See cv::cornerSubPix(). 0 disables sub pixel refining.");
|
||||||
|
RTABMAP_PARAM(OdomSubPix, Eps, double, 0.02, "Can be used with BOW and optical flow approaches. See cv::cornerSubPix().");
|
||||||
|
|
||||||
|
RTABMAP_PARAM(OdomStereo, MaxSlope, float, 0.1, "The maximum slope for each stereo pairs.");
|
||||||
|
|
||||||
// Loop closure constraint
|
// Loop closure constraint
|
||||||
RTABMAP_PARAM(LccIcp, Type, int, 0, "0=No ICP, 1=ICP 3D, 2=ICP 2D");
|
RTABMAP_PARAM(LccIcp, Type, int, 0, "0=No ICP, 1=ICP 3D, 2=ICP 2D");
|
||||||
@@ -321,9 +328,7 @@ class RTABMAP_EXP Parameters
|
|||||||
RTABMAP_PARAM(Stereo, Iterations, int, 20, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(Stereo, Iterations, int, 20, "See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(Stereo, Eps, double, 0.02, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(Stereo, Eps, double, 0.02, "See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(Stereo, MaxLevel, int, 4, "See cv::calcOpticalFlowPyrLK().");
|
RTABMAP_PARAM(Stereo, MaxLevel, int, 4, "See cv::calcOpticalFlowPyrLK().");
|
||||||
RTABMAP_PARAM(Stereo, SubPixWinSize, int, 3, "See cv::cornerSubPix().");
|
RTABMAP_PARAM(Stereo, MaxSlope, float, 0.1, "The maximum slope for each stereo pairs.");
|
||||||
RTABMAP_PARAM(Stereo, SubPixIterations, int, 0, "See cv::cornerSubPix(). 0 disables sub pixel refining.");
|
|
||||||
RTABMAP_PARAM(Stereo, SubPixEps, double, 0.02, "See cv::cornerSubPix().");
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Parameters();
|
virtual ~Parameters();
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ cv::Mat RTABMAP_EXP disparityFromStereoImages(
|
|||||||
int flowWinSize = 9,
|
int flowWinSize = 9,
|
||||||
int flowMaxLevel = 4,
|
int flowMaxLevel = 4,
|
||||||
int flowIterations = 20,
|
int flowIterations = 20,
|
||||||
double flowEps = 0.02);
|
double flowEps = 0.02,
|
||||||
|
float maxCorrespondencesSlope = 0.1f);
|
||||||
|
|
||||||
cv::Mat RTABMAP_EXP depthFromStereoImages(
|
cv::Mat RTABMAP_EXP depthFromStereoImages(
|
||||||
const cv::Mat & leftImage,
|
const cv::Mat & leftImage,
|
||||||
@@ -207,7 +208,8 @@ cv::Mat RTABMAP_EXP disparityFromStereoCorrespondences(
|
|||||||
const cv::Mat & leftImage,
|
const cv::Mat & leftImage,
|
||||||
const std::vector<cv::Point2f> & leftCorners,
|
const std::vector<cv::Point2f> & leftCorners,
|
||||||
const std::vector<cv::Point2f> & rightCorners,
|
const std::vector<cv::Point2f> & rightCorners,
|
||||||
const std::vector<unsigned char> & mask);
|
const std::vector<unsigned char> & mask,
|
||||||
|
float maxSlope = 0.1f);
|
||||||
|
|
||||||
cv::Mat RTABMAP_EXP depthFromStereoCorrespondences(
|
cv::Mat RTABMAP_EXP depthFromStereoCorrespondences(
|
||||||
const cv::Mat & leftImage,
|
const cv::Mat & leftImage,
|
||||||
|
|||||||
@@ -108,10 +108,11 @@ Memory::Memory(const ParametersMap & parameters) :
|
|||||||
_stereoFlowIterations(Parameters::defaultStereoIterations()),
|
_stereoFlowIterations(Parameters::defaultStereoIterations()),
|
||||||
_stereoFlowEpsilon(Parameters::defaultStereoEps()),
|
_stereoFlowEpsilon(Parameters::defaultStereoEps()),
|
||||||
_stereoFlowMaxLevel(Parameters::defaultStereoMaxLevel()),
|
_stereoFlowMaxLevel(Parameters::defaultStereoMaxLevel()),
|
||||||
|
_stereoMaxSlope(Parameters::defaultStereoMaxSlope()),
|
||||||
|
|
||||||
_stereoSubPixWinSize(Parameters::defaultStereoSubPixWinSize()),
|
_subPixWinSize(Parameters::defaultKpSubPixWinSize()),
|
||||||
_stereoSubPixIterations(Parameters::defaultStereoSubPixIterations()),
|
_subPixIterations(Parameters::defaultKpSubPixIterations()),
|
||||||
_stereoSubPixEps(Parameters::defaultStereoSubPixEps())
|
_subPixEps(Parameters::defaultKpSubPixEps())
|
||||||
{
|
{
|
||||||
_vwd = new VWDictionary(parameters);
|
_vwd = new VWDictionary(parameters);
|
||||||
this->parseParameters(parameters);
|
this->parseParameters(parameters);
|
||||||
@@ -418,9 +419,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
|
|||||||
Parameters::parse(parameters, Parameters::kStereoIterations(), _stereoFlowIterations);
|
Parameters::parse(parameters, Parameters::kStereoIterations(), _stereoFlowIterations);
|
||||||
Parameters::parse(parameters, Parameters::kStereoEps(), _stereoFlowEpsilon);
|
Parameters::parse(parameters, Parameters::kStereoEps(), _stereoFlowEpsilon);
|
||||||
Parameters::parse(parameters, Parameters::kStereoMaxLevel(), _stereoFlowMaxLevel);
|
Parameters::parse(parameters, Parameters::kStereoMaxLevel(), _stereoFlowMaxLevel);
|
||||||
Parameters::parse(parameters, Parameters::kStereoSubPixWinSize(), _stereoSubPixWinSize);
|
Parameters::parse(parameters, Parameters::kStereoMaxSlope(), _stereoMaxSlope);
|
||||||
Parameters::parse(parameters, Parameters::kStereoSubPixIterations(), _stereoSubPixIterations);
|
|
||||||
Parameters::parse(parameters, Parameters::kStereoSubPixEps(), _stereoSubPixEps);
|
|
||||||
|
|
||||||
UASSERT_MSG(_bowMinInliers >= 1, uFormat("value=%d", _bowMinInliers).c_str());
|
UASSERT_MSG(_bowMinInliers >= 1, uFormat("value=%d", _bowMinInliers).c_str());
|
||||||
UASSERT_MSG(_bowInlierDistance > 0.0f, uFormat("value=%f", _bowInlierDistance).c_str());
|
UASSERT_MSG(_bowInlierDistance > 0.0f, uFormat("value=%f", _bowInlierDistance).c_str());
|
||||||
@@ -452,6 +451,10 @@ void Memory::parseParameters(const ParametersMap & parameters)
|
|||||||
Parameters::parse(parameters, Parameters::kKpMaxDepth(), _wordsMaxDepth);
|
Parameters::parse(parameters, Parameters::kKpMaxDepth(), _wordsMaxDepth);
|
||||||
Parameters::parse(parameters, Parameters::kKpWordsPerImage(), _wordsPerImageTarget);
|
Parameters::parse(parameters, Parameters::kKpWordsPerImage(), _wordsPerImageTarget);
|
||||||
|
|
||||||
|
Parameters::parse(parameters, Parameters::kKpSubPixWinSize(), _subPixWinSize);
|
||||||
|
Parameters::parse(parameters, Parameters::kKpSubPixIterations(), _subPixIterations);
|
||||||
|
Parameters::parse(parameters, Parameters::kKpSubPixEps(), _subPixEps);
|
||||||
|
|
||||||
if((iter=parameters.find(Parameters::kKpRoiRatios())) != parameters.end())
|
if((iter=parameters.find(Parameters::kKpRoiRatios())) != parameters.end())
|
||||||
{
|
{
|
||||||
this->setRoi((*iter).second);
|
this->setRoi((*iter).second);
|
||||||
@@ -3098,101 +3101,166 @@ Signature * Memory::createSignature(const SensorData & data, bool keepRawData, S
|
|||||||
{
|
{
|
||||||
//stereo
|
//stereo
|
||||||
cv::Mat disparity;
|
cv::Mat disparity;
|
||||||
keypoints = _feature2D->generateKeypoints(imageMono, 0, roi);
|
bool subPixelOn = false;
|
||||||
|
if(_subPixWinSize > 0 && _subPixIterations > 0)
|
||||||
|
{
|
||||||
|
subPixelOn = true;
|
||||||
|
}
|
||||||
|
keypoints = _feature2D->generateKeypoints(imageMono, subPixelOn?_wordsPerImageTarget:0, roi);
|
||||||
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);
|
||||||
|
|
||||||
std::vector<cv::Point2f> leftCorners;
|
|
||||||
cv::KeyPoint::convert(keypoints, leftCorners);
|
|
||||||
if(_stereoSubPixWinSize > 0 && _stereoSubPixIterations > 0)
|
|
||||||
{
|
|
||||||
cv::cornerSubPix( imageMono, leftCorners,
|
|
||||||
cv::Size( _stereoSubPixWinSize, _stereoSubPixWinSize ),
|
|
||||||
cv::Size( -1, -1 ),
|
|
||||||
cv::TermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, _stereoSubPixIterations, _stereoSubPixEps ) );
|
|
||||||
t = timer.ticks();
|
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_subpixel(), t*1000.0f);
|
|
||||||
UDEBUG("time subpix left kpts=%fs", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
//generate a disparity map
|
|
||||||
disparity = util3d::disparityFromStereoImages(
|
|
||||||
imageMono,
|
|
||||||
data.rightImage(),
|
|
||||||
leftCorners,
|
|
||||||
_stereoFlowWinSize,
|
|
||||||
_stereoFlowMaxLevel,
|
|
||||||
_stereoFlowIterations,
|
|
||||||
_stereoFlowEpsilon);
|
|
||||||
t = timer.ticks();
|
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_correspondences(), t*1000.0f);
|
|
||||||
UDEBUG("generate disparity = %fs", t);
|
|
||||||
|
|
||||||
if(_wordsMaxDepth > 0.0f)
|
|
||||||
{
|
|
||||||
// disparity = baseline * fx / depth;
|
|
||||||
float minDisparity = data.baseline() * data.fx() / _wordsMaxDepth;
|
|
||||||
Feature2D::filterKeypointsByDisparity(keypoints, disparity, minDisparity);
|
|
||||||
UDEBUG("filter keypoints by disparity (%d)", (int)keypoints.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_wordsPerImageTarget && (int)keypoints.size() > _wordsPerImageTarget)
|
|
||||||
{
|
|
||||||
Feature2D::limitKeypoints(keypoints, _wordsPerImageTarget);
|
|
||||||
UDEBUG("limit keypoints max (%d)", _wordsPerImageTarget);
|
|
||||||
}
|
|
||||||
t = timer.ticks();
|
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_filtering(), t*1000.0f);
|
|
||||||
UDEBUG("time keypoints filtering = %fs", _wordsPerImageTarget);
|
|
||||||
|
|
||||||
if(keypoints.size())
|
if(keypoints.size())
|
||||||
{
|
{
|
||||||
descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
|
std::vector<cv::Point2f> leftCorners;
|
||||||
t = timer.ticks();
|
if(subPixelOn)
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
|
{
|
||||||
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
|
// descriptors should be extracted before subpixel
|
||||||
|
descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
|
||||||
|
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
|
||||||
|
|
||||||
keypoints3D = util3d::generateKeypoints3DDisparity(keypoints, disparity, data.fx(), data.baseline(), data.cx(), data.cy(), data.localTransform());
|
cv::KeyPoint::convert(keypoints, leftCorners);
|
||||||
|
cv::cornerSubPix( imageMono, leftCorners,
|
||||||
|
cv::Size( _subPixWinSize, _subPixWinSize ),
|
||||||
|
cv::Size( -1, -1 ),
|
||||||
|
cv::TermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, _subPixIterations, _subPixEps ) );
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<leftCorners.size(); ++i)
|
||||||
|
{
|
||||||
|
keypoints[i].pt = leftCorners[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_subpixel(), t*1000.0f);
|
||||||
|
UDEBUG("time subpix left kpts=%fs", t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cv::KeyPoint::convert(keypoints, leftCorners);
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate a disparity map
|
||||||
|
disparity = util3d::disparityFromStereoImages(
|
||||||
|
imageMono,
|
||||||
|
data.rightImage(),
|
||||||
|
leftCorners,
|
||||||
|
_stereoFlowWinSize,
|
||||||
|
_stereoFlowMaxLevel,
|
||||||
|
_stereoFlowIterations,
|
||||||
|
_stereoFlowEpsilon,
|
||||||
|
_stereoMaxSlope);
|
||||||
t = timer.ticks();
|
t = timer.ticks();
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
|
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_correspondences(), t*1000.0f);
|
||||||
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D->size(), t);
|
UDEBUG("generate disparity = %fs", t);
|
||||||
|
|
||||||
|
if(_wordsMaxDepth > 0.0f)
|
||||||
|
{
|
||||||
|
// disparity = baseline * fx / depth;
|
||||||
|
float minDisparity = data.baseline() * data.fx() / _wordsMaxDepth;
|
||||||
|
Feature2D::filterKeypointsByDisparity(keypoints, descriptors, disparity, minDisparity);
|
||||||
|
UDEBUG("filter keypoints by disparity (%d)", (int)keypoints.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_wordsPerImageTarget && (int)keypoints.size() > _wordsPerImageTarget)
|
||||||
|
{
|
||||||
|
Feature2D::limitKeypoints(keypoints, descriptors, _wordsPerImageTarget);
|
||||||
|
UDEBUG("limit keypoints max (%d)", _wordsPerImageTarget);
|
||||||
|
}
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_filtering(), t*1000.0f);
|
||||||
|
UDEBUG("time keypoints filtering = %fs", _wordsPerImageTarget);
|
||||||
|
|
||||||
|
|
||||||
|
if(keypoints.size())
|
||||||
|
{
|
||||||
|
if(!subPixelOn)
|
||||||
|
{
|
||||||
|
descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
|
||||||
|
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
keypoints3D = util3d::generateKeypoints3DDisparity(keypoints, disparity, data.fx(), data.baseline(), data.cx(), data.cy(), data.localTransform());
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
|
||||||
|
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D->size(), t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(!data.depth().empty())
|
else if(!data.depth().empty())
|
||||||
{
|
{
|
||||||
//depth
|
//depth
|
||||||
keypoints = _feature2D->generateKeypoints(imageMono, 0, roi);
|
bool subPixelOn = false;
|
||||||
|
if(_subPixWinSize > 0 && _subPixIterations > 0)
|
||||||
|
{
|
||||||
|
subPixelOn = true;
|
||||||
|
}
|
||||||
|
keypoints = _feature2D->generateKeypoints(imageMono, subPixelOn?_wordsPerImageTarget:0, roi);
|
||||||
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);
|
||||||
|
|
||||||
if(_wordsMaxDepth > 0.0f)
|
|
||||||
{
|
|
||||||
Feature2D::filterKeypointsByDepth(keypoints, data.depth(), _wordsMaxDepth);
|
|
||||||
UDEBUG("filter keypoints by depth (%d)", (int)keypoints.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_wordsPerImageTarget && (int)keypoints.size() > _wordsPerImageTarget)
|
|
||||||
{
|
|
||||||
Feature2D::limitKeypoints(keypoints, _wordsPerImageTarget);
|
|
||||||
UDEBUG("limit keypoints max (%d)", _wordsPerImageTarget);
|
|
||||||
}
|
|
||||||
t = timer.ticks();
|
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_filtering(), t*1000.0f);
|
|
||||||
UDEBUG("time keypoints filtering = %fs", _wordsPerImageTarget);
|
|
||||||
|
|
||||||
if(keypoints.size())
|
if(keypoints.size())
|
||||||
{
|
{
|
||||||
descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
|
if(subPixelOn)
|
||||||
t = timer.ticks();
|
{
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
|
// descriptors should be extracted before subpixel
|
||||||
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
|
descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
|
||||||
|
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
|
||||||
|
|
||||||
keypoints3D = util3d::generateKeypoints3DDepth(keypoints, data.depth(), data.fx(), data.fy(), data.cx(), data.cy(), data.localTransform());
|
std::vector<cv::Point2f> leftCorners;
|
||||||
|
cv::KeyPoint::convert(keypoints, leftCorners);
|
||||||
|
cv::cornerSubPix( imageMono, leftCorners,
|
||||||
|
cv::Size( _subPixWinSize, _subPixWinSize ),
|
||||||
|
cv::Size( -1, -1 ),
|
||||||
|
cv::TermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, _subPixIterations, _subPixEps ) );
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<leftCorners.size(); ++i)
|
||||||
|
{
|
||||||
|
keypoints[i].pt = leftCorners[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_subpixel(), t*1000.0f);
|
||||||
|
UDEBUG("time subpix left kpts=%fs", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_wordsMaxDepth > 0.0f)
|
||||||
|
{
|
||||||
|
Feature2D::filterKeypointsByDepth(keypoints, descriptors, data.depth(), _wordsMaxDepth);
|
||||||
|
UDEBUG("filter keypoints by depth (%d)", (int)keypoints.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_wordsPerImageTarget && (int)keypoints.size() > _wordsPerImageTarget)
|
||||||
|
{
|
||||||
|
Feature2D::limitKeypoints(keypoints, descriptors, _wordsPerImageTarget);
|
||||||
|
UDEBUG("limit keypoints max (%d)", _wordsPerImageTarget);
|
||||||
|
}
|
||||||
t = timer.ticks();
|
t = timer.ticks();
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
|
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_filtering(), t*1000.0f);
|
||||||
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D->size(), t);
|
UDEBUG("time keypoints filtering = %fs", _wordsPerImageTarget);
|
||||||
|
|
||||||
|
if(keypoints.size())
|
||||||
|
{
|
||||||
|
if(!subPixelOn)
|
||||||
|
{
|
||||||
|
descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
|
||||||
|
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
keypoints3D = util3d::generateKeypoints3DDepth(keypoints, data.depth(), data.fx(), data.fy(), data.cx(), data.cy(), data.localTransform());
|
||||||
|
t = timer.ticks();
|
||||||
|
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
|
||||||
|
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D->size(), t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -3252,7 +3320,8 @@ Signature * Memory::createSignature(const SensorData & data, bool keepRawData, S
|
|||||||
_stereoFlowWinSize,
|
_stereoFlowWinSize,
|
||||||
_stereoFlowMaxLevel,
|
_stereoFlowMaxLevel,
|
||||||
_stereoFlowIterations,
|
_stereoFlowIterations,
|
||||||
_stereoFlowEpsilon);
|
_stereoFlowEpsilon,
|
||||||
|
_stereoMaxSlope);
|
||||||
t = timer.ticks();
|
t = timer.ticks();
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_correspondences(), t*1000.0f);
|
if(stats) stats->addStatistic(Statistics::kTimingMemStereo_correspondences(), t*1000.0f);
|
||||||
UDEBUG("generate disparity = %fs", t);
|
UDEBUG("generate disparity = %fs", t);
|
||||||
|
|||||||
@@ -157,23 +157,25 @@ OdometryBOW::OdometryBOW(const ParametersMap & parameters) :
|
|||||||
int flowIterations_ = Parameters::defaultOdomFlowIterations();
|
int flowIterations_ = Parameters::defaultOdomFlowIterations();
|
||||||
double flowEps_ = Parameters::defaultOdomFlowEps();
|
double flowEps_ = Parameters::defaultOdomFlowEps();
|
||||||
int flowMaxLevel_ = Parameters::defaultOdomFlowMaxLevel();
|
int flowMaxLevel_ = Parameters::defaultOdomFlowMaxLevel();
|
||||||
int subPixWinSize_ = Parameters::defaultOdomFlowSubPixWinSize();
|
float stereoMaxSlope_ = Parameters::defaultOdomStereoMaxSlope();
|
||||||
int subPixIterations_ = Parameters::defaultOdomFlowSubPixIterations();
|
int subPixWinSize_ = Parameters::defaultOdomSubPixWinSize();
|
||||||
double subPixEps_ = Parameters::defaultOdomFlowSubPixEps();
|
int subPixIterations_ = Parameters::defaultOdomSubPixIterations();
|
||||||
|
double subPixEps_ = Parameters::defaultOdomSubPixEps();
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowWinSize(), flowWinSize);
|
Parameters::parse(parameters, Parameters::kOdomFlowWinSize(), flowWinSize);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowIterations(), flowIterations_);
|
Parameters::parse(parameters, Parameters::kOdomFlowIterations(), flowIterations_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowEps(), flowEps_);
|
Parameters::parse(parameters, Parameters::kOdomFlowEps(), flowEps_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowMaxLevel(), flowMaxLevel_);
|
Parameters::parse(parameters, Parameters::kOdomFlowMaxLevel(), flowMaxLevel_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowSubPixWinSize(), subPixWinSize_);
|
Parameters::parse(parameters, Parameters::kOdomSubPixWinSize(), subPixWinSize_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowSubPixIterations(), subPixIterations_);
|
Parameters::parse(parameters, Parameters::kOdomSubPixIterations(), subPixIterations_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowSubPixEps(), subPixEps_);
|
Parameters::parse(parameters, Parameters::kOdomSubPixEps(), subPixEps_);
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoWinSize(), uNumber2Str(flowWinSize)));
|
customParameters.insert(ParametersPair(Parameters::kStereoWinSize(), uNumber2Str(flowWinSize)));
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoIterations(), uNumber2Str(flowIterations_)));
|
customParameters.insert(ParametersPair(Parameters::kStereoIterations(), uNumber2Str(flowIterations_)));
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoEps(), uNumber2Str(flowEps_)));
|
customParameters.insert(ParametersPair(Parameters::kStereoEps(), uNumber2Str(flowEps_)));
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoMaxLevel(), uNumber2Str(flowMaxLevel_)));
|
customParameters.insert(ParametersPair(Parameters::kStereoMaxLevel(), uNumber2Str(flowMaxLevel_)));
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoSubPixWinSize(), uNumber2Str(subPixWinSize_)));
|
customParameters.insert(ParametersPair(Parameters::kStereoMaxSlope(), uNumber2Str(stereoMaxSlope_)));
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoSubPixIterations(), uNumber2Str(subPixIterations_)));
|
customParameters.insert(ParametersPair(Parameters::kKpSubPixWinSize(), uNumber2Str(subPixWinSize_)));
|
||||||
customParameters.insert(ParametersPair(Parameters::kStereoSubPixEps(), uNumber2Str(subPixEps_)));
|
customParameters.insert(ParametersPair(Parameters::kKpSubPixIterations(), uNumber2Str(subPixIterations_)));
|
||||||
|
customParameters.insert(ParametersPair(Parameters::kKpSubPixEps(), uNumber2Str(subPixEps_)));
|
||||||
|
|
||||||
// add only feature stuff
|
// add only feature stuff
|
||||||
for(ParametersMap::const_iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
|
for(ParametersMap::const_iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
|
||||||
@@ -445,18 +447,20 @@ OdometryOpticalFlow::OdometryOpticalFlow(const ParametersMap & parameters) :
|
|||||||
flowIterations_(Parameters::defaultOdomFlowIterations()),
|
flowIterations_(Parameters::defaultOdomFlowIterations()),
|
||||||
flowEps_(Parameters::defaultOdomFlowEps()),
|
flowEps_(Parameters::defaultOdomFlowEps()),
|
||||||
flowMaxLevel_(Parameters::defaultOdomFlowMaxLevel()),
|
flowMaxLevel_(Parameters::defaultOdomFlowMaxLevel()),
|
||||||
subPixWinSize_(Parameters::defaultOdomFlowSubPixWinSize()),
|
stereoMaxSlope_(Parameters::defaultOdomStereoMaxSlope()),
|
||||||
subPixIterations_(Parameters::defaultOdomFlowSubPixIterations()),
|
subPixWinSize_(Parameters::defaultOdomSubPixWinSize()),
|
||||||
subPixEps_(Parameters::defaultOdomFlowSubPixEps()),
|
subPixIterations_(Parameters::defaultOdomSubPixIterations()),
|
||||||
|
subPixEps_(Parameters::defaultOdomSubPixEps()),
|
||||||
lastCorners3D_(new pcl::PointCloud<pcl::PointXYZ>)
|
lastCorners3D_(new pcl::PointCloud<pcl::PointXYZ>)
|
||||||
{
|
{
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowWinSize(), flowWinSize_);
|
Parameters::parse(parameters, Parameters::kOdomFlowWinSize(), flowWinSize_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowIterations(), flowIterations_);
|
Parameters::parse(parameters, Parameters::kOdomFlowIterations(), flowIterations_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowEps(), flowEps_);
|
Parameters::parse(parameters, Parameters::kOdomFlowEps(), flowEps_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowMaxLevel(), flowMaxLevel_);
|
Parameters::parse(parameters, Parameters::kOdomFlowMaxLevel(), flowMaxLevel_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowSubPixWinSize(), subPixWinSize_);
|
Parameters::parse(parameters, Parameters::kOdomStereoMaxSlope(), stereoMaxSlope_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowSubPixIterations(), subPixIterations_);
|
Parameters::parse(parameters, Parameters::kOdomSubPixWinSize(), subPixWinSize_);
|
||||||
Parameters::parse(parameters, Parameters::kOdomFlowSubPixEps(), subPixEps_);
|
Parameters::parse(parameters, Parameters::kOdomSubPixIterations(), subPixIterations_);
|
||||||
|
Parameters::parse(parameters, Parameters::kOdomSubPixEps(), subPixEps_);
|
||||||
|
|
||||||
ParametersMap::const_iterator iter;
|
ParametersMap::const_iterator iter;
|
||||||
Feature2D::Type detectorStrategy = (Feature2D::Type)Parameters::defaultOdomFeatureType();
|
Feature2D::Type detectorStrategy = (Feature2D::Type)Parameters::defaultOdomFeatureType();
|
||||||
@@ -624,7 +628,10 @@ Transform OdometryOpticalFlow::computeTransformStereo(
|
|||||||
{
|
{
|
||||||
float lastDisparity = lastCornersKept[i].x - lastCornersKeptRight[i].x;
|
float lastDisparity = lastCornersKept[i].x - lastCornersKeptRight[i].x;
|
||||||
float newDisparity = newCornersKept[i].x - newCornersKeptRight[i].x;
|
float newDisparity = newCornersKept[i].x - newCornersKeptRight[i].x;
|
||||||
if(lastDisparity > 0.0f && newDisparity > 0.0f)
|
float lastSlope = fabs((lastCornersKept[i].y-lastCornersKeptRight[i].y) / (lastCornersKept[i].x-lastCornersKeptRight[i].x));
|
||||||
|
float newSlope = fabs((newCornersKept[i].y-newCornersKeptRight[i].y) / (newCornersKept[i].x-newCornersKeptRight[i].x));
|
||||||
|
if(lastDisparity > 0.0f && newDisparity > 0.0f &&
|
||||||
|
lastSlope < stereoMaxSlope_ && newSlope < stereoMaxSlope_)
|
||||||
{
|
{
|
||||||
pcl::PointXYZ lastPt3D = util3d::projectDisparityTo3D(
|
pcl::PointXYZ lastPt3D = util3d::projectDisparityTo3D(
|
||||||
lastCornersKept[i],
|
lastCornersKept[i],
|
||||||
@@ -697,14 +704,14 @@ Transform OdometryOpticalFlow::computeTransformStereo(
|
|||||||
UWARN("Transform not valid (inliers = %d/%d)", inliers, correspondences);
|
UWARN("Transform not valid (inliers = %d/%d)", inliers, correspondences);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if(correspondencesLast->size() >= 6)
|
//if(correspondencesLast->size() >= 6)
|
||||||
{
|
//{
|
||||||
UWARN("saved pcd");
|
// UWARN("saved pcd");
|
||||||
pcl::io::savePCDFile("last.pcd", *correspondencesLast);
|
// pcl::io::savePCDFile("last.pcd", *correspondencesLast);
|
||||||
pcl::io::savePCDFile("new.pcd", *correspondencesNew);
|
// pcl::io::savePCDFile("new.pcd", *correspondencesNew);
|
||||||
correspondencesNew = util3d::transformPointCloud(correspondencesNew, output);
|
//correspondencesNew = util3d::transformPointCloud(correspondencesNew, output);
|
||||||
pcl::io::savePCDFile("new2.pcd", *correspondencesNew);
|
//pcl::io::savePCDFile("new2.pcd", *correspondencesNew);
|
||||||
}*/
|
//}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -893,7 +893,8 @@ cv::Mat disparityFromStereoImages(
|
|||||||
int flowWinSize,
|
int flowWinSize,
|
||||||
int flowMaxLevel,
|
int flowMaxLevel,
|
||||||
int flowIterations,
|
int flowIterations,
|
||||||
double flowEps)
|
double flowEps,
|
||||||
|
float maxCorrespondencesSlope)
|
||||||
{
|
{
|
||||||
UASSERT(!leftImage.empty() && !rightImage.empty() &&
|
UASSERT(!leftImage.empty() && !rightImage.empty() &&
|
||||||
leftImage.type() == CV_8UC1 && rightImage.type() == CV_8UC1 &&
|
leftImage.type() == CV_8UC1 && rightImage.type() == CV_8UC1 &&
|
||||||
@@ -917,7 +918,7 @@ cv::Mat disparityFromStereoImages(
|
|||||||
cv::OPTFLOW_LK_GET_MIN_EIGENVALS, 1e-4);
|
cv::OPTFLOW_LK_GET_MIN_EIGENVALS, 1e-4);
|
||||||
UDEBUG("cv::calcOpticalFlowPyrLK() end");
|
UDEBUG("cv::calcOpticalFlowPyrLK() end");
|
||||||
|
|
||||||
return disparityFromStereoCorrespondences(leftImage, leftCorners, rightCorners, status);
|
return disparityFromStereoCorrespondences(leftImage, leftCorners, rightCorners, status, maxCorrespondencesSlope);
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat depthFromStereoImages(
|
cv::Mat depthFromStereoImages(
|
||||||
@@ -961,7 +962,8 @@ cv::Mat disparityFromStereoCorrespondences(
|
|||||||
const cv::Mat & leftImage,
|
const cv::Mat & leftImage,
|
||||||
const std::vector<cv::Point2f> & leftCorners,
|
const std::vector<cv::Point2f> & leftCorners,
|
||||||
const std::vector<cv::Point2f> & rightCorners,
|
const std::vector<cv::Point2f> & rightCorners,
|
||||||
const std::vector<unsigned char> & mask)
|
const std::vector<unsigned char> & mask,
|
||||||
|
float maxSlope)
|
||||||
{
|
{
|
||||||
UASSERT(!leftImage.empty() && leftCorners.size() == rightCorners.size());
|
UASSERT(!leftImage.empty() && leftCorners.size() == rightCorners.size());
|
||||||
UASSERT(mask.size() == 0 || mask.size() == leftCorners.size());
|
UASSERT(mask.size() == 0 || mask.size() == leftCorners.size());
|
||||||
@@ -971,7 +973,8 @@ cv::Mat disparityFromStereoCorrespondences(
|
|||||||
if(mask.size() == 0 || mask[i])
|
if(mask.size() == 0 || mask[i])
|
||||||
{
|
{
|
||||||
float d = leftCorners[i].x - rightCorners[i].x;
|
float d = leftCorners[i].x - rightCorners[i].x;
|
||||||
if(d > 0.0f)
|
float slope = fabs((leftCorners[i].y - rightCorners[i].y) / (leftCorners[i].x - rightCorners[i].x));
|
||||||
|
if(d > 0.0f && slope < maxSlope)
|
||||||
{
|
{
|
||||||
disparity.at<float>(int(leftCorners[i].y+0.5f), int(leftCorners[i].x+0.5f)) = d;
|
disparity.at<float>(int(leftCorners[i].y+0.5f), int(leftCorners[i].x+0.5f)) = d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ namespace rtabmap
|
|||||||
{
|
{
|
||||||
class Memory;
|
class Memory;
|
||||||
class ImageView;
|
class ImageView;
|
||||||
|
class Signature;
|
||||||
|
|
||||||
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
|
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
|
||||||
{
|
{
|
||||||
@@ -104,6 +105,7 @@ private:
|
|||||||
rtabmap::ImageView * view,
|
rtabmap::ImageView * view,
|
||||||
QLabel * labelId,
|
QLabel * labelId,
|
||||||
bool updateConstraintView = true);
|
bool updateConstraintView = true);
|
||||||
|
void updateStereo(const Signature * data);
|
||||||
void updateWordsMatching();
|
void updateWordsMatching();
|
||||||
void updateConstraintView(const rtabmap::Link & link,
|
void updateConstraintView(const rtabmap::Link & link,
|
||||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloudFrom = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>),
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloudFrom = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>),
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <QtGui/QInputDialog>
|
#include <QtGui/QInputDialog>
|
||||||
#include <QtGui/QGraphicsLineItem>
|
#include <QtGui/QGraphicsLineItem>
|
||||||
#include <QtGui/QCloseEvent>
|
#include <QtGui/QCloseEvent>
|
||||||
|
#include <QtGui/QGraphicsOpacityEffect>
|
||||||
#include <QtCore/QBuffer>
|
#include <QtCore/QBuffer>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
#include <rtabmap/utilite/ULogger.h>
|
#include <rtabmap/utilite/ULogger.h>
|
||||||
@@ -47,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "rtabmap/gui/UCv2Qt.h"
|
#include "rtabmap/gui/UCv2Qt.h"
|
||||||
#include "rtabmap/core/util3d.h"
|
#include "rtabmap/core/util3d.h"
|
||||||
#include "rtabmap/core/Signature.h"
|
#include "rtabmap/core/Signature.h"
|
||||||
|
#include "rtabmap/core/Features2d.h"
|
||||||
#include "rtabmap/gui/DataRecorder.h"
|
#include "rtabmap/gui/DataRecorder.h"
|
||||||
#include "rtabmap/core/SensorData.h"
|
#include "rtabmap/core/SensorData.h"
|
||||||
#include "ExportDialog.h"
|
#include "ExportDialog.h"
|
||||||
@@ -76,12 +78,14 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
|
|||||||
ui_->dockWidget_graphView->setVisible(false);
|
ui_->dockWidget_graphView->setVisible(false);
|
||||||
ui_->dockWidget_icp->setVisible(false);
|
ui_->dockWidget_icp->setVisible(false);
|
||||||
ui_->dockWidget_visual->setVisible(false);
|
ui_->dockWidget_visual->setVisible(false);
|
||||||
|
ui_->dockWidget_stereoView->setVisible(false);
|
||||||
ui_->dockWidget_icp->setFloating(true);
|
ui_->dockWidget_icp->setFloating(true);
|
||||||
ui_->dockWidget_visual->setFloating(true);
|
ui_->dockWidget_visual->setFloating(true);
|
||||||
ui_->menuView->addAction(ui_->dockWidget_constraints->toggleViewAction());
|
ui_->menuView->addAction(ui_->dockWidget_constraints->toggleViewAction());
|
||||||
ui_->menuView->addAction(ui_->dockWidget_graphView->toggleViewAction());
|
ui_->menuView->addAction(ui_->dockWidget_graphView->toggleViewAction());
|
||||||
ui_->menuView->addAction(ui_->dockWidget_icp->toggleViewAction());
|
ui_->menuView->addAction(ui_->dockWidget_icp->toggleViewAction());
|
||||||
ui_->menuView->addAction(ui_->dockWidget_visual->toggleViewAction());
|
ui_->menuView->addAction(ui_->dockWidget_visual->toggleViewAction());
|
||||||
|
ui_->menuView->addAction(ui_->dockWidget_stereoView->toggleViewAction());
|
||||||
connect(ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateGraphView()));
|
connect(ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateGraphView()));
|
||||||
|
|
||||||
connect(ui_->actionQuit, SIGNAL(triggered()), this, SLOT(close()));
|
connect(ui_->actionQuit, SIGNAL(triggered()), this, SLOT(close()));
|
||||||
@@ -994,6 +998,12 @@ void DatabaseViewer::update(int value,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mapId = memory_->getMapId(id);
|
mapId = memory_->getMapId(id);
|
||||||
|
|
||||||
|
//stereo
|
||||||
|
if(!data.getDepthRaw().empty() && data.getDepthRaw().type() == CV_8UC1)
|
||||||
|
{
|
||||||
|
this->updateStereo(&data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!imgDepth.isNull())
|
if(!imgDepth.isNull())
|
||||||
@@ -1121,6 +1131,168 @@ void DatabaseViewer::update(int value,
|
|||||||
view->fitInView(view->sceneRect(), Qt::KeepAspectRatio);
|
view->fitInView(view->sceneRect(), Qt::KeepAspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseViewer::updateStereo(const Signature * data)
|
||||||
|
{
|
||||||
|
if(ui_->dockWidget_stereoView->isVisible() && !data->getImageRaw().empty() && !data->getDepthRaw().empty() && data->getDepthRaw().type() == CV_8UC1)
|
||||||
|
{
|
||||||
|
cv::Mat leftMono;
|
||||||
|
if(data->getImageRaw().channels() == 3)
|
||||||
|
{
|
||||||
|
cv::cvtColor(data->getImageRaw(), leftMono, CV_BGR2GRAY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
leftMono = data->getImageRaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
UTimer timer;
|
||||||
|
|
||||||
|
// generate kpts
|
||||||
|
std::vector<cv::KeyPoint> kpts;
|
||||||
|
cv::Rect roi = Feature2D::computeRoi(leftMono, "0.03 0.03 0.04 0.04");
|
||||||
|
ParametersMap parameters;
|
||||||
|
parameters.insert(ParametersPair(Parameters::kGFTTMaxCorners(), "1000"));
|
||||||
|
parameters.insert(ParametersPair(Parameters::kGFTTMinDistance(), "10"));
|
||||||
|
Feature2D::Type type = Feature2D::kFeatureGfttBrief;
|
||||||
|
Feature2D * kptDetector = Feature2D::create(type, parameters);
|
||||||
|
kpts = kptDetector->generateKeypoints(leftMono, 0, roi);
|
||||||
|
delete kptDetector;
|
||||||
|
|
||||||
|
float timeKpt = timer.ticks();
|
||||||
|
|
||||||
|
std::vector<cv::Point2f> leftCorners;
|
||||||
|
cv::KeyPoint::convert(kpts, leftCorners);
|
||||||
|
|
||||||
|
// Find features in the new left image
|
||||||
|
std::vector<unsigned char> status;
|
||||||
|
std::vector<float> err;
|
||||||
|
std::vector<cv::Point2f> rightCorners;
|
||||||
|
cv::calcOpticalFlowPyrLK(
|
||||||
|
leftMono,
|
||||||
|
data->getDepthRaw(),
|
||||||
|
leftCorners,
|
||||||
|
rightCorners,
|
||||||
|
status,
|
||||||
|
err,
|
||||||
|
cv::Size(21, 21), 4,
|
||||||
|
cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 20, 0.02));
|
||||||
|
|
||||||
|
float timeFlow = timer.ticks();
|
||||||
|
|
||||||
|
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||||
|
cloud->resize(kpts.size());
|
||||||
|
float bad_point = std::numeric_limits<float>::quiet_NaN ();
|
||||||
|
UASSERT(status.size() == kpts.size());
|
||||||
|
int oi = 0;
|
||||||
|
for(unsigned int i=0; i<status.size(); ++i)
|
||||||
|
{
|
||||||
|
pcl::PointXYZ pt(bad_point, bad_point, bad_point);
|
||||||
|
if(status[i])
|
||||||
|
{
|
||||||
|
float disparity = leftCorners[i].x - rightCorners[i].x;
|
||||||
|
if(disparity > 0.0f)
|
||||||
|
{
|
||||||
|
if(fabs((leftCorners[i].y-rightCorners[i].y) / (leftCorners[i].x-rightCorners[i].x)) < 0.1)
|
||||||
|
{
|
||||||
|
pcl::PointXYZ tmpPt = util3d::projectDisparityTo3D(
|
||||||
|
leftCorners[i],
|
||||||
|
disparity,
|
||||||
|
data->getDepthCx(), data->getDepthCy(), data->getDepthFx(), data->getDepthFy());
|
||||||
|
|
||||||
|
if(pcl::isFinite(tmpPt))
|
||||||
|
{
|
||||||
|
pt = pcl::transformPoint(tmpPt, util3d::transformToEigen3f(data->getLocalTransform()));
|
||||||
|
if(fabs(pt.x) > 2 || fabs(pt.y) > 2 || fabs(pt.z) > 2)
|
||||||
|
{
|
||||||
|
status[i] = 100; //blue
|
||||||
|
}
|
||||||
|
cloud->at(oi++) = pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status[i] = 101; //yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status[i] = 102; //magenta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cloud->resize(oi);
|
||||||
|
|
||||||
|
UINFO("correspondences = %d/%d (%f) (time kpt=%fs flow=%fs)",
|
||||||
|
(int)cloud->size(), (int)leftCorners.size(), float(cloud->size())/float(leftCorners.size()), timeKpt, timeFlow);
|
||||||
|
|
||||||
|
ui_->stereoViewer->updateCameraPosition(Transform::getIdentity());
|
||||||
|
ui_->stereoViewer->addOrUpdateCloud("stereo", cloud);
|
||||||
|
ui_->stereoViewer->render();
|
||||||
|
|
||||||
|
std::vector<cv::KeyPoint> rightKpts;
|
||||||
|
cv::KeyPoint::convert(rightCorners, rightKpts);
|
||||||
|
std::vector<cv::DMatch> good_matches(kpts.size());
|
||||||
|
for(unsigned int i=0; i<good_matches.size(); ++i)
|
||||||
|
{
|
||||||
|
good_matches[i].trainIdx = i;
|
||||||
|
good_matches[i].queryIdx = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//cv::Mat imageMatches;
|
||||||
|
//cv::drawMatches( leftMono, kpts, data->getDepthRaw(), rightKpts,
|
||||||
|
// good_matches, imageMatches, cv::Scalar::all(-1), cv::Scalar::all(-1),
|
||||||
|
// std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
|
||||||
|
|
||||||
|
//ui_->graphicsView_stereo->setImage(uCvMat2QImage(imageMatches));
|
||||||
|
|
||||||
|
ui_->graphicsView_stereo->scene()->clear();
|
||||||
|
ui_->graphicsView_stereo->setSceneRect(0,0,(float)leftMono.cols, (float)leftMono.rows);
|
||||||
|
ui_->graphicsView_stereo->setLinesShown(true);
|
||||||
|
ui_->graphicsView_stereo->setFeaturesShown(false);
|
||||||
|
|
||||||
|
QGraphicsPixmapItem * item1 = ui_->graphicsView_stereo->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(data->getImageRaw())));
|
||||||
|
QGraphicsPixmapItem * item2 = ui_->graphicsView_stereo->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(data->getDepthRaw())));
|
||||||
|
|
||||||
|
QGraphicsOpacityEffect * effect1 = new QGraphicsOpacityEffect();
|
||||||
|
QGraphicsOpacityEffect * effect2 = new QGraphicsOpacityEffect();
|
||||||
|
effect1->setOpacity(0.5);
|
||||||
|
effect2->setOpacity(0.5);
|
||||||
|
item1->setGraphicsEffect(effect1);
|
||||||
|
item2->setGraphicsEffect(effect2);
|
||||||
|
|
||||||
|
// Draw lines between corresponding features...
|
||||||
|
for(unsigned int i=0; i<kpts.size(); ++i)
|
||||||
|
{
|
||||||
|
QColor c = Qt::green;
|
||||||
|
if(status[i] == 0)
|
||||||
|
{
|
||||||
|
c = Qt::red;
|
||||||
|
}
|
||||||
|
else if(status[i] == 100)
|
||||||
|
{
|
||||||
|
c = Qt::blue;
|
||||||
|
}
|
||||||
|
else if(status[i] == 101)
|
||||||
|
{
|
||||||
|
c = Qt::yellow;
|
||||||
|
}
|
||||||
|
else if(status[i] == 102)
|
||||||
|
{
|
||||||
|
c = Qt::magenta;
|
||||||
|
}
|
||||||
|
QGraphicsLineItem * item = ui_->graphicsView_stereo->scene()->addLine(
|
||||||
|
kpts[i].pt.x,
|
||||||
|
kpts[i].pt.y,
|
||||||
|
rightKpts[i].pt.x,
|
||||||
|
rightKpts[i].pt.y,
|
||||||
|
QPen(c));
|
||||||
|
item->setZValue(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseViewer::updateWordsMatching()
|
void DatabaseViewer::updateWordsMatching()
|
||||||
{
|
{
|
||||||
int from = ids_.at(ui_->horizontalSlider_A->value());
|
int from = ids_.at(ui_->horizontalSlider_A->value());
|
||||||
|
|||||||
@@ -346,6 +346,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
|||||||
connect(_ui->toolButton_dictionaryPath, SIGNAL(clicked()), this, SLOT(changeDictionaryPath()));
|
connect(_ui->toolButton_dictionaryPath, SIGNAL(clicked()), this, SLOT(changeDictionaryPath()));
|
||||||
_ui->checkBox_kp_newWordsComparedTogether->setObjectName(Parameters::kKpNewWordsComparedTogether().c_str());
|
_ui->checkBox_kp_newWordsComparedTogether->setObjectName(Parameters::kKpNewWordsComparedTogether().c_str());
|
||||||
|
|
||||||
|
_ui->subpix_winSize->setObjectName(Parameters::kKpSubPixWinSize().c_str());
|
||||||
|
_ui->subpix_iterations->setObjectName(Parameters::kKpSubPixIterations().c_str());
|
||||||
|
_ui->subpix_eps->setObjectName(Parameters::kKpSubPixEps().c_str());
|
||||||
|
|
||||||
//SURF detector
|
//SURF detector
|
||||||
_ui->surf_doubleSpinBox_hessianThr->setObjectName(Parameters::kSURFHessianThreshold().c_str());
|
_ui->surf_doubleSpinBox_hessianThr->setObjectName(Parameters::kSURFHessianThreshold().c_str());
|
||||||
_ui->surf_spinBox_octaves->setObjectName(Parameters::kSURFOctaves().c_str());
|
_ui->surf_spinBox_octaves->setObjectName(Parameters::kSURFOctaves().c_str());
|
||||||
@@ -478,18 +482,18 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
|||||||
_ui->odom_flow_maxLevel->setObjectName(Parameters::kOdomFlowMaxLevel().c_str());
|
_ui->odom_flow_maxLevel->setObjectName(Parameters::kOdomFlowMaxLevel().c_str());
|
||||||
_ui->odom_flow_iterations->setObjectName(Parameters::kOdomFlowIterations().c_str());
|
_ui->odom_flow_iterations->setObjectName(Parameters::kOdomFlowIterations().c_str());
|
||||||
_ui->odom_flow_eps->setObjectName(Parameters::kOdomFlowEps().c_str());
|
_ui->odom_flow_eps->setObjectName(Parameters::kOdomFlowEps().c_str());
|
||||||
_ui->odom_flow_subpix_winSize->setObjectName(Parameters::kOdomFlowSubPixWinSize().c_str());
|
_ui->odom_stereo_maxSlope->setObjectName(Parameters::kOdomStereoMaxSlope().c_str());
|
||||||
_ui->odom_flow_subpix_iterations->setObjectName(Parameters::kOdomFlowSubPixIterations().c_str());
|
_ui->odom_subpix_winSize->setObjectName(Parameters::kOdomSubPixWinSize().c_str());
|
||||||
_ui->odom_flow_subpix_eps->setObjectName(Parameters::kOdomFlowSubPixEps().c_str());
|
_ui->odom_subpix_iterations->setObjectName(Parameters::kOdomSubPixIterations().c_str());
|
||||||
|
_ui->odom_subpix_eps->setObjectName(Parameters::kOdomSubPixEps().c_str());
|
||||||
|
|
||||||
//Stereo
|
//Stereo
|
||||||
_ui->stereo_winSize->setObjectName(Parameters::kStereoWinSize().c_str());
|
_ui->stereo_flow_winSize->setObjectName(Parameters::kStereoWinSize().c_str());
|
||||||
_ui->stereo_maxLevel->setObjectName(Parameters::kStereoMaxLevel().c_str());
|
_ui->stereo_flow_maxLevel->setObjectName(Parameters::kStereoMaxLevel().c_str());
|
||||||
_ui->stereo_iterations->setObjectName(Parameters::kStereoIterations().c_str());
|
_ui->stereo_flow_iterations->setObjectName(Parameters::kStereoIterations().c_str());
|
||||||
_ui->stereo_eps->setObjectName(Parameters::kStereoEps().c_str());
|
_ui->stereo_flow_eps->setObjectName(Parameters::kStereoEps().c_str());
|
||||||
_ui->stereo_subpix_winSize->setObjectName(Parameters::kStereoSubPixWinSize().c_str());
|
_ui->stereo_maxSlope->setObjectName(Parameters::kStereoMaxSlope().c_str());
|
||||||
_ui->stereo_subpix_iterations->setObjectName(Parameters::kStereoSubPixIterations().c_str());
|
|
||||||
_ui->stereo_subpix_eps->setObjectName(Parameters::kStereoSubPixEps().c_str());
|
|
||||||
|
|
||||||
setupSignals();
|
setupSignals();
|
||||||
// custom signals
|
// custom signals
|
||||||
@@ -813,8 +817,8 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
|
|||||||
_ui->checkBox_mls->setChecked(false);
|
_ui->checkBox_mls->setChecked(false);
|
||||||
_ui->doubleSpinBox_mlsRadius->setValue(0.04);
|
_ui->doubleSpinBox_mlsRadius->setValue(0.04);
|
||||||
|
|
||||||
_ui->groupBox_poseFiltering->setChecked(false);
|
_ui->groupBox_poseFiltering->setChecked(true);
|
||||||
_ui->doubleSpinBox_cloudFilterRadius->setValue(0.1);
|
_ui->doubleSpinBox_cloudFilterRadius->setValue(0.3);
|
||||||
_ui->doubleSpinBox_cloudFilterAngle->setValue(30);
|
_ui->doubleSpinBox_cloudFilterAngle->setValue(30);
|
||||||
|
|
||||||
_ui->checkBox_map_shown->setChecked(false);
|
_ui->checkBox_map_shown->setChecked(false);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1187</width>
|
<width>1187</width>
|
||||||
<height>711</height>
|
<height>851</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -1011,6 +1011,24 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QDockWidget" name="dockWidget_stereoView">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Stereo view</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="dockWidgetArea">
|
||||||
|
<number>4</number>
|
||||||
|
</attribute>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents_5">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="rtabmap::ImageView" name="graphicsView_stereo"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="rtabmap::CloudViewer" name="stereoViewer" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
<action name="actionOpen_database">
|
<action name="actionOpen_database">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open database</string>
|
<string>Open database</string>
|
||||||
@@ -1103,17 +1121,17 @@
|
|||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
|
||||||
<class>rtabmap::ImageView</class>
|
|
||||||
<extends>QGraphicsView</extends>
|
|
||||||
<header>rtabmap/gui/ImageView.h</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>rtabmap::CloudViewer</class>
|
<class>rtabmap::CloudViewer</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
<header>rtabmap/gui/CloudViewer.h</header>
|
<header>rtabmap/gui/CloudViewer.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>rtabmap::ImageView</class>
|
||||||
|
<extends>QGraphicsView</extends>
|
||||||
|
<header>rtabmap/gui/ImageView.h</header>
|
||||||
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>rtabmap::GraphViewer</class>
|
<class>rtabmap::GraphViewer</class>
|
||||||
<extends>QGraphicsView</extends>
|
<extends>QGraphicsView</extends>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user