mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 01:20:25 +08:00
Vocabulary: Binary descriptors are saved as is even if there is a float conversion for flann
This commit is contained in:
@@ -626,6 +626,25 @@ void VWDictionary::update()
|
||||
{
|
||||
VisualWord* w = uValue(_visualWords, *iter, (VisualWord*)0);
|
||||
UASSERT(w);
|
||||
|
||||
cv::Mat descriptor;
|
||||
if(w->getDescriptor().type() == CV_8U)
|
||||
{
|
||||
useDistanceL1_ = true;
|
||||
if(_strategy == kNNFlannKdTree || _strategy == kNNFlannNaive)
|
||||
{
|
||||
w->getDescriptor().convertTo(descriptor, CV_32F);
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor = w->getDescriptor();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor = w->getDescriptor();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
if(!_flannIndex->isBuilt())
|
||||
{
|
||||
@@ -633,15 +652,15 @@ void VWDictionary::update()
|
||||
switch(_strategy)
|
||||
{
|
||||
case kNNFlannNaive:
|
||||
_flannIndex->build(w->getDescriptor(), rtflann::LinearIndexParams(), useDistanceL1_);
|
||||
_flannIndex->build(descriptor, rtflann::LinearIndexParams(), useDistanceL1_);
|
||||
break;
|
||||
case kNNFlannKdTree:
|
||||
UASSERT_MSG(w->getDescriptor().type() == CV_32F, "To use KdTree dictionary, float descriptors are required!");
|
||||
_flannIndex->build(w->getDescriptor(), rtflann::KDTreeIndexParams(), useDistanceL1_);
|
||||
UASSERT_MSG(descriptor.type() == CV_32F, "To use KdTree dictionary, float descriptors are required!");
|
||||
_flannIndex->build(descriptor, rtflann::KDTreeIndexParams(), useDistanceL1_);
|
||||
break;
|
||||
case kNNFlannLSH:
|
||||
UASSERT_MSG(w->getDescriptor().type() == CV_8U, "To use LSH dictionary, binary descriptors are required!");
|
||||
_flannIndex->build(w->getDescriptor(), rtflann::LshIndexParams(12, 20, 2), useDistanceL1_);
|
||||
UASSERT_MSG(descriptor.type() == CV_8U, "To use LSH dictionary, binary descriptors are required!");
|
||||
_flannIndex->build(descriptor, rtflann::LshIndexParams(12, 20, 2), useDistanceL1_);
|
||||
break;
|
||||
default:
|
||||
UFATAL("Not supposed to be here!");
|
||||
@@ -651,9 +670,9 @@ void VWDictionary::update()
|
||||
}
|
||||
else
|
||||
{
|
||||
UASSERT(w->getDescriptor().cols == _flannIndex->featuresDim());
|
||||
UASSERT(w->getDescriptor().type() == _flannIndex->featuresType());
|
||||
index = _flannIndex->addPoint(w->getDescriptor());
|
||||
UASSERT(descriptor.cols == _flannIndex->featuresDim());
|
||||
UASSERT(descriptor.type() == _flannIndex->featuresType());
|
||||
index = _flannIndex->addPoint(descriptor);
|
||||
}
|
||||
std::pair<std::map<int, int>::iterator, bool> inserted;
|
||||
inserted = _mapIndexId.insert(std::pair<int, int>(index, w->id()));
|
||||
@@ -698,7 +717,23 @@ void VWDictionary::update()
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
|
||||
int type = _visualWords.begin()->second->getDescriptor().type();
|
||||
int type;
|
||||
if(_visualWords.begin()->second->getDescriptor().type() == CV_8U)
|
||||
{
|
||||
useDistanceL1_ = true;
|
||||
if(_strategy == kNNFlannKdTree || _strategy == kNNFlannNaive)
|
||||
{
|
||||
type = CV_32F;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = _visualWords.begin()->second->getDescriptor().type();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = _visualWords.begin()->second->getDescriptor().type();
|
||||
}
|
||||
int dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
@@ -709,10 +744,27 @@ void VWDictionary::update()
|
||||
std::map<int, VisualWord*>::const_iterator iter = _visualWords.begin();
|
||||
for(unsigned int i=0; i < _visualWords.size(); ++i, ++iter)
|
||||
{
|
||||
UASSERT(iter->second->getDescriptor().cols == dim);
|
||||
UASSERT(iter->second->getDescriptor().type() == type);
|
||||
cv::Mat descriptor;
|
||||
if(iter->second->getDescriptor().type() == CV_8U)
|
||||
{
|
||||
if(_strategy == kNNFlannKdTree || _strategy == kNNFlannNaive)
|
||||
{
|
||||
iter->second->getDescriptor().convertTo(descriptor, CV_32F);
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor = iter->second->getDescriptor();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor = iter->second->getDescriptor();
|
||||
}
|
||||
|
||||
iter->second->getDescriptor().copyTo(_dataTree.row(i));
|
||||
UASSERT(descriptor.cols == dim);
|
||||
UASSERT(descriptor.type() == type);
|
||||
|
||||
descriptor.copyTo(_dataTree.row(i));
|
||||
_mapIndexId.insert(_mapIndexId.end(), std::pair<int, int>(i, iter->second->id()));
|
||||
_mapIdIndex.insert(_mapIdIndex.end(), std::pair<int, int>(iter->second->id(), i));
|
||||
}
|
||||
@@ -827,6 +879,42 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
{
|
||||
UASSERT(signatureId > 0);
|
||||
|
||||
UDEBUG("id=%d descriptors=%d", signatureId, descriptorsIn.rows);
|
||||
UTimer timer;
|
||||
std::list<int> wordIds;
|
||||
if(descriptorsIn.rows == 0 || descriptorsIn.cols == 0)
|
||||
{
|
||||
UERROR("Descriptors size is null!");
|
||||
return wordIds;
|
||||
}
|
||||
|
||||
if(!_incrementalDictionary && _visualWords.empty())
|
||||
{
|
||||
UERROR("Dictionary mode is set to fixed but no words are in it!");
|
||||
return wordIds;
|
||||
}
|
||||
|
||||
// verify we have the same features
|
||||
int dim = 0;
|
||||
int type = -1;
|
||||
if(_visualWords.size())
|
||||
{
|
||||
dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
type = _visualWords.begin()->second->getDescriptor().type();
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
}
|
||||
if(dim && dim != descriptorsIn.cols)
|
||||
{
|
||||
UERROR("Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", descriptorsIn.cols, dim);
|
||||
return wordIds;
|
||||
}
|
||||
if(type>=0 && type != descriptorsIn.type())
|
||||
{
|
||||
UERROR("Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", descriptorsIn.type(), type);
|
||||
return wordIds;
|
||||
}
|
||||
|
||||
// now compare with the actual index
|
||||
cv::Mat descriptors;
|
||||
if(descriptorsIn.type() == CV_8U)
|
||||
{
|
||||
@@ -844,21 +932,12 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
{
|
||||
descriptors = descriptorsIn;
|
||||
}
|
||||
|
||||
UDEBUG("id=%d descriptors=%d", signatureId, descriptors.rows);
|
||||
UTimer timer;
|
||||
std::list<int> wordIds;
|
||||
if(descriptors.rows == 0 || descriptors.cols == 0)
|
||||
dim = 0;
|
||||
type = -1;
|
||||
if(_dataTree.rows || _flannIndex->isBuilt())
|
||||
{
|
||||
UERROR("Descriptors size is null!");
|
||||
return wordIds;
|
||||
}
|
||||
int dim = 0;
|
||||
int type = -1;
|
||||
if(_visualWords.size())
|
||||
{
|
||||
dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
type = _visualWords.begin()->second->getDescriptor().type();
|
||||
dim = _flannIndex->isBuilt()?_flannIndex->featuresDim():_dataTree.cols;
|
||||
type = _flannIndex->isBuilt()?_flannIndex->featuresType():_dataTree.type();
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
}
|
||||
|
||||
@@ -867,20 +946,12 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
UERROR("Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", descriptors.cols, dim);
|
||||
return wordIds;
|
||||
}
|
||||
dim = descriptors.cols;
|
||||
|
||||
if(type>=0 && type != descriptors.type())
|
||||
{
|
||||
UERROR("Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", descriptors.type(), type);
|
||||
return wordIds;
|
||||
}
|
||||
type = descriptors.type();
|
||||
|
||||
if(!_incrementalDictionary && _visualWords.empty())
|
||||
{
|
||||
UERROR("Dictionary mode is set to fixed but no words are in it!");
|
||||
return wordIds;
|
||||
}
|
||||
|
||||
int dupWordsCountFromDict= 0;
|
||||
int dupWordsCountFromLast= 0;
|
||||
@@ -910,7 +981,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
else if(_strategy == kNNBruteForce)
|
||||
{
|
||||
bruteForce = true;
|
||||
cv::BFMatcher matcher(type==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
|
||||
cv::BFMatcher matcher(descriptors.type()==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
|
||||
matcher.knnMatch(descriptors, _dataTree, matches, k);
|
||||
}
|
||||
else if(_strategy == kNNBruteForceGPU)
|
||||
@@ -920,7 +991,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
#ifdef HAVE_OPENCV_GPU
|
||||
cv::gpu::GpuMat newDescriptorsGpu(descriptors);
|
||||
cv::gpu::GpuMat lastDescriptorsGpu(_dataTree);
|
||||
if(type==CV_8U)
|
||||
if(descriptors.type()==CV_8U)
|
||||
{
|
||||
cv::gpu::BruteForceMatcher_GPU<cv::Hamming> gpuMatcher;
|
||||
gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
|
||||
@@ -938,7 +1009,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
cv::cuda::GpuMat newDescriptorsGpu(descriptors);
|
||||
cv::cuda::GpuMat lastDescriptorsGpu(_dataTree);
|
||||
cv::Ptr<cv::cuda::DescriptorMatcher> gpuMatcher;
|
||||
if(type==CV_8U)
|
||||
if(descriptors.type()==CV_8U)
|
||||
{
|
||||
gpuMatcher = cv::cuda::DescriptorMatcher::createBFMatcher(cv::NORM_HAMMING);
|
||||
gpuMatcher->knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
|
||||
@@ -1010,7 +1081,8 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
if(_newWordsComparedTogether && newWords.rows)
|
||||
{
|
||||
std::vector<std::vector<cv::DMatch> > matchesNewWords;
|
||||
cv::BFMatcher matcher(type==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
|
||||
cv::BFMatcher matcher(descriptors.type()==CV_8U?cv::NORM_HAMMING:useDistanceL1_?cv::NORM_L1:cv::NORM_L2SQR);
|
||||
UASSERT(descriptors.cols == newWords.cols && descriptors.type() == newWords.type());
|
||||
matcher.knnMatch(descriptors.row(i), newWords, matchesNewWords, newWords.rows>1?2:1);
|
||||
UASSERT(matchesNewWords.size() == 1);
|
||||
for(unsigned int j=0; j<matchesNewWords.at(0).size(); ++j)
|
||||
@@ -1053,10 +1125,11 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptorsIn,
|
||||
|
||||
if(badDist)
|
||||
{
|
||||
VisualWord * vw = new VisualWord(getNextId(), descriptors.row(i), signatureId);
|
||||
// use original descriptor
|
||||
VisualWord * vw = new VisualWord(getNextId(), descriptorsIn.row(i), signatureId);
|
||||
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord *>(vw->id(), vw));
|
||||
_notIndexedWords.insert(_notIndexedWords.end(), vw->id());
|
||||
newWords.push_back(vw->getDescriptor());
|
||||
newWords.push_back(descriptors.row(i));
|
||||
newWordsId.push_back(vw->id());
|
||||
wordIds.push_back(vw->id());
|
||||
UASSERT(vw->id()>0);
|
||||
@@ -1103,16 +1176,16 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
|
||||
if(_visualWords.size() && vws.size())
|
||||
{
|
||||
int dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
int type = _visualWords.begin()->second->getDescriptor().type();
|
||||
int type = (*vws.begin())->getDescriptor().type();
|
||||
int dim = (*vws.begin())->getDescriptor().cols;
|
||||
|
||||
if(dim != (*vws.begin())->getDescriptor().cols)
|
||||
if(dim != _visualWords.begin()->second->getDescriptor().cols)
|
||||
{
|
||||
UERROR("Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", (*vws.begin())->getDescriptor().cols, dim);
|
||||
return std::vector<int>(vws.size(), 0);
|
||||
}
|
||||
|
||||
if(type != (*vws.begin())->getDescriptor().type())
|
||||
if(type != _visualWords.begin()->second->getDescriptor().type())
|
||||
{
|
||||
UERROR("Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", (*vws.begin())->getDescriptor().type(), type);
|
||||
return std::vector<int>(vws.size(), 0);
|
||||
@@ -1126,6 +1199,7 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
{
|
||||
vw = *iter;
|
||||
UASSERT(vw);
|
||||
|
||||
UASSERT(vw->getDescriptor().cols == dim);
|
||||
UASSERT(vw->getDescriptor().type() == type);
|
||||
|
||||
@@ -1137,25 +1211,64 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
}
|
||||
return std::vector<int>(vws.size(), 0);
|
||||
}
|
||||
std::vector<int> VWDictionary::findNN(const cv::Mat & query) const
|
||||
std::vector<int> VWDictionary::findNN(const cv::Mat & queryIn) const
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::vector<int> resultIds(query.rows, 0);
|
||||
std::vector<int> resultIds(queryIn.rows, 0);
|
||||
unsigned int k=2; // k nearest neighbor
|
||||
|
||||
if(_visualWords.size() && query.rows)
|
||||
if(_visualWords.size() && queryIn.rows)
|
||||
{
|
||||
// verify we have the same features
|
||||
int dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
int type = _visualWords.begin()->second->getDescriptor().type();
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
|
||||
if(dim != query.cols)
|
||||
if(dim != queryIn.cols)
|
||||
{
|
||||
UERROR("Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", queryIn.cols, dim);
|
||||
return resultIds;
|
||||
}
|
||||
if(type != queryIn.type())
|
||||
{
|
||||
UERROR("Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", queryIn.type(), type);
|
||||
return resultIds;
|
||||
}
|
||||
|
||||
// now compare with the actual index
|
||||
cv::Mat query;
|
||||
if(queryIn.type() == CV_8U)
|
||||
{
|
||||
if(_strategy == kNNFlannKdTree || _strategy == kNNFlannNaive)
|
||||
{
|
||||
queryIn.convertTo(query, CV_32F);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = queryIn;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = queryIn;
|
||||
}
|
||||
dim = 0;
|
||||
type = -1;
|
||||
if(_dataTree.rows || _flannIndex->isBuilt())
|
||||
{
|
||||
dim = _flannIndex->isBuilt()?_flannIndex->featuresDim():_dataTree.cols;
|
||||
type = _flannIndex->isBuilt()?_flannIndex->featuresType():_dataTree.type();
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
}
|
||||
|
||||
if(dim && dim != query.cols)
|
||||
{
|
||||
UERROR("Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", query.cols, dim);
|
||||
return resultIds;
|
||||
}
|
||||
|
||||
if(type != query.type())
|
||||
if(type>=0 && type != query.type())
|
||||
{
|
||||
UERROR("Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", query.type(), type);
|
||||
return resultIds;
|
||||
@@ -1178,7 +1291,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & query) const
|
||||
else if(_strategy == kNNBruteForce)
|
||||
{
|
||||
bruteForce = true;
|
||||
cv::BFMatcher matcher(type==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
|
||||
cv::BFMatcher matcher(query.type()==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
|
||||
matcher.knnMatch(query, _dataTree, matches, k);
|
||||
}
|
||||
else if(_strategy == kNNBruteForceGPU)
|
||||
@@ -1188,7 +1301,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & query) const
|
||||
#ifdef HAVE_OPENCV_GPU
|
||||
cv::gpu::GpuMat newDescriptorsGpu(query);
|
||||
cv::gpu::GpuMat lastDescriptorsGpu(_dataTree);
|
||||
if(type==CV_8U)
|
||||
if(query.type()==CV_8U)
|
||||
{
|
||||
cv::gpu::BruteForceMatcher_GPU<cv::Hamming> gpuMatcher;
|
||||
gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
|
||||
@@ -1206,7 +1319,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & query) const
|
||||
cv::cuda::GpuMat newDescriptorsGpu(query);
|
||||
cv::cuda::GpuMat lastDescriptorsGpu(_dataTree);
|
||||
cv::Ptr<cv::cuda::DescriptorMatcher> gpuMatcher;
|
||||
if(type==CV_8U)
|
||||
if(query.type()==CV_8U)
|
||||
{
|
||||
gpuMatcher = cv::cuda::DescriptorMatcher::createBFMatcher(cv::NORM_HAMMING);
|
||||
gpuMatcher->knnMatchAsync(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
|
||||
@@ -1240,20 +1353,38 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & query) const
|
||||
std::vector<std::vector<cv::DMatch> > matchesNotIndexed;
|
||||
if(_notIndexedWords.size())
|
||||
{
|
||||
cv::Mat dataNotIndexed = cv::Mat::zeros(_notIndexedWords.size(), dim, type);
|
||||
cv::Mat dataNotIndexed = cv::Mat::zeros(_notIndexedWords.size(), query.cols, query.type());
|
||||
unsigned int index = 0;
|
||||
VisualWord * vw;
|
||||
for(std::set<int>::iterator iter = _notIndexedWords.begin(); iter != _notIndexedWords.end(); ++iter, ++index)
|
||||
{
|
||||
vw = _visualWords.at(*iter);
|
||||
UASSERT(vw != 0 && vw->getDescriptor().cols == dim && vw->getDescriptor().type() == type);
|
||||
|
||||
cv::Mat descriptor;
|
||||
if(vw->getDescriptor().type() == CV_8U)
|
||||
{
|
||||
if(_strategy == kNNFlannKdTree || _strategy == kNNFlannNaive)
|
||||
{
|
||||
vw->getDescriptor().convertTo(descriptor, CV_32F);
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor = vw->getDescriptor();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor = vw->getDescriptor();
|
||||
}
|
||||
|
||||
UASSERT(vw != 0 && descriptor.cols == query.cols && descriptor.type() == query.type());
|
||||
vw->getDescriptor().copyTo(dataNotIndexed.row(index));
|
||||
mapIndexIdNotIndexed.insert(mapIndexIdNotIndexed.end(), std::pair<int,int>(index, vw->id()));
|
||||
}
|
||||
|
||||
// Find nearest neighbor
|
||||
ULOGGER_DEBUG("Searching in words not indexed...");
|
||||
cv::BFMatcher matcher(type==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
|
||||
cv::BFMatcher matcher(query.type()==CV_8U?cv::NORM_HAMMING:useDistanceL1_?cv::NORM_L1:cv::NORM_L2SQR);
|
||||
matcher.knnMatch(query, dataNotIndexed, matchesNotIndexed, dataNotIndexed.rows>1?2:1);
|
||||
}
|
||||
ULOGGER_DEBUG("Search not yet indexed words time = %fs", timer.ticks());
|
||||
|
||||
Reference in New Issue
Block a user