mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-03 01:50:24 +08:00
MERGE branch STM 325:449 into trunk
git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@450 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
@@ -19,15 +19,17 @@
|
||||
|
||||
#include "BayesFilter.h"
|
||||
#include "Memory.h"
|
||||
#include "Signature.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "utilite/UtiLite.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
BayesFilter::BayesFilter(const ParametersMap & parameters) :
|
||||
_virtualPlacePrior(Parameters::defaultBayesVirtualPlacePriorThr())
|
||||
_virtualPlacePrior(Parameters::defaultBayesVirtualPlacePriorThr()),
|
||||
_predictionOnNonNullActionsOnly(Parameters::defaultBayesPredictionOnNonNullActionsOnly())
|
||||
{
|
||||
this->setPredictionLC(Parameters::defaultBayesPredictionLC());
|
||||
this->parseParameters(parameters);
|
||||
@@ -47,6 +49,11 @@ void BayesFilter::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
this->setPredictionLC((*iter).second);
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kBayesPredictionOnNonNullActionsOnly())) != parameters.end())
|
||||
{
|
||||
_predictionOnNonNullActionsOnly = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BayesFilter::setVirtualPlacePrior(float virtualPlacePrior)
|
||||
@@ -73,23 +80,18 @@ void BayesFilter::setPredictionLC(const std::string & prediction)
|
||||
std::list<std::string> strValues = uSplit(prediction, ' ');
|
||||
if(strValues.size() < 2)
|
||||
{
|
||||
ULOGGER_ERROR("The number of values < 2 (prediction=\"%s\")", prediction.c_str());
|
||||
UERROR("The number of values < 2 (prediction=\"%s\")", prediction.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<double> tmpValues(strValues.size());
|
||||
int i=0;
|
||||
bool valid = true;
|
||||
float sum = 0;;
|
||||
for(std::list<std::string>::iterator iter = strValues.begin(); iter!=strValues.end(); ++iter)
|
||||
{
|
||||
tmpValues[i] = std::atof((*iter).c_str());
|
||||
sum += tmpValues[i];
|
||||
if(i>1)
|
||||
{
|
||||
sum += tmpValues[i]; // add a second time
|
||||
}
|
||||
if(tmpValues[i] < 0 || tmpValues[i]>1)
|
||||
//UINFO("%d=%e", i, tmpValues[i]);
|
||||
if(tmpValues[i] < 0.0 || tmpValues[i]>1.0)
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
@@ -97,9 +99,9 @@ void BayesFilter::setPredictionLC(const std::string & prediction)
|
||||
++i;
|
||||
}
|
||||
|
||||
if(!valid || sum <= 0 || sum > 1.001)
|
||||
if(!valid)
|
||||
{
|
||||
ULOGGER_ERROR("The prediction is not valid (the sum must be between >0 && <=1, sum=%f), negative values are not allowed (prediction=\"%s\")", sum, prediction.c_str());
|
||||
UERROR("The prediction is not valid (values must be between >0 && <=1) prediction=\"%s\"", prediction.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,7 +121,7 @@ std::string BayesFilter::getPredictionLCStr() const
|
||||
std::string values;
|
||||
for(unsigned int i=0; i<_predictionLC.size(); ++i)
|
||||
{
|
||||
values.append(uNumber2str(_predictionLC[i]));
|
||||
values.append(uNumber2Str(_predictionLC[i]));
|
||||
if(i+1 < _predictionLC.size())
|
||||
{
|
||||
values.append(" ");
|
||||
@@ -167,16 +169,10 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
// Recursive Bayes estimation...
|
||||
// STEP 1 - Prediction : Prior*lastPosterior
|
||||
prediction = cvCreateMat(likelihood.size(), likelihood.size(), CV_32FC1);
|
||||
std::map<int, int> likelihoodKeys;
|
||||
int index = 0;
|
||||
for(std::map<int, float>::const_iterator iter=likelihood.begin(); iter!=likelihood.end(); ++iter)
|
||||
{
|
||||
likelihoodKeys.insert(likelihoodKeys.end(), std::pair<int, int>(iter->first, index++));
|
||||
}
|
||||
|
||||
if(this->generatePrediction(prediction, memory, likelihoodKeys))
|
||||
if(this->generatePrediction(prediction, memory, uKeys(likelihood)))
|
||||
{
|
||||
ULOGGER_DEBUG("STEP1-generate prior=%fs, rows=%d, cols=%d", timer.ticks(), prediction->rows, prediction->cols);
|
||||
//std::cout << "Prediction=" << cv::Mat(prediction) << std::endl;
|
||||
|
||||
// Adjust the last posterior if some images were
|
||||
// reactivated or removed from the working memory
|
||||
@@ -188,12 +184,18 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
posterior->data.fl[j++] = (*i).second;
|
||||
}
|
||||
ULOGGER_DEBUG("STEP1-update posterior=%fs, posterior=%d, _posterior size=%d", posterior->rows, _posterior.size());
|
||||
//std::cout << "LastPosterior=" << cv::Mat(posterior) << std::endl;
|
||||
|
||||
// Multiply prediction matrix with the last posterior
|
||||
// (m,m) X (m,1) = (m,1)
|
||||
prior = cvCreateMat(likelihood.size(), 1, CV_32FC1);
|
||||
cvMatMul(prediction, posterior, prior);
|
||||
ULOGGER_DEBUG("STEP1-matrix mult time=%fs", timer.ticks());
|
||||
//std::cout << "ResultingPrior=" << cv::Mat(prior) << std::endl;
|
||||
|
||||
ULOGGER_DEBUG("STEP1-matrix mult time=%fs", timer.ticks());
|
||||
std::vector<float> likelihoodValues = uValues(likelihood);
|
||||
//std::cout << "Likelihood=" << cv::Mat(likelihoodValues) << std::endl;
|
||||
|
||||
// STEP 2 - Update : Multiply with observations (likelihood)
|
||||
j=0;
|
||||
@@ -231,7 +233,7 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
return _posterior;
|
||||
}
|
||||
|
||||
bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory, const std::map<int, int> & likelihoodIds) const
|
||||
bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory, const std::vector<int> & ids) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
UTimer timer;
|
||||
@@ -239,97 +241,108 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
UTimer timerGlobal;
|
||||
timerGlobal.start();
|
||||
|
||||
if(!likelihoodIds.size() ||
|
||||
if(!memory ||
|
||||
prediction == 0 ||
|
||||
prediction->rows != prediction->cols ||
|
||||
(unsigned int)prediction->rows != likelihoodIds.size()/*||
|
||||
prediction->type != CV_32FC1*/ ||
|
||||
(unsigned int)prediction->rows != ids.size() ||
|
||||
_predictionLC.size() < 2 ||
|
||||
!memory)
|
||||
!ids.size())
|
||||
{
|
||||
ULOGGER_ERROR( "fail");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<int, int> idToIndexMap;
|
||||
for(unsigned int i=0; i<ids.size(); ++i)
|
||||
{
|
||||
if(ids[i] == 0)
|
||||
{
|
||||
UFATAL("Signature id is null ?!?");
|
||||
}
|
||||
idToIndexMap.insert(idToIndexMap.end(), std::make_pair(ids[i], i));
|
||||
}
|
||||
|
||||
//int rows = prediction->rows;
|
||||
cvSetZero(prediction);
|
||||
int cols = prediction->cols;
|
||||
|
||||
// Each priors are column vectors
|
||||
unsigned int i=0;
|
||||
// Each prior is a column vector
|
||||
ULOGGER_DEBUG("_predictionLC.size()=%d",_predictionLC.size());
|
||||
for(std::map<int, int>::const_iterator iter=likelihoodIds.begin(); iter!=likelihoodIds.end(); ++iter)
|
||||
for(unsigned int i=0; i<ids.size(); ++i)
|
||||
{
|
||||
if(iter->first > 0)
|
||||
int loopSignId = ids[i];
|
||||
if(loopSignId > 0)
|
||||
{
|
||||
// Create the sum of 2 gaussians around the loop closure
|
||||
|
||||
int loopClosureId = iter->first;
|
||||
|
||||
// Set high values (gaussians curves) to loop closure neighbors
|
||||
const Signature * loopSign = memory->getSignature(loopClosureId);
|
||||
if(!loopSign)
|
||||
|
||||
float sum = 0.0f; // sum values added
|
||||
|
||||
float totalModelValues = 0.0f;
|
||||
for(unsigned int j=0; j<_predictionLC.size(); ++j)
|
||||
{
|
||||
ULOGGER_ERROR("loopSign %d is not found?!?", loopClosureId);
|
||||
totalModelValues += _predictionLC[j];
|
||||
}
|
||||
|
||||
// LoopID
|
||||
prediction->data.fl[i + i*cols] += _predictionLC[1];
|
||||
|
||||
// look up for each neighbors (RECURSIVE)
|
||||
this->addNeighborProb(prediction, i, memory, likelihoodIds, loopSign, 1);
|
||||
|
||||
//ULOGGER_DEBUG("neighbor prob for %d, neighbors=%d, time = %fs", loopSign->id(), loopSign->getNeighborIds().size(), timer.ticks());
|
||||
|
||||
float totalModelValues = _predictionLC[0] + _predictionLC[1];
|
||||
for(unsigned int j=2; j<_predictionLC.size(); ++j)
|
||||
// ADD prob for each neighbors
|
||||
double dbAccessTime = 0.0;
|
||||
std::map<int, int> neighbors = memory->getNeighborsId(dbAccessTime, loopSignId, _predictionLC.size()-1, 0, _predictionOnNonNullActionsOnly);
|
||||
sum += this->addNeighborProb(prediction, i, neighbors, idToIndexMap);
|
||||
// ADD values of not found neighbors to loop closure
|
||||
if(sum < totalModelValues-_predictionLC[0])
|
||||
{
|
||||
totalModelValues += _predictionLC[j]*2;
|
||||
float delta = totalModelValues-_predictionLC[0]-sum;
|
||||
prediction->data.fl[i + i*cols] += delta;
|
||||
sum+=delta;
|
||||
}
|
||||
|
||||
//Add values of not found neighbors to the loop closure
|
||||
float sum = 0;
|
||||
for(int j=0; j<cols; ++j)
|
||||
float allOtherPlacesValue = 0;
|
||||
if(totalModelValues < 1)
|
||||
{
|
||||
sum += prediction->data.fl[i + j*cols];
|
||||
}
|
||||
if(sum < (totalModelValues-_predictionLC[0]))
|
||||
{
|
||||
float gap = (totalModelValues-_predictionLC[0]) - sum;
|
||||
prediction->data.fl[i + i*cols] += gap;
|
||||
sum += gap;
|
||||
}
|
||||
|
||||
// add virtual place prob
|
||||
if(likelihoodIds.begin()->first < 0)
|
||||
{
|
||||
sum += prediction->data.fl[i] = _predictionLC[0];
|
||||
allOtherPlacesValue = 1.0f - totalModelValues;
|
||||
}
|
||||
|
||||
// Set all loop events to small values according to the model
|
||||
if(totalModelValues < 1.0f)
|
||||
if(allOtherPlacesValue > 0 && cols>1)
|
||||
{
|
||||
float value = (1.0f-totalModelValues) / float(cols);
|
||||
for(int j=0; j<cols; ++j)
|
||||
float value = allOtherPlacesValue / float(cols - 1);
|
||||
for(int j=ids[0] < 0?1:0; j<cols; ++j)
|
||||
{
|
||||
if(!prediction->data.fl[i + j*cols])
|
||||
if(prediction->data.fl[i + j*cols] == 0)
|
||||
{
|
||||
sum += prediction->data.fl[i + j*cols] = value;
|
||||
prediction->data.fl[i + j*cols] = value;
|
||||
sum += prediction->data.fl[i + j*cols];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//normalize this row,
|
||||
for(int j=0; j<cols; ++j)
|
||||
//normalize this row
|
||||
float maxNorm = 1 - (ids[0]<0?_predictionLC[0]:0); // 1 - virtual place probability
|
||||
if(sum<maxNorm-0.0001 || sum>maxNorm+0.0001)
|
||||
{
|
||||
prediction->data.fl[i + j*cols] /= sum;
|
||||
for(int j=ids[0] < 0?1:0; j<cols; ++j)
|
||||
{
|
||||
prediction->data.fl[i + j*cols] *= maxNorm / sum;
|
||||
}
|
||||
sum = maxNorm;
|
||||
}
|
||||
|
||||
// ADD virtual place prob
|
||||
if(ids[0] < 0)
|
||||
{
|
||||
prediction->data.fl[i] = _predictionLC[0];
|
||||
sum += prediction->data.fl[i];
|
||||
}
|
||||
|
||||
//debug
|
||||
//for(int j=0; j<cols; ++j)
|
||||
//{
|
||||
// ULOGGER_DEBUG("test = %f", prediction->data.fl[i + j*cols]);
|
||||
// ULOGGER_DEBUG("test col=%d = %f", i, prediction->data.fl[i + j*cols]);
|
||||
//}
|
||||
|
||||
if(sum<0.99 || sum > 1.01)
|
||||
{
|
||||
UWARN("Prediction is not normalized sum=%f", sum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -368,7 +381,6 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("time = %fs", timerGlobal.ticks());
|
||||
@@ -402,57 +414,21 @@ void BayesFilter::updatePosterior(const Memory * memory, const std::vector<int>
|
||||
_posterior = newPosterior;
|
||||
}
|
||||
|
||||
//recursive...
|
||||
float BayesFilter::addNeighborProb(CvMat * prediction, unsigned int row, const Memory * memory, const std::map<int, int> & likelihoodIds, const Signature * s, unsigned int level) const
|
||||
float BayesFilter::addNeighborProb(CvMat * prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const
|
||||
{
|
||||
if(!likelihoodIds.size() ||
|
||||
prediction == 0 ||
|
||||
prediction->rows != prediction->cols ||
|
||||
(unsigned int)prediction->rows != likelihoodIds.size() ||
|
||||
_predictionLC.size() < 2 ||
|
||||
!memory ||
|
||||
!prediction ||
|
||||
level<1)
|
||||
if((unsigned int)prediction->cols != idToIndexMap.size() ||
|
||||
(unsigned int)prediction->rows != idToIndexMap.size())
|
||||
{
|
||||
ULOGGER_ERROR( "fail");
|
||||
return 0;
|
||||
UFATAL("Requirements no met");
|
||||
}
|
||||
|
||||
if(level+1 >= _predictionLC.size() || !s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double value = _predictionLC[level+1];
|
||||
float sum=0;
|
||||
|
||||
const NeighborsMap & neighbors = s->getNeighbors();
|
||||
for(NeighborsMap::const_iterator iter=neighbors.begin(); iter!= neighbors.end(); ++iter)
|
||||
for(std::map<int, int>::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
int index = uValue(likelihoodIds, iter->first, -1);
|
||||
int index = uValue(idToIndexMap, iter->first, -1);
|
||||
if(index >= 0)
|
||||
{
|
||||
bool alreadyAdded = false;
|
||||
// the value can be already added in the recursion
|
||||
if(value > prediction->data.fl[row + index*prediction->cols])
|
||||
{
|
||||
sum -= prediction->data.fl[row + index*prediction->cols];
|
||||
prediction->data.fl[row + index*prediction->cols] = value;
|
||||
sum += value;
|
||||
}
|
||||
else
|
||||
{
|
||||
alreadyAdded = true;
|
||||
}
|
||||
|
||||
if(!alreadyAdded && level+1 < _predictionLC.size())
|
||||
{
|
||||
sum += addNeighborProb(prediction, row, memory, likelihoodIds, memory->getSignature(iter->first), level+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//ULOGGER_DEBUG("BayesFilter::generatePrediction(...) F (id %d) Not found for loop %d", loopSign->getNeighborForward(), loopClosureId);
|
||||
sum += prediction->data.fl[col + index*prediction->cols] = _predictionLC[iter->second+1];
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
|
||||
@@ -51,17 +51,19 @@ public:
|
||||
float getVirtualPlacePrior() const {return _virtualPlacePrior;}
|
||||
const std::vector<double> & getPredictionLC() const; // {Vp, Lc, l1, l2, l3, l4...}
|
||||
std::string getPredictionLCStr() const; // for convenience {Vp, Lc, l1, l2, l3, l4...}
|
||||
bool isPredictionOnNonNullActionsOnly() const {return _predictionOnNonNullActionsOnly;}
|
||||
|
||||
bool generatePrediction(CvMat * prediction, const Memory * memory, const std::map<int, int> & likelihoodIds) const;
|
||||
float addNeighborProb(CvMat * prediction, unsigned int row, const Memory * memory, const std::map<int, int> & likelihoodIds, const Signature * s, unsigned int level) const;
|
||||
bool generatePrediction(CvMat * prediction, const Memory * memory, const std::vector<int> & ids) const;
|
||||
|
||||
private:
|
||||
void updatePosterior(const Memory * memory, const std::vector<int> & likelihoodIds);
|
||||
float addNeighborProb(CvMat * prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const;
|
||||
|
||||
private:
|
||||
std::map<int, float> _posterior;
|
||||
float _virtualPlacePrior;
|
||||
std::vector<double> _predictionLC; // {Vp, Lc, l1, l2, l3, l4...}
|
||||
bool _predictionOnNonNullActionsOnly;
|
||||
};
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -21,30 +21,109 @@ SET(SRC_FILES
|
||||
KeypointDescriptor.cpp
|
||||
VerifyHypotheses.cpp
|
||||
NearestNeighbor.cpp
|
||||
ColorTable.cpp
|
||||
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${UTILITE_INCLUDE_DIR}
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
${SQLITE3_INCLUDE_DIR}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
SET(LIBRARIES
|
||||
${UTILITE_LIBRARY}
|
||||
${UTILITE_LIBRARIES}
|
||||
${OpenCV_LIBS}
|
||||
${SQLITE3_LIBRARY}
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
####################################
|
||||
# Generate resources files
|
||||
####################################
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/DatabaseSchema_sql.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql
|
||||
COMMENT "[Creating resources]"
|
||||
COMMENT "[Creating database resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql
|
||||
)
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes65536_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes65536.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes65536.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes1024_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes1024.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes1024.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes512_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes512.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes512.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes256_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes256.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes256.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes128_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes128.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes128.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes64_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes64.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes64.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes32_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes32.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes32.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes16_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes16.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes16.bin.zip
|
||||
)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes8_bin_zip.h
|
||||
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes8.bin.zip
|
||||
COMMENT "[Creating color table resource]"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/ColorIndexes8.bin.zip
|
||||
)
|
||||
SET(RESOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/DatabaseSchema_sql.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes65536_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes1024_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes512_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes256_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes128_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes64_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes32_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes16_bin_zip.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ColorIndexes8_bin_zip.h
|
||||
)
|
||||
|
||||
####################################
|
||||
# Generate resources files END
|
||||
####################################
|
||||
|
||||
|
||||
# Make sure the compiler can find include files from our library.
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
|
||||
@@ -58,7 +137,7 @@ ENDIF(WIN32)
|
||||
|
||||
# Add binary that is built from the source file "main.cpp".
|
||||
# The extension is automatically found.
|
||||
ADD_LIBRARY(corelib ${SRC_FILES} ${CMAKE_CURRENT_BINARY_DIR}/DatabaseSchema_sql.h)
|
||||
ADD_LIBRARY(corelib ${SRC_FILES} ${RESOURCES})
|
||||
TARGET_LINK_LIBRARIES(corelib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES(
|
||||
|
||||
@@ -54,10 +54,10 @@ CamKeypointTreatment::~CamKeypointTreatment()
|
||||
}
|
||||
void CamKeypointTreatment::process(SMState * smState) const
|
||||
{
|
||||
if(smState && smState->getImage() && smState->getKeypoints().size() == 0 && smState->getSensors().size() == 0)
|
||||
if(_keypointDetector && _keypointDescriptor && smState && smState->getImage() && smState->getKeypoints().size() == 0 && smState->getSensors().empty())
|
||||
{
|
||||
std::list<cv::KeyPoint> keypoints = _keypointDetector->generateKeypoints(smState->getImage());
|
||||
std::list<std::vector<float> > descriptors = _keypointDescriptor->generateDescriptors(smState->getImage(), keypoints);
|
||||
std::vector<cv::KeyPoint> keypoints = _keypointDetector->generateKeypoints(smState->getImage());
|
||||
cv::Mat descriptors = _keypointDescriptor->generateDescriptors(smState->getImage(), keypoints);
|
||||
smState->setSensors(descriptors);
|
||||
smState->setKeypoints(keypoints);
|
||||
}
|
||||
@@ -90,6 +90,9 @@ void CamKeypointTreatment::parseParameters(const ParametersMap & parameters)
|
||||
case kDetectorSift:
|
||||
_keypointDetector = new SIFTDetector(parameters);
|
||||
break;
|
||||
case kDetectorFast:
|
||||
_keypointDetector = new FASTDetector(parameters);
|
||||
break;
|
||||
case kDetectorSurf:
|
||||
default:
|
||||
_keypointDetector = new SURFDetector(parameters);
|
||||
@@ -117,20 +120,17 @@ void CamKeypointTreatment::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
switch(descriptorStrategy)
|
||||
{
|
||||
case kDescriptorColorSurf:
|
||||
// see decorator pattern...
|
||||
_keypointDescriptor = new ColorDescriptor(parameters, new SURFDescriptor(parameters));
|
||||
break;
|
||||
case kDescriptorLaplacianSurf:
|
||||
// see decorator pattern...
|
||||
_keypointDescriptor = new LaplacianDescriptor(parameters, new SURFDescriptor(parameters));
|
||||
break;
|
||||
case kDescriptorSift:
|
||||
_keypointDescriptor = new SIFTDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorHueSurf:
|
||||
// see decorator pattern...
|
||||
_keypointDescriptor = new HueDescriptor(parameters, new SURFDescriptor(parameters));
|
||||
case kDescriptorBrief:
|
||||
_keypointDescriptor = new BRIEFDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorColor:
|
||||
_keypointDescriptor = new ColorDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorHue:
|
||||
_keypointDescriptor = new HueDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorSurf:
|
||||
default:
|
||||
@@ -174,12 +174,25 @@ Camera::Camera(float imageRate,
|
||||
UEventsManager::addHandler(this);
|
||||
}
|
||||
|
||||
Camera::~Camera(void)
|
||||
Camera::~Camera()
|
||||
{
|
||||
this->kill();
|
||||
join(true);
|
||||
delete _postThreatement;
|
||||
}
|
||||
|
||||
SMState * Camera::takeSMState()
|
||||
{
|
||||
std::list<std::vector<float> > actions;
|
||||
IplImage * img = this->takeImage(&actions);
|
||||
if(img)
|
||||
{
|
||||
SMState * smState = new SMState(cv::Mat(), actions);
|
||||
smState->setImage(img);
|
||||
return smState;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Camera::mainLoop()
|
||||
{
|
||||
State state = kStateCapturing;
|
||||
@@ -231,36 +244,6 @@ void Camera::pushNewState(State newState, const ParametersMap & parameters)
|
||||
|
||||
void Camera::handleEvent(UEvent* anEvent)
|
||||
{
|
||||
if(anEvent->getClassName().compare("CameraEvent") == 0)
|
||||
{
|
||||
CameraEvent * cameraEvent = (CameraEvent*)anEvent;
|
||||
if(cameraEvent->getCode() == CameraEvent::kCodeCtrl)
|
||||
{
|
||||
CameraEvent::Cmd cmd = cameraEvent->getCommand();
|
||||
|
||||
if(cmd == CameraEvent::kCmdPause)
|
||||
{
|
||||
if(this->isRunning())
|
||||
{
|
||||
this->kill();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
}
|
||||
else if(cmd == CameraEvent::kCmdChangeParam)
|
||||
{
|
||||
// TODO : Put in global Parameters ?
|
||||
_imageRate = cameraEvent->getImageRate();
|
||||
_autoRestart = cameraEvent->getAutoRestart();
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_DEBUG("Camera::handleEvent(Util::Event* anEvent) : command undefined...");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(anEvent->getClassName().compare("ParamEvent") == 0)
|
||||
{
|
||||
if(this->isIdle())
|
||||
@@ -281,7 +264,7 @@ void Camera::process()
|
||||
{
|
||||
UTimer timer;
|
||||
ULOGGER_DEBUG("Camera::process()");
|
||||
SMState * smState = this->takeImage();
|
||||
SMState * smState = this->takeSMState();
|
||||
if(smState)
|
||||
{
|
||||
_postThreatement->process(smState);
|
||||
@@ -336,7 +319,7 @@ CameraImages::CameraImages(const std::string & path,
|
||||
|
||||
CameraImages::~CameraImages(void)
|
||||
{
|
||||
this->kill();
|
||||
join(true);
|
||||
if(_dir)
|
||||
{
|
||||
delete _dir;
|
||||
@@ -361,11 +344,19 @@ bool CameraImages::init()
|
||||
{
|
||||
ULOGGER_ERROR("Directory path not valid \"%s\"", _path.c_str());
|
||||
}
|
||||
else if(_dir->getFileNames().size() == 0)
|
||||
{
|
||||
UWARN("Directory is empty \"%s\"", _path.c_str());
|
||||
}
|
||||
return _dir != 0;
|
||||
}
|
||||
|
||||
SMState * CameraImages::takeImage()
|
||||
IplImage * CameraImages::takeImage(std::list<std::vector<float> > * actions)
|
||||
{
|
||||
if(actions)
|
||||
{
|
||||
actions->clear();
|
||||
}
|
||||
IplImage * img = 0;
|
||||
if(_dir)
|
||||
{
|
||||
@@ -406,6 +397,10 @@ SMState * CameraImages::takeImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Directory is not set, camera must be initialized.");
|
||||
}
|
||||
if(img &&
|
||||
getImageWidth() &&
|
||||
getImageHeight() &&
|
||||
@@ -422,11 +417,7 @@ SMState * CameraImages::takeImage()
|
||||
cvReleaseImage(&img);
|
||||
img = resampledImg;
|
||||
}
|
||||
if(img)
|
||||
{
|
||||
return new SMState(img);
|
||||
}
|
||||
return 0;
|
||||
return img;
|
||||
}
|
||||
|
||||
|
||||
@@ -461,7 +452,7 @@ CameraVideo::CameraVideo(const std::string & fileName,
|
||||
|
||||
CameraVideo::~CameraVideo()
|
||||
{
|
||||
this->kill();
|
||||
join(true);
|
||||
if(_capture)
|
||||
{
|
||||
cvReleaseCapture(&_capture);
|
||||
@@ -503,8 +494,12 @@ bool CameraVideo::init()
|
||||
return true;
|
||||
}
|
||||
|
||||
SMState * CameraVideo::takeImage()
|
||||
IplImage * CameraVideo::takeImage(std::list<std::vector<float> > * actions)
|
||||
{
|
||||
if(actions)
|
||||
{
|
||||
actions->clear();
|
||||
}
|
||||
IplImage * img = 0; // Null image
|
||||
if(_capture)
|
||||
{
|
||||
@@ -528,9 +523,9 @@ SMState * CameraVideo::takeImage()
|
||||
getImageHeight() != (unsigned int)img->height)
|
||||
{
|
||||
// declare a destination IplImage object with correct size, depth and channels
|
||||
IplImage * resampledImg = cvCreateImage( cvSize((int)(getImageWidth()) ,
|
||||
(int)(getImageHeight()) ),
|
||||
img->depth, img->nChannels );
|
||||
IplImage * resampledImg = cvCreateImage( cvSize((int)(getImageWidth()),(int)(getImageHeight())),
|
||||
img->depth,
|
||||
img->nChannels );
|
||||
|
||||
//use cvResize to resize source to a destination image (linear interpolation)
|
||||
cvResize(img, resampledImg);
|
||||
@@ -541,11 +536,7 @@ SMState * CameraVideo::takeImage()
|
||||
img = cvCloneImage(img);
|
||||
}
|
||||
|
||||
if(img)
|
||||
{
|
||||
return new SMState(img);
|
||||
}
|
||||
return 0;
|
||||
return img;
|
||||
}
|
||||
|
||||
|
||||
@@ -558,14 +549,14 @@ SMState * CameraVideo::takeImage()
|
||||
// CameraDatabase
|
||||
/////////////////////////
|
||||
CameraDatabase::CameraDatabase(const std::string & path,
|
||||
bool ignoreChildren,
|
||||
bool loadActions,
|
||||
float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight),
|
||||
_path(path),
|
||||
_ignoreChildren(ignoreChildren),
|
||||
_loadActions(loadActions),
|
||||
_indexIter(_ids.begin()),
|
||||
_dbDriver(0)
|
||||
{
|
||||
@@ -573,7 +564,7 @@ CameraDatabase::CameraDatabase(const std::string & path,
|
||||
|
||||
CameraDatabase::~CameraDatabase(void)
|
||||
{
|
||||
this->kill();
|
||||
join(true);
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->closeConnection();
|
||||
@@ -614,37 +605,41 @@ bool CameraDatabase::init()
|
||||
return true;
|
||||
}
|
||||
|
||||
SMState * CameraDatabase::takeImage()
|
||||
IplImage * CameraDatabase::takeImage(std::list<std::vector<float> > * actions)
|
||||
{
|
||||
if(actions)
|
||||
{
|
||||
actions->clear();
|
||||
}
|
||||
IplImage * img = 0;
|
||||
if(_dbDriver && _indexIter != _ids.end())
|
||||
{
|
||||
if(_ignoreChildren)
|
||||
// Get image
|
||||
_dbDriver->getImage(*_indexIter, &img);
|
||||
|
||||
// Get actions from its previous neighbor
|
||||
if(actions && _loadActions)
|
||||
{
|
||||
bool ignore = true;
|
||||
while(img == 0 && _indexIter != _ids.end() && ignore)
|
||||
if(*_indexIter-1 > 0)
|
||||
{
|
||||
ignore = false;
|
||||
int loopId = 0;
|
||||
if(_dbDriver->getLoopClosureId(*_indexIter, loopId))
|
||||
NeighborsMultiMap neighbors;
|
||||
_dbDriver->loadNeighbors(*_indexIter-1, neighbors);
|
||||
for(NeighborsMultiMap::iterator iter = neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
if(loopId == *_indexIter+1)
|
||||
if(iter->first>*_indexIter-1 && iter->second.actions().size())
|
||||
{
|
||||
ignore = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbDriver->getImage(*_indexIter, &img);
|
||||
*actions = iter->second.actions();
|
||||
break;
|
||||
}
|
||||
}
|
||||
++_indexIter;
|
||||
if(actions->size() == 0)
|
||||
{
|
||||
UWARN("actions from previous %d to current %d are null", *_indexIter-1, *_indexIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbDriver->getImage(*_indexIter, &img);
|
||||
++_indexIter;
|
||||
}
|
||||
|
||||
++_indexIter;
|
||||
}
|
||||
else if(!_dbDriver)
|
||||
{
|
||||
@@ -672,27 +667,7 @@ SMState * CameraDatabase::takeImage()
|
||||
img = resampledImg;
|
||||
}
|
||||
|
||||
if(img)
|
||||
{
|
||||
SMState * smState = new SMState(img);
|
||||
if(_dbDriver && _indexIter!=_ids.begin())
|
||||
{
|
||||
std::set<int>::iterator iter = _indexIter;
|
||||
--iter;
|
||||
std::map<int, std::list<std::vector<float> > > neighbors;
|
||||
_dbDriver->loadNeighbors(*iter, neighbors);
|
||||
for(std::map<int, std::list<std::vector<float> > >::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
|
||||
{
|
||||
if(i->first > *iter && i->second.size())
|
||||
{
|
||||
smState->setActuators(i->second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return smState;
|
||||
}
|
||||
return 0;
|
||||
return img;
|
||||
}
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
67723
corelib/src/ColorTable.cpp
Normal file
67723
corelib/src/ColorTable.cpp
Normal file
File diff suppressed because it is too large
Load Diff
40
corelib/src/ColorTable.h
Normal file
40
corelib/src/ColorTable.h
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
#ifndef COLORTABLE_H
|
||||
#define COLORTABLE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
class ColorTable
|
||||
{
|
||||
public:
|
||||
ColorTable(int size);
|
||||
virtual ~ColorTable() {}
|
||||
|
||||
static unsigned char INDEXED_TABLE_8[24];
|
||||
static unsigned char INDEXED_TABLE_16[48];
|
||||
static unsigned char INDEXED_TABLE_32[96];
|
||||
static unsigned char INDEXED_TABLE_64[192];
|
||||
static unsigned char INDEXED_TABLE_128[384];
|
||||
static unsigned char INDEXED_TABLE_256[768];
|
||||
static unsigned char INDEXED_TABLE_512[1536];
|
||||
static unsigned char INDEXED_TABLE_1024[3076];
|
||||
static unsigned char INDEXED_TABLE_65536[196608];
|
||||
|
||||
int size() const {return _size;}
|
||||
unsigned short getIndex(unsigned char r, unsigned char g, unsigned char b) const;
|
||||
void getRgb(unsigned short index, unsigned char & r, unsigned char & g, unsigned char & b) const;
|
||||
|
||||
unsigned short getNNIndex(unsigned char r, unsigned char g, unsigned char b) const;
|
||||
void getNNRgb(unsigned short index, unsigned char & r, unsigned char & g, unsigned char & b) const;
|
||||
|
||||
private:
|
||||
int _size;
|
||||
std::vector<unsigned short> _rgb2indexed;
|
||||
unsigned char * _indexedTable;
|
||||
};
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
#endif // COLORTABLE_H
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
|
||||
#include "Signature.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include "utilite/UMath.h"
|
||||
@@ -32,6 +32,7 @@ namespace rtabmap {
|
||||
DBDriver::DBDriver(const ParametersMap & parameters) :
|
||||
_minSignaturesToSave(Parameters::defaultDbMinSignaturesToSave()),
|
||||
_minWordsToSave(Parameters::defaultDbMinWordsToSave()),
|
||||
_imagesCompressed(Parameters::defaultDbImagesCompressed()),
|
||||
_asyncWaiting(true),
|
||||
_emptyTrashesTime(0)
|
||||
{
|
||||
@@ -40,7 +41,7 @@ DBDriver::DBDriver(const ParametersMap & parameters) :
|
||||
|
||||
DBDriver::~DBDriver()
|
||||
{
|
||||
this->kill();
|
||||
join(true);
|
||||
this->emptyTrashes();
|
||||
}
|
||||
|
||||
@@ -55,24 +56,31 @@ void DBDriver::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
_minWordsToSave = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kDbImagesCompressed())) != parameters.end())
|
||||
{
|
||||
_imagesCompressed = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void DBDriver::closeConnection()
|
||||
{
|
||||
this->kill();
|
||||
UDEBUG("isRunning=%d", this->isRunning());
|
||||
this->join(true);
|
||||
UDEBUG("");
|
||||
this->emptyTrashes();
|
||||
_dbSafeAccessMutex.lock();
|
||||
this->disconnectDatabaseQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
bool DBDriver::openConnection(const std::string & url)
|
||||
bool DBDriver::openConnection(const std::string & url, bool overwritten)
|
||||
{
|
||||
UDEBUG("");
|
||||
_url = url;
|
||||
_dbSafeAccessMutex.lock();
|
||||
if(this->connectDatabaseQuery(url))
|
||||
if(this->connectDatabaseQuery(url, overwritten))
|
||||
{
|
||||
this->start();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
@@ -103,6 +111,7 @@ void DBDriver::mainLoop()
|
||||
{
|
||||
UDEBUG("");
|
||||
this->emptyTrashes();
|
||||
UDEBUG("");
|
||||
this->kill(); // Do it only once
|
||||
UDEBUG("");
|
||||
}
|
||||
@@ -243,19 +252,15 @@ bool DBDriver::getSignature(int signatureId, Signature ** s)
|
||||
*s = 0;
|
||||
_trashesMutex.lock();
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
for(std::map<int, Signature*>::iterator i=_trashSignatures.begin(); i!=_trashSignatures.end();)
|
||||
if(_trashSignatures.size())
|
||||
{
|
||||
if(i->first == signatureId)
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
std::map<int, Signature*>::iterator iter =_trashSignatures.find(signatureId);
|
||||
if(iter != _trashSignatures.end())
|
||||
{
|
||||
*s = i->second;
|
||||
_trashSignatures.erase(i++);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
*s = iter->second;
|
||||
_trashSignatures.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,15 +283,15 @@ bool DBDriver::getVisualWord(int wordId, VisualWord ** vw)
|
||||
*vw = 0;
|
||||
_trashesMutex.lock();
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
for(std::map<int, VisualWord*>::iterator i=_trashVisualWords.begin(); i!=_trashVisualWords.end(); ++i)
|
||||
if(_trashVisualWords.size())
|
||||
{
|
||||
if((*i).first == wordId)
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
std::map<int, VisualWord*>::iterator iter = _trashVisualWords.find(wordId);
|
||||
if(iter != _trashVisualWords.end())
|
||||
{
|
||||
*vw = (*i).second;
|
||||
_trashVisualWords.erase(i);
|
||||
break;
|
||||
*vw = iter->second;
|
||||
_trashVisualWords.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,7 +313,7 @@ bool DBDriver::getVisualWord(int wordId, VisualWord ** vw)
|
||||
bool DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<KeypointSignature *> toSaveK;
|
||||
std::list<Signature *> toSave;
|
||||
std::list<Signature *> toUpdate;
|
||||
if(this->isConnected() && signatures.size())
|
||||
{
|
||||
@@ -318,13 +323,9 @@ bool DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures) const
|
||||
{
|
||||
toUpdate.push_back(*i);
|
||||
}
|
||||
else if((*i)->signatureType().compare("KeypointSignature") == 0)
|
||||
{
|
||||
toSaveK.push_back((KeypointSignature *)(*i));
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("Unknown signature type ?!?");
|
||||
toSave.push_back(*i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,9 +333,9 @@ bool DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures) const
|
||||
{
|
||||
this->updateQuery(toUpdate);
|
||||
}
|
||||
if(toSaveK.size())
|
||||
if(toSave.size())
|
||||
{
|
||||
this->saveQuery(toSaveK);
|
||||
this->saveQuery(toSave);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -358,7 +359,7 @@ bool DBDriver::loadLastSignatures(std::list<Signature *> & signatures) const
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBDriver::loadKeypointSignatures(const std::list<int> & signIds, std::list<Signature *> & signatures, bool onlyParents)
|
||||
bool DBDriver::loadKeypointSignatures(const std::list<int> & signIds, std::list<Signature *> & signatures)
|
||||
{
|
||||
UDEBUG("");
|
||||
// look up in the trash before the database
|
||||
@@ -376,15 +377,9 @@ bool DBDriver::loadKeypointSignatures(const std::list<int> & signIds, std::list<
|
||||
{
|
||||
if(sIter->first == *iter)
|
||||
{
|
||||
if((onlyParents && sIter->second->getLoopClosureId() == 0) || !onlyParents)
|
||||
{
|
||||
signatures.push_back(sIter->second);
|
||||
_trashSignatures.erase(sIter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++sIter;
|
||||
}
|
||||
signatures.push_back(sIter->second);
|
||||
_trashSignatures.erase(sIter++);
|
||||
|
||||
valueFound = true;
|
||||
break;
|
||||
}
|
||||
@@ -409,7 +404,64 @@ bool DBDriver::loadKeypointSignatures(const std::list<int> & signIds, std::list<
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->loadKeypointSignaturesQuery(ids, signatures, onlyParents);
|
||||
r = this->loadKeypointSignaturesQuery(ids, signatures);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
else if(signatures.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO the same code of method loadKeypointSignatures() above is used here
|
||||
bool DBDriver::loadSMSignatures(const std::list<int> & signIds, std::list<Signature *> & signatures)
|
||||
{
|
||||
UDEBUG("");
|
||||
// look up in the trash before the database
|
||||
std::list<int> ids = signIds;
|
||||
std::list<Signature*>::iterator sIter;
|
||||
bool valueFound = false;
|
||||
_trashesMutex.lock();
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
for(std::list<int>::iterator iter = ids.begin(); iter != ids.end();)
|
||||
{
|
||||
valueFound = false;
|
||||
for(std::map<int, Signature*>::iterator sIter = _trashSignatures.begin(); sIter!=_trashSignatures.end();)
|
||||
{
|
||||
if(sIter->first == *iter)
|
||||
{
|
||||
signatures.push_back(sIter->second);
|
||||
_trashSignatures.erase(sIter++);
|
||||
|
||||
valueFound = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
++sIter;
|
||||
}
|
||||
}
|
||||
if(valueFound)
|
||||
{
|
||||
iter = ids.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
UDEBUG("");
|
||||
if(ids.size())
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->loadSMSignaturesQuery(ids, signatures);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
@@ -429,23 +481,27 @@ bool DBDriver::loadWords(const std::list<int> & wordIds, std::list<VisualWord *>
|
||||
// look up in the trash before the database
|
||||
std::list<int> ids = wordIds;
|
||||
std::map<int, VisualWord*>::iterator wIter;
|
||||
std::list<VisualWord *> puttedBack;
|
||||
_trashesMutex.lock();
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
for(std::list<int>::iterator iter = ids.begin(); iter != ids.end();)
|
||||
if(_trashVisualWords.size())
|
||||
{
|
||||
wIter = _trashVisualWords.find(*iter);
|
||||
if(wIter != _trashVisualWords.end())
|
||||
_dbSafeAccessMutex.lock();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
for(std::list<int>::iterator iter = ids.begin(); iter != ids.end();)
|
||||
{
|
||||
//UDEBUG("put back word %d from trash", *iter);
|
||||
vws.push_back(wIter->second);
|
||||
_trashVisualWords.erase(wIter);
|
||||
iter = ids.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
wIter = _trashVisualWords.find(*iter);
|
||||
if(wIter != _trashVisualWords.end())
|
||||
{
|
||||
UDEBUG("put back word %d from trash", *iter);
|
||||
puttedBack.push_back(wIter->second);
|
||||
_trashVisualWords.erase(wIter);
|
||||
iter = ids.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,10 +512,12 @@ bool DBDriver::loadWords(const std::list<int> & wordIds, std::list<VisualWord *>
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->loadWordsQuery(ids, vws);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
uAppend(vws, puttedBack);
|
||||
return r;
|
||||
}
|
||||
else if(vws.size())
|
||||
else if(puttedBack.size())
|
||||
{
|
||||
uAppend(vws, puttedBack);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -571,78 +629,27 @@ bool DBDriver::deleteUnreferencedWords() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBDriver::addNeighbor(int id, int newNeighbor, int oldNeighbor)
|
||||
{
|
||||
bool r = false;
|
||||
Signature * s = 0;
|
||||
_trashesMutex.lock();
|
||||
s = uValue(_trashSignatures, id, s);
|
||||
if(s)
|
||||
{
|
||||
std::list<std::vector<float> > actions = uValue(s->getNeighbors(), oldNeighbor, std::list<std::vector<float> >());
|
||||
s->addNeighbor(newNeighbor, actions);
|
||||
r = true;
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
|
||||
if(!r)
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->addNeighborQuery(id, newNeighbor, oldNeighbor);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBDriver::removeNeighbor(int id, int neighbor)
|
||||
{
|
||||
bool r = false;
|
||||
Signature * s = 0;
|
||||
_trashesMutex.lock();
|
||||
s = uValue(_trashSignatures, id, s);
|
||||
if(s)
|
||||
{
|
||||
s->removeNeighbor(neighbor);
|
||||
r = true;
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
|
||||
if(!r)
|
||||
{
|
||||
r = executeNoResult("DELETE FROM Neighbor WHERE sid=" + uNumber2str(id) + " AND nid=" + uNumber2str(neighbor));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getImage(int id, IplImage ** img) const
|
||||
{
|
||||
CvMat * compressed = 0;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bool result = this->getImageCompressedQuery(id, &compressed);
|
||||
if(compressed)
|
||||
{
|
||||
(*img) = cvDecodeImage(compressed, CV_LOAD_IMAGE_ANYCOLOR);
|
||||
cvReleaseMat(&compressed);
|
||||
}
|
||||
bool result = this->getImageQuery(id, img);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getNeighborIds(int signatureId, std::set<int> & neighbors) const
|
||||
bool DBDriver::getNeighborIds(int signatureId, std::list<int> & neighbors, bool onlyWithActions) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getNeighborIdsQuery(signatureId, neighbors);
|
||||
r = this->getNeighborIdsQuery(signatureId, neighbors, onlyWithActions);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::loadNeighbors(int signatureId, std::map<int, std::list<std::vector<float> > > & neighbors) const
|
||||
bool DBDriver::loadNeighbors(int signatureId, NeighborsMultiMap & neighbors) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
@@ -662,21 +669,11 @@ bool DBDriver::getWeight(int signatureId, int & weight) const
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getLoopClosureId(int signatureId, int & loopId) const
|
||||
bool DBDriver::getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getLoopClosureIdQuery(signatureId, loopId);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getImageCompressed(int id, CvMat ** compressed) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getImageCompressedQuery(id, compressed);
|
||||
r = this->getLoopClosureIdsQuery(signatureId, loopIds, childIds);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
@@ -721,16 +718,6 @@ bool DBDriver::getSurfNi(int signatureId, int & ni) const
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getChildrenIds(int signatureId, std::list<int> & ids) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getChildrenIdsQuery(signatureId, ids);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBDriver::getHighestWeightedSignatures(unsigned int count, std::multimap<int, int> & ids) const
|
||||
{
|
||||
bool r;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,13 +32,16 @@ public:
|
||||
DBDriverSqlite3(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~DBDriverSqlite3();
|
||||
|
||||
virtual std::string getDriverName() const {return "sqlite3";}
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
void setDbInMemory(bool dbInMemory);
|
||||
void setJournalMode(int journalMode);
|
||||
void setCacheSize(unsigned int cacheSize);
|
||||
void setSynchronous(int synchronous);
|
||||
void setTempStore(int tempStore);
|
||||
|
||||
private:
|
||||
virtual bool connectDatabaseQuery(const std::string & url);
|
||||
virtual bool connectDatabaseQuery(const std::string & url, bool overwirtten = false);
|
||||
virtual void disconnectDatabaseQuery();
|
||||
virtual bool isConnectedQuery() const;
|
||||
virtual long getMemoryUsedQuery() const; // In bytes
|
||||
@@ -47,15 +50,13 @@ private:
|
||||
|
||||
virtual bool changeWordsRefQuery(const std::map<int, int> & refsToChange) const; // <oldWordId, activeWordId>
|
||||
virtual bool deleteWordsQuery(const std::vector<int> & ids) const;
|
||||
virtual bool getNeighborIdsQuery(int signatureId, std::set<int> & neighbors) const;
|
||||
virtual bool getNeighborIdsQuery(int signatureId, std::list<int> & neighbors, bool onlyWithActions = false) const;
|
||||
virtual bool getWeightQuery(int signatureId, int & weight) const;
|
||||
virtual bool getLoopClosureIdQuery(int signatureId, int & loopId) const;
|
||||
virtual bool addNeighborQuery(int id, int newNeighbor, int oldNeighbor) const;
|
||||
virtual bool getLoopClosureIdsQuery(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const;
|
||||
|
||||
virtual bool saveQuery(const std::vector<VisualWord *> & visualWords) const;
|
||||
virtual bool updateQuery(const std::list<Signature *> & signatures) const;
|
||||
virtual bool saveQuery(const KeypointSignature * ss) const;
|
||||
virtual bool saveQuery(const std::list<KeypointSignature *> & signatures) const;
|
||||
virtual bool saveQuery(const std::list<Signature *> & signatures) const;
|
||||
|
||||
// Load objects
|
||||
virtual bool loadQuery(VWDictionary * dictionary) const;
|
||||
@@ -63,18 +64,34 @@ private:
|
||||
virtual bool loadQuery(int signatureId, Signature ** s) const;
|
||||
virtual bool loadQuery(int wordId, VisualWord ** vw) const;
|
||||
virtual bool loadQuery(int signatureId, KeypointSignature * ss) const;
|
||||
virtual bool loadKeypointSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures, bool onlyParents = false) const;
|
||||
virtual bool loadQuery(int signatureId, SMSignature * ss) const;
|
||||
virtual bool loadKeypointSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const;
|
||||
virtual bool loadSMSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const;
|
||||
virtual bool loadWordsQuery(const std::list<int> & wordIds, std::list<VisualWord *> & vws) const;
|
||||
virtual bool loadNeighborsQuery(int signatureId, std::map<int, std::list<std::vector<float> > > & neighbors) const;
|
||||
virtual bool loadNeighborsQuery(int signatureId, NeighborsMultiMap & neighbors) const;
|
||||
bool loadNeighborsQuery(std::list<Signature *> & signatures) const;
|
||||
|
||||
virtual bool getImageCompressedQuery(int id, CvMat ** compressed) const;
|
||||
virtual bool getImageQuery(int id, IplImage ** image) const;
|
||||
virtual bool getAllSignatureIdsQuery(std::set<int> & ids) const;
|
||||
virtual bool getLastSignatureIdQuery(int & id) const;
|
||||
virtual bool getLastVisualWordIdQuery(int & id) const;
|
||||
virtual bool getSurfNiQuery(int signatureId, int & ni) const;
|
||||
virtual bool getChildrenIdsQuery(int signatureId, std::list<int> & ids) const;
|
||||
virtual bool getHighestWeightedSignaturesQuery(unsigned int count, std::multimap<int, int> & ids) const;
|
||||
|
||||
private:
|
||||
std::string queryStepSignature() const;
|
||||
std::string queryStepImage() const;
|
||||
std::string queryStepNeighborLink() const;
|
||||
std::string queryStepWordsChanged() const;
|
||||
std::string queryStepKeypoint() const;
|
||||
std::string queryStepSensors() const;
|
||||
int stepSignature(sqlite3_stmt * ppStmt, const Signature * s) const;
|
||||
int stepImage(sqlite3_stmt * ppStmt, int id, const IplImage * img) const;
|
||||
int stepNeighborLink(sqlite3_stmt * ppStmt, int signatureId, const NeighborLink & n) const;
|
||||
int stepWordsChanged(sqlite3_stmt * ppStmt, int signatureId, int oldWordId, int newWordId) const;
|
||||
int stepKeypoint(sqlite3_stmt * ppStmt, int signatureId, int wordId, const cv::KeyPoint & kp) const;
|
||||
int stepSensors(sqlite3_stmt * ppStmt, const SMSignature * s) const;
|
||||
|
||||
private:
|
||||
int loadOrSaveDb(sqlite3 *pInMemory, const std::string & fileName, int isSave) const;
|
||||
|
||||
@@ -83,6 +100,8 @@ private:
|
||||
bool _dbInMemory;
|
||||
unsigned int _cacheSize;
|
||||
int _journalMode;
|
||||
int _synchronous;
|
||||
int _tempStore;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -31,72 +31,31 @@
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
KeypointDescriptor::KeypointDescriptor(const ParametersMap & parameters, KeypointDescriptor * childDescriptor) :
|
||||
_childDescriptor(childDescriptor)
|
||||
KeypointDescriptor::KeypointDescriptor(const ParametersMap & parameters)
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
|
||||
KeypointDescriptor::~KeypointDescriptor()
|
||||
{
|
||||
if(_childDescriptor)
|
||||
{
|
||||
delete _childDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
void KeypointDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
if(_childDescriptor)
|
||||
{
|
||||
_childDescriptor->parseParameters(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::vector<float> > KeypointDescriptor::generateDescriptors(const IplImage * image, const std::list<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
// see decorator pattern...
|
||||
std::list<std::vector<float> > descriptors = this->_generateDescriptors(image, keypoints);
|
||||
std::list<std::vector<float> > childDescriptors;
|
||||
if(_childDescriptor)
|
||||
{
|
||||
childDescriptors = _childDescriptor->generateDescriptors(image, keypoints);
|
||||
|
||||
if(childDescriptors.size() && childDescriptors.size() == descriptors.size())
|
||||
{
|
||||
std::list<std::vector<float> >::iterator iterDesc = descriptors.begin();
|
||||
std::list<std::vector<float> >::iterator iterChild = childDescriptors.begin();
|
||||
for(; iterDesc!=descriptors.end(); ++iterDesc, ++iterChild)
|
||||
{
|
||||
iterDesc->insert(iterDesc->end(), iterChild->begin(), iterChild->end());
|
||||
}
|
||||
}
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
void KeypointDescriptor::setChildDescriptor(KeypointDescriptor * childDescriptor)
|
||||
{
|
||||
if(_childDescriptor)
|
||||
{
|
||||
delete _childDescriptor;
|
||||
}
|
||||
_childDescriptor = childDescriptor;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//SURFDescriptor
|
||||
//////////////////////////
|
||||
SURFDescriptor::SURFDescriptor(const ParametersMap & parameters, KeypointDescriptor * childDescriptor) :
|
||||
KeypointDescriptor(parameters, childDescriptor)
|
||||
SURFDescriptor::SURFDescriptor(const ParametersMap & parameters) :
|
||||
KeypointDescriptor(parameters)
|
||||
{
|
||||
_surf.hessianThreshold = Parameters::defaultSURFHessianThreshold();
|
||||
_surf.extended = Parameters::defaultSURFExtended();
|
||||
_surf.nOctaveLayers = Parameters::defaultSURFOctaveLayers();
|
||||
_surf.nOctaves = Parameters::defaultSURFOctaves();
|
||||
_params.hessianThreshold = Parameters::defaultSURFHessianThreshold();
|
||||
_params.extended = Parameters::defaultSURFExtended();
|
||||
_params.nOctaveLayers = Parameters::defaultSURFOctaveLayers();
|
||||
_params.nOctaves = Parameters::defaultSURFOctaves();
|
||||
_params.upright = Parameters::defaultSURFUpright();
|
||||
_gpuVersion = Parameters::defaultSURFGpuVersion();
|
||||
_upright = Parameters::defaultSURFUpright();
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
|
||||
@@ -109,35 +68,35 @@ void SURFDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
|
||||
{
|
||||
_surf.extended = uStr2Bool((*iter).second.c_str());
|
||||
_params.extended = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
|
||||
{
|
||||
_surf.hessianThreshold = std::atof((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
_params.hessianThreshold = std::atof((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
|
||||
{
|
||||
_surf.nOctaveLayers = std::atoi((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
_params.nOctaveLayers = std::atoi((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_surf.nOctaves = std::atoi((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
_params.nOctaves = std::atoi((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
|
||||
{
|
||||
_params.upright = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
|
||||
{
|
||||
_gpuVersion = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
|
||||
{
|
||||
_upright = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<std::vector<float> > SURFDescriptor::_generateDescriptors(const IplImage * image, const std::list<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat SURFDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<std::vector<float> > descriptors;
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -159,33 +118,35 @@ std::list<std::vector<float> > SURFDescriptor::_generateDescriptors(const IplIma
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
}
|
||||
cv::Mat mask;
|
||||
std::vector<cv::KeyPoint> k = uListToVector(keypoints);
|
||||
std::vector<float> d;
|
||||
#if OPENCV_SURF_GPU
|
||||
if(_gpuVersion)
|
||||
{
|
||||
std::vector<float> d;
|
||||
cv::gpu::GpuMat imgGpu(img);
|
||||
cv::gpu::GpuMat descriptorsGpu;
|
||||
cv::gpu::GpuMat keypointsGpu;
|
||||
cv::gpu::SURF_GPU surfGpu(_surf.hessianThreshold, _surf.nOctaves, _surf.nOctaveLayers, _surf.extended, 0.01f, _upright);
|
||||
surfGpu.uploadKeypoints(k, keypointsGpu);
|
||||
cv::gpu::SURF_GPU surfGpu(_params.hessianThreshold, _params.nOctaves, _params.nOctaveLayers, _params.extended, 0.01f, _params.upright);
|
||||
surfGpu.uploadKeypoints(keypoints, keypointsGpu);
|
||||
surfGpu(imgGpu, cv::gpu::GpuMat(), keypointsGpu, descriptorsGpu, true);
|
||||
surfGpu.downloadDescriptors(descriptorsGpu, d);
|
||||
unsigned int dim = _params.extended?128:64;
|
||||
descriptors = cv::Mat(d.size()/dim, dim, CV_32F);
|
||||
for(int i=0; i<descriptors.rows; ++i)
|
||||
{
|
||||
float * rowFl = descriptors.ptr<float>(i);
|
||||
memcpy(rowFl, &d[i*dim], dim*sizeof(float));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_surf(img, mask, k, d, true); // Opencv surf descriptors
|
||||
cv::SurfDescriptorExtractor extractor(_params.nOctaves, _params.nOctaveLayers, _params.extended, _params.upright);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
}
|
||||
#else
|
||||
_surf(img, mask, k, d, true); // Opencv surf descriptors
|
||||
cv::SurfDescriptorExtractor extractor(_params.nOctaves, _params.nOctaveLayers, _params.extended, _params.upright);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
#endif
|
||||
|
||||
unsigned int dim = _surf.descriptorSize();
|
||||
for(unsigned int i=0; i<d.size(); i+=dim)
|
||||
{
|
||||
descriptors.push_back(std::vector<float>(d.begin()+i, d.begin()+i+dim));
|
||||
}
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
@@ -196,8 +157,8 @@ std::list<std::vector<float> > SURFDescriptor::_generateDescriptors(const IplIma
|
||||
//////////////////////////
|
||||
//SIFTDescriptor
|
||||
//////////////////////////
|
||||
SIFTDescriptor::SIFTDescriptor(const ParametersMap & parameters, KeypointDescriptor * childDescriptor) :
|
||||
KeypointDescriptor(parameters, childDescriptor)
|
||||
SIFTDescriptor::SIFTDescriptor(const ParametersMap & parameters) :
|
||||
KeypointDescriptor(parameters)
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
@@ -212,10 +173,10 @@ void SIFTDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<std::vector<float> > SIFTDescriptor::_generateDescriptors(const IplImage * image, const std::list<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat SIFTDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<std::vector<float> > descriptors;
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -237,17 +198,8 @@ std::list<std::vector<float> > SIFTDescriptor::_generateDescriptors(const IplIma
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
}
|
||||
cv::Mat mask;
|
||||
std::vector<cv::KeyPoint> k = uListToVector(keypoints);
|
||||
cv::Mat d;
|
||||
cv::SIFT sift(_commonParams, cv::SIFT::DetectorParams(), _descriptorParams);
|
||||
sift(img, mask, k, d, true); // Opencv surf descriptors
|
||||
unsigned int dim = sift.descriptorSize();
|
||||
//ULOGGER_DEBUG("row=%d, col=%d, type=%d (float=%d)", d.rows, d.cols, d.type(), CV_32F);
|
||||
for(int i=0; i<d.rows; ++i)
|
||||
{
|
||||
descriptors.push_back(std::vector<float>(d.ptr<float>(i), d.ptr<float>(i)+dim));
|
||||
}
|
||||
cv::SiftDescriptorExtractor extractor(_descriptorParams, _commonParams);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
@@ -256,35 +208,60 @@ std::list<std::vector<float> > SIFTDescriptor::_generateDescriptors(const IplIma
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//LaplacianDescriptor
|
||||
//BRIEFDescriptor
|
||||
//////////////////////////
|
||||
LaplacianDescriptor::LaplacianDescriptor(const ParametersMap & parameters, KeypointDescriptor * childDescriptor) :
|
||||
KeypointDescriptor(parameters, childDescriptor)
|
||||
BRIEFDescriptor::BRIEFDescriptor(const ParametersMap & parameters) :
|
||||
KeypointDescriptor(parameters),
|
||||
_size(Parameters::defaultBRIEFSize())
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
|
||||
LaplacianDescriptor::~LaplacianDescriptor()
|
||||
BRIEFDescriptor::~BRIEFDescriptor()
|
||||
{
|
||||
}
|
||||
|
||||
void LaplacianDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
void BRIEFDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
// No parameter...
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kBRIEFSize())) != parameters.end())
|
||||
{
|
||||
_size = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<std::vector<float> > LaplacianDescriptor::_generateDescriptors(const IplImage * image, const std::list<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat BRIEFDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<std::vector<float> > descriptors;
|
||||
|
||||
//create descriptors...
|
||||
for(std::list<cv::KeyPoint>::const_iterator key=keypoints.begin(); key!=keypoints.end(); ++key)
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
{
|
||||
std::vector<float> laplacian(1);
|
||||
laplacian[0] = uSign(key->response);
|
||||
descriptors.push_back(laplacian);
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return descriptors;
|
||||
}
|
||||
// BRIEF support only grayscale images ?
|
||||
IplImage * imageGrayScale = 0;
|
||||
if(image->nChannels != 1 || image->depth != IPL_DEPTH_8U)
|
||||
{
|
||||
imageGrayScale = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);
|
||||
cvCvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
}
|
||||
cv::Mat img;
|
||||
if(imageGrayScale)
|
||||
{
|
||||
img = cv::Mat(imageGrayScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
}
|
||||
cv::BriefDescriptorExtractor brief(_size);
|
||||
brief.compute(img, keypoints, descriptors);
|
||||
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
@@ -292,8 +269,8 @@ std::list<std::vector<float> > LaplacianDescriptor::_generateDescriptors(const I
|
||||
//////////////////////////
|
||||
//ColorDescriptor
|
||||
//////////////////////////
|
||||
ColorDescriptor::ColorDescriptor(const ParametersMap & parameters, KeypointDescriptor * childDescriptor) :
|
||||
KeypointDescriptor(parameters, childDescriptor)
|
||||
ColorDescriptor::ColorDescriptor(const ParametersMap & parameters) :
|
||||
KeypointDescriptor(parameters)
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
@@ -308,10 +285,10 @@ void ColorDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<std::vector<float> > ColorDescriptor::_generateDescriptors(const IplImage * image, const std::list<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat ColorDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<std::vector<float> > descriptors;
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -335,7 +312,9 @@ std::list<std::vector<float> > ColorDescriptor::_generateDescriptors(const IplIm
|
||||
}
|
||||
|
||||
//create descriptors...
|
||||
for(std::list<cv::KeyPoint>::const_iterator key=keypoints.begin(); key!=keypoints.end(); ++key)
|
||||
descriptors = cv::Mat(keypoints.size(), 6, CV_32F);
|
||||
int i=0;
|
||||
for(std::vector<cv::KeyPoint>::const_iterator key=keypoints.begin(); key!=keypoints.end(); ++key)
|
||||
{
|
||||
|
||||
int grayMax = -1; // grayValue
|
||||
@@ -380,11 +359,11 @@ std::list<std::vector<float> > ColorDescriptor::_generateDescriptors(const IplIm
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i=0; i<6; ++i)
|
||||
for(int j=0; j<6; ++j)
|
||||
{
|
||||
d[i] /= 255; // Normalize between 0 and 1
|
||||
descriptors.at<float>(i,j) = d[j] / 255; // Normalize between 0 and 1
|
||||
}
|
||||
descriptors.push_back(std::vector<float>(d, d + sizeof(d) / sizeof(float)));
|
||||
++i;
|
||||
}
|
||||
|
||||
if(imageConverted)
|
||||
@@ -409,8 +388,8 @@ void ColorDescriptor::getCircularROI(int R, std::vector<int> & RxV) const
|
||||
//////////////////////////
|
||||
//HueDescriptor
|
||||
//////////////////////////
|
||||
HueDescriptor::HueDescriptor(const ParametersMap & parameters, KeypointDescriptor * childDescriptor) :
|
||||
ColorDescriptor(parameters, childDescriptor)
|
||||
HueDescriptor::HueDescriptor(const ParametersMap & parameters) :
|
||||
ColorDescriptor(parameters)
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
@@ -425,10 +404,10 @@ void HueDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<std::vector<float> > HueDescriptor::_generateDescriptors(const IplImage * image, const std::list<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat HueDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<std::vector<float> > descriptors;
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -452,7 +431,9 @@ std::list<std::vector<float> > HueDescriptor::_generateDescriptors(const IplImag
|
||||
}
|
||||
|
||||
//create descriptors...
|
||||
for(std::list<cv::KeyPoint>::const_iterator key=keypoints.begin(); key!=keypoints.end(); ++key)
|
||||
descriptors = cv::Mat(keypoints.size(), 2, CV_32F);
|
||||
int i=0;
|
||||
for(std::vector<cv::KeyPoint>::const_iterator key=keypoints.begin(); key!=keypoints.end(); ++key)
|
||||
{
|
||||
|
||||
int intensityMax = -1;
|
||||
@@ -512,7 +493,9 @@ std::list<std::vector<float> > HueDescriptor::_generateDescriptors(const IplImag
|
||||
r = float(img(center.y+dyd, center.x+dxd)[2]) / 255.0f;
|
||||
d[1] = rgb2hue(r, g, b);
|
||||
|
||||
descriptors.push_back(std::vector<float>(d, d + sizeof(d) / sizeof(float)));
|
||||
float * rowFl = descriptors.ptr<float>(i);
|
||||
memcpy(rowFl, &d[i*2], 2*sizeof(float));
|
||||
++i;
|
||||
}
|
||||
|
||||
if(imageConverted)
|
||||
|
||||
@@ -60,10 +60,10 @@ void KeypointDetector::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
}
|
||||
|
||||
std::list<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * image)
|
||||
std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * image)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<cv::KeyPoint> keypoints;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(image)
|
||||
{
|
||||
UTimer timer;
|
||||
@@ -97,28 +97,40 @@ std::list<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * ima
|
||||
// Remove words under the new hessian threshold
|
||||
|
||||
// Sort words by hessian
|
||||
std::multimap<float, std::list<cv::KeyPoint>::iterator> hessianMap; // <hessian,id>
|
||||
for(std::list<cv::KeyPoint>::iterator itKey = keypoints.begin(); itKey != keypoints.end(); ++itKey)
|
||||
std::multimap<float, std::vector<cv::KeyPoint>::iterator> hessianMap; // <hessian,id>
|
||||
for(std::vector<cv::KeyPoint>::iterator itKey = keypoints.begin(); itKey != keypoints.end(); ++itKey)
|
||||
{
|
||||
//Keep track of the data, to be easier to manage the data in the next step
|
||||
hessianMap.insert(std::pair<float, std::list<cv::KeyPoint>::iterator>(fabs(itKey->response), itKey));
|
||||
hessianMap.insert(std::pair<float, std::vector<cv::KeyPoint>::iterator>(fabs(itKey->response), itKey));
|
||||
}
|
||||
|
||||
// Remove them from the signature
|
||||
int removed = 0;
|
||||
unsigned int stopIndex = hessianMap.size()-_wordsPerImageTarget;
|
||||
std::multimap<float, std::list<cv::KeyPoint>::iterator>::iterator iter = hessianMap.begin();
|
||||
for(unsigned int k=0; k < stopIndex && iter!=hessianMap.end(); ++k, ++iter)
|
||||
int removed = hessianMap.size()-_wordsPerImageTarget;
|
||||
std::multimap<float, std::vector<cv::KeyPoint>::iterator>::reverse_iterator iter = hessianMap.rbegin();
|
||||
std::vector<cv::KeyPoint> kptsTmp(_wordsPerImageTarget);
|
||||
for(unsigned int k=0; k < kptsTmp.size() && iter!=hessianMap.rend(); ++k, ++iter)
|
||||
{
|
||||
keypoints.erase(iter->second);
|
||||
++removed;
|
||||
kptsTmp[k] = *iter->second;
|
||||
// Adjust keypoint position to raw image
|
||||
kptsTmp[k].pt.x += roi.x;
|
||||
kptsTmp[k].pt.y += roi.y;
|
||||
}
|
||||
if(iter->first!=0)
|
||||
{
|
||||
_adaptiveResponseThr = iter->first;
|
||||
}
|
||||
keypoints = kptsTmp;
|
||||
ULOGGER_DEBUG("%d keypoints removed, (kept %d)", removed, keypoints.size());
|
||||
}
|
||||
else if(roi.x || roi.y)
|
||||
{
|
||||
// Adjust keypoint position to raw image
|
||||
for(std::vector<cv::KeyPoint>::iterator iter=keypoints.begin(); iter!=keypoints.end(); ++iter)
|
||||
{
|
||||
iter->pt.x += roi.x;
|
||||
iter->pt.y += roi.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -133,12 +145,14 @@ std::list<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * ima
|
||||
ULOGGER_DEBUG("new _adaptiveResponseThr=%f", _adaptiveResponseThr);
|
||||
ULOGGER_DEBUG("adjusting hessian threshold time = %f s", timer.ticks());
|
||||
}
|
||||
|
||||
// Adjust keypoint position to raw image
|
||||
for(std::list<cv::KeyPoint>::iterator iter=keypoints.begin(); iter!=keypoints.end(); ++iter)
|
||||
else if(roi.x || roi.y)
|
||||
{
|
||||
iter->pt.x += roi.x;
|
||||
iter->pt.y += roi.y;
|
||||
// Adjust keypoint position to raw image
|
||||
for(std::vector<cv::KeyPoint>::iterator iter=keypoints.begin(); iter!=keypoints.end(); ++iter)
|
||||
{
|
||||
iter->pt.x += roi.x;
|
||||
iter->pt.y += roi.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -232,14 +246,14 @@ cv::Rect KeypointDetector::computeRoi(const IplImage * image) const
|
||||
SURFDetector::SURFDetector(const ParametersMap & parameters) :
|
||||
KeypointDetector(parameters)
|
||||
{
|
||||
_surf.hessianThreshold = Parameters::defaultSURFHessianThreshold();
|
||||
_surf.extended = Parameters::defaultSURFExtended();
|
||||
_surf.nOctaveLayers = Parameters::defaultSURFOctaveLayers();
|
||||
_surf.nOctaves = Parameters::defaultSURFOctaves();
|
||||
_params.hessianThreshold = Parameters::defaultSURFHessianThreshold();
|
||||
_params.extended = Parameters::defaultSURFExtended();
|
||||
_params.nOctaveLayers = Parameters::defaultSURFOctaveLayers();
|
||||
_params.nOctaves = Parameters::defaultSURFOctaves();
|
||||
_gpuVersion = Parameters::defaultSURFGpuVersion();
|
||||
_upright = Parameters::defaultSURFUpright();
|
||||
_params.upright = Parameters::defaultSURFUpright();
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_surf.hessianThreshold);
|
||||
this->setAdaptiveResponseThr(_params.hessianThreshold);
|
||||
}
|
||||
|
||||
SURFDetector::~SURFDetector()
|
||||
@@ -251,24 +265,24 @@ void SURFDetector::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
|
||||
{
|
||||
_surf.extended = uStr2Bool((*iter).second.c_str());
|
||||
_params.extended = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
|
||||
{
|
||||
_surf.hessianThreshold = std::atof((*iter).second.c_str());
|
||||
this->setAdaptiveResponseThr(_surf.hessianThreshold);
|
||||
_params.hessianThreshold = std::atof((*iter).second.c_str());
|
||||
this->setAdaptiveResponseThr(_params.hessianThreshold);
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
|
||||
{
|
||||
_surf.nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
_params.nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_surf.nOctaves = std::atoi((*iter).second.c_str());
|
||||
_params.nOctaves = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_surf.nOctaves = std::atoi((*iter).second.c_str());
|
||||
_params.nOctaves = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
|
||||
{
|
||||
@@ -276,15 +290,15 @@ void SURFDetector::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
|
||||
{
|
||||
_upright = uStr2Bool((*iter).second.c_str());
|
||||
_params.upright = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<cv::KeyPoint> SURFDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<cv::KeyPoint> keypoints;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -307,32 +321,31 @@ std::list<cv::KeyPoint> SURFDetector::_generateKeypoints(const IplImage * image,
|
||||
img = cv::Mat(image);
|
||||
}
|
||||
|
||||
cv::SURF surf = _surf;
|
||||
CvSURFParams params = _params;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
surf.hessianThreshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
params.hessianThreshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
|
||||
cv::Mat imgRoi(img, roi);
|
||||
std::vector<cv::KeyPoint> k;
|
||||
#if OPENCV_SURF_GPU
|
||||
if(_gpuVersion )
|
||||
{
|
||||
cv::gpu::GpuMat imgGpu(imgRoi);
|
||||
cv::gpu::GpuMat keypointsGpu;
|
||||
cv::gpu::SURF_GPU surfGpu(surf.hessianThreshold, surf.nOctaves, surf.nOctaveLayers, surf.extended, 0.01f, _upright);
|
||||
cv::gpu::SURF_GPU surfGpu(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.extended, 0.01f, params.upright);
|
||||
surfGpu(imgGpu, cv::gpu::GpuMat(), keypointsGpu);
|
||||
surfGpu.downloadKeypoints(keypointsGpu, k);
|
||||
surfGpu.downloadKeypoints(keypointsGpu, keypoints);
|
||||
}
|
||||
else
|
||||
{
|
||||
surf(imgRoi, cv::Mat(), k); // Opencv surf keypoints
|
||||
cv::SurfFeatureDetector detector(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.upright);
|
||||
detector.detect(imgRoi, keypoints);
|
||||
}
|
||||
#else
|
||||
surf(imgRoi, cv::Mat(), k); // Opencv surf keypoints
|
||||
cv::SurfFeatureDetector detector(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.upright);
|
||||
detector.detect(imgRoi, keypoints);
|
||||
#endif
|
||||
keypoints = uVectorToList(k);
|
||||
|
||||
|
||||
if(imageGrayScale)
|
||||
{
|
||||
@@ -372,10 +385,10 @@ void SIFTDetector::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<cv::KeyPoint> SIFTDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> SIFTDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<cv::KeyPoint> keypoints;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -403,13 +416,10 @@ std::list<cv::KeyPoint> SIFTDetector::_generateKeypoints(const IplImage * image,
|
||||
{
|
||||
detectorParam.threshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
cv::Mat mask;
|
||||
cv::SIFT sift(_commonParams, detectorParam);
|
||||
|
||||
cv::SiftFeatureDetector detector(detectorParam, _commonParams);
|
||||
cv::Mat imgRoi(img, roi);
|
||||
std::vector<cv::KeyPoint> k;
|
||||
sift(imgRoi, mask, k); // Opencv surf keypoints
|
||||
keypoints = uVectorToList(k);
|
||||
detector.detect(imgRoi, keypoints); // Opencv surf keypoints
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
@@ -424,13 +434,13 @@ std::list<cv::KeyPoint> SIFTDetector::_generateKeypoints(const IplImage * image,
|
||||
StarDetector::StarDetector(const ParametersMap & parameters) :
|
||||
KeypointDetector(parameters)
|
||||
{
|
||||
_star.lineThresholdBinarized = Parameters::defaultStarLineThresholdBinarized();
|
||||
_star.lineThresholdProjected = Parameters::defaultStarLineThresholdProjected();
|
||||
_star.maxSize = Parameters::defaultStarMaxSize();
|
||||
_star.responseThreshold = Parameters::defaultStarResponseThreshold();
|
||||
_star.suppressNonmaxSize = Parameters::defaultStarSuppressNonmaxSize();
|
||||
_params.lineThresholdBinarized = Parameters::defaultStarLineThresholdBinarized();
|
||||
_params.lineThresholdProjected = Parameters::defaultStarLineThresholdProjected();
|
||||
_params.maxSize = Parameters::defaultStarMaxSize();
|
||||
_params.responseThreshold = Parameters::defaultStarResponseThreshold();
|
||||
_params.suppressNonmaxSize = Parameters::defaultStarSuppressNonmaxSize();
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_star.responseThreshold);
|
||||
this->setAdaptiveResponseThr(_params.responseThreshold);
|
||||
}
|
||||
|
||||
StarDetector::~StarDetector()
|
||||
@@ -443,32 +453,32 @@ void StarDetector::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kStarLineThresholdBinarized())) != parameters.end())
|
||||
{
|
||||
_star.lineThresholdBinarized = std::atoi((*iter).second.c_str());
|
||||
_params.lineThresholdBinarized = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarLineThresholdProjected())) != parameters.end())
|
||||
{
|
||||
_star.lineThresholdProjected = std::atoi((*iter).second.c_str());
|
||||
_params.lineThresholdProjected = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarMaxSize())) != parameters.end())
|
||||
{
|
||||
_star.maxSize = std::atoi((*iter).second.c_str());
|
||||
_params.maxSize = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarResponseThreshold())) != parameters.end())
|
||||
{
|
||||
_star.responseThreshold = int(std::atof((*iter).second.c_str()));
|
||||
this->setAdaptiveResponseThr(_star.responseThreshold);
|
||||
_params.responseThreshold = int(std::atof((*iter).second.c_str()));
|
||||
this->setAdaptiveResponseThr(_params.responseThreshold);
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarSuppressNonmaxSize())) != parameters.end())
|
||||
{
|
||||
_star.suppressNonmaxSize = std::atoi((*iter).second.c_str());
|
||||
_params.suppressNonmaxSize = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::list<cv::KeyPoint> StarDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> StarDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::list<cv::KeyPoint> keypoints;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
@@ -476,20 +486,72 @@ std::list<cv::KeyPoint> StarDetector::_generateKeypoints(const IplImage * image,
|
||||
}
|
||||
|
||||
cv::Mat img(image);
|
||||
cv::Mat mask;
|
||||
// TODO More testing needed with the star detector, NN search distance must be changed to 0.8
|
||||
//find keypoints with the star detector
|
||||
cv::StarDetector star = _star;
|
||||
CvStarDetectorParams params = _params;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
star.responseThreshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
params.responseThreshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
|
||||
// Get keypoints with the star detector
|
||||
cv::Mat imgRoi(img, roi);
|
||||
std::vector<cv::KeyPoint> k;
|
||||
star(imgRoi, k);
|
||||
keypoints = uVectorToList(k);
|
||||
cv::StarFeatureDetector detector(params);
|
||||
detector.detect(imgRoi, keypoints);
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//FastDetector
|
||||
//////////////////////////
|
||||
FASTDetector::FASTDetector(const ParametersMap & parameters) :
|
||||
KeypointDetector(parameters),
|
||||
_threshold(Parameters::defaultFASTThreshold()),
|
||||
_nonmaxSuppression(Parameters::defaultFASTNonmaxSuppression())
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_threshold);
|
||||
}
|
||||
|
||||
FASTDetector::~FASTDetector()
|
||||
{
|
||||
}
|
||||
|
||||
void FASTDetector::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kFASTThreshold())) != parameters.end())
|
||||
{
|
||||
_threshold = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kFASTNonmaxSuppression())) != parameters.end())
|
||||
{
|
||||
_nonmaxSuppression = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> FASTDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
cv::Mat img(image);
|
||||
cv::Mat imgRoi(img, roi);
|
||||
int threshold = _threshold;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
threshold = (int)this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
cv::FastFeatureDetector fast(threshold, _nonmaxSuppression);
|
||||
|
||||
// Get keypoints with the fast detector
|
||||
fast.detect(imgRoi, keypoints);
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "KeypointMemory.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "Signature.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "utilite/UtiLite.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
@@ -43,7 +43,6 @@ KeypointMemory::KeypointMemory(const ParametersMap & parameters) :
|
||||
_badSignRatio(Parameters::defaultKpBadSignRatio()),
|
||||
_tfIdfLikelihoodUsed(Parameters::defaultKpTfIdfLikelihoodUsed()),
|
||||
_parallelized(Parameters::defaultKpParallelized()),
|
||||
_sensorStateOnly(Parameters::defaultKpSensorStateOnly()),
|
||||
_tfIdfNormalized(Parameters::defaultKpTfIdfNormalized())
|
||||
{
|
||||
_vwd = new VWDictionary(parameters);
|
||||
@@ -95,11 +94,6 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
_parallelized = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
|
||||
if((iter=parameters.find(Parameters::kKpSensorStateOnly())) != parameters.end())
|
||||
{
|
||||
_sensorStateOnly = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
|
||||
if((iter=parameters.find(Parameters::kKpTfIdfNormalized())) != parameters.end())
|
||||
{
|
||||
_tfIdfNormalized = uStr2Bool((*iter).second.c_str());
|
||||
@@ -133,6 +127,9 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
case kDetectorSift:
|
||||
_keypointDetector = new SIFTDetector(parameters);
|
||||
break;
|
||||
case kDetectorFast:
|
||||
_keypointDetector = new FASTDetector(parameters);
|
||||
break;
|
||||
case kDetectorSurf:
|
||||
default:
|
||||
_keypointDetector = new SURFDetector(parameters);
|
||||
@@ -160,20 +157,17 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
switch(descriptorStrategy)
|
||||
{
|
||||
case kDescriptorColorSurf:
|
||||
// see decorator pattern...
|
||||
_keypointDescriptor = new ColorDescriptor(parameters, new SURFDescriptor(parameters));
|
||||
break;
|
||||
case kDescriptorLaplacianSurf:
|
||||
// see decorator pattern...
|
||||
_keypointDescriptor = new LaplacianDescriptor(parameters, new SURFDescriptor(parameters));
|
||||
break;
|
||||
case kDescriptorSift:
|
||||
_keypointDescriptor = new SIFTDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorHueSurf:
|
||||
// see decorator pattern...
|
||||
_keypointDescriptor = new HueDescriptor(parameters, new SURFDescriptor(parameters));
|
||||
case kDescriptorBrief:
|
||||
_keypointDescriptor = new BRIEFDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorColor:
|
||||
_keypointDescriptor = new ColorDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorHue:
|
||||
_keypointDescriptor = new HueDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorSurf:
|
||||
default:
|
||||
@@ -207,7 +201,7 @@ KeypointMemory::DetectorStrategy KeypointMemory::detectorStrategy() const
|
||||
|
||||
bool KeypointMemory::init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten, const ParametersMap & parameters)
|
||||
{
|
||||
ULOGGER_DEBUG("KeypointMemory::init()");
|
||||
UDEBUG("");
|
||||
// This will open a connection to the database,
|
||||
// this calls also clear()
|
||||
bool success = Memory::init(dbDriverName, dbUrl, dbOverwritten, parameters);
|
||||
@@ -217,8 +211,8 @@ bool KeypointMemory::init(const std::string & dbDriverName, const std::string &
|
||||
{
|
||||
UEventsManager::post(new RtabmapEventInit(std::string("Loading dictionary...")));
|
||||
_dbDriver->load(_vwd);
|
||||
ULOGGER_DEBUG("%d words loaded!", _vwd->getVisualWords().size());
|
||||
UEventsManager::post(new RtabmapEventInit(std::string("Loading dictionary, done! (") + uNumber2str(int(_vwd->getVisualWords().size())) + " loaded)"));
|
||||
UDEBUG("%d words loaded!", _vwd->getVisualWords().size());
|
||||
UEventsManager::post(new RtabmapEventInit(std::string("Loading dictionary, done! (") + uNumber2Str(int(_vwd->getVisualWords().size())) + " loaded)"));
|
||||
}
|
||||
|
||||
// Enable loaded signatures
|
||||
@@ -290,7 +284,7 @@ void KeypointMemory::clear()
|
||||
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->kill();
|
||||
_dbDriver->join(true);
|
||||
cleanUnusedWords();
|
||||
_dbDriver->emptyTrashes();
|
||||
|
||||
@@ -302,7 +296,7 @@ void KeypointMemory::clear()
|
||||
// all signatures with the old word to the active one...
|
||||
//_dbDriver->changeWordsRef(_wordRefsToChange);
|
||||
//remove old values
|
||||
_dbDriver->deleteUnreferencedWords();
|
||||
//_dbDriver->deleteUnreferencedWords();
|
||||
// _dbDriver->commit();
|
||||
//}
|
||||
ULOGGER_DEBUG("");
|
||||
@@ -328,40 +322,6 @@ void KeypointMemory::preUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO Really useful?
|
||||
/*void KeypointMemory::postUpdate()
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
// Detect if the last signature is a bad one. If the signature has less than 15% of
|
||||
// the average words/signature.
|
||||
KeypointSignature * ss = dynamic_cast<KeypointSignature *>(this->_getLastSignature());
|
||||
|
||||
float ratio = 0;
|
||||
if(ss)
|
||||
{
|
||||
ratio = float(uUniqueKeys(ss->getWords()).size()) / float(ss->getWords().size());
|
||||
}
|
||||
|
||||
int nbCommonWords = 0;
|
||||
ULOGGER_DEBUG("_workingMem.size() = %d, _stMem.size()=%d", _workingMem.size(), _stMem.size());
|
||||
int treeSize= _workingMem.size() + _stMem.size();//Don't count the virtual place
|
||||
if(treeSize > 0)
|
||||
{
|
||||
nbCommonWords = _vwd->getTotalActiveReferences() / treeSize;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("ratio=%f, treeSize=%d, nbCommonWords=%d", ratio, treeSize, nbCommonWords);
|
||||
|
||||
if(//(ratio < _badSignRatio) ||
|
||||
(nbCommonWords && ss && ss->getWords().size() < _badSignRatio * nbCommonWords))
|
||||
{
|
||||
ULOGGER_WARN("id %d is a bad signature", ss->id());
|
||||
this->disableWordsRef(ss->id());
|
||||
ss->removeAllWords();
|
||||
}
|
||||
}*/
|
||||
|
||||
// NON class method! only used in merge()
|
||||
std::multimap<int, cv::KeyPoint> getMostDescriptiveWords(const std::multimap<int, cv::KeyPoint> & words, int max, const std::set<int> & ignoredIds)
|
||||
{
|
||||
@@ -398,49 +358,57 @@ std::multimap<int, cv::KeyPoint> getMostDescriptiveWords(const std::multimap<int
|
||||
return mostDescriptiveWords;
|
||||
}
|
||||
|
||||
void KeypointMemory::merge(const Signature * from, Signature * to, MergingStrategy s)
|
||||
std::multimap<int, cv::KeyPoint> KeypointMemory::getWords(int signatureId) const
|
||||
{
|
||||
// The signatures must be KeypointSignature
|
||||
const KeypointSignature * sFrom = dynamic_cast<const KeypointSignature *>(from);
|
||||
KeypointSignature * sTo = dynamic_cast<KeypointSignature *>(to);
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
if(sFrom && sTo)
|
||||
std::multimap<int, cv::KeyPoint> words;
|
||||
if(signatureId>0)
|
||||
{
|
||||
if(s == kUseOnlyFromMerging)
|
||||
const Signature * s = this->getSignature(signatureId);
|
||||
if(s)
|
||||
{
|
||||
this->disableWordsRef(sTo->id());
|
||||
sTo->setWords(sFrom->getWords());
|
||||
const KeypointSignature * ks = dynamic_cast<const KeypointSignature*>(s);
|
||||
if(ks)
|
||||
{
|
||||
words = ks->getWords();
|
||||
}
|
||||
}
|
||||
else if(_dbDriver)
|
||||
{
|
||||
std::list<int> ids;
|
||||
ids.push_back(signatureId);
|
||||
std::list<Signature *> signatures;
|
||||
_dbDriver->loadKeypointSignatures(ids, signatures);
|
||||
if(signatures.size())
|
||||
{
|
||||
const KeypointSignature * ks = dynamic_cast<const KeypointSignature*>(signatures.front());
|
||||
if(ks)
|
||||
{
|
||||
words = ks->getWords();
|
||||
}
|
||||
}
|
||||
for(std::list<Signature *>::iterator iter = signatures.begin(); iter!=signatures.end(); ++iter)
|
||||
{
|
||||
delete *iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
return words;
|
||||
}
|
||||
|
||||
std::list<int> id;
|
||||
id.push_back(sTo->id());
|
||||
this->enableWordsRef(id);
|
||||
// Set old image to new merged signature
|
||||
sTo->setImage(sFrom->getImage());
|
||||
}
|
||||
else if(s == kUseOnlyDestMerging)
|
||||
{
|
||||
// do nothing... already "merged"
|
||||
}
|
||||
std::map<int, float> KeypointMemory::computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore)
|
||||
{
|
||||
if(!_tfIdfLikelihoodUsed)
|
||||
{
|
||||
return Memory::computeLikelihood(signature, ids, maximumScore);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("Can't merge the signatures because there are not same type.");
|
||||
}
|
||||
ULOGGER_DEBUG("Merging time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
std::map<int, float> KeypointMemory::computeLikelihood(const Signature * signature, const std::set<int> & signatureIds) const
|
||||
{
|
||||
//return Memory::computeLikelihood(signature, signatureIds);
|
||||
|
||||
// TODO cleanup , old way...
|
||||
if(_tfIdfLikelihoodUsed)
|
||||
{
|
||||
// TODO cleanup , old way...
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::map<int, float> likelihood;
|
||||
std::map<int, float> calculatedWordsRatio;
|
||||
maximumScore = 0;
|
||||
|
||||
const KeypointSignature * newSurf = dynamic_cast<const KeypointSignature *>(signature);
|
||||
if(!newSurf)
|
||||
@@ -448,61 +416,34 @@ std::map<int, float> KeypointMemory::computeLikelihood(const Signature * signatu
|
||||
ULOGGER_ERROR("The signature is not a KeypointSignature");
|
||||
return likelihood; // Must be a KeypointSignature *
|
||||
}
|
||||
|
||||
if(signatureIds.size() == 0)
|
||||
else if(ids.empty())
|
||||
{
|
||||
const std::map<int, int> & wm = this->getWorkingMem();
|
||||
for(std::map<int, int>::const_iterator iter = wm.begin(); iter!=wm.end(); ++iter)
|
||||
{
|
||||
likelihood.insert(likelihood.end(), std::pair<int, float>(iter->first, 0));
|
||||
if(_tfIdfNormalized)
|
||||
{
|
||||
const KeypointSignature * s = dynamic_cast<const KeypointSignature *>(this->getSignature(iter->first));
|
||||
float wordsCountRatio = -1; // default invalid
|
||||
if(s)
|
||||
{
|
||||
if(s->getWords().size() > newSurf->getWords().size())
|
||||
{
|
||||
wordsCountRatio = float(newSurf->getWords().size()) / float(s->getWords().size());
|
||||
}
|
||||
else if(newSurf->getWords().size())
|
||||
{
|
||||
wordsCountRatio = float(s->getWords().size()) / float(newSurf->getWords().size());
|
||||
}
|
||||
calculatedWordsRatio.insert(std::pair<int, float>(iter->first, wordsCountRatio));
|
||||
}
|
||||
else
|
||||
{
|
||||
calculatedWordsRatio.insert(std::pair<int, float>(iter->first, wordsCountRatio));
|
||||
}
|
||||
}
|
||||
}
|
||||
UWARN("ids list is empty");
|
||||
return likelihood;
|
||||
}
|
||||
else
|
||||
|
||||
for(std::list<int>::const_iterator iter = ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
for(std::set<int>::const_iterator i=signatureIds.begin(); i != signatureIds.end(); ++i)
|
||||
likelihood.insert(likelihood.end(), std::pair<int, float>(*iter, 0));
|
||||
if(_tfIdfNormalized)
|
||||
{
|
||||
likelihood.insert(likelihood.end(), std::pair<int, float>(*i, 0));
|
||||
if(_tfIdfNormalized)
|
||||
const KeypointSignature * s = dynamic_cast<const KeypointSignature *>(this->getSignature(*iter));
|
||||
float wordsCountRatio = -1; // default invalid
|
||||
if(s)
|
||||
{
|
||||
const KeypointSignature * s = dynamic_cast<const KeypointSignature *>(this->getSignature(*i));
|
||||
float wordsCountRatio = -1; // default invalid
|
||||
if(s)
|
||||
if(s->getWords().size() > newSurf->getWords().size())
|
||||
{
|
||||
if(s->getWords().size() > newSurf->getWords().size())
|
||||
{
|
||||
wordsCountRatio = float(newSurf->getWords().size()) / float(s->getWords().size());
|
||||
}
|
||||
else if(newSurf->getWords().size())
|
||||
{
|
||||
wordsCountRatio = float(s->getWords().size()) / float(newSurf->getWords().size());
|
||||
}
|
||||
calculatedWordsRatio.insert(std::pair<int, float>(*i, wordsCountRatio));
|
||||
wordsCountRatio = float(newSurf->getWords().size()) / float(s->getWords().size());
|
||||
}
|
||||
else
|
||||
else if(newSurf->getWords().size())
|
||||
{
|
||||
calculatedWordsRatio.insert(std::pair<int, float>(*i, wordsCountRatio));
|
||||
wordsCountRatio = float(s->getWords().size()) / float(newSurf->getWords().size());
|
||||
}
|
||||
calculatedWordsRatio.insert(std::pair<int, float>(*iter, wordsCountRatio));
|
||||
}
|
||||
else
|
||||
{
|
||||
calculatedWordsRatio.insert(std::pair<int, float>(*iter, wordsCountRatio));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -518,7 +459,7 @@ std::map<int, float> KeypointMemory::computeLikelihood(const Signature * signatu
|
||||
const VisualWord * vw;
|
||||
float normalizationRatio;
|
||||
|
||||
N = likelihood.size();
|
||||
N = this->getSignatures().size();
|
||||
|
||||
if(N)
|
||||
{
|
||||
@@ -572,15 +513,12 @@ std::map<int, float> KeypointMemory::computeLikelihood(const Signature * signatu
|
||||
}
|
||||
}
|
||||
}
|
||||
maximumScore = log(N);
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("compute likelihood... %f s", timer.ticks());
|
||||
ULOGGER_DEBUG("compute likelihood, maximumScore=%f... %f s", maximumScore, timer.ticks());
|
||||
return likelihood;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Memory::computeLikelihood(signature, signatureIds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -599,11 +537,34 @@ int KeypointMemory::getNi(int signatureId) const
|
||||
return ni;
|
||||
}
|
||||
|
||||
void KeypointMemory::copyData(const Signature * from, Signature * to)
|
||||
{
|
||||
// The signatures must be KeypointSignature
|
||||
const KeypointSignature * sFrom = dynamic_cast<const KeypointSignature *>(from);
|
||||
KeypointSignature * sTo = dynamic_cast<KeypointSignature *>(to);
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
if(sFrom && sTo)
|
||||
{
|
||||
this->disableWordsRef(sTo->id());
|
||||
sTo->setWords(sFrom->getWords());
|
||||
|
||||
std::list<int> id;
|
||||
id.push_back(sTo->id());
|
||||
this->enableWordsRef(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("Can't merge the signatures because there are not same type.");
|
||||
}
|
||||
ULOGGER_DEBUG("Merging time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
class PreUpdateThread : public UThreadNode
|
||||
{
|
||||
public:
|
||||
PreUpdateThread(VWDictionary * vwp) : _vwp(vwp) {}
|
||||
~PreUpdateThread() {}
|
||||
virtual ~PreUpdateThread() {}
|
||||
private:
|
||||
void mainLoop() {
|
||||
if(_vwp)
|
||||
@@ -621,8 +582,8 @@ Signature * KeypointMemory::createSignature(int id, const SMState * smState, boo
|
||||
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::list<cv::KeyPoint> keypoints;
|
||||
std::list<std::vector<float> > descriptors;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
cv::Mat descriptors;
|
||||
const IplImage * image = 0;
|
||||
|
||||
if(smState)
|
||||
@@ -657,7 +618,7 @@ Signature * KeypointMemory::createSignature(int id, const SMState * smState, boo
|
||||
}
|
||||
else
|
||||
{
|
||||
if(smState->getSensors().size() >= _badSignRatio * nbCommonWords)
|
||||
if(smState->getSensors().rows >= _badSignRatio * nbCommonWords)
|
||||
{
|
||||
descriptors = smState->getSensors();
|
||||
keypoints = smState->getKeypoints();
|
||||
@@ -672,62 +633,29 @@ Signature * KeypointMemory::createSignature(int id, const SMState * smState, boo
|
||||
}
|
||||
|
||||
std::list<int> wordIds;
|
||||
if(descriptors.size())
|
||||
if(descriptors.rows)
|
||||
{
|
||||
unsigned int descriptorSize = descriptors.begin()->size();
|
||||
if(_parallelized)
|
||||
{
|
||||
ULOGGER_DEBUG("time descriptor and memory update (%d of size=%d) = %fs", (int)descriptors.size(), (int)descriptorSize, timer.ticks());
|
||||
ULOGGER_DEBUG("time descriptor and memory update (%d of size=%d) = %fs", descriptors.rows, descriptors.cols, timer.ticks());
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_DEBUG("time descriptor (%d of size=%d) = %fs", (int)descriptors.size(), (int)descriptorSize, timer.ticks());
|
||||
ULOGGER_DEBUG("time descriptor (%d of size=%d) = %fs", descriptors.rows, descriptors.cols, timer.ticks());
|
||||
}
|
||||
|
||||
//append actuators
|
||||
if(!_sensorStateOnly && smState->getActuators().size())
|
||||
{
|
||||
const std::list<std::vector<float> > & actuators = smState->getActuators();
|
||||
|
||||
unsigned int actuatorSize = actuators.begin()->size();
|
||||
if(actuatorSize > descriptorSize)
|
||||
{
|
||||
UERROR("Actuator's size (%d) is larger than descriptor size (%d)", actuatorSize, descriptorSize);
|
||||
}
|
||||
|
||||
for(std::list<std::vector<float> >::const_iterator iter = actuators.begin(); iter!=actuators.end(); ++iter)
|
||||
{
|
||||
std::vector<float> descriptor(descriptorSize);
|
||||
// normalize actuator values
|
||||
std::vector<float> actuatorNormalized = uNormalize(*iter);
|
||||
for(unsigned int i=0; i<descriptorSize; ++i)
|
||||
{
|
||||
if(i<actuatorSize)
|
||||
{
|
||||
descriptor[i] = actuatorNormalized[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor[i] = 0;
|
||||
}
|
||||
}
|
||||
descriptors.push_back(descriptor);
|
||||
}
|
||||
ULOGGER_DEBUG("time setup actuators (%d of length %d) like descriptors %fs", (int)actuators.size(), (int)actuatorSize, timer.ticks());
|
||||
}
|
||||
|
||||
wordIds = _vwd->addNewWords(descriptors, descriptorSize, id);
|
||||
wordIds = _vwd->addNewWords(descriptors, id);
|
||||
ULOGGER_DEBUG("time addNewWords %fs", timer.ticks());
|
||||
}
|
||||
else
|
||||
else if(id>0)
|
||||
{
|
||||
ULOGGER_WARN("id %d is a bad signature", id);
|
||||
UDEBUG("id %d is a bad signature", id);
|
||||
}
|
||||
|
||||
std::multimap<int, cv::KeyPoint> words;
|
||||
if(wordIds.size() > 0)
|
||||
{
|
||||
std::list<cv::KeyPoint>::iterator kpIter = keypoints.begin();
|
||||
std::vector<cv::KeyPoint>::iterator kpIter = keypoints.begin();
|
||||
for(std::list<int>::iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter)
|
||||
{
|
||||
if(kpIter != keypoints.end())
|
||||
@@ -737,6 +665,7 @@ Signature * KeypointMemory::createSignature(int id, const SMState * smState, boo
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Words (%d) and keypoints(%d) are not the same size ?!?", (int)wordIds.size(), (int)keypoints.size());
|
||||
words.insert(std::pair<int, cv::KeyPoint >(*iter, cv::KeyPoint()));
|
||||
}
|
||||
}
|
||||
@@ -787,7 +716,7 @@ void KeypointMemory::disableWordsRef(int signatureId)
|
||||
|
||||
void KeypointMemory::cleanUnusedWords()
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
UINFO("");
|
||||
if(_vwd->isIncremental())
|
||||
{
|
||||
std::vector<VisualWord*> removedWords = _vwd->getUnusedWords();
|
||||
@@ -799,7 +728,7 @@ void KeypointMemory::cleanUnusedWords()
|
||||
|
||||
for(unsigned int i=0; i<removedWords.size(); ++i)
|
||||
{
|
||||
if(_dbDriver)
|
||||
if(_dbDriver && !removedWords[i]->isSaved())
|
||||
{
|
||||
_dbDriver->asyncSave(removedWords[i]);
|
||||
}
|
||||
@@ -809,7 +738,7 @@ void KeypointMemory::cleanUnusedWords()
|
||||
}
|
||||
}
|
||||
}
|
||||
ULOGGER_DEBUG("%d words removed...", removedWords.size());
|
||||
UINFO("%d words removed...", removedWords.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,23 +763,9 @@ void KeypointMemory::enableWordsRef(const std::list<int> & signatureIds)
|
||||
//Find words in the signature which they are not in the current dictionary
|
||||
for(std::list<int>::const_iterator k=uniqueKeys.begin(); k!=uniqueKeys.end(); ++k)
|
||||
{
|
||||
if(_vwd->getWord(*k) == 0)
|
||||
if(_vwd->getWord(*k) == 0 && _vwd->getUnusedWord(*k) == 0)
|
||||
{
|
||||
//std::map<int,int>::iterator iter = _wordRefsToChange.find(*k);
|
||||
//if(iter != _wordRefsToChange.end())
|
||||
//{
|
||||
// ss->changeWordsRef(iter->first, iter->second);
|
||||
// uniqueKeys.push_back(iter->second);
|
||||
//}
|
||||
//else
|
||||
if(oldWordIds.find(*k) == oldWordIds.end())
|
||||
{
|
||||
oldWordIds.insert(oldWordIds.end(), *k);
|
||||
}
|
||||
else
|
||||
{
|
||||
//UDEBUG("*k=%d", *k);
|
||||
}
|
||||
oldWordIds.insert(oldWordIds.end(), *k);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -862,7 +777,8 @@ void KeypointMemory::enableWordsRef(const std::list<int> & signatureIds)
|
||||
std::list<VisualWord *> vws;
|
||||
if(oldWordIds.size() && _dbDriver)
|
||||
{
|
||||
_dbDriver->loadWords(std::list<int>(oldWordIds.begin(), oldWordIds.end()), vws); // get the descriptors
|
||||
// get the descriptors
|
||||
_dbDriver->loadWords(std::list<int>(oldWordIds.begin(), oldWordIds.end()), vws);
|
||||
}
|
||||
ULOGGER_DEBUG("loading words(%d) time=%fs", oldWordIds.size(), timer.ticks());
|
||||
|
||||
@@ -879,11 +795,11 @@ void KeypointMemory::enableWordsRef(const std::list<int> & signatureIds)
|
||||
{
|
||||
//ULOGGER_DEBUG("Match found %d with %d", (*iterVws)->id(), vwActiveIds[i]);
|
||||
refsToChange.insert(refsToChange.end(), std::pair<int, int>((*iterVws)->id(), vwActiveIds[i]));
|
||||
if((*iterVws)->isSaved() || !_dbDriver)
|
||||
if((*iterVws)->isSaved())
|
||||
{
|
||||
delete (*iterVws);
|
||||
}
|
||||
else
|
||||
else if(_dbDriver)
|
||||
{
|
||||
_dbDriver->asyncSave(*iterVws);
|
||||
}
|
||||
@@ -891,7 +807,7 @@ void KeypointMemory::enableWordsRef(const std::list<int> & signatureIds)
|
||||
else
|
||||
{
|
||||
//add to dictionary
|
||||
_vwd->addWord(*iterVws);
|
||||
_vwd->addWord(*iterVws); // take ownership
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@@ -930,7 +846,7 @@ void KeypointMemory::enableWordsRef(const std::list<int> & signatureIds)
|
||||
ULOGGER_DEBUG("%d words total ref added from %d signatures, time=%fs...", count, surfSigns.size(), timer.ticks());
|
||||
}
|
||||
|
||||
int KeypointMemory::forget(const std::list<int> & ignoredIds)
|
||||
int KeypointMemory::forget(const std::set<int> & ignoredIds)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
int signaturesRemoved = 0;
|
||||
@@ -946,12 +862,20 @@ int KeypointMemory::forget(const std::list<int> & ignoredIds)
|
||||
// dictionary to respect the limit.
|
||||
while(wordsRemoved < newWords)
|
||||
{
|
||||
KeypointSignature * s = dynamic_cast<KeypointSignature *>(this->getRemovableSignature(ignoredIds));
|
||||
if(s)
|
||||
std::list<Signature *> signatures = this->getRemovableSignatures(1, ignoredIds);
|
||||
if(signatures.size())
|
||||
{
|
||||
++signaturesRemoved;
|
||||
this->moveToTrash(s);
|
||||
wordsRemoved = _vwd->getUnusedWordsSize();
|
||||
KeypointSignature * s = dynamic_cast<KeypointSignature *>(signatures.front());
|
||||
if(s)
|
||||
{
|
||||
++signaturesRemoved;
|
||||
this->moveToTrash(s);
|
||||
wordsRemoved = _vwd->getUnusedWordsSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -968,7 +892,7 @@ int KeypointMemory::forget(const std::list<int> & ignoredIds)
|
||||
return signaturesRemoved;
|
||||
}
|
||||
|
||||
int KeypointMemory::reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, unsigned int maxTouched)
|
||||
std::set<int> KeypointMemory::reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess)
|
||||
{
|
||||
// get the signatures, if not in the working memory, they
|
||||
// will be loaded from the database in an more efficient way
|
||||
@@ -977,7 +901,6 @@ int KeypointMemory::reactivateSignatures(const std::list<int> & ids, unsigned in
|
||||
ULOGGER_DEBUG("");
|
||||
UTimer timer;
|
||||
std::list<int> idsToLoad;
|
||||
unsigned int touched = 0;
|
||||
std::map<int, int>::iterator wmIter;
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
@@ -985,16 +908,10 @@ int KeypointMemory::reactivateSignatures(const std::list<int> & ids, unsigned in
|
||||
{
|
||||
if(!maxLoaded || idsToLoad.size() < maxLoaded)
|
||||
{
|
||||
//When loaded from the long-term memory, the signature
|
||||
// is automatically added on top of the working memory
|
||||
idsToLoad.push_back(*i);
|
||||
UINFO("Loading location %d from database...", *i);
|
||||
}
|
||||
}
|
||||
else if(touched < maxTouched)
|
||||
{
|
||||
this->touch(*i);
|
||||
}
|
||||
++touched;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("idsToLoad = %d", idsToLoad.size());
|
||||
@@ -1002,8 +919,9 @@ int KeypointMemory::reactivateSignatures(const std::list<int> & ids, unsigned in
|
||||
std::list<Signature *> reactivatedSigns;
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->loadKeypointSignatures(idsToLoad, reactivatedSigns, true);
|
||||
_dbDriver->loadKeypointSignatures(idsToLoad, reactivatedSigns);
|
||||
}
|
||||
timeDbAccess = timer.getElapsedTime();
|
||||
std::list<int> idsLoaded;
|
||||
for(std::list<Signature *>::iterator i=reactivatedSigns.begin(); i!=reactivatedSigns.end(); ++i)
|
||||
{
|
||||
@@ -1013,7 +931,7 @@ int KeypointMemory::reactivateSignatures(const std::list<int> & ids, unsigned in
|
||||
}
|
||||
this->enableWordsRef(idsLoaded);
|
||||
ULOGGER_DEBUG("time = %fs", timer.ticks());
|
||||
return reactivatedSigns.size();
|
||||
return std::set<int>(idsToLoad.begin(), idsToLoad.end());
|
||||
}
|
||||
|
||||
void KeypointMemory::moveToTrash(Signature * s)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "Memory.h"
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -34,8 +35,8 @@ class KeypointDescriptor;
|
||||
class RTABMAP_EXP KeypointMemory : public Memory
|
||||
{
|
||||
public:
|
||||
enum DetectorStrategy {kDetectorSurf, kDetectorStar, kDetectorSift, kDetectorUndef};
|
||||
enum DescriptorStrategy {kDescriptorSurf, kDescriptorColorSurf, kDescriptorLaplacianSurf, kDescriptorSift, kDescriptorHueSurf, kDescriptorUndef};
|
||||
enum DetectorStrategy {kDetectorSurf, kDetectorStar, kDetectorSift, kDetectorFast, kDetectorUndef};
|
||||
enum DescriptorStrategy {kDescriptorSurf, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef};
|
||||
|
||||
public:
|
||||
KeypointMemory(const ParametersMap & parameters = ParametersMap());
|
||||
@@ -43,9 +44,9 @@ public:
|
||||
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual bool init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten = false, const ParametersMap & parameters = ParametersMap());
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::set<int> & signatureIds = std::set<int>()) const;
|
||||
virtual int forget(const std::list<int> & ignoredIds = std::list<int>());
|
||||
virtual int reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, unsigned int maxTouched);
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore);
|
||||
virtual int forget(const std::set<int> & ignoredIds = std::set<int>());
|
||||
virtual std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
|
||||
virtual void dumpMemory(std::string directory) const;
|
||||
virtual void dumpSignatures(const char * fileNameSign) const;
|
||||
|
||||
@@ -54,6 +55,7 @@ public:
|
||||
const KeypointDetector * getKeypointDetector() const {return _keypointDetector;}
|
||||
const KeypointDescriptor * getKeypointDescriptor() const {return _keypointDescriptor;}
|
||||
const VWDictionary * getVWD() const {return _vwd;}
|
||||
std::multimap<int, cv::KeyPoint> getWords(int signatureId) const;
|
||||
DetectorStrategy detectorStrategy() const;
|
||||
|
||||
protected:
|
||||
@@ -62,10 +64,11 @@ protected:
|
||||
virtual void clear();
|
||||
virtual void moveToTrash(Signature * s);
|
||||
virtual void preUpdate();
|
||||
virtual void merge(const Signature * from, Signature * to, MergingStrategy s);
|
||||
|
||||
private:
|
||||
virtual void copyData(const Signature * from, Signature * to);
|
||||
virtual Signature * createSignature(int id, const SMState * rawData, bool keepRawData=false);
|
||||
|
||||
void disableWordsRef(int signatureId);
|
||||
void enableWordsRef(const std::list<int> & signatureIds);
|
||||
void cleanUnusedWords();
|
||||
@@ -81,7 +84,6 @@ private:
|
||||
float _badSignRatio;;
|
||||
bool _tfIdfLikelihoodUsed;
|
||||
bool _parallelized;
|
||||
bool _sensorStateOnly;
|
||||
bool _tfIdfNormalized;
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@
|
||||
namespace rtabmap {
|
||||
|
||||
class Signature;
|
||||
class NeighborLink;
|
||||
class DBDriver;
|
||||
class Node;
|
||||
class SMState;
|
||||
@@ -46,8 +47,6 @@ public:
|
||||
static const int kIdVirtual;
|
||||
static const int kIdInvalid;
|
||||
|
||||
enum MergingStrategy{kUseOnlyFromMerging, kUseOnlyDestMerging};
|
||||
|
||||
public:
|
||||
Memory(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~Memory();
|
||||
@@ -55,31 +54,34 @@ public:
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
bool update(const SMState * rawData, std::map<std::string, float> & stats);
|
||||
virtual bool init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten = false, const ParametersMap & parameters = ParametersMap());
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::set<int> & signatureIds = std::set<int>()) const;
|
||||
virtual int forget(const std::list<int> & ignoredIds = std::list<int>());
|
||||
virtual int reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, unsigned int maxTouched);
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore);
|
||||
virtual int forget(const std::set<int> & ignoredIds = std::set<int>());
|
||||
virtual std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
|
||||
|
||||
int cleanup(const std::list<int> & ignoredIds = std::list<int>());
|
||||
void emptyTrash();
|
||||
void joinTrashThread();
|
||||
void addLoopClosureLink(int oldId, int newId, bool rehearsal = false);
|
||||
void getNeighborsId(std::map<int,int> & ids, int signatureId, unsigned int margin, bool checkInDatabase = true, int ignoredId = 0) const;
|
||||
bool addLoopClosureLink(int oldId, int newId);
|
||||
std::map<int, int> getNeighborsId(double & dbAccessTime, int signatureId, unsigned int margin, int maxCheckedInDatabase = -1, bool onlyWithActions = false, bool incrementMarginOnLoop = false, bool ignoreSTM = true, bool ignoreLoopIds = false) const;
|
||||
float compareOneToOne(const std::vector<int> & idsA, const std::vector<int> & idsB);
|
||||
|
||||
//getters
|
||||
unsigned int getWorkingMemSize() const {return _workingMem.size();}
|
||||
unsigned int getStMemSize() const {return _stMem.size();};
|
||||
const std::map<int, int> & getWorkingMem() const {return _workingMem;}
|
||||
const std::set<int> & getWorkingMem() const {return _workingMem;}
|
||||
const std::set<int> & getStMem() const {return _stMem;}
|
||||
std::list<int> getChildrenIds(int signatureId) const;
|
||||
std::list<NeighborLink> getNeighborLinks(int signatureId, bool ignoreNeighborByLoopClosure = false, bool lookInDatabase = false) const;
|
||||
void getLoopClosureIds(int signatureId, std::set<int> & loopClosureIds, std::set<int> & childLoopClosureIds, bool lookInDatabase = false) const;
|
||||
bool isRawDataKept() const {return _rawDataKept;}
|
||||
float getSimilarityThr() const {return _similarityThreshold;}
|
||||
std::map<int, int> getWeights() const;
|
||||
int getWeight(int id) const;
|
||||
const std::vector<int> & getLastBaseIds() const {return _lastBaseIds;}
|
||||
float getSimilarityOnlyLast() const {return _similarityOnlyLast;}
|
||||
const Signature * getLastSignature() const;
|
||||
int getDatabaseMemoryUsed() const; // in bytes
|
||||
double getDbSavingTime() const;
|
||||
IplImage * getImage(int id) const;
|
||||
bool isDatabaseCleaned() const {return _databaseCleaned;}
|
||||
bool isCommonSignatureUsed() const {return _commonSignatureUsed;}
|
||||
std::set<int> getAllSignatureIds() const;
|
||||
bool memoryChanged() const {return _memoryChanged;}
|
||||
@@ -93,7 +95,6 @@ public:
|
||||
void setSimilarityOnlyLast(int similarityOnlyLast) {_similarityOnlyLast = similarityOnlyLast;}
|
||||
void setOldSignatureRatio(float oldSignatureRatio);
|
||||
void setMaxStMemSize(unsigned int maxStMemSize);
|
||||
void setDelayRequired(int delayRequired);
|
||||
void setRecentWmRatio(float recentWmRatio);
|
||||
void setCommonSignatureUsed(bool commonSignatureUsed);
|
||||
void setRawDataKept(bool rawDataKept) {_rawDataKept = rawDataKept;}
|
||||
@@ -109,7 +110,6 @@ public:
|
||||
protected:
|
||||
virtual void preUpdate();
|
||||
virtual void postUpdate() {}
|
||||
virtual void merge(const Signature * from, Signature * to, MergingStrategy s) = 0;
|
||||
|
||||
virtual void addSignatureToStm(Signature * signature, const std::list<std::vector<float> > & actions = std::list<std::vector<float> >());
|
||||
virtual void clear();
|
||||
@@ -118,41 +118,45 @@ protected:
|
||||
|
||||
void addSignatureToWm(Signature * signature);
|
||||
Signature * _getSignature(int id) const;
|
||||
Signature * _getLastSignature();
|
||||
Signature * getRemovableSignature(const std::list<int> & ignoredIds = std::list<int>(), bool onlyLoopedSignatures = false);
|
||||
std::list<Signature *> getRemovableSignatures(int count, const std::set<int> & ignoredIds = std::set<int>());
|
||||
int getNextId();
|
||||
void initCountId();
|
||||
int rehearsal(const Signature * signature, bool onlyLast, float & similarity);
|
||||
void touch(int signatureId);
|
||||
void rehearsal(Signature * signature, std::map<std::string, float> & stats);
|
||||
|
||||
const std::map<int, Signature*> & getSignatures() const {return _signatures;}
|
||||
|
||||
private:
|
||||
void createVirtualSignature(Signature ** signature);
|
||||
virtual void copyData(const Signature * from, Signature * to) = 0;
|
||||
virtual Signature * createSignature(int id, const SMState * rawData, bool keepRawData=false) = 0;
|
||||
|
||||
void createVirtualSignature(Signature ** signature);
|
||||
void cleanGraph(const Node * root);
|
||||
protected:
|
||||
DBDriver * _dbDriver;
|
||||
|
||||
private:
|
||||
// parameters
|
||||
float _similarityThreshold;
|
||||
bool _similarityOnlyLast;
|
||||
bool _rawDataKept;
|
||||
int _idCount;
|
||||
Signature * _lastSignature;
|
||||
int _lastLoopClosureId;
|
||||
bool _incrementalMemory;
|
||||
unsigned int _maxStMemSize;
|
||||
bool _commonSignatureUsed;
|
||||
bool _databaseCleaned; //if true, delete old signatures in the database
|
||||
int _delayRequired;
|
||||
float _recentWmRatio;
|
||||
bool _dataMergedOnRehearsal;
|
||||
|
||||
int _idCount;
|
||||
Signature * _lastSignature;
|
||||
int _lastLoopClosureId;
|
||||
bool _memoryChanged; // False by default, become true when Memory::update() is called.
|
||||
bool _merging;
|
||||
int _signaturesAdded;
|
||||
|
||||
std::map<int, Signature *> _signatures; // TODO : check if a signature is already added? although it is not supposed to occur...
|
||||
std::set<int> _stMem;
|
||||
std::map<int, int> _workingMem; // id, timeStamp
|
||||
std::set<int> _stMem; // id
|
||||
std::set<int> _workingMem; // id,age
|
||||
std::vector<int> _lastBaseIds;
|
||||
std::map<int, std::map<int, float> > _similaritiesMap;
|
||||
};
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -24,9 +24,8 @@
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
Parameters * Parameters::instance_ = 0;
|
||||
UDestroyer<Parameters> Parameters::destroyer_;
|
||||
ParametersMap Parameters::parameters_;
|
||||
Parameters Parameters::instance_;
|
||||
|
||||
Parameters::Parameters()
|
||||
{
|
||||
@@ -37,30 +36,10 @@ Parameters::~Parameters()
|
||||
}
|
||||
|
||||
const ParametersMap & Parameters::getDefaultParameters()
|
||||
{
|
||||
return Parameters::getInstance()->getParameters();
|
||||
}
|
||||
|
||||
Parameters * Parameters::getInstance()
|
||||
{
|
||||
if(!instance_)
|
||||
{
|
||||
instance_ = new Parameters();
|
||||
destroyer_.setDoomed(instance_);
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
const ParametersMap & Parameters::getParameters() const
|
||||
{
|
||||
return parameters_;
|
||||
}
|
||||
|
||||
void Parameters::addParameter(const std::string & key, const std::string & value)
|
||||
{
|
||||
parameters_.insert(ParametersPair(key, value));
|
||||
}
|
||||
|
||||
std::string Parameters::getDefaultWorkingDirectory()
|
||||
{
|
||||
std::string path = UDirectory::homeDir();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -115,7 +115,6 @@ void Statistics::setLoopClosureImage(const IplImage * loopClosureImage)
|
||||
|
||||
Statistics & Statistics::operator=(const Statistics & s)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
_data = s.data();
|
||||
if(_refImage)
|
||||
{
|
||||
@@ -143,7 +142,9 @@ Statistics & Statistics::operator=(const Statistics & s)
|
||||
_weights = s.weights();
|
||||
_refWords = s.refWords();
|
||||
_loopWords = s.loopWords();
|
||||
|
||||
_refMotionMask = s.refMotionMask();
|
||||
_loopMotionMask = s.loopMotionMask();
|
||||
_actions = s.getActions();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
607
corelib/src/SMMemory.cpp
Normal file
607
corelib/src/SMMemory.cpp
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SMMemory.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "utilite/UtiLite.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "utilite/UStl.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include <opencv2/imgproc/imgproc_c.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "ColorTable.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
|
||||
SMMemory::SMMemory(const ParametersMap & parameters) :
|
||||
Memory(parameters),
|
||||
_useLogPolar(Parameters::defaultSMLogPolarUsed()),
|
||||
_useVotingScheme(Parameters::defaultSMVotingSchemeUsed()),
|
||||
_colorTable(0),
|
||||
_useMotionMask(Parameters::defaultSMMotionMaskUsed())
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
if(!_colorTable)
|
||||
{
|
||||
int i=1;
|
||||
this->setColorTable(i<<(Parameters::defaultSMColorTable() + 3));
|
||||
}
|
||||
}
|
||||
|
||||
SMMemory::~SMMemory()
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
if(this->memoryChanged())
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
delete _colorTable;
|
||||
}
|
||||
|
||||
void SMMemory::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSMLogPolarUsed())) != parameters.end())
|
||||
{
|
||||
_useLogPolar = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMVotingSchemeUsed())) != parameters.end())
|
||||
{
|
||||
this->setVotingScheme(uStr2Bool((*iter).second.c_str()));
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMMotionMaskUsed())) != parameters.end())
|
||||
{
|
||||
_useMotionMask = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMColorTable())) != parameters.end())
|
||||
{
|
||||
// index 0 = 8, index 1 = 16...
|
||||
if(atoi((*iter).second.c_str()) == 8)
|
||||
{
|
||||
setColorTable(65536);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i=1;
|
||||
setColorTable(i<<(atoi((*iter).second.c_str()) + 3));
|
||||
}
|
||||
}
|
||||
|
||||
Memory::parseParameters(parameters);
|
||||
}
|
||||
|
||||
void SMMemory::setVotingScheme(bool useVotingScheme)
|
||||
{
|
||||
_useVotingScheme = useVotingScheme;
|
||||
_dictionary.clear();
|
||||
if(_useVotingScheme)
|
||||
{
|
||||
const std::map<int, Signature *> & signatures = this->getSignatures();
|
||||
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
this->updateDictionary(i->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SMMemory::setColorTable(int size)
|
||||
{
|
||||
if(_colorTable)
|
||||
{
|
||||
if(_colorTable->size() != size)
|
||||
{
|
||||
delete _colorTable;
|
||||
_colorTable = new ColorTable(size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_colorTable = new ColorTable(size);
|
||||
}
|
||||
}
|
||||
|
||||
void SMMemory::copyData(const Signature * from, Signature * to)
|
||||
{
|
||||
// The signatures must be SMSignature
|
||||
const SMSignature * sFrom = dynamic_cast<const SMSignature *>(from);
|
||||
SMSignature * sTo = dynamic_cast<SMSignature *>(to);
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
if(sFrom && sTo)
|
||||
{
|
||||
sTo->setSensors(sFrom->getSensors());
|
||||
sTo->setMotionMask(sFrom->getMotionMask());
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("Can't merge the signatures because there are not same type.");
|
||||
}
|
||||
ULOGGER_DEBUG("Merging time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
Signature * SMMemory::createSignature(int id, const SMState * smState, bool keepRawData)
|
||||
{
|
||||
UDEBUG("");
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
UTimer timerDetails;
|
||||
timerDetails.start();
|
||||
std::vector<int> sensors;
|
||||
const std::vector<int> * sensorsPrevious = 0;
|
||||
std::vector<unsigned char> motionMask;
|
||||
const IplImage * image = 0;
|
||||
IplImage * polar = 0;
|
||||
IplImage * indexed = 0;
|
||||
const SMSignature * previousSignature = dynamic_cast<const SMSignature *>(this->getLastSignature());
|
||||
if(previousSignature)
|
||||
{
|
||||
UDEBUG("");
|
||||
sensorsPrevious = &previousSignature->getSensors();
|
||||
}
|
||||
if(smState)
|
||||
{
|
||||
image = smState->getImage();
|
||||
|
||||
// sensors
|
||||
if(!smState->getSensors().empty() == 0 && image && image->imageSize)
|
||||
{
|
||||
if(image->depth != IPL_DEPTH_8U && image->nChannels != 3)
|
||||
{
|
||||
UFATAL("Only IplImage depth of IPL_DEPTH_8U and 3 channels (BGR) is supported.");
|
||||
}
|
||||
|
||||
UDEBUG("depth=%d, alpha=%d, widthStep=%d, width=%d, height=%d, nChannels=%d, imageSize=%d,", image->depth, image->alphaChannel, image->widthStep, image->width, image->height, image->nChannels, image->imageSize);
|
||||
|
||||
if(_useLogPolar)
|
||||
{
|
||||
// Log-polar transform
|
||||
int radius = image->height < image->width ? image->height/2: image->width/2;
|
||||
CvSize polarSize = cvSize(64, 128);
|
||||
float M = polarSize.width/std::log(radius);
|
||||
polar = cvCreateImage( polarSize, 8, 3 );
|
||||
cvLogPolar( image, polar, cvPoint2D32f(image->width/2,image->height/2), double(M), CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );
|
||||
|
||||
UDEBUG("polar size= %d, %d, time=%fs", polar->width, polar->height, timerDetails.ticks());
|
||||
|
||||
// IND transform
|
||||
unsigned char * data = (unsigned char *)polar->imageData;
|
||||
sensors = std::vector<int>(polar->width*polar->height);
|
||||
if(_useVotingScheme && (_dictionary.empty() || _dictionary.size() != sensors.size()))
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensors.size());
|
||||
}
|
||||
if(_useMotionMask)
|
||||
{
|
||||
motionMask = std::vector<unsigned char>(sensors.size(), 0);
|
||||
}
|
||||
bool updateMask = sensorsPrevious && sensorsPrevious->size() == motionMask.size();
|
||||
int k=0;
|
||||
for(int i=0; i<polar->height; ++i)
|
||||
{
|
||||
for(int j=0; j<polar->width; ++j)
|
||||
{
|
||||
unsigned char & b = data[i*polar->widthStep+j*3+0];
|
||||
unsigned char & g = data[i*polar->widthStep+j*3+1];
|
||||
unsigned char & r = data[i*polar->widthStep+j*3+2];
|
||||
int index = (int)_colorTable->getIndex(r, g, b);
|
||||
sensors[k] = index;
|
||||
_colorTable->getRgb(index, r, g , b);
|
||||
|
||||
if(_useMotionMask && updateMask && sensorsPrevious->at(k) != sensors[k])
|
||||
{
|
||||
motionMask[k] = 1;
|
||||
}
|
||||
|
||||
if(!_dictionary.empty())
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(id);
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[k].insert(std::make_pair(sensors[k], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
UDEBUG("indexing time = %fs", timerDetails.ticks());
|
||||
|
||||
//cv::Mat indPolar;
|
||||
//fromIndPolar = cvCreateImage(cvGetSize(image), 8, 3);
|
||||
//cvLogPolar(polar, fromIndPolar, cvPoint2D32f(image->width/2,image->height/2), double(M), CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP );
|
||||
//UDEBUG("back from polar time = %fs", timerDetails());
|
||||
|
||||
//image = polar;
|
||||
}
|
||||
else
|
||||
{
|
||||
// IND transform
|
||||
indexed = cvCloneImage(image);
|
||||
unsigned char * data = (unsigned char *)indexed->imageData;
|
||||
sensors = std::vector<int>(indexed->width*indexed->height);
|
||||
if(_useVotingScheme && (_dictionary.empty() || _dictionary.size() != sensors.size()))
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensors.size());
|
||||
}
|
||||
if(_useMotionMask)
|
||||
{
|
||||
motionMask = std::vector<unsigned char>(sensors.size(), 0);
|
||||
}
|
||||
bool updateMask = sensorsPrevious && sensorsPrevious->size() == motionMask.size();
|
||||
int k=0;
|
||||
int sum=0;
|
||||
for(int i=0; i<indexed->height; ++i)
|
||||
{
|
||||
for(int j=0; j<indexed->width; ++j)
|
||||
{
|
||||
unsigned char & b = data[i*indexed->widthStep+j*3+0];
|
||||
unsigned char & g = data[i*indexed->widthStep+j*3+1];
|
||||
unsigned char & r = data[i*indexed->widthStep+j*3+2];
|
||||
int index = (int)_colorTable->getIndex(r, g, b);
|
||||
sensors[k] = index;
|
||||
_colorTable->getRgb(index, r, g , b);
|
||||
|
||||
if(_useMotionMask && updateMask && sensorsPrevious->at(k) != sensors[k])
|
||||
{
|
||||
motionMask[k] = 1;
|
||||
++sum;
|
||||
}
|
||||
|
||||
if(!_dictionary.empty())
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(id);
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[k].insert(std::make_pair(sensors[k], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
}
|
||||
image = indexed;
|
||||
|
||||
UDEBUG("sum=%d, indexing time = %fs", sum, timerDetails.ticks());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<float> sensorsMerged;
|
||||
int buf;
|
||||
smState->getSensorsMerged(sensorsMerged, buf);
|
||||
sensors = std::vector<int>(sensorsMerged.size());
|
||||
if(_useVotingScheme && (_dictionary.empty() || _dictionary.size() != sensorsMerged.size()))
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensorsMerged.size());
|
||||
}
|
||||
if(_useMotionMask)
|
||||
{
|
||||
motionMask = std::vector<unsigned char>(sensors.size(), 0);
|
||||
}
|
||||
bool updateMask = sensorsPrevious && sensorsPrevious->size() == motionMask.size();
|
||||
for(unsigned int i=0; i<sensorsMerged.size(); ++i)
|
||||
{
|
||||
if(sensorsMerged[i]>0 && sensorsMerged[i]<1)
|
||||
{
|
||||
UWARN("Conversion from float to int may lost precision...");
|
||||
}
|
||||
sensors[i] = (int)sensorsMerged[i];
|
||||
if(_useMotionMask && updateMask && sensorsPrevious->at(i) != sensors[i])
|
||||
{
|
||||
motionMask[i] = 1;
|
||||
}
|
||||
|
||||
if(!_dictionary.empty())
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(id);
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[i].insert(std::make_pair(sensors[i], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SMSignature * s = new SMSignature(sensors, motionMask, id, image, keepRawData);
|
||||
|
||||
if(polar)
|
||||
{
|
||||
cvReleaseImage(&polar);
|
||||
}
|
||||
if(indexed)
|
||||
{
|
||||
cvReleaseImage(&indexed);
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("time new signature (id=%d) %fs", id, timer.ticks());
|
||||
return s;
|
||||
}
|
||||
|
||||
std::map<int, float> SMMemory::computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore)
|
||||
{
|
||||
if(!_useVotingScheme)
|
||||
{
|
||||
return Memory::computeLikelihood(signature, ids, maximumScore);
|
||||
}
|
||||
else
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::map<int, float> likelihood;
|
||||
maximumScore = 0;
|
||||
|
||||
const SMSignature * query = dynamic_cast<const SMSignature *>(signature);
|
||||
if(!query)
|
||||
{
|
||||
ULOGGER_ERROR("The signature is not a SMSignature");
|
||||
return likelihood; // Must be a SMSignature *
|
||||
}
|
||||
else if(ids.empty())
|
||||
{
|
||||
UWARN("ids list is empty");
|
||||
return likelihood;
|
||||
}
|
||||
|
||||
UDEBUG("Likelihood for %d", query->id());
|
||||
|
||||
const std::vector<int> & sensors = query->getSensors();
|
||||
if(_dictionary.size() != sensors.size())
|
||||
{
|
||||
UERROR("Dictionary (%d) and sensor (%d) are not the same size!", (int)_dictionary.size(), (int)sensors.size());
|
||||
return likelihood;
|
||||
}
|
||||
const std::vector<unsigned char> & mask = query->getMotionMask();
|
||||
bool maskUsed = false;
|
||||
if(mask.size() != 0 && mask.size() != sensors.size())
|
||||
{
|
||||
UWARN("mask's size (%d) and sensor's size (%d) are not equal", (int)mask.size(), (int)sensors.size());
|
||||
}
|
||||
else if(mask.size())
|
||||
{
|
||||
maskUsed = true;
|
||||
}
|
||||
|
||||
// prepare likelihood
|
||||
for(std::list<int>::const_iterator iter = ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
likelihood.insert(likelihood.end(), std::make_pair(*iter, 0.0f));
|
||||
}
|
||||
|
||||
//float nwi; // nwi is the number of a specific word referenced by a place
|
||||
//float ni; // ni is the total of words referenced by a place
|
||||
float nw; // nw is the number of places referenced by a specific word
|
||||
float N; // N is the total number of places
|
||||
float logNnw;
|
||||
|
||||
N = this->getSignatures().size();
|
||||
|
||||
if(N)
|
||||
{
|
||||
for(unsigned int i=0; i<sensors.size(); ++i)
|
||||
{
|
||||
if(!maskUsed || mask[i])
|
||||
{
|
||||
// "Inverted index"
|
||||
std::map<int, std::set<int> >::iterator iter = _dictionary[i].find(sensors[i]);
|
||||
if(iter == _dictionary[i].end())
|
||||
{
|
||||
UERROR("Sensor %d not found in dictionary ?!?", sensors[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nw = iter->second.size();
|
||||
if(nw)
|
||||
{
|
||||
if(nw > N)
|
||||
{
|
||||
for(std::set<int>::iterator jter = iter->second.begin(); jter!=iter->second.end(); ++jter)
|
||||
{
|
||||
UERROR("sensor pos %d, refid = %d", (int)i, *jter);
|
||||
}
|
||||
|
||||
UFATAL("id=%d, N = %f, nw=%f", signature->id(), N, nw);
|
||||
}
|
||||
logNnw = log10(N/nw);
|
||||
if(logNnw)
|
||||
{
|
||||
for(std::set<int>::iterator jter = iter->second.begin(); jter!=iter->second.end(); ++jter)
|
||||
{
|
||||
std::map<int, float>::iterator kter = likelihood.find(*jter);
|
||||
if(kter != likelihood.end())
|
||||
{
|
||||
kter->second += logNnw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sensors.size())
|
||||
{
|
||||
maximumScore = log(N) * float(sensors.size());
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("compute likelihood, maximumScore=%f... %f s", maximumScore, timer.ticks());
|
||||
return likelihood;
|
||||
}
|
||||
}
|
||||
|
||||
void SMMemory::moveToTrash(Signature * s)
|
||||
{
|
||||
if(_useVotingScheme)
|
||||
{
|
||||
UTimer timer;
|
||||
SMSignature * sm = dynamic_cast<SMSignature *>(s);
|
||||
if(sm && sm->id() > 0)
|
||||
{
|
||||
const std::vector<int> & sensors = sm->getSensors();
|
||||
if(sensors.size() == _dictionary.size())
|
||||
{
|
||||
for(unsigned int i=0; i<sensors.size(); ++i)
|
||||
{
|
||||
std::map<int, std::set<int> >::iterator iter = _dictionary[i].find(sensors[i]);
|
||||
if(iter != _dictionary[i].end())
|
||||
{
|
||||
if(!iter->second.erase(sm->id()))
|
||||
{
|
||||
UWARN("Sensor id %d not found in dictionary at pos %d", sm->id(), (int)i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Sensor value %d at sensor pos %d is not found in dictionary", sensors[i], (int)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Dictionary size (%d) is not the same as the sensor (%d), signId=%d", (int)_dictionary.size(), (int)sensors.size(), sm->id());
|
||||
}
|
||||
}
|
||||
UDEBUG("time=%fs", timer.ticks());
|
||||
}
|
||||
Memory::moveToTrash(s);
|
||||
}
|
||||
|
||||
Signature * SMMemory::getSignatureLtMem(int id)
|
||||
{
|
||||
Signature * s = Memory::getSignatureLtMem(id);
|
||||
if(_useVotingScheme && s)
|
||||
{
|
||||
this->updateDictionary(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool SMMemory::init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten, const ParametersMap & parameters)
|
||||
{
|
||||
UDEBUG("");
|
||||
bool success = Memory::init(dbDriverName, dbUrl, dbOverwritten, parameters);
|
||||
|
||||
if(_useVotingScheme)
|
||||
{
|
||||
// Update sensory dictionary
|
||||
const std::map<int, Signature *> & signatures = this->getSignatures();
|
||||
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
this->updateDictionary(i->second);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void SMMemory::updateDictionary(const Signature * s)
|
||||
{
|
||||
if(s)
|
||||
{
|
||||
const SMSignature * sm = dynamic_cast<const SMSignature *>(s);
|
||||
if(sm)
|
||||
{
|
||||
const std::vector<int> & sensors = sm->getSensors();
|
||||
if(_dictionary.empty())
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensors.size());
|
||||
}
|
||||
if(sensors.size() == _dictionary.size())
|
||||
{
|
||||
for(unsigned int i=0; i<sensors.size(); ++i)
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(sm->id());
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[i].insert(std::make_pair(sensors[i], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(sm->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(_dictionary.size())
|
||||
{
|
||||
UWARN("Loaded signature %d with size (%d) doesn't have the same size as the dicitonary (%d)", sm->id(), (int)sensors.size(), (int)_dictionary.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("Signature must not be null!");
|
||||
}
|
||||
}
|
||||
|
||||
std::set<int> SMMemory::reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess)
|
||||
{
|
||||
// get the signatures, if not in the working memory, they
|
||||
// will be loaded from the database in an more efficient way
|
||||
// than how it is done in the Memory
|
||||
|
||||
ULOGGER_DEBUG("");
|
||||
UTimer timer;
|
||||
std::list<int> idsToLoad;
|
||||
std::map<int, int>::iterator wmIter;
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
if(!this->getSignature(*i) && !uContains(idsToLoad, *i))
|
||||
{
|
||||
if(!maxLoaded || idsToLoad.size() < maxLoaded)
|
||||
{
|
||||
idsToLoad.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("idsToLoad = %d", idsToLoad.size());
|
||||
|
||||
std::list<Signature *> reactivatedSigns;
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->loadSMSignatures(idsToLoad, reactivatedSigns);
|
||||
}
|
||||
timeDbAccess = timer.getElapsedTime();
|
||||
for(std::list<Signature *>::iterator i=reactivatedSigns.begin(); i!=reactivatedSigns.end(); ++i)
|
||||
{
|
||||
//append to working memory
|
||||
this->addSignatureToWm(*i);
|
||||
}
|
||||
ULOGGER_DEBUG("time = %fs", timer.ticks());
|
||||
return std::set<int>(idsToLoad.begin(), idsToLoad.end());
|
||||
}
|
||||
|
||||
} // namespace rtabmap
|
||||
64
corelib/src/SMMemory.h
Normal file
64
corelib/src/SMMemory.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SIMPLEMEMORY_H_
|
||||
#define SIMPLEMEMORY_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class ColorTable;
|
||||
class SMSignature;
|
||||
|
||||
class RTABMAP_EXP SMMemory : public Memory
|
||||
{
|
||||
public:
|
||||
SMMemory(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SMMemory();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual bool init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten = false, const ParametersMap & parameters = ParametersMap());
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore);
|
||||
virtual std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
|
||||
void setRoi(const std::string & roi);
|
||||
void setVotingScheme(bool useVotingScheme);
|
||||
void setColorTable(int size);
|
||||
|
||||
protected:
|
||||
virtual void moveToTrash(Signature * s);
|
||||
virtual Signature * getSignatureLtMem(int id);
|
||||
|
||||
private:
|
||||
virtual void copyData(const Signature * from, Signature * to);
|
||||
virtual Signature * createSignature(int id, const SMState * rawData, bool keepRawData=false);
|
||||
void updateDictionary(const Signature * s);
|
||||
|
||||
private:
|
||||
bool _useLogPolar;
|
||||
bool _useVotingScheme;
|
||||
ColorTable * _colorTable;
|
||||
bool _useMotionMask;
|
||||
std::vector<std::map<int, std::set<int> > > _dictionary;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* KEYPOINTMEMORY_H_ */
|
||||
@@ -17,16 +17,36 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Signature.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "Memory.h"
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
|
||||
#include "utilite/UtiLite.h"
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
bool NeighborLink::updateIds(int idFrom, int idTo)
|
||||
{
|
||||
bool modified = false;
|
||||
if(_id == idFrom)
|
||||
{
|
||||
_id = idTo;
|
||||
modified = true;
|
||||
}
|
||||
for(unsigned int i=0; i<_baseIds.size(); ++i)
|
||||
{
|
||||
if(_baseIds[i] == idFrom)
|
||||
{
|
||||
_baseIds[i] = idTo;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
Signature::~Signature()
|
||||
{
|
||||
ULOGGER_DEBUG("id=%d", _id);
|
||||
@@ -39,16 +59,12 @@ Signature::~Signature()
|
||||
Signature::Signature(int id, const IplImage * image, bool keepImage) :
|
||||
_id(id),
|
||||
_weight(0),
|
||||
_loopClosureId(0),
|
||||
_image(0),
|
||||
_saved(false),
|
||||
_width(0),
|
||||
_height(0)
|
||||
_modified(true)
|
||||
{
|
||||
if(image)
|
||||
{
|
||||
_width = image->width;
|
||||
_height = image->height;
|
||||
if(keepImage)
|
||||
{
|
||||
_image = cvCloneImage(image);
|
||||
@@ -68,10 +84,11 @@ void Signature::setImage(const IplImage * image)
|
||||
{
|
||||
cvReleaseImage(&_image);
|
||||
_image = cvCloneImage(image);
|
||||
_modified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Parameter is null or no image is saved.");
|
||||
UDEBUG("Parameter is null or no image is saved.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,47 +128,60 @@ IplImage * Signature::decompressImage(const CvMat * imageCompressed)
|
||||
return cvDecodeImage(imageCompressed, CV_LOAD_IMAGE_ANYCOLOR);
|
||||
}
|
||||
|
||||
void Signature::addNeighbors(const NeighborsMap & neighbors)
|
||||
void Signature::addNeighbors(const NeighborsMultiMap & neighbors)
|
||||
{
|
||||
for(NeighborsMap::const_iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
|
||||
for(NeighborsMultiMap::const_iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
|
||||
{
|
||||
this->addNeighbor(i->first, i->second);
|
||||
//UDEBUG("%d -> %d, a=%d", this->id(), i->first, i->second.size());
|
||||
this->addNeighbor(i->second);
|
||||
}
|
||||
}
|
||||
|
||||
void Signature::addNeighbor(int neighbor, const std::list<std::vector<float> > & actions)
|
||||
void Signature::addNeighbor(const NeighborLink & neighbor)
|
||||
{
|
||||
ULOGGER_DEBUG("Adding neighbor %d to %d with %d actions", neighbor, this->id(), actions.size());
|
||||
std::pair<NeighborsMap::iterator, bool> inserted = _neighbors.insert(std::pair<int, std::list<std::vector<float> > >(neighbor, actions));
|
||||
//UDEBUG("%d -> %d, a=%d", this->id(), neighbor, actions.size());
|
||||
if(!inserted.second)
|
||||
UDEBUG("Add neighbor %d to %d", neighbor.id(), this->id());
|
||||
/*std::string baseIdsDebug;
|
||||
const std::vector<int> & baseIds = neighbor.baseIds();
|
||||
for(unsigned int i=0; i<baseIds.size(); ++i)
|
||||
{
|
||||
ULOGGER_ERROR("neighbor %d already added to %d", neighbor, this->id());
|
||||
return;
|
||||
}
|
||||
if(neighbor == _id)
|
||||
{
|
||||
ULOGGER_ERROR("same Id ? (%d)", neighbor, this->id());
|
||||
return;
|
||||
baseIdsDebug.append(uNumber2str(baseIds[i]));
|
||||
if(i+1 < baseIds.size())
|
||||
{
|
||||
baseIdsDebug.append(", ");
|
||||
}
|
||||
}
|
||||
UDEBUG("Adding neighbor %d to %d with %d actions, %d baseIds = [%s]", neighbor.id(), this->id(), neighbor.actions().size(), neighbor.baseIds().size(), baseIdsDebug.c_str());
|
||||
*/
|
||||
|
||||
_neighbors.insert(std::pair<int, NeighborLink>(neighbor.id(), neighbor));
|
||||
_neighborsModified = true;
|
||||
}
|
||||
|
||||
void Signature::removeNeighbor(int neighbor)
|
||||
void Signature::changeNeighborIds(int idFrom, int idTo)
|
||||
{
|
||||
ULOGGER_DEBUG("Removing neighbor %d to %d", neighbor, this->id());
|
||||
// we delete the first found because there is not supposed
|
||||
// to have more than one occurrence of this neighbor (see addNeighbor())
|
||||
int erased = _neighbors.erase(neighbor);
|
||||
if(!erased)
|
||||
std::pair<NeighborsMultiMap::iterator, NeighborsMultiMap::iterator> pair = _neighbors.equal_range(idFrom);
|
||||
|
||||
if(pair.first != _neighbors.end() && pair.first != pair.second)
|
||||
{
|
||||
ULOGGER_WARN("neighbor %d not found in %d", neighbor, this->id());
|
||||
std::list<NeighborLink> linksToAdd;
|
||||
for(NeighborsMultiMap::iterator iter = pair.first; iter!=pair.second; ++iter)
|
||||
{
|
||||
NeighborLink link = iter->second;
|
||||
link.updateIds(idFrom, idTo);
|
||||
linksToAdd.push_back(link);
|
||||
}
|
||||
_neighbors.erase(idFrom);
|
||||
for(std::list<NeighborLink>::iterator iter=linksToAdd.begin(); iter!=linksToAdd.end(); ++iter)
|
||||
{
|
||||
_neighbors.insert(std::pair<int, NeighborLink>(iter->id(), *iter));
|
||||
}
|
||||
_modified = true;
|
||||
_neighborsModified = true;
|
||||
UDEBUG("(%d) neighbor ids changed from %d to %d", _id, idFrom, idTo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//KeypointSignature
|
||||
KeypointSignature::KeypointSignature(
|
||||
const std::multimap<int, cv::KeyPoint> & words,
|
||||
@@ -191,19 +221,6 @@ float KeypointSignature::compareTo(const Signature * s) const
|
||||
HypVerificatorEpipolarGeo::findPairsDirect(words, _words, pairs, pairsId);
|
||||
|
||||
similarity = float(pairs.size()) / float(totalWords);
|
||||
|
||||
// Adjust similarity with the ratio of words between the signatures
|
||||
/*float ratio = 1;
|
||||
if(_words.size() > words.size() && _words.size())
|
||||
{
|
||||
ratio = float(words.size()) / float(_words.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
ratio = float(_words.size()) / float(words.size());
|
||||
}
|
||||
|
||||
similarity *= ratio;*/
|
||||
}
|
||||
}
|
||||
return similarity;
|
||||
@@ -215,6 +232,7 @@ void KeypointSignature::changeWordsRef(int oldWordId, int activeWordId)
|
||||
if(kps.size())
|
||||
{
|
||||
_words.erase(oldWordId);
|
||||
_wordsChanged.insert(std::make_pair(oldWordId, activeWordId));
|
||||
for(std::list<cv::KeyPoint>::const_iterator iter=kps.begin(); iter!=kps.end(); ++iter)
|
||||
{
|
||||
_words.insert(std::pair<int, cv::KeyPoint>(activeWordId, (*iter)));
|
||||
@@ -240,4 +258,126 @@ void KeypointSignature::removeWord(int wordId)
|
||||
_words.erase(wordId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//SMSignature
|
||||
SMSignature::SMSignature(
|
||||
const std::vector<int> & sensors,
|
||||
const std::vector<unsigned char> & motionMask,
|
||||
int id,
|
||||
const IplImage * image,
|
||||
bool keepRawData) :
|
||||
Signature(id, image, keepRawData),
|
||||
_sensors(sensors),
|
||||
_motionMask(motionMask)
|
||||
{
|
||||
if(_sensors.size() != _motionMask.size() && _motionMask.size() > 0)
|
||||
{
|
||||
UFATAL("Sensors and mask must have the same size (%d vs %d)", (int)_sensors.size(), (int)_motionMask.size());
|
||||
}
|
||||
UDEBUG("sensors=%d", (int)_sensors.size());
|
||||
}
|
||||
|
||||
SMSignature::SMSignature(int id) :
|
||||
Signature(id)
|
||||
{
|
||||
}
|
||||
|
||||
SMSignature::~SMSignature()
|
||||
{
|
||||
}
|
||||
|
||||
float SMSignature::compareTo(const Signature * s) const
|
||||
{
|
||||
const SMSignature * sm = dynamic_cast<const SMSignature *>(s);
|
||||
float similarity = 0;
|
||||
|
||||
if(sm)
|
||||
{
|
||||
const std::vector<int> & sensorsB = sm->getSensors();
|
||||
const std::vector<unsigned char> & motionMaskB = sm->getMotionMask();
|
||||
|
||||
if(_sensors.size() == sensorsB.size() && _sensors.size()) //Compatible
|
||||
{
|
||||
bool appearanceOnly = false;
|
||||
if(appearanceOnly)
|
||||
{
|
||||
std::multiset<int> sensorsSetA(_sensors.begin(), _sensors.end());
|
||||
std::multiset<int> sensorsSetB(sensorsB.begin(), sensorsB.end());
|
||||
std::set<int> ids(_sensors.begin(), _sensors.end());
|
||||
std::multiset<int>::iterator iterA;
|
||||
std::multiset<int>::iterator iterB;
|
||||
float realPairsCount = 0;
|
||||
for(std::set<int>::iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
iterA = sensorsSetA.find(*i);
|
||||
iterB = sensorsSetB.find(*i);
|
||||
while(iterA != sensorsSetA.end() && iterB != sensorsSetB.end() && *iterA == *iterB && *iterA == *i)
|
||||
{
|
||||
++iterA;
|
||||
++iterB;
|
||||
++realPairsCount;
|
||||
}
|
||||
}
|
||||
similarity = realPairsCount / float(_sensors.size());
|
||||
}
|
||||
else if(_motionMask.size() == _sensors.size() &&
|
||||
_motionMask.size() == motionMaskB.size())
|
||||
{
|
||||
int sum = 0;
|
||||
int maskSumA = 0;
|
||||
int maskSumB = 0;
|
||||
|
||||
// compare sensors
|
||||
for(unsigned int i=0; i<_sensors.size(); ++i)
|
||||
{
|
||||
maskSumA += _motionMask[i];
|
||||
maskSumB += motionMaskB[i];
|
||||
sum += _sensors.at(i) == sensorsB.at(i) && _motionMask[i] && motionMaskB[i] ? 1 : 0;
|
||||
}
|
||||
|
||||
int totalSize = maskSumA>maskSumB?maskSumA:maskSumB;
|
||||
if(totalSize)
|
||||
{
|
||||
similarity = float(sum)/float(totalSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sum = 0;
|
||||
// compare sensors
|
||||
for(unsigned int i=0; i<_sensors.size(); ++i)
|
||||
{
|
||||
sum += _sensors.at(i) == sensorsB.at(i) ? 1 : 0;
|
||||
}
|
||||
similarity = float(sum)/float(_sensors.size());
|
||||
}
|
||||
|
||||
if(similarity<0 || similarity>1)
|
||||
{
|
||||
UERROR("Something wrong! similarity is not between 0 and 1 (%f)", similarity);
|
||||
}
|
||||
}
|
||||
else if(!s->isBadSignature() && !this->isBadSignature())
|
||||
{
|
||||
UWARN("Not compatible signatures : nb sensors A=%d B=%d", (int)_sensors.size(), (int)sensorsB.size());
|
||||
}
|
||||
}
|
||||
else if(s)
|
||||
{
|
||||
UWARN("Only SM signatures are compared. (type tested=%s)", s->signatureType().c_str());
|
||||
}
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
bool SMSignature::isBadSignature() const
|
||||
{
|
||||
if(_sensors.size() == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} //namespace rtabmap
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
//TODO : add copy constructor
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
class Memory;
|
||||
typedef std::map<int, std::list<std::vector<float> > > NeighborsMap;
|
||||
|
||||
class RTABMAP_EXP Signature
|
||||
{
|
||||
public:
|
||||
static CvMat * compressImage(const IplImage * image);
|
||||
static IplImage * decompressImage(const CvMat * imageCompressed);
|
||||
|
||||
public:
|
||||
virtual ~Signature();
|
||||
|
||||
/**
|
||||
* Must return a value between >=0 and <=1 (1 means 100% similarity)
|
||||
*/
|
||||
virtual float compareTo(const Signature * signature) const = 0;
|
||||
virtual bool isBadSignature() const = 0;
|
||||
virtual std::string signatureType() const = 0;
|
||||
|
||||
const IplImage * getImage() const;
|
||||
void setImage(const IplImage * image);
|
||||
|
||||
int id() const {return _id;}
|
||||
|
||||
void addNeighbors(const NeighborsMap & neighbors);
|
||||
void addNeighbor(int neighborId, const std::list<std::vector<float> > & actions);
|
||||
void removeNeighbor(int neighborId);
|
||||
bool hasNeighbor(int neighborId) const {return _neighbors.find(neighborId) != _neighbors.end();}
|
||||
void setWeight(int weight) {_weight = weight;}
|
||||
void setLoopClosureId(int loopClosureId) {_loopClosureId = loopClosureId;}
|
||||
void setWidth(int width) {_width = width;}
|
||||
void setHeight(int height) {_height = height;}
|
||||
void setSaved(bool saved) {_saved = saved;}
|
||||
|
||||
const NeighborsMap & getNeighbors() const {return _neighbors;}
|
||||
int getWeight() const {return _weight;}
|
||||
int getLoopClosureId() const {return _loopClosureId;}
|
||||
int getWidth() const {return _width;}
|
||||
int getHeight() const {return _height;}
|
||||
bool isSaved() const {return _saved;}
|
||||
|
||||
protected:
|
||||
Signature(int id, const IplImage * image = 0, bool keepImage = false);
|
||||
|
||||
private:
|
||||
int _id;
|
||||
NeighborsMap _neighbors; // id, [action1, action2, ...] All actions must have the same length
|
||||
int _weight;
|
||||
int _loopClosureId;
|
||||
IplImage * _image;
|
||||
bool _saved; // If it's saved to bd
|
||||
int _width; // pixels
|
||||
int _height; // pixels
|
||||
};
|
||||
|
||||
|
||||
class KeypointDetector;
|
||||
class VWDictionary;
|
||||
|
||||
class RTABMAP_EXP KeypointSignature :
|
||||
public Signature
|
||||
{
|
||||
public:
|
||||
KeypointSignature(
|
||||
const std::multimap<int, cv::KeyPoint> & words,
|
||||
int id,
|
||||
const IplImage * image = 0,
|
||||
bool keepRawData = false);
|
||||
KeypointSignature(int id);
|
||||
|
||||
virtual ~KeypointSignature();
|
||||
|
||||
virtual float compareTo(const Signature * signature) const;
|
||||
virtual bool isBadSignature() const;
|
||||
virtual std::string signatureType() const {return "KeypointSignature";};
|
||||
|
||||
void removeAllWords();
|
||||
void removeWord(int wordId);
|
||||
void changeWordsRef(int oldWordId, int activeWordId);
|
||||
|
||||
void setWords(const std::multimap<int, cv::KeyPoint> & words) {_enabled = false;_words = words;}
|
||||
bool isEnabled() const {return _enabled;}
|
||||
void setEnabled(bool enabled) {_enabled = enabled;}
|
||||
const std::multimap<int, cv::KeyPoint> & getWords() const {return _words;}
|
||||
|
||||
private:
|
||||
// Contains all words (Some can be duplicates -> if a word appears 2
|
||||
// times in the signature, it will be 2 times in this list)
|
||||
// Words match with the CvSeq keypoints and descriptors
|
||||
std::multimap<int, cv::KeyPoint> _words; // word <id, keypoint>
|
||||
bool _enabled;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace rtabmap
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "VWDictionary.h"
|
||||
|
||||
#include "VisualWord.h"
|
||||
#include "Signature.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "NearestNeighbor.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
@@ -406,24 +406,23 @@ void VWDictionary::removeAllWordRef(int wordId, int signatureId)
|
||||
}
|
||||
}
|
||||
|
||||
std::list<int> VWDictionary::addNewWords(const std::list<std::vector<float> > & descriptors,
|
||||
unsigned int dim,
|
||||
std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
int signatureId)
|
||||
{
|
||||
UTimer timer;
|
||||
std::list<int> wordIds;
|
||||
ULOGGER_DEBUG("");
|
||||
if(_dim && _dim != dim && dim)
|
||||
if(_dim && _dim != descriptors.cols && descriptors.cols)
|
||||
{
|
||||
ULOGGER_WARN("Descriptor size has changed! (%d to %d), Nearest neighbor approaches may not work with different descriptor sizes.", _dim, dim);
|
||||
ULOGGER_WARN("Descriptor size has changed! (%d to %d), Nearest neighbor approaches may not work with different descriptor sizes.", _dim, descriptors.cols);
|
||||
}
|
||||
else if(!dim)
|
||||
else if(!descriptors.cols)
|
||||
{
|
||||
ULOGGER_ERROR("Descriptor size is null?!?");
|
||||
return wordIds;
|
||||
}
|
||||
_dim = dim;
|
||||
if (descriptors.size() == 0 || !_dim)
|
||||
_dim = descriptors.cols;
|
||||
if (descriptors.empty() || !_dim)
|
||||
{
|
||||
ULOGGER_ERROR("Parameters don't fit the requirements of this method");
|
||||
return wordIds;
|
||||
@@ -442,31 +441,24 @@ std::list<int> VWDictionary::addNewWords(const std::list<std::vector<float> > &
|
||||
{
|
||||
std::list<VisualWord *> newWords;
|
||||
|
||||
cv::Mat results(descriptors.size(), k, CV_32SC1); // results index
|
||||
cv::Mat results(descriptors.rows, k, CV_32SC1); // results index
|
||||
cv::Mat dists;
|
||||
if(_nn->isDist64F())
|
||||
{
|
||||
dists = cv::Mat(descriptors.size(), k, CV_64FC1); // Distance results are CV_64FC1;
|
||||
dists = cv::Mat(descriptors.rows, k, CV_64FC1); // Distance results are CV_64FC1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dists = cv::Mat(descriptors.size(), k, CV_32FC1); // Distance results are CV_32FC1
|
||||
dists = cv::Mat(descriptors.rows, k, CV_32FC1); // Distance results are CV_32FC1
|
||||
}
|
||||
cv::Mat newPts(descriptors.size(), _dim, CV_32F); // SURF descriptors are CV_32F
|
||||
|
||||
// fill the request matrix
|
||||
std::list<std::vector<float> >::const_iterator itDesc = descriptors.begin();
|
||||
for(unsigned int i=0; i<descriptors.size(); ++itDesc, ++i)
|
||||
cv::Mat newPts; // SURF descriptors are CV_32F
|
||||
if(descriptors.type()!=CV_32F)
|
||||
{
|
||||
float * rowFl = newPts.ptr<float>(i);
|
||||
if(itDesc->size() == _dim)
|
||||
{
|
||||
memcpy(rowFl, (const float *)itDesc->data(), _dim*sizeof(float));
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_WARN("Descriptors are not the same size! The result may be wrong...");
|
||||
}
|
||||
descriptors.convertTo(newPts, CV_32F); // make sure it's CV_32F
|
||||
}
|
||||
else
|
||||
{
|
||||
newPts = descriptors;
|
||||
}
|
||||
|
||||
UTimer timerLocal;
|
||||
@@ -480,7 +472,7 @@ std::list<int> VWDictionary::addNewWords(const std::list<std::vector<float> > &
|
||||
}
|
||||
|
||||
//
|
||||
for(unsigned int i = 0; i < descriptors.size(); ++i)
|
||||
for(int i = 0; i < descriptors.rows; ++i)
|
||||
{
|
||||
// Check if this descriptor matches with a word from the last signature (a word not already added to the tree)
|
||||
std::map<float, int> fullResults; // Contains results from the kd-tree search and the naive search in new words
|
||||
@@ -531,7 +523,10 @@ std::list<int> VWDictionary::addNewWords(const std::list<std::vector<float> > &
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Not enough nearest neighbors found! fullResults=%d (descriptor %d)", fullResults.size(), i);
|
||||
if(!_dataTree.empty())
|
||||
{
|
||||
UWARN("Not enough nearest neighbors found! fullResults=%d (descriptor %d)", fullResults.size(), i);
|
||||
}
|
||||
badDist = true; // Rejected
|
||||
}
|
||||
}
|
||||
@@ -566,10 +561,9 @@ std::list<int> VWDictionary::addNewWords(const std::list<std::vector<float> > &
|
||||
ULOGGER_DEBUG("Naive NN");
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::list<std::vector<float> >::const_iterator itDesc = descriptors.begin();
|
||||
for(; itDesc!=descriptors.end();++itDesc)
|
||||
for(int i=0; i<descriptors.rows; ++i)
|
||||
{
|
||||
const float* d = itDesc->data();
|
||||
const float* d = descriptors.ptr<float>(i);
|
||||
|
||||
std::map<float, int> results;
|
||||
naiveNNSearch(uValuesList(_visualWords), d, _dim, results, k);
|
||||
@@ -871,14 +865,14 @@ void VWDictionary::addWord(VisualWord * vw)
|
||||
}
|
||||
|
||||
// dist = (euclidean dist)^2, "k" nearest neighbors
|
||||
void VWDictionary::naiveNNSearch(const std::list<VisualWord *> & words, const float * d, unsigned int length, std::map<float, int> & results, unsigned int k) const
|
||||
void VWDictionary::naiveNNSearch(const std::list<VisualWord *> & words, const float * d, int length, std::map<float, int> & results, unsigned int k) const
|
||||
{
|
||||
double total_cost = 0;
|
||||
double t0, t1, t2, t3;
|
||||
const float * dw = 0;
|
||||
bool goodMatch;
|
||||
|
||||
if(!words.size() && k > 0)
|
||||
if(!words.size() || k == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -896,7 +890,7 @@ void VWDictionary::naiveNNSearch(const std::list<VisualWord *> & words, const fl
|
||||
total_cost += t0*t0;
|
||||
|
||||
// compare descriptors
|
||||
unsigned int i = 0;
|
||||
int i = 0;
|
||||
if(length>=4)
|
||||
{
|
||||
for(; i <= length-4; i += 4 )
|
||||
@@ -1036,16 +1030,12 @@ void VWDictionary::getCommonWords(unsigned int nbCommonWords, int totalSign, std
|
||||
|
||||
const VisualWord * VWDictionary::getWord(int id) const
|
||||
{
|
||||
return uValue(_visualWords, id);
|
||||
return uValue(_visualWords, id, (VisualWord *)0);
|
||||
}
|
||||
|
||||
void VWDictionary::setWordSaved(int id, bool saved)
|
||||
const VisualWord * VWDictionary::getUnusedWord(int id) const
|
||||
{
|
||||
VisualWord * w = uValue(_visualWords, id);
|
||||
if(w)
|
||||
{
|
||||
w->setSaved(saved);
|
||||
}
|
||||
return uValue(_unusedWords, id, (VisualWord *)0);
|
||||
}
|
||||
|
||||
std::vector<VisualWord*> VWDictionary::getUnusedWords() const
|
||||
|
||||
@@ -50,18 +50,17 @@ public:
|
||||
virtual void update();
|
||||
|
||||
virtual std::list<int> addNewWords(
|
||||
const std::list<std::vector<float> > & descriptors,
|
||||
unsigned int dim,
|
||||
const cv::Mat & descriptors,
|
||||
int signatureId);
|
||||
virtual void addWord(VisualWord * vw);
|
||||
|
||||
virtual std::vector<int> findNN(const std::list<VisualWord *> & vws, bool searchInNewlyAddedWords = true) const;
|
||||
void naiveNNSearch(const std::list<VisualWord *> & words, const float * d, unsigned int length, std::map<float, int> & results, unsigned int k) const;
|
||||
void naiveNNSearch(const std::list<VisualWord *> & words, const float * d, int length, std::map<float, int> & results, unsigned int k) const;
|
||||
|
||||
void addWordRef(int wordId, int signatureId);
|
||||
void removeAllWordRef(int wordId, int signatureId);
|
||||
const VisualWord * getWord(int id) const;
|
||||
void setWordSaved(int id, bool saved);
|
||||
const VisualWord * getUnusedWord(int id) const;
|
||||
void setLastWordId(int id) {_lastWordId = id;}
|
||||
void getCommonWords(unsigned int nbCommonWords, int totalSign, std::list<int> & commonWords) const;
|
||||
const std::map<int, VisualWord *> & getVisualWords() const {return _visualWords;}
|
||||
@@ -105,12 +104,12 @@ private:
|
||||
float _nndrRatio;
|
||||
unsigned int _maxLeafs;
|
||||
std::string _dictionaryPath; // a pre-computed dictionary (.txt)
|
||||
unsigned int _dim;
|
||||
int _dim;
|
||||
int _lastWordId;
|
||||
NearestNeighbor * _nn;
|
||||
cv::Mat _dataTree;
|
||||
std::map<int ,int> _mapIndexId;
|
||||
std::map<int, VisualWord*> _unusedWords; //<id,VisualWord*>
|
||||
std::map<int, VisualWord*> _unusedWords; //<id,VisualWord*>, note that these words stay in _visualWords
|
||||
};
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "Signature.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include <cstdlib>
|
||||
#include <opencv2/calib3d/calib3d.hpp>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
VisualWord::VisualWord(int id, const float * descriptor, unsigned int dim, int signatureId) :
|
||||
VisualWord::VisualWord(int id, const float * descriptor, int dim, int signatureId) :
|
||||
_id(id),
|
||||
_saved(false),
|
||||
_totalReferences(0)
|
||||
|
||||
@@ -31,7 +31,7 @@ class SignatureSurf;
|
||||
class RTABMAP_EXP VisualWord
|
||||
{
|
||||
public:
|
||||
VisualWord(int id, const float * descriptor, unsigned int dim, int signatureId = 0);
|
||||
VisualWord(int id, const float * descriptor, int dim, int signatureId = 0);
|
||||
~VisualWord();
|
||||
|
||||
void addRef(int signatureId);
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
int getTotalReferences() const {return _totalReferences;}
|
||||
int id() const {return _id;}
|
||||
const float * getDescriptor() const {return _descriptor;}
|
||||
unsigned int getDim() const {return _dim;}
|
||||
int getDim() const {return _dim;}
|
||||
const std::map<int, int> & getReferences() const {return _references;} // (signature id , occurrence in the signature)
|
||||
|
||||
bool isSaved() const {return _saved;}
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
private:
|
||||
int _id;
|
||||
float * _descriptor;
|
||||
unsigned int _dim;
|
||||
int _dim;
|
||||
bool _saved; // If it's saved to bd
|
||||
|
||||
int _totalReferences;
|
||||
|
||||
BIN
corelib/src/resources/ColorIndexes1024.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes1024.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes128.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes128.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes16.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes16.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes256.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes256.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes32.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes32.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes512.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes512.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes64.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes64.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes65536.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes65536.bin.zip
Normal file
Binary file not shown.
BIN
corelib/src/resources/ColorIndexes8.bin.zip
Normal file
BIN
corelib/src/resources/ColorIndexes8.bin.zip
Normal file
Binary file not shown.
@@ -23,14 +23,30 @@ CREATE TABLE Signature (
|
||||
id INTEGER NOT NULL,
|
||||
type VARCHAR NOT NULL,
|
||||
weight INTEGER,
|
||||
loopClosureId INTEGER,
|
||||
image BLOB,
|
||||
imgWidth INTEGER,
|
||||
imgHeight INTEGER,
|
||||
loopClosureIds BLOB,
|
||||
childLoopClosureIds BLOB,
|
||||
timeEnter DATE,
|
||||
PRIMARY KEY (id),
|
||||
FOREIGN KEY (type) REFERENCES SignatureType(type),
|
||||
FOREIGN KEY (loopClosureId) REFERENCES Signature(id)
|
||||
FOREIGN KEY (type) REFERENCES SignatureType(type)
|
||||
);
|
||||
|
||||
CREATE TABLE Image (
|
||||
id INTEGER NOT NULL,
|
||||
width INTEGER NOT NULL,
|
||||
height INTEGER NOT NULL,
|
||||
channels INTEGER NOT NULL,
|
||||
compressed CHAR NOT NULL,
|
||||
data BLOB,
|
||||
timeEnter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE SMState (
|
||||
id INTEGER NOT NULL,
|
||||
sensors BLOB,
|
||||
motionMask BLOB,
|
||||
timeEnter DATE,
|
||||
FOREIGN KEY (id) REFERENCES Signature(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Neighbor (
|
||||
@@ -38,8 +54,7 @@ CREATE TABLE Neighbor (
|
||||
nid INTEGER NOT NULL,
|
||||
actionSize INTEGER,
|
||||
actions BLOB,
|
||||
timeEnter DATE,
|
||||
PRIMARY KEY (sid, nid),
|
||||
baseIds BLOB,
|
||||
FOREIGN KEY (sid) REFERENCES Signature(id),
|
||||
FOREIGN KEY (nid) REFERENCES Signature(id)
|
||||
);
|
||||
@@ -66,7 +81,6 @@ CREATE TABLE Map_SS_VW (
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
hessian FLOAT NOT NULL,
|
||||
timeEnter DATE,
|
||||
FOREIGN KEY (signatureId) REFERENCES Signature(id),
|
||||
FOREIGN KEY (visualWordId) REFERENCES VisualWord(id)
|
||||
);
|
||||
@@ -90,20 +104,38 @@ CREATE TABLE StatisticsAfterRunSurf (
|
||||
CREATE TRIGGER insert_Signature BEFORE INSERT ON Signature
|
||||
WHEN NOT EXISTS (SELECT type FROM SignatureType WHERE SignatureType.type = NEW.type)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed');
|
||||
SELECT RAISE(ABORT, 'Foreign key Signature.type constraint failed');
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Neighbor BEFORE INSERT ON Neighbor
|
||||
CREATE TRIGGER insert_SMState BEFORE INSERT ON SMState
|
||||
WHEN NOT EXISTS (SELECT id FROM Signature WHERE Signature.id = NEW.id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key SMState.id constraint failed');
|
||||
END;
|
||||
|
||||
--CREATE TRIGGER insert_Neighbor_unique BEFORE INSERT ON Neighbor
|
||||
--WHEN NEW.sid = NEW.nid
|
||||
--BEGIN
|
||||
-- SELECT RAISE(ABORT, 'Cannot add self references');
|
||||
--END;
|
||||
|
||||
CREATE TRIGGER insert_Neighbor_sid BEFORE INSERT ON Neighbor
|
||||
WHEN NOT EXISTS (SELECT id FROM Signature WHERE Signature.id = NEW.sid)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed');
|
||||
SELECT RAISE(ABORT, 'Foreign key Neighbor.sid constraint failed');
|
||||
END;
|
||||
|
||||
--Commented before a link can be added before the neighbor is saved...
|
||||
--CREATE TRIGGER insert_Neighbor_nid BEFORE INSERT ON Neighbor
|
||||
--WHEN NOT EXISTS (SELECT id FROM Signature WHERE Signature.id = NEW.nid)
|
||||
--BEGIN
|
||||
-- SELECT RAISE(ABORT, 'Foreign key Neighbor.nid constraint failed');
|
||||
--END;
|
||||
|
||||
CREATE TRIGGER insert_Map_SS_VW BEFORE INSERT ON Map_SS_VW
|
||||
WHEN NOT EXISTS (SELECT type FROM Signature WHERE Signature.id = NEW.signatureId AND type='surf')
|
||||
--OR NOT EXISTS (SELECT id FROM VisualWord WHERE VisualWord.id = NEW.visualWordId)
|
||||
WHEN NOT EXISTS (SELECT type FROM Signature WHERE Signature.id = NEW.signatureId AND type='KeypointSignature')
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed');
|
||||
SELECT RAISE(ABORT, 'KeypointSignature type constraint failed');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for timeEnter
|
||||
@@ -112,21 +144,11 @@ BEGIN
|
||||
UPDATE Signature SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Neighbor_timeEnter AFTER INSERT ON Neighbor
|
||||
BEGIN
|
||||
UPDATE Neighbor SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_VisualWord_timeEnter AFTER INSERT ON VisualWord
|
||||
BEGIN
|
||||
UPDATE VisualWord SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Map_SS_VW_timeEnter AFTER INSERT ON Map_SS_VW
|
||||
BEGIN
|
||||
UPDATE Map_SS_VW SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_StatisticsAfterRun_timeEnter AFTER INSERT ON StatisticsAfterRun
|
||||
BEGIN
|
||||
UPDATE StatisticsAfterRun SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
@@ -142,18 +164,19 @@ END;
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE INDEX IDX_Map_SS_VW_SignatureId on Map_SS_VW (signatureId);
|
||||
CREATE INDEX IDX_Map_SS_VW_VisualWordId on Map_SS_VW (visualWordId);
|
||||
CREATE INDEX IDX_Signature_Id on Signature (id);
|
||||
CREATE INDEX IDX_VisualWord_Id on VisualWord (id);
|
||||
CREATE INDEX IDX_Signature_TimeEnter on Signature (timeEnter);
|
||||
CREATE INDEX IDX_VisualWord_TimeEnter on VisualWord (timeEnter);
|
||||
-- CREATE INDEX IDX_Map_SS_VW_VisualWordId on Map_SS_VW (visualWordId);
|
||||
-- CREATE INDEX IDX_Signature_Id on Signature (id);
|
||||
-- CREATE INDEX IDX_VisualWord_Id on VisualWord (id);
|
||||
CREATE INDEX IDX_SMState_Id on SMState (id);
|
||||
-- CREATE INDEX IDX_Signature_TimeEnter on Signature (timeEnter);
|
||||
-- CREATE INDEX IDX_VisualWord_TimeEnter on VisualWord (timeEnter);
|
||||
CREATE INDEX IDX_Neighbor_Sid on Neighbor (sid);
|
||||
|
||||
-- *******************************************************************
|
||||
-- Data
|
||||
-- *******************************************************************
|
||||
INSERT INTO SignatureType(type) VALUES ('fourier');
|
||||
INSERT INTO SignatureType(type) VALUES ('surf');
|
||||
INSERT INTO SignatureType(type) VALUES ('KeypointSignature');
|
||||
INSERT INTO SignatureType(type) VALUES ('SMSignature');
|
||||
|
||||
-- *******************************************************************
|
||||
-- TESTS
|
||||
|
||||
Reference in New Issue
Block a user