Save intermediate node input features

This commit is contained in:
matlabbe
2026-05-09 10:57:59 -07:00
parent f04067fa16
commit f0b2aee5f1
7 changed files with 555 additions and 457 deletions
+3
View File
@@ -60,6 +60,7 @@ public:
int stopMapId = -1, int stopMapId = -1,
bool priorsIgnored = false, bool priorsIgnored = false,
bool imuIgnored = false, bool imuIgnored = false,
bool intermediateNodesAreNormalNodes = false,
const std::vector<Transform> & cameraLocalTransformOverrides = std::vector<Transform>()); const std::vector<Transform> & cameraLocalTransformOverrides = std::vector<Transform>());
DBReader(const std::list<std::string> & databasePaths, DBReader(const std::list<std::string> & databasePaths,
float frameRate = 0.0f, // -1 = use Database stamps, 0 = inf float frameRate = 0.0f, // -1 = use Database stamps, 0 = inf
@@ -76,6 +77,7 @@ public:
int stopMapId = -1, int stopMapId = -1,
bool priorsIgnored = false, bool priorsIgnored = false,
bool imuIgnored = false, bool imuIgnored = false,
bool intermediateNodesAreNormalNodes = false,
const std::vector<Transform> & cameraLocalTransformOverrides = std::vector<Transform>()); const std::vector<Transform> & cameraLocalTransformOverrides = std::vector<Transform>());
virtual ~DBReader(); virtual ~DBReader();
@@ -106,6 +108,7 @@ private:
int _stopId; int _stopId;
std::vector<unsigned int> _cameraIndices; std::vector<unsigned int> _cameraIndices;
bool _intermediateNodesIgnored; bool _intermediateNodesIgnored;
bool _intermediateNodesAreNormalNodes;
bool _landmarksIgnored; bool _landmarksIgnored;
bool _featuresIgnored; bool _featuresIgnored;
bool _priorsIgnored; bool _priorsIgnored;
+5 -1
View File
@@ -57,6 +57,7 @@ DBReader::DBReader(const std::string & databasePath,
int stopMapId, int stopMapId,
bool priorsIgnored, bool priorsIgnored,
bool imuIgnored, bool imuIgnored,
bool intermediateNodesAreNormalNodes,
const std::vector<Transform> & cameraLocalTransformOverrides) : const std::vector<Transform> & cameraLocalTransformOverrides) :
Camera(frameRate), Camera(frameRate),
_paths(uSplit(databasePath, ';')), _paths(uSplit(databasePath, ';')),
@@ -67,6 +68,7 @@ DBReader::DBReader(const std::string & databasePath,
_stopId(stopId), _stopId(stopId),
_cameraIndices(cameraIndices), _cameraIndices(cameraIndices),
_intermediateNodesIgnored(intermediateNodesIgnored), _intermediateNodesIgnored(intermediateNodesIgnored),
_intermediateNodesAreNormalNodes(intermediateNodesAreNormalNodes),
_landmarksIgnored(landmarksIgnored), _landmarksIgnored(landmarksIgnored),
_featuresIgnored(featuresIgnored), _featuresIgnored(featuresIgnored),
_priorsIgnored(priorsIgnored), _priorsIgnored(priorsIgnored),
@@ -99,6 +101,7 @@ DBReader::DBReader(const std::list<std::string> & databasePaths,
int stopMapId, int stopMapId,
bool priorsIgnored, bool priorsIgnored,
bool imuIgnored, bool imuIgnored,
bool intermediateNodesAreNormalNodes,
const std::vector<Transform> & cameraLocalTransformOverrides) : const std::vector<Transform> & cameraLocalTransformOverrides) :
Camera(frameRate), Camera(frameRate),
_paths(databasePaths), _paths(databasePaths),
@@ -109,6 +112,7 @@ DBReader::DBReader(const std::list<std::string> & databasePaths,
_stopId(stopId), _stopId(stopId),
_cameraIndices(cameraIndices), _cameraIndices(cameraIndices),
_intermediateNodesIgnored(intermediateNodesIgnored), _intermediateNodesIgnored(intermediateNodesIgnored),
_intermediateNodesAreNormalNodes(intermediateNodesAreNormalNodes),
_landmarksIgnored(landmarksIgnored), _landmarksIgnored(landmarksIgnored),
_featuresIgnored(featuresIgnored), _featuresIgnored(featuresIgnored),
_priorsIgnored(priorsIgnored), _priorsIgnored(priorsIgnored),
@@ -749,7 +753,7 @@ SensorData DBReader::getNextData(SensorCaptureInfo * info)
data.setStereoCameraModels(combinedStereoModels); data.setStereoCameraModels(combinedStereoModels);
} }
} }
data.setId(s->getWeight()==-1 ? -1 : seq); data.setId(!_intermediateNodesAreNormalNodes && s->getWeight()==-1 ? -1 : seq);
data.setStamp(s->getStamp()); data.setStamp(s->getStamp());
data.setGroundTruth(s->getGroundTruthPose()); data.setGroundTruth(s->getGroundTruthPose());
if(!globalPose.isNull()) if(!globalPose.isNull())
+328 -270
View File
@@ -4317,18 +4317,44 @@ bool Memory::rehearsalMerge(int oldId, int newId)
// just update weight // just update weight
int w = oldS->getWeight()>=0?oldS->getWeight():0; int w = oldS->getWeight()>=0?oldS->getWeight():0;
newS->setWeight(w + newS->getWeight() + 1); newS->setWeight(w + newS->getWeight() + 1);
oldS->setWeight(intermediateMerge?-1:0); // convert to intermediate node oldS->setWeight(0);
if(_lastGlobalLoopClosureId == oldS->id()) if(_lastGlobalLoopClosureId == oldS->id())
{ {
_lastGlobalLoopClosureId = newS->id(); _lastGlobalLoopClosureId = newS->id();
} }
if(intermediateMerge)
{
this->disableWordsRef(oldS->id());
static bool warned = false;
if(!warned)
{
UWARN("A rehearsal was accepted (%d->%d) while not moving but "
"there are intermediate nodes in between them the graph. "
"Because %s=true, the node %d cannot be converted "
"into an intermediate node so it will be kept in the graph "
"even if we are not moving. Set %s=false to handle intermediate "
"nodes with rehearsal enabled so that loop closure hypotheses "
"are propagated correctly. This message is only "
"printed once.",
oldS->id(),
newS->id(),
Parameters::kMemRehearsalIdUpdatedToNewOne().c_str(),
oldS->id(),
Parameters::kMemRehearsalIdUpdatedToNewOne().c_str());
warned = true;
}
}
} }
else // !_idUpdatedToNewOneRehearsal else // !_idUpdatedToNewOneRehearsal
{ {
int w = newS->getWeight()>=0?newS->getWeight():0; int w = newS->getWeight()>=0?newS->getWeight():0;
oldS->setWeight(w + oldS->getWeight() + 1); oldS->setWeight(w + oldS->getWeight() + 1);
newS->setWeight(intermediateMerge?-1:0); // convert to intermediate node newS->setWeight(intermediateMerge?-1:0); // convert to intermediate node
if(intermediateMerge)
{
this->disableWordsRef(newS->id());
}
} }
} }
} }
@@ -5584,7 +5610,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
UDEBUG("Intermediate node detected, don't extract features!"); UDEBUG("Intermediate node detected, don't extract features!");
} }
} }
else if(_feature2D->getMaxFeatures() >= 0 && !isIntermediateNode) else
{ {
_receivingOdometryFeatures = true; _receivingOdometryFeatures = true;
UINFO("Use odometry features: kpts=%d 3d=%d desc=%d (dim=%d, type=%d)", UINFO("Use odometry features: kpts=%d 3d=%d desc=%d (dim=%d, type=%d)",
@@ -5600,133 +5626,75 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
UASSERT(descriptors.empty() || descriptors.rows == (int)keypoints.size()); UASSERT(descriptors.empty() || descriptors.rows == (int)keypoints.size());
UASSERT(keypoints3D.empty() || keypoints3D.size() == keypoints.size()); UASSERT(keypoints3D.empty() || keypoints3D.size() == keypoints.size());
int maxFeatures = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visMaxFeatures:_feature2D->getMaxFeatures(); if(_feature2D->getMaxFeatures() >= 0 && !isIntermediateNode)
bool ssc = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visSSC:_feature2D->getSSC();
if((int)keypoints.size() > maxFeatures)
{ {
if(data.cameraModels().size()>=1 || data.stereoCameraModels().size()>=1) int maxFeatures = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visMaxFeatures:_feature2D->getMaxFeatures();
_feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures, data.cameraModels().size()?cv::Size(data.cameraModels()[0].imageWidth()*data.cameraModels().size(), data.cameraModels()[0].imageHeight()):cv::Size(data.stereoCameraModels()[0].left().imageWidth()*data.stereoCameraModels().size(), data.stereoCameraModels()[0].left().imageHeight()), ssc); if((int)keypoints.size() > maxFeatures)
else
_feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures);
}
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_detection(), t*1000.0f);
UDEBUG("time keypoints (%d) = %fs", (int)keypoints.size(), t);
if(descriptors.empty())
{
cv::Mat imageMono;
if(data.imageRaw().channels() == 3)
{ {
cv::cvtColor(data.imageRaw(), imageMono, CV_BGR2GRAY); bool ssc = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visSSC:_feature2D->getSSC();
} if(data.cameraModels().size()>=1 || data.stereoCameraModels().size()>=1)
else _feature2D->limitKeypoints(keypoints,
{ keypoints3D,
imageMono = data.imageRaw(); descriptors,
} maxFeatures,
data.cameraModels().size()?cv::Size(data.cameraModels()[0].imageWidth()*data.cameraModels().size(),
UASSERT_MSG(imagesRectified, "Cannot extract descriptors on not rectified image from keypoints which assumed to be undistorted"); data.cameraModels()[0].imageHeight()):cv::Size(data.stereoCameraModels()[0].left().imageWidth()*data.stereoCameraModels().size(),
descriptors = _feature2D->generateDescriptors(imageMono, keypoints); data.stereoCameraModels()[0].left().imageHeight()),
} ssc);
else if(!imagesRectified && !data.cameraModels().empty())
{
std::vector<cv::KeyPoint> keypointsValid;
keypointsValid.reserve(keypoints.size());
cv::Mat descriptorsValid;
descriptorsValid.reserve(descriptors.rows);
std::vector<cv::Point3f> keypoints3DValid;
keypoints3DValid.reserve(keypoints3D.size());
//undistort keypoints before projection (RGB-D)
if(data.cameraModels().size() == 1)
{
std::vector<cv::Point2f> pointsIn, pointsOut;
cv::KeyPoint::convert(keypoints,pointsIn);
if(data.cameraModels()[0].D_raw().cols == 6)
{
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = data.cameraModels()[0].D_raw().at<double>(0,0);
D.at<double>(0,1) = data.cameraModels()[0].D_raw().at<double>(0,1);
D.at<double>(0,2) = data.cameraModels()[0].D_raw().at<double>(0,4);
D.at<double>(0,3) = data.cameraModels()[0].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[0].K_raw(),
D,
data.cameraModels()[0].R(),
data.cameraModels()[0].P());
}
else else
#else _feature2D->limitKeypoints(keypoints,
UWARN("Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!", keypoints3D,
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION); descriptors,
} maxFeatures);
#endif
{
//RadialTangential
cv::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[0].K_raw(),
data.cameraModels()[0].D_raw(),
data.cameraModels()[0].R(),
data.cameraModels()[0].P());
}
UASSERT(pointsOut.size() == keypoints.size());
for(unsigned int i=0; i<pointsOut.size(); ++i)
{
if(pointsOut.at(i).x>=0 && pointsOut.at(i).x<data.cameraModels()[0].imageWidth() &&
pointsOut.at(i).y>=0 && pointsOut.at(i).y<data.cameraModels()[0].imageHeight())
{
keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut.at(i).x;
keypointsValid.back().pt.y = pointsOut.at(i).y;
descriptorsValid.push_back(descriptors.row(i));
if(!keypoints3D.empty())
{
keypoints3DValid.push_back(keypoints3D.at(i));
}
}
}
} }
else t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_detection(), t*1000.0f);
UDEBUG("time keypoints (%d) = %fs", (int)keypoints.size(), t);
if(descriptors.empty())
{ {
float subImageWidth; cv::Mat imageMono;
if(!data.imageRaw().empty()) if(data.imageRaw().channels() == 3)
{ {
UASSERT(int((data.imageRaw().cols/data.cameraModels().size())*data.cameraModels().size()) == data.imageRaw().cols); cv::cvtColor(data.imageRaw(), imageMono, CV_BGR2GRAY);
subImageWidth = data.imageRaw().cols/data.cameraModels().size();
} }
else else
{ {
UASSERT(data.cameraModels()[0].imageWidth()>0); imageMono = data.imageRaw();
subImageWidth = data.cameraModels()[0].imageWidth();
} }
for(unsigned int i=0; i<keypoints.size(); ++i) UASSERT_MSG(imagesRectified, "Cannot extract descriptors on not rectified image from keypoints which assumed to be undistorted");
{ descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
int cameraIndex = int(keypoints.at(i).pt.x / subImageWidth); }
UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (int)data.cameraModels().size(), else if(!imagesRectified && !data.cameraModels().empty())
uFormat("cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)", {
cameraIndex, (int)data.cameraModels().size(), keypoints[i].pt.x, subImageWidth, data.cameraModels()[0].imageWidth()).c_str()); std::vector<cv::KeyPoint> keypointsValid;
keypointsValid.reserve(keypoints.size());
cv::Mat descriptorsValid;
descriptorsValid.reserve(descriptors.rows);
std::vector<cv::Point3f> keypoints3DValid;
keypoints3DValid.reserve(keypoints3D.size());
//undistort keypoints before projection (RGB-D)
if(data.cameraModels().size() == 1)
{
std::vector<cv::Point2f> pointsIn, pointsOut; std::vector<cv::Point2f> pointsIn, pointsOut;
pointsIn.push_back(cv::Point2f(keypoints.at(i).pt.x-subImageWidth*cameraIndex, keypoints.at(i).pt.y)); cv::KeyPoint::convert(keypoints,pointsIn);
if(data.cameraModels()[cameraIndex].D_raw().cols == 6) if(data.cameraModels()[0].D_raw().cols == 6)
{ {
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye // Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4) // get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1); cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,0); D.at<double>(0,0) = data.cameraModels()[0].D_raw().at<double>(0,0);
D.at<double>(0,1) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,1); D.at<double>(0,1) = data.cameraModels()[0].D_raw().at<double>(0,1);
D.at<double>(0,2) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,4); D.at<double>(0,2) = data.cameraModels()[0].D_raw().at<double>(0,4);
D.at<double>(0,3) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,5); D.at<double>(0,3) = data.cameraModels()[0].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut, cv::fisheye::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[cameraIndex].K_raw(), data.cameraModels()[0].K_raw(),
D, D,
data.cameraModels()[cameraIndex].R(), data.cameraModels()[0].R(),
data.cameraModels()[cameraIndex].P()); data.cameraModels()[0].P());
} }
else else
#else #else
@@ -5737,57 +5705,128 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
{ {
//RadialTangential //RadialTangential
cv::undistortPoints(pointsIn, pointsOut, cv::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[cameraIndex].K_raw(), data.cameraModels()[0].K_raw(),
data.cameraModels()[cameraIndex].D_raw(), data.cameraModels()[0].D_raw(),
data.cameraModels()[cameraIndex].R(), data.cameraModels()[0].R(),
data.cameraModels()[cameraIndex].P()); data.cameraModels()[0].P());
} }
UASSERT(pointsOut.size() == keypoints.size());
if(pointsOut[0].x>=0 && pointsOut[0].x<data.cameraModels()[cameraIndex].imageWidth() && for(unsigned int i=0; i<pointsOut.size(); ++i)
pointsOut[0].y>=0 && pointsOut[0].y<data.cameraModels()[cameraIndex].imageHeight())
{ {
keypointsValid.push_back(keypoints.at(i)); if(pointsOut.at(i).x>=0 && pointsOut.at(i).x<data.cameraModels()[0].imageWidth() &&
keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex; pointsOut.at(i).y>=0 && pointsOut.at(i).y<data.cameraModels()[0].imageHeight())
keypointsValid.back().pt.y = pointsOut[0].y;
descriptorsValid.push_back(descriptors.row(i));
if(!keypoints3D.empty())
{ {
keypoints3DValid.push_back(keypoints3D.at(i)); keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut.at(i).x;
keypointsValid.back().pt.y = pointsOut.at(i).y;
descriptorsValid.push_back(descriptors.row(i));
if(!keypoints3D.empty())
{
keypoints3DValid.push_back(keypoints3D.at(i));
}
} }
} }
} }
else
{
float subImageWidth;
if(!data.imageRaw().empty())
{
UASSERT(int((data.imageRaw().cols/data.cameraModels().size())*data.cameraModels().size()) == data.imageRaw().cols);
subImageWidth = data.imageRaw().cols/data.cameraModels().size();
}
else
{
UASSERT(data.cameraModels()[0].imageWidth()>0);
subImageWidth = data.cameraModels()[0].imageWidth();
}
for(unsigned int i=0; i<keypoints.size(); ++i)
{
int cameraIndex = int(keypoints.at(i).pt.x / subImageWidth);
UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (int)data.cameraModels().size(),
uFormat("cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
cameraIndex, (int)data.cameraModels().size(), keypoints[i].pt.x, subImageWidth, data.cameraModels()[0].imageWidth()).c_str());
std::vector<cv::Point2f> pointsIn, pointsOut;
pointsIn.push_back(cv::Point2f(keypoints.at(i).pt.x-subImageWidth*cameraIndex, keypoints.at(i).pt.y));
if(data.cameraModels()[cameraIndex].D_raw().cols == 6)
{
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,0);
D.at<double>(0,1) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,1);
D.at<double>(0,2) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,4);
D.at<double>(0,3) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[cameraIndex].K_raw(),
D,
data.cameraModels()[cameraIndex].R(),
data.cameraModels()[cameraIndex].P());
}
else
#else
UWARN("Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
}
#endif
{
//RadialTangential
cv::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[cameraIndex].K_raw(),
data.cameraModels()[cameraIndex].D_raw(),
data.cameraModels()[cameraIndex].R(),
data.cameraModels()[cameraIndex].P());
}
if(pointsOut[0].x>=0 && pointsOut[0].x<data.cameraModels()[cameraIndex].imageWidth() &&
pointsOut[0].y>=0 && pointsOut[0].y<data.cameraModels()[cameraIndex].imageHeight())
{
keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex;
keypointsValid.back().pt.y = pointsOut[0].y;
descriptorsValid.push_back(descriptors.row(i));
if(!keypoints3D.empty())
{
keypoints3DValid.push_back(keypoints3D.at(i));
}
}
}
}
keypoints = keypointsValid;
descriptors = descriptorsValid;
keypoints3D = keypoints3DValid;
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemRectification(), t*1000.0f);
UDEBUG("time rectification = %fs", t);
} }
keypoints = keypointsValid;
descriptors = descriptorsValid;
keypoints3D = keypoints3DValid;
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemRectification(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
UDEBUG("time rectification = %fs", t); UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
}
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
if(keypoints3D.empty() && if(keypoints3D.empty() &&
((!data.depthRaw().empty() && data.cameraModels().size() && data.cameraModels()[0].isValidForProjection()) || ((!data.depthRaw().empty() && data.cameraModels().size() && data.cameraModels()[0].isValidForProjection()) ||
(!data.rightRaw().empty() && data.stereoCameraModels().size() && data.stereoCameraModels()[0].isValidForProjection()))) (!data.rightRaw().empty() && data.stereoCameraModels().size() && data.stereoCameraModels()[0].isValidForProjection())))
{ {
keypoints3D = _feature2D->generateKeypoints3D(data, keypoints); keypoints3D = _feature2D->generateKeypoints3D(data, keypoints);
} }
if(_feature2D->getMinDepth() > 0.0f || _feature2D->getMaxDepth() > 0.0f) if(_feature2D->getMinDepth() > 0.0f || _feature2D->getMaxDepth() > 0.0f)
{ {
_feature2D->filterKeypointsByDepth(keypoints, descriptors, keypoints3D, _feature2D->getMinDepth(), _feature2D->getMaxDepth()); _feature2D->filterKeypointsByDepth(keypoints, descriptors, keypoints3D, _feature2D->getMinDepth(), _feature2D->getMaxDepth());
} }
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D.size(), t); UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D.size(), t);
UDEBUG("ratio=%f, meanWordsPerLocation=%d", _badSignRatio, meanWordsPerLocation); UDEBUG("ratio=%f, meanWordsPerLocation=%d", _badSignRatio, meanWordsPerLocation);
if(descriptors.rows && descriptors.rows < _badSignRatio * float(meanWordsPerLocation)) if(descriptors.rows && descriptors.rows < _badSignRatio * float(meanWordsPerLocation))
{ {
descriptors = cv::Mat(); descriptors = cv::Mat();
}
} }
} }
@@ -5810,107 +5849,117 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
} }
std::list<int> wordIds; std::list<int> wordIds;
if(descriptors.rows) bool addedToDictionary = false;
if(!keypoints.empty())
{ {
// In case the number of features we want to do quantization is lower if(descriptors.rows && !isIntermediateNode)
// than extracted ones (that would be used for transform estimation)
std::vector<bool> inliers;
cv::Mat descriptorsForQuantization = descriptors;
std::vector<int> quantizedToRawIndices;
if(_feature2D->getMaxFeatures()>0 && descriptors.rows > _feature2D->getMaxFeatures())
{ {
UASSERT((int)keypoints.size() == descriptors.rows); // In case the number of features we want to do quantization is lower
int inliersCount = 0; // than extracted ones (that would be used for transform estimation)
if((_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1) && std::vector<bool> inliers;
(decimatedData.cameraModels().size()==1 || decimatedData.stereoCameraModels().size()==1 || cv::Mat descriptorsForQuantization = descriptors;
data.cameraModels().size()==1 || data.stereoCameraModels().size()==1)) std::vector<int> quantizedToRawIndices;
if(_feature2D->getMaxFeatures()>0 && descriptors.rows > _feature2D->getMaxFeatures())
{ {
Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures(), UASSERT((int)keypoints.size() == descriptors.rows);
decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize(): int inliersCount = 0;
decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize(): if((_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1) &&
data.cameraModels().size()?data.cameraModels()[0].imageSize():data.stereoCameraModels()[0].left().imageSize(), (decimatedData.cameraModels().size()==1 || decimatedData.stereoCameraModels().size()==1 ||
_feature2D->getGridRows(), _feature2D->getGridCols(), _feature2D->getSSC()); data.cameraModels().size()==1 || data.stereoCameraModels().size()==1))
}
else
{
if(_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1)
{ {
UWARN("Ignored %s and %s parameters as they cannot be used for multi-cameras setup or uncalibrated camera.", Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures(),
Parameters::kKpGridCols().c_str(), Parameters::kKpGridRows().c_str()); decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize():
} decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize():
if(decimatedData.cameraModels().size()>=1 || decimatedData.stereoCameraModels().size()>=1 || data.cameraModels().size()?data.cameraModels()[0].imageSize():data.stereoCameraModels()[0].left().imageSize(),
data.cameraModels().size()>=1 || data.stereoCameraModels().size()>=1) _feature2D->getGridRows(), _feature2D->getGridCols(), _feature2D->getSSC());
{
Feature2D::limitKeypoints(
keypoints,
inliers,
_feature2D->getMaxFeatures(),
decimatedData.cameraModels().size()?cv::Size(decimatedData.cameraModels()[0].imageWidth()*decimatedData.cameraModels().size(), decimatedData.cameraModels()[0].imageHeight()):
decimatedData.stereoCameraModels().size()?cv::Size(decimatedData.stereoCameraModels()[0].left().imageWidth()*decimatedData.stereoCameraModels().size(), decimatedData.stereoCameraModels()[0].left().imageWidth()):
data.cameraModels().size()?cv::Size(data.cameraModels()[0].imageWidth()*data.cameraModels().size(), data.cameraModels()[0].imageHeight()):
cv::Size(data.stereoCameraModels()[0].left().imageWidth()*data.stereoCameraModels().size(), data.stereoCameraModels()[0].left().imageHeight()),
_feature2D->getSSC());
} }
else else
{ {
Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures()); if(_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1)
}
}
for(size_t i=0; i<inliers.size(); ++i)
{
if(inliers[i])
++inliersCount;
}
descriptorsForQuantization = cv::Mat(inliersCount, descriptors.cols, descriptors.type());
quantizedToRawIndices.resize(inliersCount);
unsigned int oi=0;
UASSERT((int)inliers.size() == descriptors.rows);
for(int k=0; k < descriptors.rows; ++k)
{
if(inliers[k])
{
UASSERT(oi < quantizedToRawIndices.size());
if(descriptors.type() == CV_32FC1)
{ {
memcpy(descriptorsForQuantization.ptr<float>(oi), descriptors.ptr<float>(k), descriptors.cols*sizeof(float)); UWARN("Ignored %s and %s parameters as they cannot be used for multi-cameras setup or uncalibrated camera.",
Parameters::kKpGridCols().c_str(), Parameters::kKpGridRows().c_str());
}
if(decimatedData.cameraModels().size()>=1 || decimatedData.stereoCameraModels().size()>=1 ||
data.cameraModels().size()>=1 || data.stereoCameraModels().size()>=1)
{
Feature2D::limitKeypoints(
keypoints,
inliers,
_feature2D->getMaxFeatures(),
decimatedData.cameraModels().size()?cv::Size(decimatedData.cameraModels()[0].imageWidth()*decimatedData.cameraModels().size(), decimatedData.cameraModels()[0].imageHeight()):
decimatedData.stereoCameraModels().size()?cv::Size(decimatedData.stereoCameraModels()[0].left().imageWidth()*decimatedData.stereoCameraModels().size(), decimatedData.stereoCameraModels()[0].left().imageWidth()):
data.cameraModels().size()?cv::Size(data.cameraModels()[0].imageWidth()*data.cameraModels().size(), data.cameraModels()[0].imageHeight()):
cv::Size(data.stereoCameraModels()[0].left().imageWidth()*data.stereoCameraModels().size(), data.stereoCameraModels()[0].left().imageHeight()),
_feature2D->getSSC());
} }
else else
{ {
memcpy(descriptorsForQuantization.ptr<char>(oi), descriptors.ptr<char>(k), descriptors.cols*sizeof(char)); Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures());
} }
quantizedToRawIndices[oi] = k;
++oi;
} }
} for(size_t i=0; i<inliers.size(); ++i)
UASSERT_MSG((int)oi == inliersCount,
uFormat("oi=%d inliersCount=%d (maxFeatures=%d, grid=%dx%d)",
oi, inliersCount, _feature2D->getMaxFeatures(), _feature2D->getGridCols(), _feature2D->getGridRows()).c_str());
}
// Quantization to vocabulary
wordIds = _vwd->addNewWords(descriptorsForQuantization, id);
// Set ID -1 to features not used for quantization
if(wordIds.size() < keypoints.size())
{
std::vector<int> allWordIds;
allWordIds.resize(keypoints.size(),-1);
int i=0;
for(std::list<int>::iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter)
{
allWordIds[quantizedToRawIndices[i]] = *iter;
++i;
}
int negIndex = -1;
for(i=0; i<(int)allWordIds.size(); ++i)
{
if(allWordIds[i] < 0)
{ {
allWordIds[i] = negIndex--; if(inliers[i])
++inliersCount;
} }
descriptorsForQuantization = cv::Mat(inliersCount, descriptors.cols, descriptors.type());
quantizedToRawIndices.resize(inliersCount);
unsigned int oi=0;
UASSERT((int)inliers.size() == descriptors.rows);
for(int k=0; k < descriptors.rows; ++k)
{
if(inliers[k])
{
UASSERT(oi < quantizedToRawIndices.size());
if(descriptors.type() == CV_32FC1)
{
memcpy(descriptorsForQuantization.ptr<float>(oi), descriptors.ptr<float>(k), descriptors.cols*sizeof(float));
}
else
{
memcpy(descriptorsForQuantization.ptr<char>(oi), descriptors.ptr<char>(k), descriptors.cols*sizeof(char));
}
quantizedToRawIndices[oi] = k;
++oi;
}
}
UASSERT_MSG((int)oi == inliersCount,
uFormat("oi=%d inliersCount=%d (maxFeatures=%d, grid=%dx%d)",
oi, inliersCount, _feature2D->getMaxFeatures(), _feature2D->getGridCols(), _feature2D->getGridRows()).c_str());
} }
wordIds = uVectorToList(allWordIds);
// Quantization to vocabulary
wordIds = _vwd->addNewWords(descriptorsForQuantization, id);
addedToDictionary = true;
// Set ID -1 to features not used for quantization
if(wordIds.size() < keypoints.size())
{
std::vector<int> allWordIds;
allWordIds.resize(keypoints.size(),-1);
int i=0;
for(std::list<int>::iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter)
{
allWordIds[quantizedToRawIndices[i]] = *iter;
++i;
}
int negIndex = -1;
for(i=0; i<(int)allWordIds.size(); ++i)
{
if(allWordIds[i] < 0)
{
allWordIds[i] = negIndex--;
}
}
wordIds = uVectorToList(allWordIds);
}
}
else
{
// Set all words as not used in dictionary
wordIds.resize(keypoints.size(),-1);
} }
t = timer.ticks(); t = timer.ticks();
@@ -5930,6 +5979,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
if(wordIds.size() > 0) if(wordIds.size() > 0)
{ {
UASSERT(wordIds.size() == keypoints.size()); UASSERT(wordIds.size() == keypoints.size());
UASSERT(descriptors.rows == 0 || descriptors.rows == (int)wordIds.size());
UASSERT(keypoints3D.size() == 0 || keypoints3D.size() == wordIds.size()); UASSERT(keypoints3D.size() == 0 || keypoints3D.size() == wordIds.size());
unsigned int i=0; unsigned int i=0;
float decimationRatio = float(preDecimation) / float(_imagePostDecimation); float decimationRatio = float(preDecimation) / float(_imagePostDecimation);
@@ -5937,7 +5987,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
for(std::list<int>::iterator iter=wordIds.begin(); iter!=wordIds.end() && i < keypoints.size(); ++iter, ++i) for(std::list<int>::iterator iter=wordIds.begin(); iter!=wordIds.end() && i < keypoints.size(); ++iter, ++i)
{ {
cv::KeyPoint kpt = keypoints[i]; cv::KeyPoint kpt = keypoints[i];
if(preDecimation != _imagePostDecimation) if(preDecimation != _imagePostDecimation && !isIntermediateNode)
{ {
// remap keypoints to final image size // remap keypoints to final image size
kpt.pt.x *= decimationRatio; kpt.pt.x *= decimationRatio;
@@ -5956,7 +6006,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
++words3DValid; ++words3DValid;
} }
} }
if(_rawDescriptorsKept) if(!descriptors.empty() && _rawDescriptorsKept)
{ {
wordsDescriptors.push_back(descriptors.row(i)); wordsDescriptors.push_back(descriptors.row(i));
} }
@@ -5964,12 +6014,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
} }
Landmarks landmarks = data.landmarks(); Landmarks landmarks = data.landmarks();
if(!landmarks.empty() && isIntermediateNode) if(_detectMarkers && !isIntermediateNode && !data.imageRaw().empty())
{
UDEBUG("Landmarks provided (size=%ld) are ignored because this signature is set as intermediate.", landmarks.size());
landmarks.clear();
}
else if(_detectMarkers && !isIntermediateNode && !data.imageRaw().empty())
{ {
UDEBUG("Detecting markers..."); UDEBUG("Detecting markers...");
if(landmarks.empty()) if(landmarks.empty())
@@ -6101,7 +6146,8 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
UDEBUG("time post-decimation = %fs", t); UDEBUG("time post-decimation = %fs", t);
} }
if(_stereoFromMotion && if(!isIntermediateNode &&
_stereoFromMotion &&
!pose.isNull() && !pose.isNull() &&
cameraModels.size() == 1 && cameraModels.size() == 1 &&
words.size() && words.size() &&
@@ -6514,9 +6560,15 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
compressedUserData)); compressedUserData));
} }
s->setWords(words, wordsKpts, if(!isIntermediateNode || _saveIntermediateNodeData)
_reextractLoopClosureFeatures?std::vector<cv::Point3f>():words3D, {
_reextractLoopClosureFeatures?cv::Mat():wordsDescriptors); s->setWords(words, wordsKpts,
_reextractLoopClosureFeatures?std::vector<cv::Point3f>():words3D,
_reextractLoopClosureFeatures?cv::Mat():wordsDescriptors);
s->sensorData().setLaserScan(laserScan, false);
s->sensorData().setUserData(data.userDataRaw(), false);
}
// set raw data // set raw data
if(!cameraModels.empty()) if(!cameraModels.empty())
@@ -6527,8 +6579,6 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
{ {
s->sensorData().setStereoImage(image, depthOrRightImage, stereoCameraModels, false); s->sensorData().setStereoImage(image, depthOrRightImage, stereoCameraModels, false);
} }
s->sensorData().setLaserScan(laserScan, false);
s->sensorData().setUserData(data.userDataRaw(), false);
UDEBUG("data.groundTruth() =%s", data.groundTruth().prettyPrint().c_str()); UDEBUG("data.groundTruth() =%s", data.groundTruth().prettyPrint().c_str());
UDEBUG("data.gps() =%s", data.gps().stamp()?"true":"false"); UDEBUG("data.gps() =%s", data.gps().stamp()?"true":"false");
@@ -6538,28 +6588,33 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
s->sensorData().setGPS(data.gps()); s->sensorData().setGPS(data.gps());
s->sensorData().setEnvSensors(data.envSensors()); s->sensorData().setEnvSensors(data.envSensors());
if(!isIntermediateNode) std::vector<GlobalDescriptor> globalDescriptors = data.globalDescriptors();
if(!isIntermediateNode && _globalDescriptorExtractor)
{ {
std::vector<GlobalDescriptor> globalDescriptors = data.globalDescriptors(); GlobalDescriptor gdescriptor = _globalDescriptorExtractor->extract(inputData);
if(_globalDescriptorExtractor) if(!gdescriptor.data().empty())
{ {
GlobalDescriptor gdescriptor = _globalDescriptorExtractor->extract(inputData); globalDescriptors.push_back(gdescriptor);
if(!gdescriptor.data().empty())
{
globalDescriptors.push_back(gdescriptor);
}
} }
s->sensorData().setGlobalDescriptors(globalDescriptors);
} }
else if(!data.globalDescriptors().empty()) if(!globalDescriptors.empty())
{ {
UDEBUG("Global descriptors provided (size=%ld) are ignored because this signature is set as intermediate.", data.globalDescriptors().size()); if(!isIntermediateNode || _saveIntermediateNodeData)
{
s->sensorData().setGlobalDescriptors(globalDescriptors);
}
else
{
UDEBUG("Global descriptors provided (size=%ld) are ignored because this signature is set as intermediate and %s=false.",
globalDescriptors.size(),
Parameters::kMemIntermediateNodeDataKept().c_str());
}
} }
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemCompressing_data(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemCompressing_data(), t*1000.0f);
UDEBUG("time compressing data (id=%d) %fs", id, t); UDEBUG("time compressing data (id=%d) %fs", id, t);
if(words.size()) if(words.size() && addedToDictionary)
{ {
s->setEnabled(true); // All references are already activated in the dictionary at this point (see _vwd->addNewWords()) s->setEnabled(true); // All references are already activated in the dictionary at this point (see _vwd->addNewWords())
} }
@@ -6699,16 +6754,19 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
s->addLandmark(landmark); s->addLandmark(landmark);
// Update landmark index // Update landmark index
std::map<int, std::set<int> >::iterator nter = _landmarksIndex.find(landmarkId); if(!isIntermediateNode)
if(nter!=_landmarksIndex.end())
{ {
nter->second.insert(s->id()); std::map<int, std::set<int> >::iterator nter = _landmarksIndex.find(landmarkId);
} if(nter!=_landmarksIndex.end())
else {
{ nter->second.insert(s->id());
std::set<int> tmp; }
tmp.insert(s->id()); else
_landmarksIndex.insert(std::make_pair(landmarkId, tmp)); {
std::set<int> tmp;
tmp.insert(s->id());
_landmarksIndex.insert(std::make_pair(landmarkId, tmp));
}
} }
} }
else else
+1 -1
View File
@@ -3166,7 +3166,7 @@ bool Rtabmap::process(
// Landmark // Landmark
//============================================================ //============================================================
std::map<int, std::set<int> > landmarksDetected; // <Landmark ID, list of nodes that saw this landmark> std::map<int, std::set<int> > landmarksDetected; // <Landmark ID, list of nodes that saw this landmark>
if(!signature->getLandmarks().empty() && !_graphOptimizer->landmarksIgnored()) if(!signature->getLandmarks().empty() && !_graphOptimizer->landmarksIgnored() && signature->getWeight()!=-1)
{ {
bool hasGlobalLoopClosuresInOdomCache = !graph::filterLinks(_odomCacheConstraints, Link::kGlobalClosure, true).empty() || _loopClosureHypothesis.first != 0; bool hasGlobalLoopClosuresInOdomCache = !graph::filterLinks(_odomCacheConstraints, Link::kGlobalClosure, true).empty() || _loopClosureHypothesis.first != 0;
UDEBUG("hasGlobalLoopClosuresInOdomCache=%d", hasGlobalLoopClosuresInOdomCache?1:0); UDEBUG("hasGlobalLoopClosuresInOdomCache=%d", hasGlobalLoopClosuresInOdomCache?1:0);
+6 -1
View File
@@ -761,6 +761,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->source_checkBox_ignoreFeatures, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->source_checkBox_ignoreFeatures, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_checkBox_ignorePriors, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->source_checkBox_ignorePriors, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_checkBox_ignoreIMU, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->source_checkBox_ignoreIMU, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_checkBox_intermediateNodesAreNormalNodes, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_spinBox_databaseStartId, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->source_spinBox_databaseStartId, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_spinBox_databaseStopId, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->source_spinBox_databaseStopId, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_checkBox_useDbStamps, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->source_checkBox_useDbStamps, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
@@ -2229,6 +2230,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->source_checkBox_ignoreFeatures->setChecked(true); _ui->source_checkBox_ignoreFeatures->setChecked(true);
_ui->source_checkBox_ignorePriors->setChecked(false); _ui->source_checkBox_ignorePriors->setChecked(false);
_ui->source_checkBox_ignoreIMU->setChecked(false); _ui->source_checkBox_ignoreIMU->setChecked(false);
_ui->source_checkBox_intermediateNodesAreNormalNodes->setChecked(false);
_ui->source_spinBox_databaseStartId->setValue(0); _ui->source_spinBox_databaseStartId->setValue(0);
_ui->source_spinBox_databaseStopId->setValue(0); _ui->source_spinBox_databaseStopId->setValue(0);
_ui->source_lineEdit_databaseCameraIndex->setText(""); _ui->source_lineEdit_databaseCameraIndex->setText("");
@@ -2991,6 +2993,7 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->source_checkBox_ignoreFeatures->setChecked(settings.value("ignoreFeatures", _ui->source_checkBox_ignoreFeatures->isChecked()).toBool()); _ui->source_checkBox_ignoreFeatures->setChecked(settings.value("ignoreFeatures", _ui->source_checkBox_ignoreFeatures->isChecked()).toBool());
_ui->source_checkBox_ignorePriors->setChecked(settings.value("ignorePriors", _ui->source_checkBox_ignorePriors->isChecked()).toBool()); _ui->source_checkBox_ignorePriors->setChecked(settings.value("ignorePriors", _ui->source_checkBox_ignorePriors->isChecked()).toBool());
_ui->source_checkBox_ignoreIMU->setChecked(settings.value("ignoreImu", _ui->source_checkBox_ignoreIMU->isChecked()).toBool()); _ui->source_checkBox_ignoreIMU->setChecked(settings.value("ignoreImu", _ui->source_checkBox_ignoreIMU->isChecked()).toBool());
_ui->source_checkBox_intermediateNodesAreNormalNodes->setChecked(settings.value("intermediateNodesAreNormalNodes", _ui->source_checkBox_intermediateNodesAreNormalNodes->isChecked()).toBool());
_ui->source_spinBox_databaseStartId->setValue(settings.value("startId", _ui->source_spinBox_databaseStartId->value()).toInt()); _ui->source_spinBox_databaseStartId->setValue(settings.value("startId", _ui->source_spinBox_databaseStartId->value()).toInt());
_ui->source_spinBox_databaseStopId->setValue(settings.value("stopId", _ui->source_spinBox_databaseStopId->value()).toInt()); _ui->source_spinBox_databaseStopId->setValue(settings.value("stopId", _ui->source_spinBox_databaseStopId->value()).toInt());
@@ -3611,6 +3614,7 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("ignoreFeatures", _ui->source_checkBox_ignoreFeatures->isChecked()); settings.setValue("ignoreFeatures", _ui->source_checkBox_ignoreFeatures->isChecked());
settings.setValue("ignorePriors", _ui->source_checkBox_ignorePriors->isChecked()); settings.setValue("ignorePriors", _ui->source_checkBox_ignorePriors->isChecked());
settings.setValue("ignoreImu", _ui->source_checkBox_ignoreIMU->isChecked()); settings.setValue("ignoreImu", _ui->source_checkBox_ignoreIMU->isChecked());
settings.setValue("intermediateNodesAreNormalNodes", _ui->source_checkBox_intermediateNodesAreNormalNodes->isChecked());
settings.setValue("startId", _ui->source_spinBox_databaseStartId->value()); settings.setValue("startId", _ui->source_spinBox_databaseStartId->value());
settings.setValue("stopId", _ui->source_spinBox_databaseStopId->value()); settings.setValue("stopId", _ui->source_spinBox_databaseStopId->value());
settings.setValue("cameraIndices", _ui->source_lineEdit_databaseCameraIndex->text()); settings.setValue("cameraIndices", _ui->source_lineEdit_databaseCameraIndex->text());
@@ -7303,13 +7307,14 @@ Camera * PreferencesDialog::createCamera(
_ui->source_spinBox_databaseStartId->value(), _ui->source_spinBox_databaseStartId->value(),
cameraIndices, cameraIndices,
_ui->source_spinBox_databaseStopId->value(), _ui->source_spinBox_databaseStopId->value(),
!_ui->general_checkBox_createIntermediateNodes->isChecked(), !_ui->source_checkBox_intermediateNodesAreNormalNodes->isChecked() && !_ui->general_checkBox_createIntermediateNodes->isChecked(),
_ui->source_checkBox_ignoreLandmarks->isChecked(), _ui->source_checkBox_ignoreLandmarks->isChecked(),
_ui->source_checkBox_ignoreFeatures->isChecked(), _ui->source_checkBox_ignoreFeatures->isChecked(),
0, 0,
-1, -1,
_ui->source_checkBox_ignorePriors->isChecked(), _ui->source_checkBox_ignorePriors->isChecked(),
_ui->source_checkBox_ignoreIMU->isChecked(), _ui->source_checkBox_ignoreIMU->isChecked(),
_ui->source_checkBox_intermediateNodesAreNormalNodes->isChecked(),
localTransformOverrides); localTransformOverrides);
} }
else else
+201 -181
View File
@@ -63,7 +63,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>-648</y>
<width>684</width> <width>684</width>
<height>5218</height> <height>5218</height>
</rect> </rect>
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>14</number> <number>5</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0"> <layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0">
@@ -3469,7 +3469,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<item> <item>
<widget class="QStackedWidget" name="stackedWidget_src"> <widget class="QStackedWidget" name="stackedWidget_src">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>3</number>
</property> </property>
<widget class="QWidget" name="page_41"> <widget class="QWidget" name="page_41">
<layout class="QVBoxLayout" name="verticalLayout_64"> <layout class="QVBoxLayout" name="verticalLayout_64">
@@ -7180,37 +7180,10 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<bool>false</bool> <bool>false</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1,0"> <layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1,0">
<item row="10" column="0"> <item row="8" column="1">
<widget class="QSpinBox" name="source_spinBox_databaseStopId"> <widget class="QLabel" name="label_786">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="source_database_lineEdit_path"/>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="source_checkBox_useDbStamps">
<property name="text"> <property name="text">
<string/> <string>Ignore IMU (i.e., gravity links).</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreGoals">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_644">
<property name="text">
<string>Ignore features.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -7220,6 +7193,13 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreGoalDelay">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QToolButton" name="source_database_toolButton_selectSource"> <widget class="QToolButton" name="source_database_toolButton_selectSource">
<property name="text"> <property name="text">
@@ -7227,123 +7207,16 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="1"> <item row="10" column="1">
<widget class="QLabel" name="label_784"> <widget class="QLabel" name="label_58">
<property name="text"> <property name="text">
<string>Override camera local transform(s) with local transform(s) set above. For multi-cameras, use a &quot;;&quot; between each transform.</string> <string>Start position (node ID).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<property name="textInteractionFlags"> <property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreOdometry">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLineEdit" name="source_lineEdit_databaseCameraIndex"/>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreGoalDelay">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLineEdit" name="source_lineEdit_databaseLocalTransformOffset"/>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="toolButton_dbViewer">
<property name="toolTip">
<string>Open database viewer</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/mag_glass.png</normaloff>:/images/mag_glass.png</iconset>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="source_checkBox_overrideLocalTransforms">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreFeatures">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_72">
<property name="text">
<string>Ignore odometry saved in the database, so if RGB-D SLAM is activated, odometry will be recomputed.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_315">
<property name="text">
<string>Camera index. If the database contains multi-camera data, you can choose which camera to use. Leave empty to use all cameras. Can also be multiple indices split by spaces in a string like &quot;0 2&quot; to stream cameras 0 and 2 only.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="source_checkBox_ignorePriors">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_785">
<property name="text">
<string>Add an y-axis offset before optical rotation on the overriden local transform(s). For multi-cameras,explicitly enumerate offsets if they are different (e.g., &quot;0.05 0.075&quot; for two cameras setup), or set single number to apply to all camera transforms.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QSpinBox" name="source_spinBox_databaseStartId">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_90"> <widget class="QLabel" name="label_90">
<property name="text"> <property name="text">
@@ -7357,25 +7230,8 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="8" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreLandmarks"> <widget class="QCheckBox" name="source_checkBox_ignoreIMU">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_58">
<property name="text">
<string>Start position (node ID).</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QCheckBox" name="source_checkBox_stereoToDepthDB">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@@ -7394,6 +7250,139 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1">
<widget class="QLineEdit" name="source_database_lineEdit_path"/>
</item>
<item row="15" column="0">
<widget class="QCheckBox" name="source_checkBox_stereoToDepthDB">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_644">
<property name="text">
<string>Ignore features.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreFeatures">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_315">
<property name="text">
<string>Camera index. If the database contains multi-camera data, you can choose which camera to use. Leave empty to use all cameras. Can also be multiple indices split by spaces in a string like &quot;0 2&quot; to stream cameras 0 and 2 only.</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="source_checkBox_ignoreLandmarks">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="toolButton_dbViewer">
<property name="toolTip">
<string>Open database viewer</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/mag_glass.png</normaloff>:/images/mag_glass.png</iconset>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_263">
<property name="text">
<string>Ignore goals saved in the database.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_797">
<property name="text">
<string>Publish intermediate nodes as normal nodes.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_557">
<property name="text">
<string>If the database contains stereo data, generate disparity image and convert it to depth. The resulting output is a RGB-D image instead of stereo images. Dense disparity parameters can be found under StereoBM tab.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QSpinBox" name="source_spinBox_databaseStopId">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_529">
<property name="text">
<string>Stop position (node ID) is the last node to process. If 0, all nodes after start position are published.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreOdometry">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_546"> <widget class="QLabel" name="label_546">
<property name="text"> <property name="text">
@@ -7407,6 +7396,19 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="0">
<widget class="QLineEdit" name="source_lineEdit_databaseLocalTransformOffset"/>
</item>
<item row="10" column="0">
<widget class="QSpinBox" name="source_spinBox_databaseStartId">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_80"> <widget class="QLabel" name="label_80">
<property name="text"> <property name="text">
@@ -7421,9 +7423,9 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</widget> </widget>
</item> </item>
<item row="14" column="1"> <item row="14" column="1">
<widget class="QLabel" name="label_557"> <widget class="QLabel" name="label_785">
<property name="text"> <property name="text">
<string>If the database contains stereo data, generate disparity image and convert it to depth. The resulting output is a RGB-D image instead of stereo images. Dense disparity parameters can be found under StereoBM tab.</string> <string>Add an y-axis offset before optical rotation on the overriden local transform(s). For multi-cameras,explicitly enumerate offsets if they are different (e.g., &quot;0.05 0.075&quot; for two cameras setup), or set single number to apply to all camera transforms.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -7433,10 +7435,10 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="13" column="1">
<widget class="QLabel" name="label_529"> <widget class="QLabel" name="label_784">
<property name="text"> <property name="text">
<string>Stop position (node ID) is the last node to process. If 0, all nodes after start position are published.</string> <string>Override camera local transform(s) with local transform(s) set above. For multi-cameras, use a &quot;;&quot; between each transform.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -7446,10 +7448,34 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="13" column="0">
<widget class="QLabel" name="label_263"> <widget class="QCheckBox" name="source_checkBox_overrideLocalTransforms">
<property name="text"> <property name="text">
<string>Ignore goals saved in the database.</string> <string/>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="source_checkBox_intermediateNodesAreNormalNodes">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="source_checkBox_ignorePriors">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLineEdit" name="source_lineEdit_databaseCameraIndex"/>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_72">
<property name="text">
<string>Ignore odometry saved in the database, so if RGB-D SLAM is activated, odometry will be recomputed.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -7459,21 +7485,15 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="3" column="0">
<widget class="QLabel" name="label_786"> <widget class="QCheckBox" name="source_checkBox_ignoreGoals">
<property name="text"> <property name="text">
<string>Ignore IMU (i.e., gravity links).</string> <string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="source_checkBox_ignoreIMU"> <widget class="QCheckBox" name="source_checkBox_useDbStamps">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
+11 -3
View File
@@ -96,6 +96,7 @@ void showUsage()
" -nopriors Don't republish priors contained in input database.\n" " -nopriors Don't republish priors contained in input database.\n"
" -noimu Don't republish IMU contained in input database.\n" " -noimu Don't republish IMU contained in input database.\n"
" -pub_loops Republish loop closures contained in input database.\n" " -pub_loops Republish loop closures contained in input database.\n"
" -pub_inter_as_normal Republish intermediate nodes as normal nodes.\n"
" -loc_null On localization mode, reset localization pose to null and map correction to identity between sessions.\n" " -loc_null On localization mode, reset localization pose to null and map correction to identity between sessions.\n"
" -gt When reprocessing a single database, load its original optimized graph, then \n" " -gt When reprocessing a single database, load its original optimized graph, then \n"
" set it as ground truth for output database. If there was a ground truth in the input database, it will be ignored.\n" " set it as ground truth for output database. If there was a ground truth in the input database, it will be ignored.\n"
@@ -279,6 +280,7 @@ int main(int argc, char * argv[])
bool ignorePriors = false; bool ignorePriors = false;
bool ignoreImu = false; bool ignoreImu = false;
bool republishLoopClosures = false; bool republishLoopClosures = false;
bool pubInterNodesAsNormalNodes = false;
bool locNull = false; bool locNull = false;
bool originalGraphAsGT = false; bool originalGraphAsGT = false;
bool scanFromDepth = false; bool scanFromDepth = false;
@@ -510,6 +512,11 @@ int main(int argc, char * argv[])
republishLoopClosures = true; republishLoopClosures = true;
printf("Republish loop closures from input database (-pub_loops option).\n"); printf("Republish loop closures from input database (-pub_loops option).\n");
} }
else if(strcmp(argv[i], "-pub_inter_as_normal") == 0 || strcmp(argv[i], "--pub_inter_as_normal") == 0)
{
pubInterNodesAsNormalNodes = true;
printf("Republish intermdiate nodes as normal nodes (-pub_inter_as_normal option).\n");
}
else if(strcmp(argv[i], "-loc_null") == 0 || strcmp(argv[i], "--loc_null") == 0) else if(strcmp(argv[i], "-loc_null") == 0 || strcmp(argv[i], "--loc_null") == 0)
{ {
locNull = true; locNull = true;
@@ -815,7 +822,7 @@ int main(int argc, char * argv[])
int totalIds = 0; int totalIds = 0;
std::set<int> ids; std::set<int> ids;
dbDriver->getAllNodeIds(ids, false, false, !intermediateNodes); dbDriver->getAllNodeIds(ids, false, false, !pubInterNodesAsNormalNodes && !intermediateNodes);
if(ids.empty()) if(ids.empty())
{ {
printf("Input database doesn't have any nodes saved in it.\n"); printf("Input database doesn't have any nodes saved in it.\n");
@@ -844,7 +851,7 @@ int main(int argc, char * argv[])
return 1; return 1;
} }
ids.clear(); ids.clear();
dbDriver->getAllNodeIds(ids, false, false, !intermediateNodes); dbDriver->getAllNodeIds(ids, false, false, !pubInterNodesAsNormalNodes && !intermediateNodes);
totalIds += ids.size(); totalIds += ids.size();
dbDriver->closeConnection(false); dbDriver->closeConnection(false);
} }
@@ -920,13 +927,14 @@ int main(int argc, char * argv[])
startId, startId,
cameraIndices, cameraIndices,
stopId, stopId,
!intermediateNodes, !pubInterNodesAsNormalNodes && !intermediateNodes,
ignoreLandmarks, ignoreLandmarks,
!useOdomFeatures, !useOdomFeatures,
startMapId, startMapId,
stopMapId, stopMapId,
ignorePriors, ignorePriors,
ignoreImu, ignoreImu,
pubInterNodesAsNormalNodes,
cameraLocalTransformOverrides); cameraLocalTransformOverrides);
dbReader->init(); dbReader->init();