mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-01 17:10:26 +08:00
Increased version to 0.20.5
Refactored how features are stored in Signature (significative memory optimization, causing major refactoring in Memory, RegistrationVis, OdometryF2M) FLANN: optimized memory usage when Kp/IncrementalFlann is false Added memory usage functions Added statistics Loop/Visual_inliers_ratio/ and Memory/RAM_estimated/MB EpipolarGeometry: templated findPairs functions graph::filterLinks: added inverted option LocalBundleOnLoopClosure: Force to use only neighbor links MainWindow: fixed max depth filtering for map's features Rtabmap::getSignatureCopy() fixed links not returned Added UPlot::getAllCurveDataAsText() function. DbViewer: fixed features not rendered in right view when failing ro refine a constraint report: added --export and --export_prefix options (to export figures data)
This commit is contained in:
@@ -275,7 +275,7 @@ int main(int argc, char * argv[])
|
||||
|
||||
if(reg.getNNType()==6 &&
|
||||
!dataFrom.getWordsDescriptors().empty() &&
|
||||
dataFrom.getWordsDescriptors().begin()->second.type()!=CV_32F)
|
||||
dataFrom.getWordsDescriptors().type()!=CV_32F)
|
||||
{
|
||||
UWARN("PyMatcher is selected for matching but binary features "
|
||||
"are not compatible. BruteForce with CrossCheck (%s=5) "
|
||||
@@ -298,7 +298,7 @@ int main(int argc, char * argv[])
|
||||
.arg(Parameters::kVisCorNNType().c_str())
|
||||
.arg(reg.getNNType())
|
||||
.arg(reg.getNNType()<VWDictionary::kNNUndef?VWDictionary::nnStrategyName((VWDictionary::NNStrategy)reg.getNNType()).c_str():
|
||||
reg.getNNType()==5||(reg.getNNType()==6&&!dataFrom.getWordsDescriptors().empty()&& dataFrom.getWordsDescriptors().begin()->second.type()!=CV_32F)?"BFCrossCheck":
|
||||
reg.getNNType()==5||(reg.getNNType()==6&&!dataFrom.getWordsDescriptors().empty()&& dataFrom.getWordsDescriptors().type()!=CV_32F)?"BFCrossCheck":
|
||||
reg.getNNType()==6?QString(uSplit(UFile::getName(pyMatcherPath), '.').front().c_str()).replace("rtabmap_", ""):
|
||||
reg.getNNType()==7?"GMS":"?")
|
||||
.arg(reg.getNNType()<5?QString(" %1=%2").arg(Parameters::kVisCorNNDR().c_str()).arg(reg.getNNDR()):"")
|
||||
@@ -322,9 +322,21 @@ int main(int argc, char * argv[])
|
||||
if(reg.getEstimationType() == 2)
|
||||
{
|
||||
// triangulate 3D words based on the transform computed
|
||||
std::map<int, int> wordsFrom = uMultimapToMapUnique(dataFrom.getWords());
|
||||
std::map<int, int> wordsTo = uMultimapToMapUnique(dataTo.getWords());
|
||||
std::map<int, cv::KeyPoint> kptsFrom;
|
||||
std::map<int, cv::KeyPoint> kptsTo;
|
||||
for(std::map<int, int>::iterator iter=wordsFrom.begin(); iter!=wordsFrom.end(); ++iter)
|
||||
{
|
||||
kptsFrom.insert(std::make_pair(iter->first, dataFrom.getWordsKpts()[iter->second]));
|
||||
}
|
||||
for(std::map<int, int>::iterator iter=wordsTo.begin(); iter!=wordsTo.end(); ++iter)
|
||||
{
|
||||
kptsTo.insert(std::make_pair(iter->first, dataTo.getWordsKpts()[iter->second]));
|
||||
}
|
||||
std::map<int, cv::Point3f> points3d = util3d::generateWords3DMono(
|
||||
uMultimapToMapUnique(dataFrom.getWords()),
|
||||
uMultimapToMapUnique(dataTo.getWords()),
|
||||
kptsFrom,
|
||||
kptsTo,
|
||||
model.isValidForProjection()?model:stereoModel.left(),
|
||||
t);
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudWordsFrom(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
@@ -353,11 +365,12 @@ int main(int argc, char * argv[])
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudWordsFrom(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
cloudWordsFrom->resize(dataFrom.getWords3().size());
|
||||
int i=0;
|
||||
for(std::multimap<int, cv::Point3f>::const_iterator iter=dataFrom.getWords3().begin();
|
||||
iter!=dataFrom.getWords3().end();
|
||||
for(std::multimap<int, int>::const_iterator iter=dataFrom.getWords().begin();
|
||||
iter!=dataFrom.getWords().end();
|
||||
++iter)
|
||||
{
|
||||
cloudWordsFrom->at(i++) = pcl::PointXYZ(iter->second.x, iter->second.y, iter->second.z);
|
||||
const cv::Point3f & pt = dataFrom.getWords3()[iter->second];
|
||||
cloudWordsFrom->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
|
||||
}
|
||||
if(cloudWordsFrom->size())
|
||||
{
|
||||
@@ -371,22 +384,23 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
if(!dataTo.getWords3().empty())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudWordsFrom(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
cloudWordsFrom->resize(dataTo.getWords3().size());
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudWordsTo(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
cloudWordsTo->resize(dataTo.getWords3().size());
|
||||
int i=0;
|
||||
for(std::multimap<int, cv::Point3f>::const_iterator iter=dataTo.getWords3().begin();
|
||||
iter!=dataTo.getWords3().end();
|
||||
for(std::multimap<int, int>::const_iterator iter=dataTo.getWords().begin();
|
||||
iter!=dataTo.getWords().end();
|
||||
++iter)
|
||||
{
|
||||
cloudWordsFrom->at(i++) = pcl::PointXYZ(iter->second.x, iter->second.y, iter->second.z);
|
||||
const cv::Point3f & pt = dataTo.getWords3()[iter->second];
|
||||
cloudWordsTo->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
|
||||
}
|
||||
if(cloudWordsFrom->size())
|
||||
if(cloudWordsTo->size())
|
||||
{
|
||||
cloudWordsFrom = rtabmap::util3d::removeNaNFromPointCloud(cloudWordsFrom);
|
||||
cloudWordsTo = rtabmap::util3d::removeNaNFromPointCloud(cloudWordsTo);
|
||||
}
|
||||
if(cloudWordsFrom->size())
|
||||
if(cloudWordsTo->size())
|
||||
{
|
||||
viewer->addCloud("wordsTo", cloudWordsFrom, t, Qt::cyan);
|
||||
viewer->addCloud("wordsTo", cloudWordsTo, t, Qt::cyan);
|
||||
viewer->setCloudPointSize("wordsTo", 5);
|
||||
}
|
||||
}
|
||||
@@ -443,8 +457,24 @@ int main(int argc, char * argv[])
|
||||
viewB->setImageDepth(uCvMat2QImage(toDepth, false, uCvQtDepthRedToBlue));
|
||||
viewB->setImageDepthShown(true);
|
||||
}
|
||||
viewA->setFeatures(dataFrom.getWords());
|
||||
viewB->setFeatures(dataTo.getWords());
|
||||
std::multimap<int, cv::KeyPoint> keypointsFrom;
|
||||
std::multimap<int, cv::KeyPoint> keypointsTo;
|
||||
if(!dataFrom.getWordsKpts().empty())
|
||||
{
|
||||
for(std::map<int, int>::const_iterator iter=dataFrom.getWords().begin(); iter!=dataFrom.getWords().end(); ++iter)
|
||||
{
|
||||
keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, dataFrom.getWordsKpts()[iter->second]));
|
||||
}
|
||||
}
|
||||
if(!dataTo.getWordsKpts().empty())
|
||||
{
|
||||
for(std::map<int, int>::const_iterator iter=dataTo.getWords().begin(); iter!=dataTo.getWords().end(); ++iter)
|
||||
{
|
||||
keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, dataTo.getWordsKpts()[iter->second]));
|
||||
}
|
||||
}
|
||||
viewA->setFeatures(keypointsFrom);
|
||||
viewB->setFeatures(keypointsTo);
|
||||
std::set<int> inliersSet(info.inliersIDs.begin(), info.inliersIDs.end());
|
||||
|
||||
const QMultiMap<int, KeypointItem*> & wordsA = viewA->getFeatures();
|
||||
|
||||
@@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifdef WITH_QT
|
||||
#include <rtabmap/utilite/UPlot.h>
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#endif
|
||||
|
||||
using namespace rtabmap;
|
||||
@@ -69,6 +70,8 @@ void showUsage()
|
||||
" database, the inverse will be done. \n"
|
||||
" --ids Use IDs for x axis instead of time in the figures. \n"
|
||||
" --start # Start from this node ID for the figures.\n"
|
||||
" --export Export figures' data to txt files.\n"
|
||||
" --export_prefix Prefix to filenames of exported figures' data (default is \"Stat\").\n"
|
||||
#endif
|
||||
" --report Export all evaluation statistics values in report.txt \n"
|
||||
" --loc # Show localization statistics for each \"Statistic/Id\" per\n"
|
||||
@@ -134,6 +137,8 @@ int main(int argc, char * argv[])
|
||||
bool invertFigures = false;
|
||||
bool useIds = false;
|
||||
int startId = 0;
|
||||
bool exportFigures = false;
|
||||
std::string exportPrefix = "Stat";
|
||||
int showLoc = 0;
|
||||
float locDelay = 60;
|
||||
std::vector<std::string> statsToShow;
|
||||
@@ -186,6 +191,24 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
useIds = true;
|
||||
}
|
||||
else if(strcmp(argv[i],"--export") == 0)
|
||||
{
|
||||
exportFigures = true;
|
||||
}
|
||||
else if(strcmp(argv[i],"--export_prefix") == 0)
|
||||
{
|
||||
++i;
|
||||
if(i<argc-1)
|
||||
{
|
||||
exportPrefix = argv[i];
|
||||
printf("Export prefix=%s (--export_prefix)\n", exportPrefix.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Missing value for \"--export_prefix\" option.\n");
|
||||
showUsage();
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[i],"--loc") == 0)
|
||||
{
|
||||
++i;
|
||||
@@ -518,14 +541,14 @@ int main(int argc, char * argv[])
|
||||
|
||||
if(uContains(stat, std::string("RtabmapROS/TotalTime/ms")))
|
||||
{
|
||||
if(w>=0)
|
||||
if(w!=-1)
|
||||
{
|
||||
slamTime.push_back(stat.at("RtabmapROS/TotalTime/ms"));
|
||||
}
|
||||
}
|
||||
else if(uContains(stat, Statistics::kTimingTotal()))
|
||||
{
|
||||
if(w>=0)
|
||||
if(w!=-1)
|
||||
{
|
||||
slamTime.push_back(stat.at(Statistics::kTimingTotal()));
|
||||
}
|
||||
@@ -1171,9 +1194,34 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
iter->second->frameData();
|
||||
}
|
||||
iter->second->show();
|
||||
if(exportFigures)
|
||||
{
|
||||
QString data = iter->second->getAllCurveDataAsText();
|
||||
if(!data.isEmpty())
|
||||
{
|
||||
QString filePath = QString(exportPrefix.c_str()) + (exportPrefix.empty()?"":"-") + iter->second->windowTitle().replace('/', "-") + ".txt";
|
||||
QFile file(filePath);
|
||||
if(file.open(QIODevice::Text | QIODevice::WriteOnly))
|
||||
{
|
||||
file.write(data.toUtf8());
|
||||
file.close();
|
||||
printf("Exported \"%s\".\n", filePath.toStdString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ERROR: could not open file \"%s\" for writing!\n", filePath.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->second->show();
|
||||
}
|
||||
}
|
||||
if(!exportFigures)
|
||||
{
|
||||
return app.exec();
|
||||
}
|
||||
return app.exec();
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user