merged attention branch to trunk

git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@657 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
matlabbe
2012-12-11 18:05:05 +00:00
parent f9033809a2
commit 2836d4c48c
216 changed files with 7983 additions and 94891 deletions

View File

@@ -1,53 +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/>.
*/
#ifndef ACTUATOR_H_
#define ACTUATOR_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <opencv2/core/core.hpp>
#include <utilite/UEvent.h>
#include <list>
namespace rtabmap {
class Actuator
{
public:
enum Type{kTypeTwist=0, kTypeNotSpecified};
public:
Actuator(const cv::Mat & data, Type type, int num = 0) :
_data(data),
_type(type),
_num(num)
{}
const cv::Mat & data() const {return _data;}
int type() const {return _type;}
int num() const {return _num;}
virtual ~Actuator() {};
private:
cv::Mat _data;
int _type;
int _num;
};
}
#endif /* ACTUATOR_H_ */

View File

@@ -29,8 +29,8 @@
#include <utilite/UDirectory.h>
#include <utilite/UTimer.h>
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/KeypointDetector.h"
#include "rtabmap/core/KeypointDescriptor.h"
#include "rtabmap/core/Features2d.h"
#include "rtabmap/core/Image.h"
#include <set>
#include <stack>
#include <list>
@@ -59,9 +59,7 @@ public:
CameraEvent(const cv::Mat & descriptors, const std::vector<cv::KeyPoint> & keypoints, const cv::Mat & image = cv::Mat(), int cameraId = 0) :
UEvent(kCodeFeatures),
_cameraId(cameraId),
_image(image),
_descriptors(descriptors),
_keypoints(keypoints)
_image(image, descriptors, keypoints)
{
}
CameraEvent(int cameraId = 0) :
@@ -73,18 +71,14 @@ public:
int cameraId() const {return _cameraId;}
// Image or descriptors
const cv::Mat & image() const {return _image;}
const cv::Mat & descriptors() const {return _descriptors;}
const std::vector<cv::KeyPoint> & keypoints() const {return _keypoints;}
const Image & image() const {return _image;}
virtual ~CameraEvent() {}
virtual std::string getClassName() const {return std::string("CameraEvent");}
private:
int _cameraId;
cv::Mat _image;
cv::Mat _descriptors;
std::vector<cv::KeyPoint> _keypoints;
Image _image;
};
/**

View File

@@ -1,52 +0,0 @@
#ifndef COLORTABLE_H
#define COLORTABLE_H
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <vector>
namespace rtabmap
{
class RTABMAP_EXP ColorTable
{
public:
enum Size{kSize8 = 8,
kSize16 = 16,
kSize32 = 32,
kSize64 = 64,
kSize128 = 128,
kSize256 = 256,
kSize512 = 512,
kSize1024 = 1024,
kSize65536 = 65536};
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

View File

@@ -30,11 +30,10 @@
#include "utilite/UMutex.h"
#include "utilite/UThreadNode.h"
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/Signature.h"
namespace rtabmap {
class KeypointSignature;
class Signature;
class SMSignature;
class VWDictionary;
class VisualWord;
@@ -53,26 +52,21 @@ class RTABMAP_EXP DBDriver : public UThreadNode
public:
virtual ~DBDriver();
virtual std::string getDriverName() const = 0;
virtual void parseParameters(const ParametersMap & parameters);
const std::string & getUrl() const {return _url;}
void beginTransaction() const;
void commit() const;
void asyncSave(Signature * s);
void asyncSave(VisualWord * s);
void asyncSave(Signature * s); //ownership transferred
void asyncSave(VisualWord * vw); //ownership transferred
void emptyTrashes(bool async = false);
double getEmptyTrashesTime() const {return _emptyTrashesTime;}
bool isImagesCompressed() const {return _imagesCompressed;}
public:
bool addStatisticsAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed) const;
bool addStatisticsAfterRunSurf(int dictionarySize) const;
bool deleteAllVisualWords() const;
bool deleteAllObsoleteSSVWLinks() const;
bool deleteUnreferencedWords() const;
void addStatisticsAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed) const;
void addStatisticsAfterRunSurf(int dictionarySize) const;
public:
// Mutex-protected methods of abstract versions below
@@ -84,31 +78,24 @@ public:
bool isConnected() const;
long getMemoryUsed() const; // In bytes
bool executeNoResult(const std::string & sql) const;
// Update
bool changeWordsRef(const std::map<int, int> & refsToChange); // <oldWordId, activeWordId>
bool deleteWords(const std::vector<int> & ids);
void executeNoResult(const std::string & sql) const;
// Load objects
bool load(VWDictionary * dictionary) const;
bool loadLastNodes(std::list<Signature *> & signatures) const;
bool loadKeypointSignatures(const std::list<int> & ids, std::list<Signature *> & signatures);
bool loadSMSignatures(const std::list<int> & ids, std::list<Signature *> & signatures);
bool loadWords(const std::list<int> & wordIds, std::list<VisualWord *> & vws);
void load(VWDictionary * dictionary) const;
void loadLastNodes(std::list<Signature *> & signatures) const;
void loadSignatures(const std::list<int> & ids, std::list<Signature *> & signatures);
void loadWords(const std::set<int> & wordIds, std::list<VisualWord *> & vws);
// Specific queries...
bool getRawData(int id, std::list<Sensor> & data) const;
bool getActuatorData(int id, std::list<Actuator> & data) const;
bool getNeighborIds(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const;
bool loadNeighbors(int signatureId, NeighborsMultiMap & neighbors) const;
bool getWeight(int signatureId, int & weight) const;
bool getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const;
bool getAllNodeIds(std::set<int> & ids) const;
bool getLastNodeId(int & id) const;
bool getLastWordId(int & id) const;
bool getInvertedIndexNi(int signatureId, int & ni) const;
bool getHighestWeightedNodeIds(unsigned int count, std::multimap<int, int> & ids) const;
void getImage(int id, cv::Mat & image) const;
void getNeighborIds(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const;
void loadNeighbors(int signatureId, std::set<int> & neighbors) const;
void getWeight(int signatureId, int & weight) const;
void getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const;
void getAllNodeIds(std::set<int> & ids) const;
void getLastNodeId(int & id) const;
void getLastWordId(int & id) const;
void getInvertedIndexNi(int signatureId, int & ni) const;
protected:
DBDriver(const ParametersMap & parameters = ParametersMap());
@@ -119,41 +106,31 @@ private:
virtual bool isConnectedQuery() const = 0;
virtual long getMemoryUsedQuery() const = 0; // In bytes
virtual bool executeNoResultQuery(const std::string & sql) const = 0;
virtual void executeNoResultQuery(const std::string & sql) const = 0;
virtual bool changeWordsRefQuery(const std::map<int, int> & refsToChange) const = 0; // <oldWordId, activeWordId>
virtual bool deleteWordsQuery(const std::vector<int> & ids) const = 0;
virtual bool getNeighborIdsQuery(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const = 0;
virtual bool getWeightQuery(int signatureId, int & weight) const = 0;
virtual bool getLoopClosureIdsQuery(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const = 0;
virtual void getNeighborIdsQuery(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const = 0;
virtual void getWeightQuery(int signatureId, int & weight) const = 0;
virtual void getLoopClosureIdsQuery(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const = 0;
virtual bool saveQuery(const std::vector<VisualWord *> & visualWords) const = 0;
virtual bool updateQuery(const std::list<Signature *> & signatures) const = 0;
virtual bool saveQuery(const std::list<Signature *> & signatures) const = 0;
virtual void saveQuery(const std::vector<VisualWord *> & visualWords) const = 0;
virtual void updateQuery(const std::list<Signature *> & signatures) const = 0;
virtual void saveQuery(const std::list<Signature *> & signatures) const = 0;
// Load objects
virtual bool loadQuery(VWDictionary * dictionary) const = 0;
virtual bool loadLastNodesQuery(std::list<Signature *> & signatures) const = 0;
virtual bool loadQuery(int signatureId, Signature ** s) const = 0;
virtual bool loadQuery(int wordId, VisualWord ** vw) const = 0;
virtual bool loadQuery(int signatureId, KeypointSignature * ss) const = 0;
virtual bool loadQuery(int signatureId, SMSignature * ss) const = 0;
virtual bool loadKeypointSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const = 0;
virtual bool loadSMSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const = 0;
virtual bool loadWordsQuery(const std::list<int> & wordIds, std::list<VisualWord *> & vws) const = 0;
virtual bool loadNeighborsQuery(int signatureId, NeighborsMultiMap & neighbors) const = 0;
virtual void loadQuery(VWDictionary * dictionary) const = 0;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const = 0;
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const = 0;
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const = 0;
virtual void loadNeighborsQuery(int signatureId, std::set<int> & neighbors) const = 0;
virtual bool getRawDataQuery(int id, std::list<Sensor> & rawData) const = 0;
virtual bool getActuatorDataQuery(int id, std::list<Actuator> & rawData) const = 0;
virtual bool getAllNodeIdsQuery(std::set<int> & ids) const = 0;
virtual bool getLastNodeIdQuery(int & id) const = 0;
virtual bool getLastWordIdQuery(int & id) const = 0;
virtual bool getInvertedIndexNiQuery(int signatureId, int & ni) const = 0;
virtual bool getHighestWeightedNodeIdsQuery(unsigned int count, std::multimap<int,int> & signatures) const = 0;
virtual void getImageQuery(int id, cv::Mat & rawData) const = 0;
virtual void getAllNodeIdsQuery(std::set<int> & ids) const = 0;
virtual void getLastIdQuery(const std::string & tableName, int & id) const = 0;
virtual void getInvertedIndexNiQuery(int signatureId, int & ni) const = 0;
private:
//non-abstract methods
bool saveOrUpdate(const std::vector<Signature *> & signatures) const;
void saveOrUpdate(const std::vector<Signature *> & signatures) const;
//thread stuff
virtual void mainLoop();
@@ -166,8 +143,6 @@ private:
UMutex _trashesMutex;
UMutex _dbSafeAccessMutex;
USemaphore _addSem;
unsigned int _minSignaturesToSave;
unsigned int _minWordsToSave;
bool _imagesCompressed;
double _emptyTrashesTime;
std::string _url;

View File

@@ -1,42 +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/>.
*/
#ifndef DBDRIVERFACTORY_H_
#define DBDRIVERFACTORY_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/Parameters.h"
#include <string>
namespace rtabmap {
class DBDriver;
class RTABMAP_EXP DBDriverFactory
{
public:
static DBDriver * createDBDriver(const std::string & dbDriverName, const ParametersMap & parameters = ParametersMap());
public:
DBDriverFactory();
virtual ~DBDriverFactory();
};
}
#endif /* DBDRIVERFACTORY_H_ */

View File

@@ -10,12 +10,11 @@
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/Sensor.h"
#include "rtabmap/core/Actuator.h"
#include <utilite/UThreadNode.h>
#include <utilite/UTimer.h>
#include <opencv2/core/core.hpp>
#include <set>
namespace rtabmap {
@@ -25,14 +24,12 @@ class DBDriver;
class RTABMAP_EXP DBReader : public UThreadNode {
public:
DBReader(const std::string & databasePath,
float frameRate = 0.0f,
const std::set<Sensor::Type> & sensorTypes = std::set<Sensor::Type>(),
const std::set<Actuator::Type> & actuatorTypes = std::set<Actuator::Type>());
float frameRate = 0.0f);
virtual ~DBReader();
bool init();
bool init(int startIndex=0);
void setFrameRate(float frameRate);
void getNextSensorimotorState(std::list<Sensor> & sensors, std::list<Actuator> & actuators);
void getNextImage(cv::Mat & sensors);
protected:
virtual void mainLoopBegin();
@@ -41,8 +38,6 @@ protected:
private:
std::string _path;
float _frameRate;
std::set<Sensor::Type> _sensorTypes;
std::set<Actuator::Type> _actuatorTypes;
DBDriver * _dbDriver;
UTimer _timer;

View File

@@ -20,7 +20,7 @@
#pragma once
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/Parameters.h"
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <list>
@@ -29,56 +29,82 @@
namespace rtabmap
{
//epipolar geometry
void RTABMAP_EXP findEpipolesFromF(
const cv::Mat & fundamentalMatrix,
cv::Vec3d & e1,
cv::Vec3d & e2);
class Signature;
cv::Mat RTABMAP_EXP findPFromF(
const cv::Mat & fundamentalMatrix,
const cv::Mat & x1,
const cv::Mat & x2);
class RTABMAP_EXP EpipolarGeometry
{
public:
EpipolarGeometry(const ParametersMap & parameters = ParametersMap());
virtual ~EpipolarGeometry();
bool check(const Signature * ssA, const Signature * ssB);
void parseParameters(const ParametersMap & parameters);
// return fundamental matrix
// status -> inliers = 1, outliers = 0
cv::Mat RTABMAP_EXP findFFromWords(
const std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs, // id, kpt1, kpt2
std::vector<uchar> & status,
double ransacParam1 = 3.0,
double ransacParam2 = 0.99);
int getMatchCountMinAccepted() const {return _matchCountMinAccepted;}
double getRansacParam1() const {return _ransacParam1;}
double getRansacParam2() const {return _ransacParam2;}
// assume a canonical camera (without K)
void RTABMAP_EXP findRTFromP(
const cv::Mat & p,
cv::Mat & r,
cv::Mat & t);
void setMatchCountMinAccepted(int matchCountMinAccepted) {_matchCountMinAccepted = matchCountMinAccepted;}
void setRansacParam1(double ransacParam1) {_ransacParam1 = ransacParam1;}
void setRansacParam2(double ransacParam2) {_ransacParam2 = ransacParam2;}
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (2,2) (4,4) (6a,6a) (6b,6b)]
* realPairsCount = 5
*/
int RTABMAP_EXP findPairs(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
* realPairsCount = 5
*/
int RTABMAP_EXP findPairsUnique(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
// STATIC STUFF
//epipolar geometry
static void RTABMAP_EXP findEpipolesFromF(
const cv::Mat & fundamentalMatrix,
cv::Vec3d & e1,
cv::Vec3d & e2);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (1,1b) (2,2) (4,4) (6a,6a) (6a,6b) (6b,6a) (6b,6b)]
* realPairsCount = 5
*/
int RTABMAP_EXP findPairsAll(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
static cv::Mat RTABMAP_EXP findPFromF(
const cv::Mat & fundamentalMatrix,
const cv::Mat & x1,
const cv::Mat & x2);
// return fundamental matrix
// status -> inliers = 1, outliers = 0
static cv::Mat RTABMAP_EXP findFFromWords(
const std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs, // id, kpt1, kpt2
std::vector<uchar> & status,
double ransacParam1 = 3.0,
double ransacParam2 = 0.99);
// assume a canonical camera (without K)
static void RTABMAP_EXP findRTFromP(
const cv::Mat & p,
cv::Mat & r,
cv::Mat & t);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (2,2) (4,4) (6a,6a) (6b,6b)]
* realPairsCount = 5
*/
static int RTABMAP_EXP findPairs(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
* realPairsCount = 5
*/
static int RTABMAP_EXP findPairsUnique(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (1,1b) (2,2) (4,4) (6a,6a) (6a,6b) (6b,6a) (6b,6b)]
* realPairsCount = 5
*/
static int RTABMAP_EXP findPairsAll(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
private:
int _matchCountMinAccepted;
double _ransacParam1;
double _ransacParam2;
};
} // namespace rtabmap

View File

@@ -1,126 +1,148 @@
/*
* 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 KEYPOINTDETECTOR_H_
#define KEYPOINTDETECTOR_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <list>
#include "rtabmap/core/Parameters.h"
namespace rtabmap
{
class VWDictionary;
class RTABMAP_EXP KeypointDetector
{
public:
enum DetectorType {kDetectorSurf, kDetectorStar, kDetectorSift, kDetectorFast, kDetectorUndef};
public:
virtual ~KeypointDetector() {}
std::vector<cv::KeyPoint> generateKeypoints(const cv::Mat & image);
virtual void parseParameters(const ParametersMap & parameters);
unsigned int getWordsPerImageTarget() const {return _wordsPerImageTarget;}
void setRoi(const std::string & roi);
cv::Rect computeRoi(const cv::Mat & image) const;
protected:
KeypointDetector(const ParametersMap & parameters = ParametersMap());
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const = 0;
private:
unsigned int _wordsPerImageTarget;
std::vector<float> _roiRatios; // size 4
};
//SURFDetector
class RTABMAP_EXP SURFDetector : public KeypointDetector
{
public:
SURFDetector(const ParametersMap & parameters = ParametersMap());
virtual ~SURFDetector();
virtual void parseParameters(const ParametersMap & parameters);
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
private:
double _hessianThreshold;
int _nOctaves;
int _nOctaveLayers;
bool _extended;
bool _upright;
bool _gpuVersion;
};
//SIFTDetector
class RTABMAP_EXP SIFTDetector : public KeypointDetector
{
public:
SIFTDetector(const ParametersMap & parameters = ParametersMap());
virtual ~SIFTDetector();
virtual void parseParameters(const ParametersMap & parameters);
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
private:
int _nfeatures;
int _nOctaveLayers;
double _contrastThreshold;
double _edgeThreshold;
double _sigma;
};
//StarDetector
class RTABMAP_EXP StarDetector : public KeypointDetector
{
public:
StarDetector(const ParametersMap & parameters = ParametersMap());
virtual ~StarDetector();
virtual void parseParameters(const ParametersMap & parameters);
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
private:
int _maxSize;
int _responseThreshold;
int _lineThresholdProjected;
int _lineThresholdBinarized;
int _suppressNonmaxSize;
};
//FASTDetector
class RTABMAP_EXP FASTDetector : public KeypointDetector
{
public:
FASTDetector(const ParametersMap & parameters = ParametersMap());
virtual ~FASTDetector();
virtual void parseParameters(const ParametersMap & parameters);
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
private:
int _threshold;
bool _nonmaxSuppression;
};
}
#endif /* KEYPOINTDETECTOR_H_ */
/*
* 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 KEYPOINTDESCRIPTOR_H_
#define KEYPOINTDESCRIPTOR_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <list>
#include "rtabmap/core/Parameters.h"
namespace rtabmap {
/////////////////////
// KeypointDescriptor
/////////////////////
class RTABMAP_EXP KeypointDescriptor {
public:
enum DescriptorType {kDescriptorSurf, kDescriptorSift, kDescriptorUndef};
public:
virtual ~KeypointDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const = 0;
protected:
KeypointDescriptor(const ParametersMap & parameters = ParametersMap());
};
//SURFDescriptor
class RTABMAP_EXP SURFDescriptor : public KeypointDescriptor
{
public:
SURFDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~SURFDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
double _hessianThreshold;
int _nOctaves;
int _nOctaveLayers;
bool _extended;
bool _upright;
bool _gpuVersion;
};
//SIFTDescriptor
class RTABMAP_EXP SIFTDescriptor : public KeypointDescriptor
{
public:
SIFTDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~SIFTDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
int _nfeatures;
int _nOctaveLayers;
double _contrastThreshold;
double _edgeThreshold;
double _sigma;
};
/////////////////////
// KeypointDetector
/////////////////////
class RTABMAP_EXP KeypointDetector
{
public:
enum DetectorType {kDetectorSurf, kDetectorSift, kDetectorUndef};
public:
virtual ~KeypointDetector() {}
std::vector<cv::KeyPoint> generateKeypoints(const cv::Mat & image);
virtual void parseParameters(const ParametersMap & parameters);
unsigned int getWordsPerImageTarget() const {return _wordsPerImageTarget;}
void setRoi(const std::string & roi);
cv::Rect computeRoi(const cv::Mat & image) const;
protected:
KeypointDetector(const ParametersMap & parameters = ParametersMap());
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const = 0;
private:
unsigned int _wordsPerImageTarget;
std::vector<float> _roiRatios; // size 4
};
//SURFDetector
class RTABMAP_EXP SURFDetector : public KeypointDetector
{
public:
SURFDetector(const ParametersMap & parameters = ParametersMap());
virtual ~SURFDetector();
virtual void parseParameters(const ParametersMap & parameters);
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
private:
double _hessianThreshold;
int _nOctaves;
int _nOctaveLayers;
bool _extended;
bool _upright;
bool _gpuVersion;
};
//SIFTDetector
class RTABMAP_EXP SIFTDetector : public KeypointDetector
{
public:
SIFTDetector(const ParametersMap & parameters = ParametersMap());
virtual ~SIFTDetector();
virtual void parseParameters(const ParametersMap & parameters);
private:
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
private:
int _nfeatures;
int _nOctaveLayers;
double _contrastThreshold;
double _edgeThreshold;
double _sigma;
};
}
#endif /* KEYPOINTDESCRIPTOR_H_ */

View File

@@ -0,0 +1,45 @@
/*
* Image.h
*
* Created on: 2012-12-08
* Author: mathieu
*/
#ifndef IMAGE_H_
#define IMAGE_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
namespace rtabmap
{
class Image
{
public:
Image(const cv::Mat & image = cv::Mat(),
const cv::Mat & descriptors = cv::Mat(),
const std::vector<cv::KeyPoint> & keypoints = std::vector<cv::KeyPoint>()) :
_image(image),
_descriptors(descriptors),
_keypoints(keypoints)
{
}
bool empty() const {return _image.empty() && _descriptors.empty() && _keypoints.size() == 0;}
const cv::Mat & image() const {return _image;}
const cv::Mat & descriptors() const {return _descriptors;}
const std::vector<cv::KeyPoint> & keypoints() const {return _keypoints;}
private:
cv::Mat _image;
cv::Mat _descriptors;
std::vector<cv::KeyPoint> _keypoints;
};
}
#endif /* IMAGE_H_ */

View File

@@ -1,139 +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/>.
*/
#ifndef KEYPOINTDESCRIPTOR_H_
#define KEYPOINTDESCRIPTOR_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <list>
#include "rtabmap/core/Parameters.h"
namespace rtabmap {
class RTABMAP_EXP KeypointDescriptor {
public:
enum DescriptorType {kDescriptorSurf, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef};
public:
virtual ~KeypointDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const = 0;
protected:
KeypointDescriptor(const ParametersMap & parameters = ParametersMap());
};
//SURFDescriptor
class RTABMAP_EXP SURFDescriptor : public KeypointDescriptor
{
public:
SURFDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~SURFDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
double _hessianThreshold;
int _nOctaves;
int _nOctaveLayers;
bool _extended;
bool _upright;
bool _gpuVersion;
};
//SIFTDescriptor
class RTABMAP_EXP SIFTDescriptor : public KeypointDescriptor
{
public:
SIFTDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~SIFTDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
int _nfeatures;
int _nOctaveLayers;
double _contrastThreshold;
double _edgeThreshold;
double _sigma;
};
//BRIEFDescriptor
class RTABMAP_EXP BRIEFDescriptor : public KeypointDescriptor
{
public:
BRIEFDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~BRIEFDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
int _size;
};
//MinMax ColorDescriptor
class RTABMAP_EXP ColorDescriptor : public KeypointDescriptor
{
public:
ColorDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~ColorDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
protected:
void getCircularROI(int R, std::vector<int> & RxV) const;
};
//MinMax HueDescriptor
class RTABMAP_EXP HueDescriptor : public ColorDescriptor
{
public:
HueDescriptor(const ParametersMap & parameters = ParametersMap());
virtual ~HueDescriptor();
virtual void parseParameters(const ParametersMap & parameters);
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
// assuming that rgb values are normalized [0,1]
float rgb2hue(float r, float g, float b) const;
// assuming that rgb values are normalized [0,1]
inline float rgb2saturation(float r, float g, float b) const
{
float min = r;
min<g?min=g:min;
min<b?min=b:min;
float eps = 0.00001f;
return 1-(3*min)/(r+g+b+eps);
}
// assuming that rgb values are normalized [0,1]
inline float rgb2intensity(float r, float g, float b) const
{
return (r+g+b)/3;
}
};
}
#endif /* KEYPOINTDESCRIPTOR_H_ */

View File

@@ -1,86 +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/>.
*/
#ifndef KEYPOINTMEMORY_H_
#define KEYPOINTMEMORY_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/Memory.h"
#include <opencv2/features2d/features2d.hpp>
namespace rtabmap {
class VWDictionary;
class VisualWord;
class KeypointDetector;
class KeypointDescriptor;
class RTABMAP_EXP KeypointMemory : public Memory
{
public:
KeypointMemory(const ParametersMap & parameters = ParametersMap());
virtual ~KeypointMemory();
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 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;
void dumpDictionary(const char * fileNameRef, const char * fileNameDesc) const;
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;
protected:
virtual Signature * getSignatureLtMem(int id);
virtual void addSignatureToStm(Signature * signature, const std::list<Actuator> & actions = std::list<Actuator>());
virtual void clear();
virtual void moveToTrash(Signature * s);
virtual void preUpdate();
private:
virtual void copyData(const Signature * from, Signature * to);
virtual Signature * createSignature(int id, const std::list<Sensor> & sensors, bool keepRawData=false);
void disableWordsRef(int signatureId);
void enableWordsRef(const std::list<int> & signatureIds);
void cleanUnusedWords();
int getNi(int signatureId) const;
private:
VWDictionary * _vwd;
KeypointDetector * _keypointDetector;
KeypointDescriptor * _keypointDescriptor;
//std::map<int, int> _wordRefsToChange;
bool _reactivatedWordsComparedToNewWords;
float _badSignRatio;;
bool _tfIdfLikelihoodUsed;
bool _parallelized;
bool _tfIdfNormalized;
};
}
#endif /* KEYPOINTMEMORY_H_ */

View File

@@ -24,22 +24,24 @@
#include "utilite/UEventsHandler.h"
#include "rtabmap/core/Parameters.h"
#include "utilite/UVariant.h"
#include "rtabmap/core/Image.h"
#include <typeinfo>
#include <list>
#include <map>
#include <set>
#include "utilite/UStl.h"
#include <opencv2/core/core.hpp>
#include "rtabmap/core/Sensor.h"
#include "rtabmap/core/Actuator.h"
#include <opencv2/features2d/features2d.hpp>
namespace rtabmap {
class Signature;
class NeighborLink;
class DBDriver;
class Node;
class GraphNode;
class VWDictionary;
class VisualWord;
class KeypointDetector;
class KeypointDescriptor;
class RTABMAP_EXP Memory
{
@@ -53,60 +55,48 @@ public:
virtual ~Memory();
virtual void parseParameters(const ParametersMap & parameters);
bool update(const std::list<Sensor> & sensors,
const std::list<Actuator> & actuators,
std::map<std::string, float> & stats);
virtual bool init(const std::string & dbDriverName,
const std::string & dbUrl,
bool update(const Image & image, std::map<std::string, float> & stats);
bool init(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 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);
std::map<int, float> computeLikelihood(const Signature * signature,
const std::list<int> & ids);
int forget(const std::set<int> & ignoredIds = std::set<int>());
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();
bool addLoopClosureLink(int oldId, int newId);
std::map<int, int> getNeighborsId(double & dbAccessTime,
int signatureId,
std::map<int, int> getNeighborsId(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);
bool ignoreLoopIds = false,
double * dbAccessTime = 0) const;
//getters
unsigned int getWorkingMemSize() const {return _workingMem.size();}
unsigned int getStMemSize() const {return _stMem.size();};
const std::set<int> & getWorkingMem() const {return _workingMem;}
const std::set<int> & getStMem() const {return _stMem;}
std::list<NeighborLink> getNeighborLinks(int signatureId,
int getMaxStMemSize() const {return _maxStMemSize;}
std::set<int> getNeighborLinks(int signatureId,
bool ignoreNeighborByLoopClosure = false,
bool lookInDatabase = false,
bool onlyWithActions = false) const;
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;}
float getSimilarityThreshold() 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 std::map<int, std::map<int, float> > & getSimilaritiesMap() const {return _similaritiesMap;}
float getSimilarityOnlyWithLast() const {return _rehearsalOnlyWithLast;}
const Signature * getLastSignature() const;
int getDatabaseMemoryUsed() const; // in bytes
double getDbSavingTime() const;
std::list<Sensor> getRawData(int id) const;
bool isCommonSignatureUsed() const {return _commonSignatureUsed;}
cv::Mat getImage(int signatureId) const;
std::set<int> getAllSignatureIds() const;
bool memoryChanged() const {return _memoryChanged;}
const Signature * getSignature(int id) const;
@@ -115,33 +105,32 @@ public:
bool isInLTM(int signatureId) const {return !this->isInSTM(signatureId) && !this->isInWM(signatureId);}
//setters
void setSimilarityThreshold(float similarityThreshold);
void setSimilarityOnlyLast(int similarityOnlyLast) {_similarityOnlyLast = similarityOnlyLast;}
void setSimilarityThreshold(float similarity);
void setSimilarityOnlyLast(int rehearsalOnlyWithLast) {_rehearsalOnlyWithLast = rehearsalOnlyWithLast;}
void setOldSignatureRatio(float oldSignatureRatio);
void setMaxStMemSize(unsigned int maxStMemSize);
void setRecentWmRatio(float recentWmRatio);
void setCommonSignatureUsed(bool commonSignatureUsed);
void setRawDataKept(bool rawDataKept) {_rawDataKept = rawDataKept;}
void dumpMemoryTree(const char * fileNameTree) const;
virtual void dumpMemory(std::string directory) const;
virtual void dumpSignatures(const char * fileNameSign) const {}
virtual void dumpSignatures(const char * fileNameSign) const;
void dumpDictionary(const char * fileNameRef, const char * fileNameDesc) const;
void generateGraph(const std::string & fileName, std::set<int> ids = std::set<int>());
void cleanLocalGraph(int id, unsigned int margin);
void cleanLTM(int maxDepth = 10);
void createGraph(Node * parent,
void createGraph(GraphNode * parent,
unsigned int maxDepth,
const std::set<int> & endIds = std::set<int>());
protected:
virtual void preUpdate();
virtual void postUpdate() {}
//keypoint stuff
int getVWDictionarySize() const;
std::multimap<int, cv::KeyPoint> getWords(int signatureId) const;
virtual void addSignatureToStm(Signature * signature,
const std::list<Actuator> & actuators = std::list<Actuator>());
virtual void clear();
virtual void moveToTrash(Signature * s);
virtual Signature * getSignatureLtMem(int id);
protected:
void preUpdate();
void addSignatureToStm(Signature * signature);
void clear();
void moveToTrash(Signature * s);
void addSignatureToWm(Signature * signature);
Signature * _getSignature(int id) const;
@@ -154,24 +143,27 @@ protected:
const std::map<int, Signature*> & getSignatures() const {return _signatures;}
private:
virtual void copyData(const Signature * from, Signature * to) = 0;
virtual Signature * createSignature(int id,
const std::list<Sensor> & sensors,
bool keepRawData=false) = 0;
void copyData(const Signature * from, Signature * to);
Signature * createSignature(int id,
const Image & image,
bool keepRawData=false);
//keypoint stuff
void disableWordsRef(int signatureId);
void enableWordsRef(const std::list<int> & signatureIds);
void cleanUnusedWords();
int getNi(int signatureId) const;
void createVirtualSignature(Signature ** signature);
void cleanGraph(const Node * root);
protected:
DBDriver * _dbDriver;
private:
// parameters
float _similarityThreshold;
bool _similarityOnlyLast;
bool _rehearsalOnlyWithLast;
bool _rawDataKept;
bool _incrementalMemory;
unsigned int _maxStMemSize;
bool _commonSignatureUsed;
int _maxStMemSize;
float _recentWmRatio;
bool _dataMergedOnRehearsal;
@@ -179,14 +171,20 @@ private:
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; // id
std::set<int> _workingMem; // id,age
std::vector<int> _lastBaseIds;
std::map<int, std::map<int, float> > _similaritiesMap;
//Heypoint stuff
VWDictionary * _vwd;
KeypointDetector * _keypointDetector;
KeypointDescriptor * _keypointDescriptor;
bool _reactivatedWordsComparedToNewWords;
float _badSignRatio;;
bool _tfIdfLikelihoodUsed;
bool _parallelized;
};
} // namespace rtabmap

View File

@@ -1,134 +0,0 @@
/*
* Micro.h
*
* Created on: Mar 5, 2012
* Author: MatLab
*/
#ifndef MICRO_H_
#define MICRO_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <utilite/UThreadNode.h>
#include <utilite/UTimer.h>
#include <utilite/UEvent.h>
#include <utilite/ULogger.h>
#include <string>
#include <vector>
#include <opencv2/core/core.hpp>
class UAudioRecorder;
namespace rtabmap {
class MicroEvent :
public UEvent
{
public:
enum Type {
kTypeFrame,
kTypeFrameFreq,
kTypeFrameFreqSqrdMagn,
kTypeNoMoreFrames
};
public:
// kTypeNoMoreFrames constructor
MicroEvent(int microId = 0) :
UEvent(kTypeNoMoreFrames),
_sampleSize(0),
_microId(microId)
{
}
// kTypeFrame constructor
MicroEvent(const cv::Mat & frame,
int sampleSize,
int fs,
int channels,
int microId = 0) :
UEvent(kTypeFrame),
_frame(frame),
_sampleSize(sampleSize),
_microId(microId)
{
}
// kTypeFrameFreq and kTypeFrameFreqSqrdMagn constructors
MicroEvent(Type frameType,
const cv::Mat & frameFreq,
int fs,
int channels,
int microId = 0) :
UEvent(frameType),
_frame(frameFreq),
_sampleSize(sizeof(float)),
_microId(microId)
{
UASSERT(frameType == kTypeFrameFreqSqrdMagn || frameType == kTypeFrameFreq);
}
int type() const {return this->getCode();}
const cv::Mat & frame() const {return _frame;}
int sampleSize() const {return _sampleSize;}
int microId() const {return _microId;}
virtual ~MicroEvent() {}
virtual std::string getClassName() const {return std::string("MicroEvent");}
private:
cv::Mat _frame;
int _sampleSize; // bytes
int _fs; //sampling rate
int _microId;
};
class RTABMAP_EXP Micro : public UThreadNode
{
typedef float fftwf_complex[2];
public:
Micro(MicroEvent::Type eventType,
int deviceId,
int fs,
int frameLength,
int channels,
int bytesPerSample,
int id = 0);
Micro(MicroEvent::Type eventType,
const std::string & path,
bool simulateFrameRate,
int frameLength,
int id = 0,
bool playWhileRecording = false);
virtual ~Micro();
bool init();
void stop(); // same as kill() but handle the case where underlying recorder is running and not the micro.
void startRecorder(); // must only be used if Micro::start() is not used
cv::Mat getFrame();
cv::Mat getFrame(cv::Mat & frameFreq, bool sqrdMagn = false);
int fs();
int bytesPerSample();
int channels();
int nfft();
protected:
virtual void mainLoopBegin();
virtual void mainLoop();
virtual void mainLoopKill();
private:
MicroEvent::Type _eventType;
UAudioRecorder* _recorder;
bool _simulateFreq;
UTimer _timer;
std::vector<float> _window;
std::vector<float> _in;
fftwf_complex * _out; // fftwf_complex
void * _p; // fftwf_plan
int _id;
};
}
#endif /* MICRO_H_ */

View File

@@ -120,74 +120,55 @@ typedef std::pair<const std::string, std::string> ParametersPair;
class RTABMAP_EXP Parameters
{
// Rtabmap parameters
RTABMAP_PARAM(Rtabmap, VhStrategy, int, 0); // None 0, Similarity 1, Epipolar 2
RTABMAP_PARAM(Rtabmap, PublishStats, bool, true); // Publishing statistics
RTABMAP_PARAM(Rtabmap, PublishRawData, bool, true); // Publishing raw data
RTABMAP_PARAM(Rtabmap, PublishPdf, bool, true); // Publishing pdf
RTABMAP_PARAM(Rtabmap, PublishLikelihood, bool, true); // Publishing likelihood
RTABMAP_PARAM(Rtabmap, RetrievalThr, float, 0.0); // Reactivation threshold
RTABMAP_PARAM(Rtabmap, TimeThr, float, 700.0); // Maximum time allowed for the detector (ms) (0 means infinity)
RTABMAP_PARAM(Rtabmap, MemoryThr, int, 0); // Maximum signatures in the Working Memory (ms) (0 means infinity)
RTABMAP_PARAM(Rtabmap, SMStateBufferSize, int, 0); // Data buffer size (0 min inf)
RTABMAP_PARAM(Rtabmap, VhStrategy, int, 0); // None 0, Similarity 1, Epipolar 2
RTABMAP_PARAM(Rtabmap, PublishStats, bool, true); // Publishing statistics
RTABMAP_PARAM(Rtabmap, PublishImage, bool, true); // Publishing image
RTABMAP_PARAM(Rtabmap, PublishPdf, bool, true); // Publishing pdf
RTABMAP_PARAM(Rtabmap, PublishLikelihood, bool, true); // Publishing likelihood
RTABMAP_PARAM(Rtabmap, TimeThr, float, 700.0); // Maximum time allowed for the detector (ms) (0 means infinity)
RTABMAP_PARAM(Rtabmap, MemoryThr, int, 0); // Maximum signatures in the Working Memory (ms) (0 means infinity)
RTABMAP_PARAM(Rtabmap, ImageBufferSize, int, 0); // Data buffer size (0 min inf)
RTABMAP_PARAM_STR(Rtabmap, WorkingDirectory, Parameters::getDefaultWorkingDirectory()); // Working directory
RTABMAP_PARAM(Rtabmap, MaxRetrieved, unsigned int, 2); // Maximum locations retrieved at the same time from LTM
RTABMAP_PARAM(Rtabmap, SelectionNeighborhoodSummationUsed, bool, false); // Neighborhood summation for hypothesis selection
RTABMAP_PARAM(Rtabmap, SelectionLikelihoodUsed, bool, false); // Neighborhood likelihood for hypothesis selection
RTABMAP_PARAM(Rtabmap, ActionsSentRejectHyp, bool, true); // Actions sent also on rejected hypotheses (on decreasing hypotheses)
RTABMAP_PARAM(Rtabmap, ConfidenceThr, float, 0.0); // Actions are not sent when the loop closure hypothesis is under the confidence threshold
RTABMAP_PARAM(Rtabmap, LikelihoodStdDevRemoved, bool, true); // Remove std dev on likelihood normalization.
RTABMAP_PARAM(Rtabmap, LikelihoodNullValuesIgnored, bool, true); // Ignore null values on likelihood normalization
RTABMAP_PARAM(Rtabmap, MaxRetrieved, unsigned int, 2); // Maximum locations retrieved at the same time from LTM
RTABMAP_PARAM(Rtabmap, LikelihoodNullValuesIgnored, bool, true); // Ignore null values on likelihood normalization
RTABMAP_PARAM(Rtabmap, StatisticLogsBufferedInRAM, bool, true); // Statistic logs buffered in RAM instead of written to hard drive after each iteration.
// Hypotheses selection
RTABMAP_PARAM(Rtabmap, LoopThr, float, 0.15); // Loop closing threshold
RTABMAP_PARAM(Rtabmap, LoopRatio, float, 0.9); // The loop closure hypothesis must be over LoopRatio x lastHypothesisValue
// Memory
RTABMAP_PARAM(Mem, SimilarityThr, float, 0.20); // Similarity between the last signature and neighbor
RTABMAP_PARAM(Mem, SimilarityOnlyLast, bool, false); // Only compare to the last signature in STM, otherwise it compares to all signatures in STM
RTABMAP_PARAM(Mem, RawDataKept, bool, true); // Keep raw data
RTABMAP_PARAM(Mem, MaxStMemSize, unsigned int, 30); // Short-time memory size
RTABMAP_PARAM(Mem, CommonSignatureUsed, bool, true); // A common signature/virtual place is automatically updated with id -1
RTABMAP_PARAM(Mem, IncrementalMemory, bool, true);
RTABMAP_PARAM(Mem, RecentWmRatio, float, 0.2); // Ratio of locations after the last loop closure in WM that cannot be transferred
RTABMAP_PARAM(Mem, DataMergedOnRehearsal, bool, true); // Merge data on rehearsal
RTABMAP_PARAM(Mem, SignatureType, int, 0); // Keypoint 0, Sensorimotor 1
RTABMAP_PARAM(Mem, RehearsalSimilarity, float, 0.2); // Rehearsal mean for each sensor
RTABMAP_PARAM(Mem, RehearsalOnlyWithLast, bool, true); // Only compare to the last signature in STM, otherwise it compares to all signatures in STM
RTABMAP_PARAM(Mem, ImageKept, bool, true); // Keep image
RTABMAP_PARAM(Mem, STMSize, unsigned int, 30); // Short-term memory size
RTABMAP_PARAM(Mem, IncrementalMemory, bool, true);
RTABMAP_PARAM(Mem, RecentWmRatio, float, 0.2); // Ratio of locations after the last loop closure in WM that cannot be transferred
RTABMAP_PARAM(Mem, DataMergedOnRehearsal, bool, true); // Merge data on rehearsal
// KeypointMemory (Keypoint-based)
RTABMAP_PARAM(Kp, PublishKeypoints, bool, true); // Publishing keypoints
RTABMAP_PARAM(Kp, NNStrategy, int, 2); // Naive 0, kdTree 1, kdForest 2
RTABMAP_PARAM(Kp, PublishKeypoints, bool, true); // Publishing keypoints
RTABMAP_PARAM(Kp, NNStrategy, int, 1); // Naive 0, kdForest 1
RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true);
RTABMAP_PARAM(Kp, WordsPerImage, int, 400);
RTABMAP_PARAM(Kp, BadSignRatio, float, 0.2); //Bad signature ratio (less than Ratio x AverageWordsPerImage = bad)
RTABMAP_PARAM(Kp, MinDistUsed, bool, false); // The nearest neighbor must have a distance < minDist
RTABMAP_PARAM(Kp, MinDist, float, 0.05); // Matching a descriptor with a word (euclidean distance ^ 2)
RTABMAP_PARAM(Kp, NndrUsed, bool, true); // If NNDR ratio is used
RTABMAP_PARAM(Kp, NndrRatio, float, 0.8); // NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)
RTABMAP_PARAM(Kp, MaxLeafs, int, 64); // Maximum number of leafs checked (when using kd-trees)
RTABMAP_PARAM(Kp, DetectorStrategy, int, 0); // Surf detector 0, Star detector 1, SIFT detector 2, FAST detector 3
RTABMAP_PARAM(Kp, DescriptorStrategy, int, 0); // kDescriptorSurf=0, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef
RTABMAP_PARAM(Kp, WordsPerImage, int, 400);
RTABMAP_PARAM(Kp, BadSignRatio, float, 0.2); //Bad signature ratio (less than Ratio x AverageWordsPerImage = bad)
RTABMAP_PARAM(Kp, MinDistUsed, bool, false); // The nearest neighbor must have a distance < minDist
RTABMAP_PARAM(Kp, MinDist, float, 0.05); // Matching a descriptor with a word (euclidean distance ^ 2)
RTABMAP_PARAM(Kp, NndrUsed, bool, true); // If NNDR ratio is used
RTABMAP_PARAM(Kp, NndrRatio, float, 0.8); // NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)
RTABMAP_PARAM(Kp, MaxLeafs, int, 64); // Maximum number of leafs checked (when using kd-trees)
RTABMAP_PARAM(Kp, DetectorStrategy, int, 0); // Surf detector 0, SIFT detector 1, undef 2
RTABMAP_PARAM(Kp, DescriptorStrategy, int, 0); // kDescriptorSurf=0, kDescriptorSift, kDescriptorUndef
RTABMAP_PARAM(Kp, ReactivatedWordsComparedToNewWords, bool, true); //Reactivated words are compared to the last words added in the dictionary (which are not indexed)
RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, false); // Use of the td-idf strategy to compute the likelihood
RTABMAP_PARAM(Kp, Parallelized, bool, true); // If the dictionary update and signature creation were parallelized
RTABMAP_PARAM(Kp, TfIdfNormalized, bool, false); // If tf-idf weighting is normalized by the words count ratio between compared signatures
RTABMAP_PARAM_STR(Kp, RoiRatios, "0.0 0.0 0.0 0.0"); // Region of interest ratios [left, right, top, bottom]
RTABMAP_PARAM_STR(Kp, DictionaryPath, ""); // Path of the pre-computed dictionary
// SM memory
RTABMAP_PARAM(SM, PublishMasks, bool, false); // Publishing motion masks
RTABMAP_PARAM(SM, MotionMaskUsed, bool, false); // Use motion mask
RTABMAP_PARAM(SM, LogPolarUsed, bool, false); // Use log-polar images
RTABMAP_PARAM(SM, ColorTable, int, 8); // Color table size 0=8, 1=16, 2=32, 3=64, 4=128, 5=256, 6=512, 7=1024, 8=65536
RTABMAP_PARAM(SM, AudioDBThreshold, float, 0.0f); // Audio dB threshold
RTABMAP_PARAM(SM, AudioDBIndexing, bool, true); // dB (decibel) indexing (otherwise it's squared magnitude indexing)
RTABMAP_PARAM(SM, MagnitudeInvariant, bool, false); // Make audio signature magnitude-invariant
RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, false); // Use of the td-idf strategy to compute the likelihood
RTABMAP_PARAM(Kp, Parallelized, bool, true); // If the dictionary update and signature creation were parallelized
RTABMAP_PARAM_STR(Kp, RoiRatios, "0.0 0.0 0.0 0.0"); // Region of interest ratios [left, right, top, bottom]
RTABMAP_PARAM_STR(Kp, DictionaryPath, ""); // Path of the pre-computed dictionary
//Database
RTABMAP_PARAM(Db, MinSignaturesToSave, int, 20); // Minimum signatures needed in the trash to save them (empty trash thread)
RTABMAP_PARAM(Db, MinWordsToSave, int, 4000); // Minimum visual words needed in the trash to save them (empty trash thread)
RTABMAP_PARAM(Db, ImagesCompressed, bool, true); // Images are compressed when save to database
RTABMAP_PARAM(Db, ImagesCompressed, bool, true); // Images are compressed when saving to database
RTABMAP_PARAM(DbSqlite3, InMemory, bool, false); // Using database in the memory instead of a file on the hard disk
RTABMAP_PARAM(DbSqlite3, CacheSize, unsigned int, 2000); // Sqlite cache size (default is 2000)
RTABMAP_PARAM(DbSqlite3, CacheSize, unsigned int, 10000); // Sqlite cache size (default is 2000)
RTABMAP_PARAM(DbSqlite3, JournalMode, int, 3); // 0=DELETE, 1=TRUNCATE, 2=PERSIST, 3=MEMORY, 4=OFF (see sqlite3 doc : "PRAGMA journal_mode")
RTABMAP_PARAM(DbSqlite3, Synchronous, int, 0); // 0=OFF, 1=NORMAL, 2=FULL (see sqlite3 doc : "PRAGMA synchronous")
RTABMAP_PARAM(DbSqlite3, TempStore, int, 2); // 0=DEFAULT, 1=FILE, 2=MEMORY (see sqlite3 doc : "PRAGMA temp_store")
@@ -200,37 +181,33 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(SURF, Upright, bool, false); // U-SURF
RTABMAP_PARAM(SURF, GpuVersion, bool, false);
RTABMAP_PARAM(SIFT, NFeatures, int, 0);
RTABMAP_PARAM(SIFT, NOctaveLayers, int, 3);
RTABMAP_PARAM(SIFT, NFeatures, int, 0);
RTABMAP_PARAM(SIFT, NOctaveLayers, int, 3);
RTABMAP_PARAM(SIFT, ContrastThreshold, double, 0.04);
RTABMAP_PARAM(SIFT, EdgeThreshold, double, 10.0);
RTABMAP_PARAM(SIFT, Sigma, double, 1.6);
RTABMAP_PARAM(FAST, Threshold, int, 10);
RTABMAP_PARAM(FAST, NonmaxSuppression, bool, true);
RTABMAP_PARAM(BRIEF, Size, int, 32); // 16, 32, 64
RTABMAP_PARAM(Star, MaxSize, int, 45);
RTABMAP_PARAM(Star, ResponseThreshold, int, 30);
RTABMAP_PARAM(Star, LineThresholdProjected, int, 10);
RTABMAP_PARAM(Star, LineThresholdBinarized, int, 8);
RTABMAP_PARAM(Star, SuppressNonmaxSize, int, 5);
RTABMAP_PARAM(SIFT, EdgeThreshold, double, 10.0);
RTABMAP_PARAM(SIFT, Sigma, double, 1.6);
// BayesFilter
RTABMAP_PARAM(Bayes, VirtualPlacePriorThr, float, 0.9); // Virtual place prior
RTABMAP_PARAM(Bayes, VirtualPlacePriorThr, float, 0.9); // Virtual place prior
RTABMAP_PARAM_STR(Bayes, PredictionLC, "0.1 0.36 0.30 0.16 0.062 0.0151 0.00255 0.000324 2.5e-05 1.3e-06 4.8e-08 1.2e-09 1.9e-11 2.2e-13 1.7e-15 8.5e-18 2.9e-20 6.9e-23"); // Prediction of loop closures (Gaussian-like, here with sigma=1.6) - Format: {VirtualPlaceProb, LoopClosureProb, NeighborLvl1, NeighborLvl2, ...}
RTABMAP_PARAM(Bayes, PredictionOnNonNullActionsOnly, bool, false); // Make prediction on non-null action neighbors only
RTABMAP_PARAM(Bayes, FullPredictionUpdate, bool, true); // Regenerate all the prediction matrix on each iteration (otherwise only removed/added ids are updated).
// Verify hypotheses
RTABMAP_PARAM(Vh, Similarity, float, 0.5); // Minimum similarity to accept an hypothesis
RTABMAP_PARAM(VhEp, MatchCountMin, int, 8); // Minimum of matching visual words pairs to accept the loop hypothesis
RTABMAP_PARAM(VhEp, RansacParam1, float, 3.0); // Fundamental matrix (see cvFindFundamentalMat()): Max distance (in pixels) from the epipolar line for a point to be inlier
RTABMAP_PARAM(VhEp, RansacParam2, float, 0.99); // Fundamental matrix (see cvFindFundamentalMat()): Performance of the RANSAC
public:
virtual ~Parameters();
static const ParametersMap & getDefaultParameters();
/**
* Get default parameters
*
*/
static const ParametersMap & getDefaultParameters()
{
return parameters_;
}
private:
Parameters();

View File

@@ -29,8 +29,7 @@
#include "utilite/UVariant.h"
#include "rtabmap/core/RtabmapEvent.h"
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/Sensor.h"
#include "rtabmap/core/Actuator.h"
#include "rtabmap/core/Image.h"
#include <opencv2/core/core.hpp>
#include <list>
#include <stack>
@@ -39,9 +38,7 @@
namespace rtabmap
{
class Signature;
class HypVerificator;
class EpipolarGeometry;
class Memory;
class BayesFilter;
@@ -58,11 +55,12 @@ public:
kStateDumpingMemory,
kStateDumpingPrediction,
kStateGeneratingGraph,
kStateGeneratingLocalGraph,
kStateDeletingMemory,
kStateCleanSensorsBuffer
};
enum VhStrategy {kVhNone, kVhSim, kVhEpipolar, kVhUndef};
enum VhStrategy {kVhNone, kVhEpipolar, kVhUndef};
static const char * kDefaultIniFileName;
static const char * kDefaultIniFilePath;
@@ -78,9 +76,10 @@ public:
Rtabmap();
virtual ~Rtabmap();
void process(const std::list<Sensor> & data);
void process(const Sensor & data); // for convenience when only one sensor is used
void process(const cv::Mat & image); // for convenience
void process(const Image & image); // for convenience
void dumpData();
void generateLocalGraph(const std::string & path, int id, int margin);
void init(const ParametersMap & param);
void init(const char * configFile = 0);
@@ -90,23 +89,19 @@ public:
int getLoopClosureId() const;
int getReactivatedId() const;
int getLastSignatureId() const;
const std::list<Actuator> & getActuator() const {return _actuators;}
float getLcHypValue() const {return _lastLcHypothesisValue;}
std::list<int> getWorkingMem() const;
std::set<int> getStMem() const;
std::map<int, int> getWeights() const;
int getTotalMemSize() const;
const std::string & getGraphFileName() const {return _graphFileName;}
void setMaxTimeAllowed(float maxTimeAllowed); // in ms
void setDataBufferSize(int size);
void setWorkingDirectory(std::string path);
void setGraphFileName(const std::string & fileName) {_graphFileName = fileName;}
void adjustLikelihood(std::map<int, float> & likelihood) const;
std::pair<int, float> selectHypothesis(const std::map<int, float> & posterior,
const std::map<int, float> & likelihood,
bool neighborSumUsed,
bool likelihoodUsed) const;
const std::map<int, float> & likelihood) const;
protected:
virtual void handleEvent(UEvent * anEvent);
@@ -117,9 +112,10 @@ private:
virtual void mainLoopBegin();
void process();
void resetMemory(bool dbOverwritten = false);
void addSensorimotor(const std::list<Sensor> & sensors, const std::list<Actuator> & actuators);
void getSensorimotor(std::list<Sensor> & sensors, std::list<Actuator> & actuators);
void addImage(const Image & image);
void getImage(Image & image);
void setupLogFiles(bool overwrite = false);
void flushStatisticLogs();
void releaseAllStrategies();
void pushNewState(State newState, const ParametersMap & parameters = ParametersMap());
void dumpPrediction() const;
@@ -128,51 +124,45 @@ private:
private:
// Modifiable parameters
bool _publishStats;
bool _publishRawData;
bool _publishImage;
bool _publishPdf;
bool _publishLikelihood;
bool _publishKeypoints;
bool _publishMasks;
float _maxTimeAllowed; // in ms
unsigned int _maxMemoryAllowed; // signatures count in WM
int _sensorsBufferMaxSize;
int _imageBufferMaxSize;
float _loopThr;
float _loopRatio;
float _retrievalThr;
unsigned int _maxRetrieved;
bool _selectionNeighborhoodSummationUsed;
bool _selectionLikelihoodUsed;
bool _actionsSentRejectHyp;
float _confidenceThr;
bool _likelihoodStdDevRemoved;
bool _likelihoodNullValuesIgnored;
bool _statisticLogsBufferedInRAM;
int _lcHypothesisId;
int _reactivateId;
int _retrievedId;
float _lastLcHypothesisValue;
int _lastLoopClosureId;
std::list<Actuator> _actuators;
UMutex _stateMutex;
std::stack<State> _state;
std::stack<ParametersMap> _stateParam;
std::list<std::pair<std::list<Sensor>, std::list<Actuator> > > _sensorimotorBuffer;
UMutex _sensorimotorMutex;
USemaphore _sensorimotorAdded;
std::list<Image> _imageBuffer;
UMutex _imageMutex;
USemaphore _imageAdded;
// Abstract classes containing all loop closure
// strategies for a type of signature or configuration.
HypVerificator * _vhStrategy;
EpipolarGeometry * _epipolarGeometry;
BayesFilter * _bayesFilter;
Memory * _memory;
FILE* _foutFloat;
FILE* _foutInt;
std::list<std::string> _bufferedLogsF;
std::list<std::string> _bufferedLogsI;
std::string _wDir;
std::string _graphFileName;
};
#endif /* RTABMAP_H_ */

View File

@@ -22,8 +22,6 @@
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/Sensor.h"
#include "rtabmap/core/Actuator.h"
#include <utilite/UEvent.h>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
@@ -51,30 +49,25 @@ class RTABMAP_EXP Statistics
RTABMAP_STATS(Loop, Highest_hypothesis_id,);
RTABMAP_STATS(Loop, Highest_hypothesis_value,);
RTABMAP_STATS(Loop, Vp_hypothesis,);
RTABMAP_STATS(Loop, Vp_likelihood,);
RTABMAP_STATS(Loop, ReactivateId,);
RTABMAP_STATS(Loop, Hypothesis_ratio,);
RTABMAP_STATS(Loop, Actions,);
RTABMAP_STATS(Loop, Actions_of,);
RTABMAP_STATS(Loop, Actions_chosen,);
RTABMAP_STATS(Memory, Working_memory_size,);
RTABMAP_STATS(Memory, Short_time_memory_size,);
RTABMAP_STATS(Memory, Database_size, MB);
RTABMAP_STATS(Memory, Process_memory_used, MB);
RTABMAP_STATS(Memory, Signatures_removed,);
RTABMAP_STATS(Memory, Signatures_retrieved,);
RTABMAP_STATS(Memory, Images_buffered,);
RTABMAP_STATS(Memory, Similarities_map,);
RTABMAP_STATS(Memory, Loop_closures_map,);
RTABMAP_STATS(Timing, Memory_update, ms);
RTABMAP_STATS(Timing, Cleaning_neighbors, ms);
RTABMAP_STATS(Timing, Reactivation, ms);
RTABMAP_STATS(Timing, Add_loop_closure_link, ms);
RTABMAP_STATS(Timing, Likelihood_computation, ms);
RTABMAP_STATS(Timing, Posterior_computation, ms);
RTABMAP_STATS(Timing, Hypotheses_creation, ms);
RTABMAP_STATS(Timing, Hypotheses_validation, ms);
RTABMAP_STATS(Timing, Action_selection, ms);
RTABMAP_STATS(Timing, Statistics_creation, ms);
RTABMAP_STATS(Timing, Memory_cleanup, ms);
RTABMAP_STATS(Timing, Total, ms);
@@ -82,7 +75,6 @@ class RTABMAP_EXP Statistics
RTABMAP_STATS(Timing, Joining_trash, ms);
RTABMAP_STATS(Timing, Emptying_trash, ms);
RTABMAP_STATS(, Parent_id,);
RTABMAP_STATS(, Hypothesis_reactivated,);
RTABMAP_STATS(Keypoint, Dictionary_size, words);
@@ -102,31 +94,27 @@ public:
void setExtended(bool extended) {_extended = extended;}
void setRefImageId(int refImageId) {_refImageId = refImageId;}
void setLoopClosureId(int loopClosureId) {_loopClosureId = loopClosureId;}
void setActuators(const std::list<Actuator> & actuators) {_actuators = actuators;}
void setRefRawData(const std::list<Sensor> & refRawData);
void setLoopClosureRawData(const std::list<Sensor> & loopClosureRawData);
void setRefImage(const cv::Mat & image);
void setLoopImage(const cv::Mat & image);
void setWeights(const std::map<int, int> & weights) {_weights = weights;}
void setPosterior(const std::map<int, float> & posterior) {_posterior = posterior;}
void setLikelihood(const std::map<int, float> & likelihood) {_likelihood = likelihood;}
void setRawLikelihood(const std::map<int, float> & rawLikelihood) {_rawLikelihood = rawLikelihood;}
void setRefWords(const std::multimap<int, cv::KeyPoint> & refWords) {_refWords = refWords;}
void setLoopWords(const std::multimap<int, cv::KeyPoint> & loopWords) {_loopWords = loopWords;}
void setRefMotionMask(const std::vector<unsigned char> & mask) {_refMotionMask = mask;}
void setLoopMotionMask(const std::vector<unsigned char> & mask) {_loopMotionMask = mask;}
// getters
bool extended() const {return _extended;}
int refImageId() const {return _refImageId;}
int loopClosureId() const {return _loopClosureId;}
const std::list<Actuator> & getActuators() const {return _actuators;}
const std::list<Sensor> & refRawData() const {return _refRawData;}
const std::list<Sensor> & loopClosureRawData() const {return _loopClosureRawData;}
const cv::Mat & refImage() const {return _refImage;}
const cv::Mat & loopImage() const {return _loopImage;}
const std::map<int, int> & weights() const {return _weights;}
const std::map<int, float> & posterior() const {return _posterior;}
const std::map<int, float> & likelihood() const {return _likelihood;}
const std::map<int, float> & rawLikelihood() const {return _rawLikelihood;}
const std::multimap<int, cv::KeyPoint> & refWords() const {return _refWords;}
const std::multimap<int, cv::KeyPoint> & loopWords() const {return _loopWords;}
const std::vector<unsigned char> & refMotionMask() const {return _refMotionMask;}
const std::vector<unsigned char> & loopMotionMask() const {return _loopMotionMask;}
const std::map<std::string, float> & data() const {return _data;}
@@ -136,24 +124,19 @@ private:
int _refImageId;
int _loopClosureId;
std::list<Actuator> _actuators;
// extended data start here...
std::list<Sensor> _refRawData;
std::list<Sensor> _loopClosureRawData;
cv::Mat _refImage;
cv::Mat _loopImage;
std::map<int, int> _weights;
std::map<int, float> _posterior;
std::map<int, float> _likelihood;
std::map<int, float> _rawLikelihood;
//keypoint memory
std::multimap<int, cv::KeyPoint> _refWords;
std::multimap<int, cv::KeyPoint> _loopWords;
//sm memory
std::vector<unsigned char> _refMotionMask;
std::vector<unsigned char> _loopMotionMask;
// Format for statistics (Plottable statistics must go in that map) :
// {"Group/Name/Unit", value}
// Example : {"Timing/Total time/ms", 500.0f}
@@ -183,13 +166,15 @@ private:
class RtabmapEventCmd : public UEvent
{
public:
enum dummy {d}; // Hack, to fix Eclipse complaining about not defined Cmd enum ?!
enum Cmd {
kCmdResetMemory,
kCmdDumpMemory,
kCmdDumpPrediction,
kCmdGenerateGraph,
kCmdDeleteMemory,
kCmdCleanSensorsBuffer};
kCmdResetMemory,
kCmdDumpMemory,
kCmdDumpPrediction,
kCmdGenerateGraph,
kCmdGenerateLocalGraph,
kCmdDeleteMemory,
kCmdCleanSensorsBuffer};
public:
RtabmapEventCmd(Cmd cmd) :
UEvent(0),
@@ -209,6 +194,7 @@ private:
class RtabmapEventInit : public UEvent
{
public:
enum dummy {d}; // Hack, to fix Eclipse complaining about not defined Status enum ?!
enum Status {
kInitializing,
kInitialized,

View File

@@ -1,57 +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/>.
*/
#ifndef SIMPLEMEMORY_H_
#define SIMPLEMEMORY_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/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 std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
void setRoi(const std::string & roi);
void setColorTable(int size);
private:
virtual void copyData(const Signature * from, Signature * to);
virtual Signature * createSignature(int id, const std::list<Sensor> & sensors, bool keepRawData=false);
private:
bool _useLogPolar;
ColorTable * _colorTable;
bool _useMotionMask;
float _dBThreshold;
bool _dBIndexing;
bool _magnitudeInvariant;
};
}
#endif /* KEYPOINTMEMORY_H_ */

View File

@@ -1,64 +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/>.
*/
#ifndef SENSOR_H_
#define SENSOR_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <vector>
#include <list>
#include <utilite/UEvent.h>
namespace rtabmap {
class Sensor
{
public:
enum Type{kTypeImage=0, kTypeImageFeatures2d, kTypeAudio, kTypeAudioFreq, kTypeAudioFreqSqrdMagn, kTypeJointState, kTypeTwist, kTypeNotSpecified};
public:
Sensor(const cv::Mat & data, Type type, int num = 0) :
_data(data),
_type(type),
_num(num)
{}
Sensor(const cv::Mat & descriptors, const std::vector<cv::KeyPoint> & keypoints, int num = 0) :
_data(descriptors),
_type(kTypeImageFeatures2d),
_num(num),
_keypoints(keypoints)
{}
const cv::Mat & data() const {return _data;}
int type() const {return _type;}
int num() const {return _num;}
virtual ~Sensor() {};
void setKeypoints(const std::vector<cv::KeyPoint> & keypoints) {_keypoints = keypoints;}
const std::vector<cv::KeyPoint> & getKeypoints() const {return _keypoints;}
private:
cv::Mat _data;
int _type;
int _num; // sensor number
std::vector<cv::KeyPoint> _keypoints; // for convenience with kTypeImageFeatures
};
}
#endif /* SENSOR_H_ */

View File

@@ -1,47 +0,0 @@
/*
* SensorimotorEvent.h
*
* Created on: 2012-05-27
* Author: mathieu
*/
#ifndef SENSORIMOTOREVENT_H_
#define SENSORIMOTOREVENT_H_
#include "rtabmap/core/Sensor.h"
#include "rtabmap/core/Actuator.h"
#include <utilite/UEvent.h>
namespace rtabmap
{
class SensorimotorEvent : public UEvent
{
public:
enum Type {
kTypeData,
kTypeNoMoreData
};
public:
SensorimotorEvent() :
UEvent(kTypeNoMoreData) {}
SensorimotorEvent(const std::list<Sensor> & sensors,
const std::list<Actuator> & actuators) :
UEvent(kTypeData),
sensors_(sensors),
actuators_(actuators) {}
virtual ~SensorimotorEvent() {}
int type() const {return this->getCode();}
virtual std::string getClassName() const {return "SensorimotorEvent";}
const std::list<Sensor> & sensors() const {return sensors_;}
const std::list<Actuator> & actuators() const {return actuators_;}
private:
std::list<Sensor> sensors_;
std::list<Actuator> actuators_;
};
}
#endif /* SENSORIMOTOREVENT_H_ */

View File

@@ -30,14 +30,14 @@
namespace rtabmap
{
class NearestNeighbor;
class FlannNN;
class DBDriver;
class VisualWord;
class RTABMAP_EXP VWDictionary
{
public:
enum NNStrategy{kNNNaive, kNNKdTree, kNNFlannKdTree, kNNUndef};
enum NNStrategy{kNNNaive, kNNFlannKdTree, kNNUndef};
static const int ID_START;
static const int ID_INVALID;
@@ -106,7 +106,7 @@ private:
std::string _dictionaryPath; // a pre-computed dictionary (.txt)
int _dim;
int _lastWordId;
NearestNeighbor * _nn;
FlannNN * _nn;
cv::Mat _dataTree;
std::map<int ,int> _mapIndexId;
std::map<int, VisualWord*> _unusedWords; //<id,VisualWord*>, note that these words stay in _visualWords

View File

@@ -1,96 +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/>.
*/
#ifndef VERIFYHYPOTHESES_H_
#define VERIFYHYPOTHESES_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <list>
#include "rtabmap/core/Parameters.h"
#include "utilite/UEventsHandler.h"
#include <map>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
namespace rtabmap
{
class Signature;
// return always true, i.e, there is no verification
class RTABMAP_EXP HypVerificator
{
public:
HypVerificator(const ParametersMap & parameters = ParametersMap());
virtual ~HypVerificator() {}
virtual bool verify(const Signature * ref, const Signature * hyp);
virtual void parseParameters(const ParametersMap & parameters);
};
/////////////////////////
// HypVerificatorSim
/////////////////////////
class HypVerificatorSim : public HypVerificator {
public:
HypVerificatorSim(const ParametersMap & parameters = ParametersMap());
virtual ~HypVerificatorSim();
virtual bool verify(const Signature * ref, const Signature * hyp);
virtual void parseParameters(const ParametersMap & parameters);
private:
float _similarity;
};
/////////////////////////
// HypVerificatorEpipolarGeo
/////////////////////////
class KeypointSignature;
class RTABMAP_EXP HypVerificatorEpipolarGeo : public HypVerificator
{
public:
HypVerificatorEpipolarGeo(const ParametersMap & parameters = ParametersMap());
virtual ~HypVerificatorEpipolarGeo();
virtual bool verify(const Signature * ref, const Signature * hyp);
virtual void parseParameters(const ParametersMap & parameters);
int getMatchCountMinAccepted() const {return _matchCountMinAccepted;}
double getRansacParam1() const {return _ransacParam1;}
double getRansacParam2() const {return _ransacParam2;}
void setMatchCountMinAccepted(int matchCountMinAccepted) {_matchCountMinAccepted = matchCountMinAccepted;}
void setRansacParam1(double ransacParam1) {_ransacParam1 = ransacParam1;}
void setRansacParam2(double ransacParam2) {_ransacParam2 = ransacParam2;}
private:
bool doEpipolarGeometry(const KeypointSignature * ssA, const KeypointSignature * ssB);
private:
int _matchCountMinAccepted;
double _ransacParam1;
double _ransacParam2;
};
} // namespace rtabmap
#endif /* VERIFYHYPOTHESES_H_ */

View File

@@ -17,9 +17,9 @@
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rtabmap/core/BayesFilter.h"
#include "BayesFilter.h"
#include "rtabmap/core/Memory.h"
#include "rtabmap/core/Signature.h"
#include "Signature.h"
#include "rtabmap/core/Parameters.h"
#include <iostream>
@@ -29,7 +29,8 @@ namespace rtabmap {
BayesFilter::BayesFilter(const ParametersMap & parameters) :
_virtualPlacePrior(Parameters::defaultBayesVirtualPlacePriorThr()),
_predictionOnNonNullActionsOnly(Parameters::defaultBayesPredictionOnNonNullActionsOnly())
_fullPredictionUpdate(Parameters::defaultBayesFullPredictionUpdate()),
_totalPredictionLCValues(0.0f)
{
this->setPredictionLC(Parameters::defaultBayesPredictionLC());
this->parseParameters(parameters);
@@ -49,9 +50,9 @@ void BayesFilter::parseParameters(const ParametersMap & parameters)
{
this->setPredictionLC((*iter).second);
}
if((iter=parameters.find(Parameters::kBayesPredictionOnNonNullActionsOnly())) != parameters.end())
if((iter=parameters.find(Parameters::kBayesFullPredictionUpdate())) != parameters.end())
{
_predictionOnNonNullActionsOnly = uStr2Bool((*iter).second.c_str());
_fullPredictionUpdate = uStr2Bool((*iter).second.c_str());
}
}
@@ -108,6 +109,11 @@ void BayesFilter::setPredictionLC(const std::string & prediction)
_predictionLC = tmpValues;
}
}
_totalPredictionLCValues = 0.0f;
for(unsigned int j=0; j<_predictionLC.size(); ++j)
{
_totalPredictionLCValues += _predictionLC[j];
}
}
const std::vector<double> & BayesFilter::getPredictionLC() const
@@ -133,6 +139,7 @@ std::string BayesFilter::getPredictionLCStr() const
void BayesFilter::reset()
{
_posterior.clear();
_prediction = cv::Mat();
}
const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory, const std::map<int, float> & likelihood)
@@ -160,7 +167,6 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
UTimer timer;
timer.start();
cv::Mat prediction;
cv::Mat prior;
cv::Mat posterior;
@@ -168,211 +174,176 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
int j=0;
// Recursive Bayes estimation...
// STEP 1 - Prediction : Prior*lastPosterior
prediction = cv::Mat(likelihood.size(), likelihood.size(), CV_32FC1);
if(this->generatePrediction(prediction, memory, uKeys(likelihood)))
_prediction = this->generatePrediction(memory, uKeys(likelihood));
ULOGGER_DEBUG("STEP1-generate prior=%fs, rows=%d, cols=%d", timer.ticks(), _prediction.rows, _prediction.cols);
//std::cout << "Prediction=" << _prediction << std::endl;
// Adjust the last posterior if some images were
// reactivated or removed from the working memory
posterior = cv::Mat(likelihood.size(), 1, CV_32FC1);
this->updatePosterior(memory, uKeys(likelihood));
j=0;
for(std::map<int, float>::const_iterator i=_posterior.begin(); i!= _posterior.end(); ++i)
{
ULOGGER_DEBUG("STEP1-generate prior=%fs, rows=%d, cols=%d", timer.ticks(), prediction.rows, prediction.cols);
//std::cout << "Prediction=" << prediction << std::endl;
// Adjust the last posterior if some images were
// reactivated or removed from the working memory
posterior = cv::Mat(likelihood.size(), 1, CV_32FC1);
this->updatePosterior(memory, uKeys(likelihood));
j=0;
for(std::map<int, float>::const_iterator i=_posterior.begin(); i!= _posterior.end(); ++i)
{
((float*)posterior.data)[j++] = (*i).second;
}
ULOGGER_DEBUG("STEP1-update posterior=%fs, posterior=%d, _posterior size=%d", posterior.rows, _posterior.size());
//std::cout << "LastPosterior=" << posterior << std::endl;
// Multiply prediction matrix with the last posterior
// (m,m) X (m,1) = (m,1)
prior = prediction * posterior;
ULOGGER_DEBUG("STEP1-matrix mult time=%fs", timer.ticks());
//std::cout << "ResultingPrior=" << 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;
for(std::map<int, float>::const_iterator i=likelihood.begin(); i!= likelihood.end(); ++i)
{
std::map<int, float>::iterator p =_posterior.find((*i).first);
if(p!= _posterior.end())
{
(*p).second = (*i).second * ((float*)prior.data)[j++];
sum+=(*p).second;
}
else
{
ULOGGER_ERROR("Problem1! can't find id=%d", (*i).first);
}
}
ULOGGER_DEBUG("STEP2-likelihood time=%fs", timer.ticks());
// Normalize
ULOGGER_DEBUG("sum=%f", sum);
if(sum != 0)
{
for(std::map<int, float>::iterator i=_posterior.begin(); i!= _posterior.end(); ++i)
{
(*i).second /= sum;
}
}
ULOGGER_DEBUG("normalize time=%fs", timer.ticks());
((float*)posterior.data)[j++] = (*i).second;
}
ULOGGER_DEBUG("STEP1-update posterior=%fs, posterior=%d, _posterior size=%d", posterior.rows, _posterior.size());
//std::cout << "LastPosterior=" << posterior << std::endl;
// Multiply prediction matrix with the last posterior
// (m,m) X (m,1) = (m,1)
prior = _prediction * posterior;
ULOGGER_DEBUG("STEP1-matrix mult time=%fs", timer.ticks());
//std::cout << "ResultingPrior=" << 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;
for(std::map<int, float>::const_iterator i=likelihood.begin(); i!= likelihood.end(); ++i)
{
std::map<int, float>::iterator p =_posterior.find((*i).first);
if(p!= _posterior.end())
{
(*p).second = (*i).second * ((float*)prior.data)[j++];
sum+=(*p).second;
}
else
{
ULOGGER_ERROR("Problem1! can't find id=%d", (*i).first);
}
}
ULOGGER_DEBUG("STEP2-likelihood time=%fs", timer.ticks());
//std::cout << "Posterior (before normalization)=" << _posterior << std::endl;
// Normalize
ULOGGER_DEBUG("sum=%f", sum);
if(sum != 0)
{
for(std::map<int, float>::iterator i=_posterior.begin(); i!= _posterior.end(); ++i)
{
(*i).second /= sum;
}
}
ULOGGER_DEBUG("normalize time=%fs", timer.ticks());
//std::cout << "Posterior=" << _posterior << std::endl;
return _posterior;
}
bool BayesFilter::generatePrediction(cv::Mat & prediction, const Memory * memory, const std::vector<int> & ids) const
cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector<int> & ids) const
{
ULOGGER_DEBUG("");
if(!_fullPredictionUpdate && !_prediction.empty())
{
return updatePrediction(_prediction, memory, uKeys(_posterior), ids);
}
UDEBUG("");
UASSERT(memory &&
_predictionLC.size() >= 2 &&
ids.size());
UTimer timer;
timer.start();
UTimer timerGlobal;
timerGlobal.start();
if(!memory ||
prediction.empty() ||
prediction.rows != prediction.cols ||
(unsigned int)prediction.rows != ids.size() ||
_predictionLC.size() < 2 ||
!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 ?!?");
}
UASSERT_MSG(ids[i] != 0, "Signature id is null ?!?");
idToIndexMap.insert(idToIndexMap.end(), std::make_pair(ids[i], i));
}
//int rows = prediction.rows;
prediction = cv::Mat::zeros(prediction.rows, prediction.cols, prediction.type());
cv::Mat prediction = cv::Mat::zeros(ids.size(), ids.size(), CV_32FC1);
int cols = prediction.cols;
// Each prior is a column vector
ULOGGER_DEBUG("_predictionLC.size()=%d",_predictionLC.size());
UDEBUG("_predictionLC.size()=%d",_predictionLC.size());
std::set<int> idsDone;
for(unsigned int i=0; i<ids.size(); ++i)
{
int loopSignId = ids[i];
if(loopSignId > 0)
if(idsDone.find(ids[i]) == idsDone.end())
{
// Set high values (gaussians curves) to loop closure neighbors
float sum = 0.0f; // sum values added
float totalModelValues = 0.0f;
for(unsigned int j=0; j<_predictionLC.size(); ++j)
if(ids[i] > 0)
{
totalModelValues += _predictionLC[j];
}
// Set high values (gaussians curves) to loop closure neighbors
// 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])
{
float delta = totalModelValues-_predictionLC[0]-sum;
((float*)prediction.data)[i + i*cols] += delta;
sum+=delta;
}
float allOtherPlacesValue = 0;
if(totalModelValues < 1)
{
allOtherPlacesValue = 1.0f - totalModelValues;
}
// Set all loop events to small values according to the model
if(allOtherPlacesValue > 0 && cols>1)
{
float value = allOtherPlacesValue / float(cols - 1);
for(int j=ids[0] < 0?1:0; j<cols; ++j)
// ADD prob for each neighbors
std::map<int, int> neighbors = memory->getNeighborsId(ids[i], _predictionLC.size()-1, 0);
std::list<int> idsLoopMargin;
//filter neighbors in STM
for(std::map<int, int>::iterator iter=neighbors.begin(); iter!=neighbors.end();)
{
if(((float*)prediction.data)[i + j*cols] == 0)
if(memory->isInSTM(iter->first))
{
((float*)prediction.data)[i + j*cols] = value;
sum += ((float*)prediction.data)[i + j*cols];
neighbors.erase(iter++);
}
else
{
if(iter->second == 0)
{
idsLoopMargin.push_back(iter->second);
}
++iter;
}
}
}
//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)
{
for(int j=ids[0] < 0?1:0; j<cols; ++j)
// should at least have 1 id in idsMarginLoop
if(idsLoopMargin.size() == 0)
{
((float*)prediction.data)[i + j*cols] *= maxNorm / sum;
UFATAL("No 0 margin neighbor for signature %d !?!?", ids[i]);
}
sum = maxNorm;
}
// ADD virtual place prob
if(ids[0] < 0)
{
((float*)prediction.data)[i] = _predictionLC[0];
sum += ((float*)prediction.data)[i];
}
//debug
//for(int j=0; j<cols; ++j)
//{
// 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
{
// Set the virtual place prior
if(_virtualPlacePrior > 0)
{
if(cols>1) // The first must be the virtual place
// same neighbor tree for loop signatures (margin = 0)
for(std::list<int>::iterator iter = idsLoopMargin.begin(); iter!=idsLoopMargin.end(); ++iter)
{
((float*)prediction.data)[i] = _virtualPlacePrior;
float val = (1.0-_virtualPlacePrior)/(cols-1);
for(int j=1; j<cols; j++)
{
((float*)prediction.data)[i + j*cols] = val;
}
}
else if(cols>0)
{
((float*)prediction.data)[i] = 1;
float sum = 0.0f; // sum values added
sum += this->addNeighborProb(prediction, i, neighbors, idToIndexMap);
idsDone.insert(*iter);
this->normalize(prediction, i, sum, ids[0]<0);
}
}
else
{
// Only for some tests...
// when _virtualPlacePrior=0, set all priors to the same value
if(cols>1)
// Set the virtual place prior
if(_virtualPlacePrior > 0)
{
float val = 1.0/cols;
for(int j=0; j<cols; j++)
if(cols>1) // The first must be the virtual place
{
((float*)prediction.data)[i + j*cols] = val;
((float*)prediction.data)[i] = _virtualPlacePrior;
float val = (1.0-_virtualPlacePrior)/(cols-1);
for(int j=1; j<cols; j++)
{
((float*)prediction.data)[i + j*cols] = val;
}
}
else if(cols>0)
{
((float*)prediction.data)[i] = 1;
}
}
else if(cols>0)
else
{
((float*)prediction.data)[i] = 1;
// Only for some tests...
// when _virtualPlacePrior=0, set all priors to the same value
if(cols>1)
{
float val = 1.0/cols;
for(int j=0; j<cols; j++)
{
((float*)prediction.data)[i + j*cols] = val;
}
}
else if(cols>0)
{
((float*)prediction.data)[i] = 1;
}
}
}
}
@@ -380,7 +351,217 @@ bool BayesFilter::generatePrediction(cv::Mat & prediction, const Memory * memory
ULOGGER_DEBUG("time = %fs", timerGlobal.ticks());
return true;
return prediction;
}
void BayesFilter::normalize(cv::Mat & prediction, unsigned int index, float addedProbabilitiesSum, bool virtualPlaceUsed) const
{
UASSERT(index < (unsigned int)prediction.rows && index < (unsigned int)prediction.cols);
int cols = prediction.cols;
// ADD values of not found neighbors to loop closure
if(addedProbabilitiesSum < _totalPredictionLCValues-_predictionLC[0])
{
float delta = _totalPredictionLCValues-_predictionLC[0]-addedProbabilitiesSum;
((float*)prediction.data)[index + index*cols] += delta;
addedProbabilitiesSum+=delta;
}
float allOtherPlacesValue = 0;
if(_totalPredictionLCValues < 1)
{
allOtherPlacesValue = 1.0f - _totalPredictionLCValues;
}
// Set all loop events to small values according to the model
if(allOtherPlacesValue > 0 && cols>1)
{
float value = allOtherPlacesValue / float(cols - 1);
for(int j=virtualPlaceUsed?1:0; j<cols; ++j)
{
if(((float*)prediction.data)[index + j*cols] == 0)
{
((float*)prediction.data)[index + j*cols] = value;
addedProbabilitiesSum += ((float*)prediction.data)[index + j*cols];
}
}
}
//normalize this row
float maxNorm = 1 - (virtualPlaceUsed?_predictionLC[0]:0); // 1 - virtual place probability
if(addedProbabilitiesSum<maxNorm-0.0001 || addedProbabilitiesSum>maxNorm+0.0001)
{
for(int j=virtualPlaceUsed?1:0; j<cols; ++j)
{
((float*)prediction.data)[index + j*cols] *= maxNorm / addedProbabilitiesSum;
}
addedProbabilitiesSum = maxNorm;
}
// ADD virtual place prob
if(virtualPlaceUsed)
{
((float*)prediction.data)[index] = _predictionLC[0];
addedProbabilitiesSum += ((float*)prediction.data)[index];
}
//debug
//for(int j=0; j<cols; ++j)
//{
// ULOGGER_DEBUG("test col=%d = %f", i, prediction.data.fl[i + j*cols]);
//}
if(addedProbabilitiesSum<0.99 || addedProbabilitiesSum > 1.01)
{
UWARN("Prediction is not normalized sum=%f", addedProbabilitiesSum);
}
}
cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction,
const Memory * memory,
const std::vector<int> & oldIds,
const std::vector<int> & newIds) const
{
UTimer timer;
UDEBUG("");
UASSERT(memory &&
oldIds.size() &&
newIds.size() &&
oldIds.size() == (unsigned int)oldPrediction.cols &&
oldIds.size() == (unsigned int)oldPrediction.rows);
cv::Mat prediction = cv::Mat::zeros(newIds.size(), newIds.size(), CV_32FC1);
// Create id to index maps
std::map<int, int> oldIdToIndexMap;
std::map<int, int> newIdToIndexMap;
for(unsigned int i=0; i<oldIds.size() || i<newIds.size(); ++i)
{
if(i<oldIds.size())
{
UASSERT(oldIds[i]);
oldIdToIndexMap.insert(oldIdToIndexMap.end(), std::make_pair(oldIds[i], i));
//UDEBUG("oldIdToIndexMap[%d] = %d", oldIds[i], i);
}
if(i<newIds.size())
{
UASSERT(newIds[i]);
newIdToIndexMap.insert(newIdToIndexMap.end(), std::make_pair(newIds[i], i));
//UDEBUG("newIdToIndexMap[%d] = %d", newIds[i], i);
}
}
UDEBUG("time creating id-index maps = %fs", timer.restart());
//Get removed ids
std::set<int> removedIds;
for(unsigned int i=0; i<oldIds.size(); ++i)
{
if(!uContains(newIdToIndexMap, oldIds[i]))
{
removedIds.insert(removedIds.end(), oldIds[i]);
UDEBUG("removed id=%d at oldIndex=%d", oldIds[i], i);
}
}
UDEBUG("time getting removed ids = %fs", timer.restart());
int added = 0;
// get ids to update
std::set<int> idsToUpdate;
for(unsigned int i=0; i<oldIds.size() || i<newIds.size(); ++i)
{
if(i<oldIds.size())
{
if(removedIds.find(oldIds[i]) != removedIds.end())
{
unsigned int cols = oldPrediction.cols;
for(unsigned int j=0; j<cols; ++j)
{
if(((const float *)oldPrediction.data)[i + j*cols] != 0.0f &&
j!=i &&
removedIds.find(oldIds[j]) == removedIds.end())
{
//UDEBUG("to update id=%d from id=%d removed (value=%f)", oldIds[j], oldIds[i], ((const float *)oldPrediction.data)[i + j*cols]);
idsToUpdate.insert(oldIds[j]);
}
}
}
}
if(i<newIds.size() && !uContains(oldIdToIndexMap,newIds[i]))
{
std::map<int, int> neighbors = memory->getNeighborsId(newIds[i], _predictionLC.size()-1, 0);
float sum = this->addNeighborProb(prediction, i, neighbors, newIdToIndexMap);
this->normalize(prediction, i, sum, newIds[0]<0);
++added;
for(std::map<int,int>::iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
{
if(uContains(oldIdToIndexMap, iter->first) &&
removedIds.find(iter->first) == removedIds.end())
{
idsToUpdate.insert(iter->first);
}
}
}
}
UDEBUG("time getting ids to update = %fs", timer.restart());
// update modified/added ids
int modified = 0;
for(std::set<int>::iterator iter = idsToUpdate.begin(); iter!=idsToUpdate.end(); ++iter)
{
std::map<int, int> neighbors = memory->getNeighborsId(*iter, _predictionLC.size()-1, 0);
int index = newIdToIndexMap.at(*iter);
float sum = this->addNeighborProb(prediction, index, neighbors, newIdToIndexMap);
this->normalize(prediction, index, sum, newIds[0]<0);
++modified;
}
UDEBUG("time updating modified/added ids = %fs", timer.restart());
//UDEBUG("oldIds.size()=%d, oldPrediction.cols=%d, oldPrediction.rows=%d", oldIds.size(), oldPrediction.cols, oldPrediction.rows);
//UDEBUG("newIdToIndexMap.size()=%d, prediction.cols=%d, prediction.rows=%d", newIdToIndexMap.size(), prediction.cols, prediction.rows);
// copy not changed probabilities
int copied = 0;
for(unsigned int i=0; i<oldIds.size(); ++i)
{
if(oldIds[i]>0 && removedIds.find(oldIds[i]) == removedIds.end() && idsToUpdate.find(oldIds[i]) == idsToUpdate.end())
{
for(int j=0; j<oldPrediction.cols; ++j)
{
if(removedIds.find(oldIds[j]) == removedIds.end() && ((const float *)oldPrediction.data)[i + j*oldPrediction.cols] != 0.0f)
{
//UDEBUG("i=%d, j=%d", i, j);
//UDEBUG("oldIds[i]=%d, oldIds[j]=%d", oldIds[i], oldIds[j]);
//UDEBUG("newIdToIndexMap.at(oldIds[i])=%d", newIdToIndexMap.at(oldIds[i]));
//UDEBUG("newIdToIndexMap.at(oldIds[j])=%d", newIdToIndexMap.at(oldIds[j]));
((float *)prediction.data)[newIdToIndexMap.at(oldIds[i]) + newIdToIndexMap.at(oldIds[j])*prediction.cols] = ((const float *)oldPrediction.data)[i + j*oldPrediction.cols];
}
}
++copied;
}
}
UDEBUG("time copying = %fs", timer.restart());
//update virtual place
if(newIds[0] < 0)
{
if(prediction.cols>1) // The first must be the virtual place
{
((float*)prediction.data)[0] = _virtualPlacePrior;
float val = (1.0-_virtualPlacePrior)/(prediction.cols-1);
for(int j=1; j<prediction.cols; j++)
{
((float*)prediction.data)[j*prediction.cols] = val;
}
}
else if(prediction.cols>0)
{
((float*)prediction.data)[0] = 1;
}
}
UDEBUG("time updating virtual place = %fs", timer.restart());
UDEBUG("Modified=%d, Added=%d, Copied=%d", modified, added, copied);
return prediction;
}
void BayesFilter::updatePosterior(const Memory * memory, const std::vector<int> & likelihoodIds)
@@ -411,11 +592,10 @@ void BayesFilter::updatePosterior(const Memory * memory, const std::vector<int>
float BayesFilter::addNeighborProb(cv::Mat & prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const
{
if((unsigned int)prediction.cols != idToIndexMap.size() ||
(unsigned int)prediction.rows != idToIndexMap.size())
{
UFATAL("Requirements no met");
}
UASSERT((unsigned int)prediction.cols == idToIndexMap.size() &&
(unsigned int)prediction.rows == idToIndexMap.size() &&
col < (unsigned int)prediction.cols &&
col < (unsigned int)prediction.rows);
float sum=0;
for(std::map<int, int>::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)

View File

@@ -51,19 +51,28 @@ 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(cv::Mat & prediction, const Memory * memory, const std::vector<int> & ids) const;
cv::Mat generatePrediction(const Memory * memory, const std::vector<int> & ids) const;
private:
cv::Mat updatePrediction(const cv::Mat & oldPrediction,
const Memory * memory,
const std::vector<int> & oldIds,
const std::vector<int> & newIds) const;
void updatePosterior(const Memory * memory, const std::vector<int> & likelihoodIds);
float addNeighborProb(cv::Mat & prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const;
float addNeighborProb(cv::Mat & prediction,
unsigned int col,
const std::map<int, int> & neighbors,
const std::map<int, int> & idToIndexMap) const;
void normalize(cv::Mat & prediction, unsigned int index, float addedProbabilitiesSum, bool virtualPlaceUsed) const;
private:
std::map<int, float> _posterior;
cv::Mat _prediction;
float _virtualPlacePrior;
std::vector<double> _predictionLC; // {Vp, Lc, l1, l2, l3, l4...}
bool _predictionOnNonNullActionsOnly;
bool _fullPredictionUpdate;
float _totalPredictionLCValues;
};
} // namespace rtabmap

View File

@@ -4,28 +4,20 @@ SET(SRC_FILES
RtabmapEvent.cpp
Memory.cpp
KeypointMemory.cpp
SMMemory.cpp
DBDriverFactory.cpp
DBDriver.cpp
DBDriverSqlite3.cpp
DBReader.cpp
Camera.cpp
Micro.cpp
EpipolarGeometry.cpp
VisualWord.cpp
VWDictionary.cpp
BayesFilter.cpp
Parameters.cpp
Signature.cpp
KeypointDetector.cpp
KeypointDescriptor.cpp
VerifyHypotheses.cpp
Features2d.cpp
NearestNeighbor.cpp
ColorTable.cpp
)
SET(INCLUDE_DIRS
@@ -35,93 +27,35 @@ SET(INCLUDE_DIRS
${UTILITE_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${SQLITE3_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
${FFTW3F_INCLUDE_DIRS}
)
SET(LIBRARIES
${UTILITE_LIBRARIES}
${OpenCV_LIBS}
${SQLITE3_LIBRARY}
${ZLIB_LIBRARIES}
${FFTW3F_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 database resource]"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql
SET(R
${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql
)
#replace semicolons by spaces
foreach(arg ${R})
set(RESOURCES "${RESOURCES}" "${arg}")
endforeach(arg ${R})
SET(RESOURCES_HEADERS
${CMAKE_CURRENT_BINARY_DIR}/DatabaseSchema_sql.h
)
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
OUTPUT ${RESOURCES_HEADERS}
COMMAND ${URESOURCEGENERATOR_EXEC} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${RESOURCES}
COMMENT "[Creating resources]"
DEPENDS ${R}
)
####################################
@@ -134,7 +68,7 @@ INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
# Add binary that is built from the source file "main.cpp".
# The extension is automatically found.
ADD_LIBRARY(rtabmap_corelib ${SRC_FILES} ${RESOURCES})
ADD_LIBRARY(rtabmap_corelib ${SRC_FILES} ${RESOURCES_HEADERS})
TARGET_LINK_LIBRARIES(rtabmap_corelib ${LIBRARIES})
SET_TARGET_PROPERTIES(

View File

@@ -21,9 +21,7 @@
#include "utilite/UEventsManager.h"
#include "utilite/UConversion.h"
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/DBDriverFactory.h"
#include "rtabmap/core/KeypointDescriptor.h"
#include "rtabmap/core/KeypointDetector.h"
#include "rtabmap/core/Features2d.h"
#include "utilite/UStl.h"
#include "utilite/UConversion.h"
#include "utilite/UFile.h"
@@ -125,15 +123,9 @@ void Camera::parseParameters(const ParametersMap & parameters)
}
switch(detector)
{
case KeypointDetector::kDetectorStar:
_keypointDetector = new StarDetector(parameters);
break;
case KeypointDetector::kDetectorSift:
_keypointDetector = new SIFTDetector(parameters);
break;
case KeypointDetector::kDetectorFast:
_keypointDetector = new FASTDetector(parameters);
break;
case KeypointDetector::kDetectorSurf:
default:
_keypointDetector = new SURFDetector(parameters);
@@ -158,15 +150,6 @@ void Camera::parseParameters(const ParametersMap & parameters)
case KeypointDescriptor::kDescriptorSift:
_keypointDescriptor = new SIFTDescriptor(parameters);
break;
case KeypointDescriptor::kDescriptorBrief:
_keypointDescriptor = new BRIEFDescriptor(parameters);
break;
case KeypointDescriptor::kDescriptorColor:
_keypointDescriptor = new ColorDescriptor(parameters);
break;
case KeypointDescriptor::kDescriptorHue:
_keypointDescriptor = new HueDescriptor(parameters);
break;
case KeypointDescriptor::kDescriptorSurf:
default:
_keypointDescriptor = new SURFDescriptor(parameters);
@@ -511,7 +494,8 @@ CameraVideo::CameraVideo(const std::string & filePath,
int id) :
Camera(imageRate, autoRestart, imageWidth, imageHeight, framesDropped, id),
_filePath(filePath),
_src(kVideoFile)
_src(kVideoFile),
_usbDevice(0)
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,9 +19,8 @@
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/Signature.h"
#include "rtabmap/core/VWDictionary.h"
#include "rtabmap/core/VisualWord.h"
#include "Signature.h"
#include "VisualWord.h"
#include "utilite/UConversion.h"
#include "utilite/UMath.h"
#include "utilite/ULogger.h"
@@ -31,8 +30,6 @@
namespace rtabmap {
DBDriver::DBDriver(const ParametersMap & parameters) :
_minSignaturesToSave(Parameters::defaultDbMinSignaturesToSave()),
_minWordsToSave(Parameters::defaultDbMinWordsToSave()),
_imagesCompressed(Parameters::defaultDbImagesCompressed()),
_emptyTrashesTime(0)
{
@@ -48,14 +45,6 @@ DBDriver::~DBDriver()
void DBDriver::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kDbMinSignaturesToSave())) != parameters.end())
{
_minSignaturesToSave = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kDbMinWordsToSave())) != parameters.end())
{
_minWordsToSave = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kDbImagesCompressed())) != parameters.end())
{
_imagesCompressed = uStr2Bool((*iter).second.c_str());
@@ -131,18 +120,15 @@ void DBDriver::commit() const
_transactionMutex.unlock();
}
bool DBDriver::executeNoResult(const std::string & sql) const
void DBDriver::executeNoResult(const std::string & sql) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->executeNoResultQuery(sql);
this->executeNoResultQuery(sql);
_dbSafeAccessMutex.unlock();
return r;
}
void DBDriver::emptyTrashes(bool async)
{
ULOGGER_DEBUG("");
if(async)
{
ULOGGER_DEBUG("Async emptying, start the trash thread");
@@ -153,11 +139,12 @@ void DBDriver::emptyTrashes(bool async)
UTimer totalTime;
totalTime.start();
std::vector<Signature*> signatures;
std::map<int, Signature*> signatures;
std::map<int, VisualWord*> visualWords;
_trashesMutex.lock();
{
signatures = uValues(_trashSignatures);
ULOGGER_DEBUG("signatures=%d, visualWords=%d", _trashSignatures.size(), _trashVisualWords.size());
signatures = _trashSignatures;
visualWords = _trashVisualWords;
_trashSignatures.clear();
_trashVisualWords.clear();
@@ -168,7 +155,6 @@ void DBDriver::emptyTrashes(bool async)
if(signatures.size() || visualWords.size())
{
ULOGGER_DEBUG("trashSignatures size = %d, trashVisualWords size = %d", signatures.size(), visualWords.size());
this->beginTransaction();
UTimer timer;
timer.start();
@@ -177,16 +163,16 @@ void DBDriver::emptyTrashes(bool async)
if(this->isConnected())
{
//Only one query to the database
this->saveOrUpdate(signatures);
this->saveOrUpdate(uValues(signatures));
}
for(std::vector<Signature *>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
for(std::map<int, Signature *>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
{
delete *iter;
delete iter->second;
}
signatures.clear();
ULOGGER_DEBUG("Time emptying memory signatures trash = %f...", timer.ticks());
}
ULOGGER_DEBUG("Time emptying memory signatures trash = %f...", timer.ticks());
if(visualWords.size())
{
if(this->isConnected())
@@ -200,8 +186,9 @@ void DBDriver::emptyTrashes(bool async)
delete (*iter).second;
}
visualWords.clear();
ULOGGER_DEBUG("Time emptying memory visualWords trash = %f...", timer.ticks());
}
ULOGGER_DEBUG("Time emptying memory visualWords trash = %f...", timer.ticks());
this->commit();
}
@@ -219,10 +206,6 @@ void DBDriver::asyncSave(Signature * s)
_trashesMutex.lock();
{
_trashSignatures.insert(std::pair<int, Signature*>(s->id(), s));
if(_trashSignatures.size() > _minSignaturesToSave && this->isIdle())
{
this->start();
}
}
_trashesMutex.unlock();
}
@@ -235,79 +218,13 @@ void DBDriver::asyncSave(VisualWord * vw)
_trashesMutex.lock();
{
_trashVisualWords.insert(std::pair<int, VisualWord*>(vw->id(), vw));
if(_trashVisualWords.size() > _minWordsToSave && this->isIdle())
{
this->start();
}
}
_trashesMutex.unlock();
}
}
bool DBDriver::getSignature(int signatureId, Signature ** s)
{
*s = 0;
_trashesMutex.lock();
{
if(_trashSignatures.size())
{
_dbSafeAccessMutex.lock();
_dbSafeAccessMutex.unlock();
std::map<int, Signature*>::iterator iter =_trashSignatures.find(signatureId);
if(iter != _trashSignatures.end())
{
*s = iter->second;
_trashSignatures.erase(iter);
}
}
}
_trashesMutex.unlock();
if(*s == 0)
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadQuery(signatureId, s);
_dbSafeAccessMutex.unlock();
return r;
}
return true;
}
bool DBDriver::getVisualWord(int wordId, VisualWord ** vw)
{
*vw = 0;
_trashesMutex.lock();
{
if(_trashVisualWords.size())
{
_dbSafeAccessMutex.lock();
_dbSafeAccessMutex.unlock();
std::map<int, VisualWord*>::iterator iter = _trashVisualWords.find(wordId);
if(iter != _trashVisualWords.end())
{
*vw = iter->second;
_trashVisualWords.erase(iter);
}
}
}
_trashesMutex.unlock();
if(*vw == 0)
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadQuery(wordId, vw);
_dbSafeAccessMutex.unlock();
return r;
}
return true;
}
//Automatically begin and commit a transaction
bool DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures) const
void DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures) const
{
ULOGGER_DEBUG("");
std::list<Signature *> toSave;
@@ -335,28 +252,23 @@ bool DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures) const
this->saveQuery(toSave);
}
}
return false;
}
bool DBDriver::load(VWDictionary * dictionary) const
void DBDriver::load(VWDictionary * dictionary) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadQuery(dictionary);
this->loadQuery(dictionary);
_dbSafeAccessMutex.unlock();
return r;
}
bool DBDriver::loadLastNodes(std::list<Signature *> & signatures) const
void DBDriver::loadLastNodes(std::list<Signature *> & signatures) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadLastNodesQuery(signatures);
this->loadLastNodesQuery(signatures);
_dbSafeAccessMutex.unlock();
return r;
}
bool DBDriver::loadKeypointSignatures(const std::list<int> & signIds, std::list<Signature *> & signatures)
void DBDriver::loadSignatures(const std::list<int> & signIds, std::list<Signature *> & signatures)
{
UDEBUG("");
// look up in the trash before the database
@@ -399,84 +311,16 @@ bool DBDriver::loadKeypointSignatures(const std::list<int> & signIds, std::list<
UDEBUG("");
if(ids.size())
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadKeypointSignaturesQuery(ids, signatures);
this->loadSignaturesQuery(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)
void DBDriver::loadWords(const std::set<int> & wordIds, std::list<VisualWord *> & vws)
{
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;
}
else if(signatures.size())
{
return true;
}
return false;
}
bool DBDriver::loadWords(const std::list<int> & wordIds, std::list<VisualWord *> & vws)
{
if(!wordIds.size())
{
return false;
}
// look up in the trash before the database
std::list<int> ids = wordIds;
std::set<int> ids = wordIds;
std::map<int, VisualWord*>::iterator wIter;
std::list<VisualWord *> puttedBack;
_trashesMutex.lock();
@@ -485,7 +329,7 @@ bool DBDriver::loadWords(const std::list<int> & wordIds, std::list<VisualWord *>
{
_dbSafeAccessMutex.lock();
_dbSafeAccessMutex.unlock();
for(std::list<int>::iterator iter = ids.begin(); iter != ids.end();)
for(std::set<int>::iterator iter = ids.begin(); iter != ids.end();)
{
wIter = _trashVisualWords.find(*iter);
if(wIter != _trashVisualWords.end())
@@ -493,7 +337,7 @@ bool DBDriver::loadWords(const std::list<int> & wordIds, std::list<VisualWord *>
UDEBUG("put back word %d from trash", *iter);
puttedBack.push_back(wIter->second);
_trashVisualWords.erase(wIter);
iter = ids.erase(iter);
ids.erase(iter++);
}
else
{
@@ -505,235 +349,90 @@ bool DBDriver::loadWords(const std::list<int> & wordIds, std::list<VisualWord *>
_trashesMutex.unlock();
if(ids.size())
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadWordsQuery(ids, vws);
this->loadWordsQuery(ids, vws);
_dbSafeAccessMutex.unlock();
uAppend(vws, puttedBack);
return r;
}
else if(puttedBack.size())
{
uAppend(vws, puttedBack);
return true;
}
return false;
}
// <oldWordId, activeWordId>
bool DBDriver::changeWordsRef(const std::map<int, int> & refsToChange)
{
//Change references in the trash
KeypointSignature * s = 0;
UTimer timer;
_trashesMutex.lock();
{
_dbSafeAccessMutex.lock();
_dbSafeAccessMutex.unlock();
timer.start();
for(std::map<int, Signature *>::iterator iter = _trashSignatures.begin(); iter!=_trashSignatures.end(); ++iter)
{
s = dynamic_cast<KeypointSignature*>(iter->second);
if(s)
{
for(std::map<int, int>::const_iterator jter = refsToChange.begin(); jter!=refsToChange.end(); ++jter)
{
s->changeWordsRef((*jter).first, (*jter).second);
}
}
}
ULOGGER_DEBUG("Trash changing words references time=%fs", timer.ticks());
}
_trashesMutex.unlock();
bool r;
_dbSafeAccessMutex.lock();
r = this->changeWordsRefQuery(refsToChange);
_dbSafeAccessMutex.unlock();
return r;
}
bool DBDriver::deleteWords(const std::vector<int> & ids)
{
//Delete words in the trash
std::map<int, VisualWord*>::iterator iter;
_trashesMutex.lock();
{
_dbSafeAccessMutex.lock();
_dbSafeAccessMutex.unlock();
for(unsigned int i=0; i<ids.size(); ++i)
{
iter = _trashVisualWords.find(ids[i]);
if(iter != _trashVisualWords.end())
{
_trashVisualWords.erase(iter);
delete (*iter).second;
}
}
}
_trashesMutex.unlock();
bool r;
_dbSafeAccessMutex.lock();
r = this->deleteWordsQuery(ids);
_dbSafeAccessMutex.unlock();
return r;
}
bool DBDriver::deleteAllVisualWords() const
{
ULOGGER_DEBUG("");
if(this->isConnected())
{
std::string query;
query += "DELETE FROM VisualWord;";
_dbSafeAccessMutex.lock();
bool r = this->executeNoResultQuery(query);
_dbSafeAccessMutex.unlock();
return r;
}
return false;
}
bool DBDriver::deleteAllObsoleteSSVWLinks() const
{
ULOGGER_DEBUG("");
if(this->isConnected())
{
std::string query;
query += "DELETE FROM Map_Node_Word WHERE NOT EXISTS (SELECT id FROM Word WHERE id = Map_Node_Word.word_id);";
_dbSafeAccessMutex.lock();
bool r = this->executeNoResultQuery(query);
_dbSafeAccessMutex.unlock();
return r;
}
return false;
}
bool DBDriver::deleteUnreferencedWords() const
{
ULOGGER_DEBUG("");
if(this->isConnected())
{
std::string query = "DELETE FROM Word WHERE id NOT IN (SELECT word_id FROM Map_Node_Word);";
_dbSafeAccessMutex.lock();
bool r = this->executeNoResultQuery(query);
_dbSafeAccessMutex.unlock();
return r;
}
return false;
}
//TODO Check also in the trash ?
bool DBDriver::getRawData(int id, std::list<Sensor> & rawData) const
void DBDriver::getImage(int signatureId, cv::Mat & rawData) const
{
_dbSafeAccessMutex.lock();
bool result = this->getRawDataQuery(id, rawData);
this->getImageQuery(signatureId, rawData);
_dbSafeAccessMutex.unlock();
return result;
}
//TODO Check also in the trash ?
bool DBDriver::getActuatorData(int id, std::list<Actuator> & data) const
void DBDriver::getNeighborIds(int signatureId, std::set<int> & neighbors, bool onlyWithActions) const
{
_dbSafeAccessMutex.lock();
bool result = this->getActuatorDataQuery(id, data);
this->getNeighborIdsQuery(signatureId, neighbors, onlyWithActions);
_dbSafeAccessMutex.unlock();
return result;
}
//TODO Check also in the trash ?
bool DBDriver::getNeighborIds(int signatureId, std::set<int> & neighbors, bool onlyWithActions) const
void DBDriver::loadNeighbors(int signatureId, std::set<int> & neighbors) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getNeighborIdsQuery(signatureId, neighbors, onlyWithActions);
this->loadNeighborsQuery(signatureId, neighbors);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::loadNeighbors(int signatureId, NeighborsMultiMap & neighbors) const
void DBDriver::getWeight(int signatureId, int & weight) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->loadNeighborsQuery(signatureId, neighbors);
this->getWeightQuery(signatureId, weight);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::getWeight(int signatureId, int & weight) const
void DBDriver::getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getWeightQuery(signatureId, weight);
this->getLoopClosureIdsQuery(signatureId, loopIds, childIds);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const
void DBDriver::getAllNodeIds(std::set<int> & ids) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getLoopClosureIdsQuery(signatureId, loopIds, childIds);
this->getAllNodeIdsQuery(ids);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::getAllNodeIds(std::set<int> & ids) const
void DBDriver::getLastNodeId(int & id) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getAllNodeIdsQuery(ids);
this->getLastIdQuery("Node", id);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::getLastNodeId(int & id) const
void DBDriver::getLastWordId(int & id) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getLastNodeIdQuery(id);
this->getLastIdQuery("Word", id);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::getLastWordId(int & id) const
void DBDriver::getInvertedIndexNi(int signatureId, int & ni) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getLastWordIdQuery(id);
this->getInvertedIndexNiQuery(signatureId, ni);
_dbSafeAccessMutex.unlock();
return r;
}
//TODO Check also in the trash ?
bool DBDriver::getInvertedIndexNi(int signatureId, int & ni) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getInvertedIndexNiQuery(signatureId, ni);
_dbSafeAccessMutex.unlock();
return r;
}
bool DBDriver::getHighestWeightedNodeIds(unsigned int count, std::multimap<int, int> & ids) const
{
bool r;
_dbSafeAccessMutex.lock();
r = this->getHighestWeightedNodeIdsQuery(count, ids);
_dbSafeAccessMutex.unlock();
return r;
}
bool DBDriver::addStatisticsAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed) const
void DBDriver::addStatisticsAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed) const
{
ULOGGER_DEBUG("");
if(this->isConnected())
@@ -745,13 +444,11 @@ bool DBDriver::addStatisticsAfterRun(int stMemSize, int lastSignAdded, int proce
<< processMemUsed << ","
<< databaseMemUsed << ");";
bool r = this->executeNoResultQuery(query.str());
return r;
this->executeNoResultQuery(query.str());
}
return false;
}
bool DBDriver::addStatisticsAfterRunSurf(int dictionarySize) const
void DBDriver::addStatisticsAfterRunSurf(int dictionarySize) const
{
ULOGGER_DEBUG("");
if(this->isConnected())
@@ -759,10 +456,8 @@ bool DBDriver::addStatisticsAfterRunSurf(int dictionarySize) const
std::stringstream query;
query << "INSERT INTO StatisticsDictionary(dictionary_size) values(" << dictionarySize << ");";
bool r = this->executeNoResultQuery(query.str());
return r;
this->executeNoResultQuery(query.str());
}
return false;
}
} // namespace rtabmap

View File

@@ -1,70 +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/>.
*/
#include "rtabmap/core/DBDriverFactory.h"
#include "DBDriverSqlite3.h"
#include "utilite/ULogger.h"
namespace rtabmap {
DBDriver * DBDriverFactory::createDBDriver(const std::string & dbDriverName, const ParametersMap & parameters)
{
// TODO Do it with dynamic link libraries...
// Find the driver...
// Link dynamically to the driver...
DBDriver * driver = 0;
// Static link
if(dbDriverName.compare("sqlite3") == 0)
{
driver = new DBDriverSqlite3(parameters);
}
else if(dbDriverName.compare("mysql") == 0)
{
// TODO mysql driver
ULOGGER_ERROR("mysql driver is not implemented!");
}
else if(dbDriverName.compare("postgresql") == 0)
{
// TODO postgresql driver
ULOGGER_ERROR("postgresql driver is not implemented!");
}
else if(dbDriverName.compare("oracle") == 0)
{
// TODO oracle driver
ULOGGER_ERROR("oracle driver is not implemented!");
}
else
{
ULOGGER_ERROR("Unknown driver \"%s\"", dbDriverName.c_str());
}
return driver;
}
DBDriverFactory::DBDriverFactory() {
}
DBDriverFactory::~DBDriverFactory() {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include "rtabmap/core/DBDriver.h"
#include <opencv2/features2d/features2d.hpp>
#include <sqlite3.h>
namespace rtabmap {
@@ -32,7 +32,6 @@ 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);
@@ -46,55 +45,44 @@ private:
virtual bool isConnectedQuery() const;
virtual long getMemoryUsedQuery() const; // In bytes
virtual bool executeNoResultQuery(const std::string & sql) const;
virtual void executeNoResultQuery(const std::string & sql) const;
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, bool onlyWithActions = false) const;
virtual bool getWeightQuery(int signatureId, int & weight) const;
virtual bool getLoopClosureIdsQuery(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const;
virtual void getNeighborIdsQuery(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const;
virtual void getWeightQuery(int signatureId, int & weight) const;
virtual void 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 std::list<Signature *> & signatures) const;
virtual void saveQuery(const std::vector<VisualWord *> & visualWords) const;
virtual void updateQuery(const std::list<Signature *> & signatures) const;
virtual void saveQuery(const std::list<Signature *> & signatures) const;
// Load objects
virtual bool loadQuery(VWDictionary * dictionary) const;
virtual bool loadLastNodesQuery(std::list<Signature *> & signatures) const;
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 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, NeighborsMultiMap & neighbors) const;
bool loadLinksQuery(std::list<Signature *> & signatures) const;
virtual void loadQuery(VWDictionary * dictionary) const;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const;
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const;
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const;
virtual void loadNeighborsQuery(int signatureId, std::set<int> & neighbors) const;
virtual bool getRawDataQuery(int id, std::list<Sensor> & rawData) const;
virtual bool getActuatorDataQuery(int id, std::list<Actuator> & data) const;
virtual bool getAllNodeIdsQuery(std::set<int> & ids) const;
virtual bool getLastNodeIdQuery(int & id) const;
virtual bool getLastWordIdQuery(int & id) const;
virtual bool getInvertedIndexNiQuery(int signatureId, int & ni) const;
virtual bool getHighestWeightedNodeIdsQuery(unsigned int count, std::multimap<int, int> & ids) const;
virtual void getImageQuery(int nodeId, cv::Mat & image) const;
virtual void getAllNodeIdsQuery(std::set<int> & ids) const;
virtual void getLastIdQuery(const std::string & tableName, int & id) const;
virtual void getInvertedIndexNiQuery(int signatureId, int & ni) const;
private:
std::string queryStepNode() const;
std::string queryStepSensor() const;
std::string queryStepNodeToSensor() const;
std::string queryStepImage() const;
std::string queryStepLink() const;
std::string queryStepActuator() const;
std::string queryStepWordsChanged() const;
std::string queryStepKeypoint() const;
std::string queryStepSensors() const;
int stepNode(sqlite3_stmt * ppStmt, const Signature * s) const;
int stepSensor(sqlite3_stmt * ppStmt, int id, int num, const std::vector<int> & data, const Sensor & sensor) const;
int stepLink(sqlite3_stmt * ppStmt, int fromId, int toId, int type, int actuator_id, const std::vector<int> & baseIds) const;
int stepActuator(sqlite3_stmt * ppStmt, int id, int num, const Actuator & actuator) 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;
void stepNode(sqlite3_stmt * ppStmt, const Signature * s) const;
void stepNodeToSensor(sqlite3_stmt * ppStmt, int nodeId, int sensorId, int num) const;
void stepImage(sqlite3_stmt * ppStmt, int id, const cv::Mat & image) const;
void stepLink(sqlite3_stmt * ppStmt, int fromId, int toId, int type) const;
void stepWordsChanged(sqlite3_stmt * ppStmt, int signatureId, int oldWordId, int newWordId) const;
void stepKeypoint(sqlite3_stmt * ppStmt, int signatureId, int wordId, const cv::KeyPoint & kp) const;
private:
void loadLinksQuery(std::list<Signature *> & signatures) const;
int loadOrSaveDb(sqlite3 *pInMemory, const std::string & fileName, int isSave) const;
private:

View File

@@ -7,24 +7,20 @@
#include "rtabmap/core/DBReader.h"
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/SensorimotorEvent.h"
#include "rtabmap/core/DBDriverFactory.h"
#include "DBDriverSqlite3.h"
#include <utilite/ULogger.h>
#include <utilite/UEventsManager.h>
#include <utilite/UFile.h>
#include "rtabmap/core/Camera.h"
namespace rtabmap {
DBReader::DBReader(const std::string & databasePath,
float frameRate,
const std::set<Sensor::Type> & sensorTypes,
const std::set<Actuator::Type> & actuatorTypes) :
float frameRate) :
_path(databasePath),
_frameRate(frameRate),
_sensorTypes(sensorTypes),
_actuatorTypes(actuatorTypes),
_dbDriver(0),
_currentId(_ids.end())
{
@@ -40,7 +36,7 @@ DBReader::~DBReader()
}
}
bool DBReader::init()
bool DBReader::init(int startIndex)
{
if(_dbDriver)
{
@@ -59,7 +55,7 @@ bool DBReader::init()
rtabmap::ParametersMap parameters;
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kDbSqlite3InMemory(), "false"));
_dbDriver = DBDriverFactory::createDBDriver("sqlite3", parameters);
_dbDriver = new DBDriverSqlite3(parameters);
if(!_dbDriver)
{
UERROR("Driver doesn't exist.");
@@ -75,6 +71,18 @@ bool DBReader::init()
_dbDriver->getAllNodeIds(_ids);
_currentId = _ids.begin();
if(startIndex>0 && _ids.size())
{
std::set<int>::iterator iter = _ids.lower_bound(startIndex);
if(iter == _ids.end())
{
UWARN("Start index is too high (%d), the last in database is %d. Starting from beginning...", startIndex, *_ids.rbegin());
}
else
{
_currentId = iter;
}
}
return true;
}
@@ -94,27 +102,23 @@ void DBReader::mainLoopBegin()
void DBReader::mainLoop()
{
std::list<Sensor> sensors;
std::list<Actuator> actuators;
this->getNextSensorimotorState(sensors, actuators);
if(!sensors.empty() || !actuators.empty())
cv::Mat image;
this->getNextImage(image);
if(!image.empty())
{
UEventsManager::post(new SensorimotorEvent(sensors, actuators));
UEventsManager::post(new CameraEvent(image));
}
else if(!this->isKilled())
{
UDEBUG("no more sensorimotor states...");
UDEBUG("no more images...");
this->kill();
UEventsManager::post(new SensorimotorEvent());
UEventsManager::post(new CameraEvent());
}
}
void DBReader::getNextSensorimotorState(std::list<Sensor> & sensors, std::list<Actuator> & actuators)
void DBReader::getNextImage(cv::Mat & image)
{
sensors.clear();
actuators.clear();
if(_dbDriver)
{
float frameRate = _frameRate;
@@ -140,49 +144,12 @@ void DBReader::getNextSensorimotorState(std::list<Sensor> & sensors, std::list<A
if(!this->isKilled() && _currentId != _ids.end())
{
//sensors
_dbDriver->getRawData(*_currentId, sensors);
//actuators
NeighborsMultiMap neighbors;
_dbDriver->getImage(*_currentId, image);
++_currentId;
if(_currentId != _ids.end())
if(image.empty())
{
_dbDriver->getActuatorData(*_currentId, actuators);
UWARN("No image loaded from the database!");
}
UDEBUG("sensors.size=%d actuators.size=%d", sensors.size(), actuators.size());
//filtering for types wanted
if(_sensorTypes.size())
{
for(std::list<Sensor>::iterator jter=sensors.begin(); jter!=sensors.end();)
{
if(_sensorTypes.find((Sensor::Type)jter->type()) == _sensorTypes.end())
{
jter = sensors.erase(jter);
}
else
{
++jter;
}
}
}
if(_actuatorTypes.size())
{
for(std::list<Actuator>::iterator jter=actuators.begin(); jter!=actuators.end();)
{
if(_actuatorTypes.find((Actuator::Type)jter->type()) == _actuatorTypes.end())
{
jter = actuators.erase(jter);
}
else
{
++jter;
}
}
}
UDEBUG("after filtering sensors.size=%d actuators.size=%d", sensors.size(), actuators.size());
}
}
else

View File

@@ -18,9 +18,11 @@
*/
#include "rtabmap/core/EpipolarGeometry.h"
#include "Signature.h"
#include "utilite/ULogger.h"
#include "utilite/UTimer.h"
#include "utilite/UStl.h"
#include "utilite/UMath.h"
#include <opencv2/core/core.hpp>
#include <opencv2/core/core_c.h>
@@ -30,8 +32,74 @@
namespace rtabmap
{
/////////////////////////
// HypVerificatorEpipolarGeo
/////////////////////////
EpipolarGeometry::EpipolarGeometry(const ParametersMap & parameters) :
_matchCountMinAccepted(Parameters::defaultVhEpMatchCountMin()),
_ransacParam1(Parameters::defaultVhEpRansacParam1()),
_ransacParam2(Parameters::defaultVhEpRansacParam2())
{
this->parseParameters(parameters);
}
EpipolarGeometry::~EpipolarGeometry() {
}
void EpipolarGeometry::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kVhEpMatchCountMin())) != parameters.end())
{
_matchCountMinAccepted = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kVhEpRansacParam1())) != parameters.end())
{
_ransacParam1 = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kVhEpRansacParam2())) != parameters.end())
{
_ransacParam2 = std::atof((*iter).second.c_str());
}
}
bool EpipolarGeometry::check(const Signature * ssA, const Signature * ssB)
{
if(ssA == 0 || ssB == 0)
{
return false;
}
ULOGGER_DEBUG("id(%d,%d)", ssA->id(), ssB->id());
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
findPairsUnique(ssA->getWords(), ssB->getWords(), pairs);
if((int)pairs.size()<_matchCountMinAccepted)
{
return false;
}
std::vector<uchar> status;
cv::Mat f = findFFromWords(pairs, status, _ransacParam1, _ransacParam2);
int inliers = uSum(status);
if(inliers < _matchCountMinAccepted)
{
ULOGGER_DEBUG("Epipolar constraint failed A : not enough inliers (%d/%d), min is %d", inliers, pairs.size(), _matchCountMinAccepted);
return false;
}
else
{
UDEBUG("inliers = %d/%d", inliers, pairs.size());
return true;
}
}
//STATIC STUFF
//Epipolar geometry
void findEpipolesFromF(const cv::Mat & fundamentalMatrix, cv::Vec3d & e1, cv::Vec3d & e2)
void EpipolarGeometry::findEpipolesFromF(const cv::Mat & fundamentalMatrix, cv::Vec3d & e1, cv::Vec3d & e2)
{
if(fundamentalMatrix.rows != 3 || fundamentalMatrix.cols != 3)
{
@@ -66,7 +134,7 @@ void findEpipolesFromF(const cv::Mat & fundamentalMatrix, cv::Vec3d & e1, cv::Ve
//Assuming P0 = [eye(3) zeros(3,1)]
// x1 and x2 are 2D points
// return camera matrix P (3x4) matrix
cv::Mat findPFromF(const cv::Mat & fundamentalMatrix, const cv::Mat & x1, const cv::Mat & x2)
cv::Mat EpipolarGeometry::findPFromF(const cv::Mat & fundamentalMatrix, const cv::Mat & x1, const cv::Mat & x2)
{
if(fundamentalMatrix.rows != 3 || fundamentalMatrix.cols != 3)
@@ -229,7 +297,7 @@ cv::Mat findPFromF(const cv::Mat & fundamentalMatrix, const cv::Mat & x1, const
return p;
}
cv::Mat findFFromWords(
cv::Mat EpipolarGeometry::findFFromWords(
const std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs, // id, kpt1, kpt2
std::vector<uchar> & status,
double ransacParam1,
@@ -312,7 +380,7 @@ cv::Mat findFFromWords(
return fundamentalMatrix;
}
void findRTFromP(
void EpipolarGeometry::findRTFromP(
const cv::Mat & p,
cv::Mat & r,
cv::Mat & t)
@@ -331,7 +399,7 @@ void findRTFromP(
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (2,2) (4,4) (6a,6a) (6b,6b)]
* realPairsCount = 5
*/
int findPairs(const std::multimap<int, cv::KeyPoint> & wordsA,
int EpipolarGeometry::findPairs(const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs)
{
@@ -359,7 +427,7 @@ int findPairs(const std::multimap<int, cv::KeyPoint> & wordsA,
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
* realPairsCount = 5
*/
int findPairsUnique(const std::multimap<int, cv::KeyPoint> & wordsA,
int EpipolarGeometry::findPairsUnique(const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs)
{
@@ -388,7 +456,7 @@ int findPairsUnique(const std::multimap<int, cv::KeyPoint> & wordsA,
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (1,1b) (2,2) (4,4) (6a,6a) (6a,6b) (6b,6a) (6b,6b)]
* realPairsCount = 5
*/
int findPairsAll(const std::multimap<int, cv::KeyPoint> & wordsA,
int EpipolarGeometry::findPairsAll(const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs)
{

619
corelib/src/Features2d.cpp Normal file
View File

@@ -0,0 +1,619 @@
/*
* 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 "rtabmap/core/Features2d.h"
#include "utilite/UStl.h"
#include "utilite/UConversion.h"
#include "utilite/ULogger.h"
#include "utilite/UMath.h"
#include "utilite/ULogger.h"
#include "utilite/UTimer.h"
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/gpu/gpu.hpp>
#include <opencv2/core/version.hpp>
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
#include <opencv2/nonfree/features2d.hpp>
#endif
#define OPENCV_SURF_GPU CV_MAJOR_VERSION >= 2 and CV_MINOR_VERSION >=2 and CV_SUBMINOR_VERSION>=1
namespace rtabmap {
/////////////////////
// KeypointDescriptor
/////////////////////
KeypointDescriptor::KeypointDescriptor(const ParametersMap & parameters)
{
this->parseParameters(parameters);
}
KeypointDescriptor::~KeypointDescriptor()
{
}
void KeypointDescriptor::parseParameters(const ParametersMap & parameters)
{
}
//////////////////////////
//SURFDescriptor
//////////////////////////
SURFDescriptor::SURFDescriptor(const ParametersMap & parameters) :
KeypointDescriptor(parameters),
_hessianThreshold(Parameters::defaultSURFHessianThreshold()),
_nOctaves(Parameters::defaultSURFOctaves()),
_nOctaveLayers(Parameters::defaultSURFOctaveLayers()),
_extended(Parameters::defaultSURFExtended()),
_upright(Parameters::defaultSURFUpright()),
_gpuVersion(Parameters::defaultSURFGpuVersion())
{
this->parseParameters(parameters);
}
SURFDescriptor::~SURFDescriptor()
{
}
void SURFDescriptor::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
{
_extended = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
{
_hessianThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
{
_upright = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
{
_gpuVersion = uStr2Bool((*iter).second.c_str());
}
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat SURFDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
/*#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(_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
{
cv::SurfDescriptorExtractor extractor(_params.nOctaves, _params.nOctaveLayers, _params.extended, _params.upright);
extractor.compute(img, keypoints, descriptors);
}
#else*/
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
cv::SURF extractor(_hessianThreshold, _nOctaves, _nOctaveLayers, _extended, _upright);
extractor.compute(img, keypoints, descriptors);
#else
cv::SurfDescriptorExtractor extractor(_nOctaves, _nOctaveLayers, _extended, _upright);
extractor.compute(img, keypoints, descriptors);
#endif
//#endif
return descriptors;
}
//////////////////////////
//SIFTDescriptor
//////////////////////////
SIFTDescriptor::SIFTDescriptor(const ParametersMap & parameters) :
KeypointDescriptor(parameters),
_nfeatures(Parameters::defaultSIFTNFeatures()),
_nOctaveLayers(Parameters::defaultSIFTNOctaveLayers()),
_contrastThreshold(Parameters::defaultSIFTContrastThreshold()),
_edgeThreshold(Parameters::defaultSIFTEdgeThreshold()),
_sigma(Parameters::defaultSIFTSigma())
{
this->parseParameters(parameters);
}
SIFTDescriptor::~SIFTDescriptor()
{
}
void SIFTDescriptor::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSIFTContrastThreshold())) != parameters.end())
{
_contrastThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTEdgeThreshold())) != parameters.end())
{
_edgeThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNFeatures())) != parameters.end())
{
_nfeatures = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTSigma())) != parameters.end())
{
_sigma = std::atof((*iter).second.c_str());
}
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat SIFTDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
cv::SIFT extractor(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma);
extractor.compute(img, keypoints, descriptors);
#else
cv::SIFT extractor(cv::SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION(),
cv::SIFT::DescriptorParams::DEFAULT_IS_NORMALIZE,
true,
cv::SIFT::CommonParams::DEFAULT_NOCTAVES,
_nOctaveLayers);
extractor(img, cv::Mat(), keypoints, descriptors, true);
#endif
return descriptors;
}
/////////////////////
// KeypointDetector
/////////////////////
KeypointDetector::KeypointDetector(const ParametersMap & parameters) :
_wordsPerImageTarget(Parameters::defaultKpWordsPerImage()),
_roiRatios(std::vector<float>(4, 0.0f))
{
this->setRoi(Parameters::defaultKpRoiRatios());
this->parseParameters(parameters);
}
void KeypointDetector::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kKpWordsPerImage())) != parameters.end())
{
_wordsPerImageTarget = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kKpRoiRatios())) != parameters.end())
{
this->setRoi((*iter).second);
}
}
std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const cv::Mat & image)
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(!image.empty())
{
UTimer timer;
timer.start();
cv::Rect roi = computeRoi(image);
// Get keypoints
keypoints = this->_generateKeypoints(image, roi);
ULOGGER_DEBUG("Keypoints extraction time = %f s, keypoints extracted = %d", timer.ticks(), keypoints.size());
//clip the number of words... to _wordsPerImageTarget
// Variable hessian threshold
if(_wordsPerImageTarget > 0)
{
if(keypoints.size() > 0)
{
// 10% margin...
if(keypoints.size() > 1.1 * _wordsPerImageTarget)
{
ULOGGER_DEBUG("too much words (%d), removing words under the new hessian threshold", keypoints.size());
// Remove words under the new hessian threshold
// Sort words by hessian
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::vector<cv::KeyPoint>::iterator>(fabs(itKey->response), itKey));
}
// Remove them from the signature
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)
{
kptsTmp[k] = *iter->second;
// Adjust keypoint position to raw image
kptsTmp[k].pt.x += roi.x;
kptsTmp[k].pt.y += roi.y;
}
keypoints = kptsTmp;
ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, keypoints.size(), kptsTmp.size()?kptsTmp.back().response:0.0f);
}
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;
}
}
}
ULOGGER_DEBUG("removing words time = %f s", timer.ticks());
}
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
{
ULOGGER_ERROR("Image is null!");
}
return keypoints;
}
void KeypointDetector::setRoi(const std::string & roi)
{
std::list<std::string> strValues = uSplit(roi, ' ');
if(strValues.size() != 4)
{
ULOGGER_ERROR("The number of values must be 4 (roi=\"%s\")", roi.c_str());
}
else
{
std::vector<float> tmpValues(4);
unsigned int i=0;
for(std::list<std::string>::iterator iter = strValues.begin(); iter!=strValues.end(); ++iter)
{
tmpValues[i] = std::atof((*iter).c_str());
++i;
}
if(tmpValues[0] >= 0 && tmpValues[0] < 1 && tmpValues[0] < 1.0f-tmpValues[1] &&
tmpValues[1] >= 0 && tmpValues[1] < 1 && tmpValues[1] < 1.0f-tmpValues[0] &&
tmpValues[2] >= 0 && tmpValues[2] < 1 && tmpValues[2] < 1.0f-tmpValues[3] &&
tmpValues[3] >= 0 && tmpValues[3] < 1 && tmpValues[3] < 1.0f-tmpValues[2])
{
_roiRatios = tmpValues;
}
else
{
ULOGGER_ERROR("The roi ratios are not valid (roi=\"%s\")", roi.c_str());
}
}
}
cv::Rect KeypointDetector::computeRoi(const cv::Mat & image) const
{
if(!image.empty() && _roiRatios.size() == 4)
{
float width = image.cols;
float height = image.rows;
cv::Rect roi(0, 0, width, height);
UDEBUG("roi ratios = %f, %f, %f, %f", _roiRatios[0],_roiRatios[1],_roiRatios[2],_roiRatios[3]);
UDEBUG("roi = %d, %d, %d, %d", roi.x, roi.y, roi.width, roi.height);
//left roi
if(_roiRatios[0] > 0 && _roiRatios[0] < 1 - _roiRatios[1])
{
roi.x = width * _roiRatios[0];
}
//right roi
roi.width = width - roi.x;
if(_roiRatios[1] > 0 && _roiRatios[1] < 1 - _roiRatios[0])
{
roi.width -= width * _roiRatios[1];
}
//top roi
if(_roiRatios[2] > 0 && _roiRatios[2] < 1 - _roiRatios[3])
{
roi.y = height * _roiRatios[2];
}
//bottom roi
roi.height = height - roi.y;
if(_roiRatios[3] > 0 && _roiRatios[3] < 1 - _roiRatios[2])
{
roi.height -= height * _roiRatios[3];
}
UDEBUG("roi = %d, %d, %d, %d", roi.x, roi.y, roi.width, roi.height);
return roi;
}
else
{
UERROR("Image is null or _roiRatios(=%d) != 4", _roiRatios.size());
return cv::Rect();
}
}
//////////////////////////
//SURFDetector
//////////////////////////
SURFDetector::SURFDetector(const ParametersMap & parameters) :
KeypointDetector(parameters),
_hessianThreshold(Parameters::defaultSURFHessianThreshold()),
_nOctaves(Parameters::defaultSURFOctaves()),
_nOctaveLayers(Parameters::defaultSURFOctaveLayers()),
_extended(Parameters::defaultSURFExtended()),
_upright(Parameters::defaultSURFUpright()),
_gpuVersion(Parameters::defaultSURFGpuVersion())
{
this->parseParameters(parameters);
}
SURFDetector::~SURFDetector()
{
}
void SURFDetector::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
{
_extended = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
{
_hessianThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
{
_upright = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
{
_gpuVersion = uStr2Bool((*iter).second.c_str());
}
KeypointDetector::parseParameters(parameters);
}
std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return keypoints;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
cv::Mat imgRoi(img, roi);
/*#if OPENCV_SURF_GPU
if(_gpuVersion )
{
cv::gpu::GpuMat imgGpu(imgRoi);
cv::gpu::GpuMat keypointsGpu;
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, keypoints);
}
else
{
cv::SurfFeatureDetector detector(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.upright);
detector.detect(imgRoi, keypoints);
}
#else*/
cv::SURF detector(_hessianThreshold, _nOctaves, _nOctaveLayers, _extended, _upright);
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
detector.detect(imgRoi, keypoints);
#else
detector(imgRoi, cv::Mat(), keypoints);
#endif
//#endif
return keypoints;
}
//////////////////////////
//SIFTDetector
//////////////////////////
SIFTDetector::SIFTDetector(const ParametersMap & parameters) :
KeypointDetector(parameters),
_nfeatures(Parameters::defaultSIFTNFeatures()),
_nOctaveLayers(Parameters::defaultSIFTNOctaveLayers()),
_contrastThreshold(Parameters::defaultSIFTContrastThreshold()),
_edgeThreshold(Parameters::defaultSIFTEdgeThreshold()),
_sigma(Parameters::defaultSIFTSigma())
{
this->parseParameters(parameters);
}
SIFTDetector::~SIFTDetector()
{
}
void SIFTDetector::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSIFTContrastThreshold())) != parameters.end())
{
_contrastThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTEdgeThreshold())) != parameters.end())
{
_edgeThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNFeatures())) != parameters.end())
{
_nfeatures = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTSigma())) != parameters.end())
{
_sigma = std::atof((*iter).second.c_str());
}
KeypointDetector::parseParameters(parameters);
}
std::vector<cv::KeyPoint> SIFTDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return keypoints;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
cv::Mat imgRoi(img, roi);
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
cv::SIFT detector(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma);
detector.detect(imgRoi, keypoints); // Opencv surf keypoints
#else
cv::SIFT detector(_contrastThreshold, _edgeThreshold, cv::SIFT::CommonParams::DEFAULT_NOCTAVES, _nOctaveLayers);
detector(imgRoi, cv::Mat(), keypoints); // Opencv surf keypoints
#endif
return keypoints;
}
}

View File

@@ -1,539 +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/>.
*/
#include "rtabmap/core/KeypointDescriptor.h"
#include "utilite/UStl.h"
#include "utilite/UConversion.h"
#include "utilite/ULogger.h"
#include "utilite/UMath.h"
#include "utilite/ULogger.h"
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/gpu/gpu.hpp>
#include <opencv2/core/version.hpp>
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
#include <opencv2/nonfree/features2d.hpp>
#endif
#define OPENCV_SURF_GPU CV_MAJOR_VERSION >= 2 and CV_MINOR_VERSION >=2 and CV_SUBMINOR_VERSION>=1
namespace rtabmap {
KeypointDescriptor::KeypointDescriptor(const ParametersMap & parameters)
{
this->parseParameters(parameters);
}
KeypointDescriptor::~KeypointDescriptor()
{
}
void KeypointDescriptor::parseParameters(const ParametersMap & parameters)
{
}
//////////////////////////
//SURFDescriptor
//////////////////////////
SURFDescriptor::SURFDescriptor(const ParametersMap & parameters) :
KeypointDescriptor(parameters),
_hessianThreshold(Parameters::defaultSURFHessianThreshold()),
_nOctaves(Parameters::defaultSURFOctaves()),
_nOctaveLayers(Parameters::defaultSURFOctaveLayers()),
_extended(Parameters::defaultSURFExtended()),
_upright(Parameters::defaultSURFUpright()),
_gpuVersion(Parameters::defaultSURFGpuVersion())
{
this->parseParameters(parameters);
}
SURFDescriptor::~SURFDescriptor()
{
}
void SURFDescriptor::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
{
_extended = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
{
_hessianThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
{
_upright = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
{
_gpuVersion = uStr2Bool((*iter).second.c_str());
}
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat SURFDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
/*#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(_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
{
cv::SurfDescriptorExtractor extractor(_params.nOctaves, _params.nOctaveLayers, _params.extended, _params.upright);
extractor.compute(img, keypoints, descriptors);
}
#else*/
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
cv::SURF extractor(_hessianThreshold, _nOctaves, _nOctaveLayers, _extended, _upright);
extractor.compute(img, keypoints, descriptors);
#else
cv::SurfDescriptorExtractor extractor(_nOctaves, _nOctaveLayers, _extended, _upright);
extractor.compute(img, keypoints, descriptors);
#endif
//#endif
return descriptors;
}
//////////////////////////
//SIFTDescriptor
//////////////////////////
SIFTDescriptor::SIFTDescriptor(const ParametersMap & parameters) :
KeypointDescriptor(parameters),
_nfeatures(Parameters::defaultSIFTNFeatures()),
_nOctaveLayers(Parameters::defaultSIFTNOctaveLayers()),
_contrastThreshold(Parameters::defaultSIFTContrastThreshold()),
_edgeThreshold(Parameters::defaultSIFTEdgeThreshold()),
_sigma(Parameters::defaultSIFTSigma())
{
this->parseParameters(parameters);
}
SIFTDescriptor::~SIFTDescriptor()
{
}
void SIFTDescriptor::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSIFTContrastThreshold())) != parameters.end())
{
_contrastThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTEdgeThreshold())) != parameters.end())
{
_edgeThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNFeatures())) != parameters.end())
{
_nfeatures = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTSigma())) != parameters.end())
{
_sigma = std::atof((*iter).second.c_str());
}
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat SIFTDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
cv::SIFT extractor(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma);
extractor.compute(img, keypoints, descriptors);
#else
cv::SIFT extractor(cv::SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION(),
cv::SIFT::DescriptorParams::DEFAULT_IS_NORMALIZE,
true,
cv::SIFT::CommonParams::DEFAULT_NOCTAVES,
_nOctaveLayers);
extractor(img, cv::Mat(), keypoints, descriptors, true);
#endif
return descriptors;
}
//////////////////////////
//BRIEFDescriptor
//////////////////////////
BRIEFDescriptor::BRIEFDescriptor(const ParametersMap & parameters) :
KeypointDescriptor(parameters),
_size(Parameters::defaultBRIEFSize())
{
this->parseParameters(parameters);
}
BRIEFDescriptor::~BRIEFDescriptor()
{
}
void BRIEFDescriptor::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kBRIEFSize())) != parameters.end())
{
_size = std::atoi((*iter).second.c_str());
}
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat BRIEFDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
// BRIEF support only grayscale images ?
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
cv::BriefDescriptorExtractor brief(_size);
brief.compute(img, keypoints, descriptors);
return descriptors;
}
//////////////////////////
//ColorDescriptor
//////////////////////////
ColorDescriptor::ColorDescriptor(const ParametersMap & parameters) :
KeypointDescriptor(parameters)
{
this->parseParameters(parameters);
}
ColorDescriptor::~ColorDescriptor()
{
}
void ColorDescriptor::parseParameters(const ParametersMap & parameters)
{
// No parameter...
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat ColorDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
cv::Mat imageConverted;
if(image.channels() != 3 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageConverted, CV_GRAY2BGR);
}
cv::Mat imgMat;
if(!imageConverted.empty())
{
imgMat = imageConverted;
}
else
{
imgMat = image;
}
//create descriptors...
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
int grayMin = -1; // grayValue
float d[6] = {0};
std::vector<int> RxV;
cv::Point center = cv::Point(cvRound(key->pt.x), cvRound(key->pt.y));
int R = cvRound(key->size*1.2/9.*2);
this->getCircularROI(R, RxV);
cv::Mat_<cv::Vec3b>& img = (cv::Mat_<cv::Vec3b>&)imgMat; //3 channel pointer to image
// find the brighter and darker pixels
for( int dy = -R; dy <= R; ++dy )
{
int Rx = RxV[abs(dy)];
for( int dx = -Rx; dx <= Rx; ++dx )
{
if(center.y+dy < img.rows && center.y+dy >= 0 && center.x+dx < img.cols && center.x+dx >= 0)
{
//bgr
uchar b = img(center.y+dy, center.x+dx)[0];
uchar g = img(center.y+dy, center.x+dx)[1];
uchar r = img(center.y+dy, center.x+dx)[2];
int gray = b*0.114 + g*0.587 + r*0.299;
if(grayMax<0 || gray > grayMax)
{
grayMax = gray;
d[0] = b;
d[1] = g;
d[2] = r;
}
if(grayMin<0 || gray < grayMin)
{
grayMin = gray;
d[3] = b;
d[4] = g;
d[5] = r;
}
}
else
{
//ULOGGER_WARN("The keypoint size is outside of the image ranges (x,y)=(%d,%d) radius=%d", center.y+dy, center.x+dx, R);
}
}
}
for(int j=0; j<6; ++j)
{
descriptors.at<float>(i,j) = d[j] / 255; // Normalize between 0 and 1
}
++i;
}
return descriptors;
}
// the function returns x boundary coordinates of
// the circle for each y. RxV[y1] = x1 means that
// when y=y1, -x1 <=x<=x1 is inside the circle
// (from OpenCv doc, C++ Cheatsheet)
void ColorDescriptor::getCircularROI(int R, std::vector<int> & RxV) const
{
RxV.resize(R+1);
for( int y = 0; y <= R; y++ )
RxV[y] = cvRound(sqrt(double(R*R - y*y)));
}
//////////////////////////
//HueDescriptor
//////////////////////////
HueDescriptor::HueDescriptor(const ParametersMap & parameters) :
ColorDescriptor(parameters)
{
this->parseParameters(parameters);
}
HueDescriptor::~HueDescriptor()
{
}
void HueDescriptor::parseParameters(const ParametersMap & parameters)
{
// No parameter...
KeypointDescriptor::parseParameters(parameters);
}
cv::Mat HueDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
ULOGGER_DEBUG("");
cv::Mat descriptors;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return descriptors;
}
cv::Mat imageConverted;
if(image.channels() != 3 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageConverted, CV_GRAY2BGR);
}
cv::Mat imgMat;
if(!imageConverted.empty())
{
imgMat = imageConverted;
}
else
{
imgMat = image;
}
//create descriptors...
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;
int intensityMin = -1;
float d[2] = {0};
std::vector<int> RxV;
cv::Point center = cv::Point(cvRound(key->pt.x), cvRound(key->pt.y));
int R = cvRound(key->size*1.2/9.*2);
this->getCircularROI(R, RxV);
cv::Mat_<cv::Vec3b>& img = (cv::Mat_<cv::Vec3b>&)imgMat; //3 channel pointer to image
// find the brighter and darker pixels using the intensity
int dxb=0;
int dyb=0;
int dxd=0;
int dyd=0;
for( int dy = -R; dy <= R; ++dy )
{
int Rx = RxV[abs(dy)];
for( int dx = -Rx; dx <= Rx; ++dx )
{
if(center.y+dy < img.rows && center.y+dy >= 0 && center.x+dx < img.cols && center.x+dx >= 0)
{
//bgr
float b = float(img(center.y+dy, center.x+dx)[0]) / 255.0f;
float g = float(img(center.y+dy, center.x+dx)[1]) / 255.0f;
float r = float(img(center.y+dy, center.x+dx)[2]) / 255.0f;
int intensity = rgb2intensity(r, g, b);
if(intensityMax<0 || intensity > intensityMax)
{
intensityMax = intensity;
dxb = dx;
dyb = dy;
}
if(intensityMin<0 || intensity < intensityMin)
{
intensityMin = intensity;
dxd = dx;
dyd = dy;
}
}
else
{
//ULOGGER_WARN("The keypoint size is outside of the image ranges (x,y)=(%d,%d) radius=%d", center.y+dy, center.x+dx, R);
}
}
}
// brighter
float b = float(img(center.y+dyb, center.x+dxb)[0]) / 255.0f;
float g = float(img(center.y+dyb, center.x+dxb)[1]) / 255.0f;
float r = float(img(center.y+dyb, center.x+dxb)[2]) / 255.0f;
d[0] = rgb2hue(r, g, b);
// darker
b = float(img(center.y+dyd, center.x+dxd)[0]) / 255.0f;
g = float(img(center.y+dyd, center.x+dxd)[1]) / 255.0f;
r = float(img(center.y+dyd, center.x+dxd)[2]) / 255.0f;
d[1] = rgb2hue(r, g, b);
float * rowFl = descriptors.ptr<float>(i);
memcpy(rowFl, &d[i*2], 2*sizeof(float));
++i;
}
return descriptors;
}
// assuming that rgb values are normalized [0,1]
float HueDescriptor::rgb2hue(float r, float g, float b) const
{
double pi = 3.14159265359;
if(b<=g)
{
return acos(((r-g)+(r-b))/(2*sqrt((r-g)*(r-g)+(r-b)*(g-b))))/pi;
}
else
{
return (pi-acos(((r-g)+(r-b))/(2*sqrt((r-g)*(r-g)+(r-b)*(g-b)))))/pi;
}
}
}

View File

@@ -36,485 +36,6 @@
namespace rtabmap
{
KeypointDetector::KeypointDetector(const ParametersMap & parameters) :
_wordsPerImageTarget(Parameters::defaultKpWordsPerImage()),
_roiRatios(std::vector<float>(4, 0.0f))
{
this->setRoi(Parameters::defaultKpRoiRatios());
this->parseParameters(parameters);
}
void KeypointDetector::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kKpWordsPerImage())) != parameters.end())
{
_wordsPerImageTarget = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kKpRoiRatios())) != parameters.end())
{
this->setRoi((*iter).second);
}
}
std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const cv::Mat & image)
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(!image.empty())
{
UTimer timer;
timer.start();
cv::Rect roi = computeRoi(image);
// Get keypoints
keypoints = this->_generateKeypoints(image, roi);
ULOGGER_DEBUG("Keypoints extraction time = %f s, keypoints extracted = %d", timer.ticks(), keypoints.size());
//clip the number of words... to _wordsPerImageTarget
// Variable hessian threshold
if(_wordsPerImageTarget > 0)
{
if(keypoints.size() > 0)
{
// 10% margin...
if(keypoints.size() > 1.1 * _wordsPerImageTarget)
{
ULOGGER_DEBUG("too much words (%d), removing words under the new hessian threshold", keypoints.size());
// Remove words under the new hessian threshold
// Sort words by hessian
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::vector<cv::KeyPoint>::iterator>(fabs(itKey->response), itKey));
}
// Remove them from the signature
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)
{
kptsTmp[k] = *iter->second;
// Adjust keypoint position to raw image
kptsTmp[k].pt.x += roi.x;
kptsTmp[k].pt.y += roi.y;
}
keypoints = kptsTmp;
ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, keypoints.size(), kptsTmp.size()?kptsTmp.back().response:0.0f);
}
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;
}
}
}
ULOGGER_DEBUG("removing words time = %f s", timer.ticks());
}
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
{
ULOGGER_ERROR("Image is null!");
}
return keypoints;
}
void KeypointDetector::setRoi(const std::string & roi)
{
std::list<std::string> strValues = uSplit(roi, ' ');
if(strValues.size() != 4)
{
ULOGGER_ERROR("The number of values must be 4 (roi=\"%s\")", roi.c_str());
}
else
{
std::vector<float> tmpValues(4);
unsigned int i=0;
for(std::list<std::string>::iterator iter = strValues.begin(); iter!=strValues.end(); ++iter)
{
tmpValues[i] = std::atof((*iter).c_str());
++i;
}
if(tmpValues[0] >= 0 && tmpValues[0] < 1 && tmpValues[0] < 1.0f-tmpValues[1] &&
tmpValues[1] >= 0 && tmpValues[1] < 1 && tmpValues[1] < 1.0f-tmpValues[0] &&
tmpValues[2] >= 0 && tmpValues[2] < 1 && tmpValues[2] < 1.0f-tmpValues[3] &&
tmpValues[3] >= 0 && tmpValues[3] < 1 && tmpValues[3] < 1.0f-tmpValues[2])
{
_roiRatios = tmpValues;
}
else
{
ULOGGER_ERROR("The roi ratios are not valid (roi=\"%s\")", roi.c_str());
}
}
}
cv::Rect KeypointDetector::computeRoi(const cv::Mat & image) const
{
if(!image.empty() && _roiRatios.size() == 4)
{
float width = image.cols;
float height = image.rows;
cv::Rect roi(0, 0, width, height);
UDEBUG("roi ratios = %f, %f, %f, %f", _roiRatios[0],_roiRatios[1],_roiRatios[2],_roiRatios[3]);
UDEBUG("roi = %d, %d, %d, %d", roi.x, roi.y, roi.width, roi.height);
//left roi
if(_roiRatios[0] > 0 && _roiRatios[0] < 1 - _roiRatios[1])
{
roi.x = width * _roiRatios[0];
}
//right roi
roi.width = width - roi.x;
if(_roiRatios[1] > 0 && _roiRatios[1] < 1 - _roiRatios[0])
{
roi.width -= width * _roiRatios[1];
}
//top roi
if(_roiRatios[2] > 0 && _roiRatios[2] < 1 - _roiRatios[3])
{
roi.y = height * _roiRatios[2];
}
//bottom roi
roi.height = height - roi.y;
if(_roiRatios[3] > 0 && _roiRatios[3] < 1 - _roiRatios[2])
{
roi.height -= height * _roiRatios[3];
}
UDEBUG("roi = %d, %d, %d, %d", roi.x, roi.y, roi.width, roi.height);
return roi;
}
else
{
UERROR("Image is null or _roiRatios(=%d) != 4", _roiRatios.size());
return cv::Rect();
}
}
//////////////////////////
//SURFDetector
//////////////////////////
SURFDetector::SURFDetector(const ParametersMap & parameters) :
KeypointDetector(parameters),
_hessianThreshold(Parameters::defaultSURFHessianThreshold()),
_nOctaves(Parameters::defaultSURFOctaves()),
_nOctaveLayers(Parameters::defaultSURFOctaveLayers()),
_extended(Parameters::defaultSURFExtended()),
_upright(Parameters::defaultSURFUpright()),
_gpuVersion(Parameters::defaultSURFGpuVersion())
{
this->parseParameters(parameters);
}
SURFDetector::~SURFDetector()
{
}
void SURFDetector::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
{
_extended = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
{
_hessianThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
{
_nOctaves = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
{
_upright = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
{
_gpuVersion = uStr2Bool((*iter).second.c_str());
}
KeypointDetector::parseParameters(parameters);
}
std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return keypoints;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
cv::Mat imgRoi(img, roi);
/*#if OPENCV_SURF_GPU
if(_gpuVersion )
{
cv::gpu::GpuMat imgGpu(imgRoi);
cv::gpu::GpuMat keypointsGpu;
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, keypoints);
}
else
{
cv::SurfFeatureDetector detector(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.upright);
detector.detect(imgRoi, keypoints);
}
#else*/
cv::SURF detector(_hessianThreshold, _nOctaves, _nOctaveLayers, _extended, _upright);
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
detector.detect(imgRoi, keypoints);
#else
detector(imgRoi, cv::Mat(), keypoints);
#endif
//#endif
return keypoints;
}
//////////////////////////
//SIFTDetector
//////////////////////////
SIFTDetector::SIFTDetector(const ParametersMap & parameters) :
KeypointDetector(parameters),
_nfeatures(Parameters::defaultSIFTNFeatures()),
_nOctaveLayers(Parameters::defaultSIFTNOctaveLayers()),
_contrastThreshold(Parameters::defaultSIFTContrastThreshold()),
_edgeThreshold(Parameters::defaultSIFTEdgeThreshold()),
_sigma(Parameters::defaultSIFTSigma())
{
this->parseParameters(parameters);
}
SIFTDetector::~SIFTDetector()
{
}
void SIFTDetector::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kSIFTContrastThreshold())) != parameters.end())
{
_contrastThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTEdgeThreshold())) != parameters.end())
{
_edgeThreshold = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNFeatures())) != parameters.end())
{
_nfeatures = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTNOctaveLayers())) != parameters.end())
{
_nOctaveLayers = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSIFTSigma())) != parameters.end())
{
_sigma = std::atof((*iter).second.c_str());
}
KeypointDetector::parseParameters(parameters);
}
std::vector<cv::KeyPoint> SIFTDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return keypoints;
}
// SURF support only grayscale images
cv::Mat imageGrayScale;
if(image.channels() != 1 || image.depth() != CV_8U)
{
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
}
cv::Mat img;
if(!imageGrayScale.empty())
{
img = imageGrayScale;
}
else
{
img = image;
}
cv::Mat imgRoi(img, roi);
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
cv::SIFT detector(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma);
detector.detect(imgRoi, keypoints); // Opencv surf keypoints
#else
cv::SIFT detector(_contrastThreshold, _edgeThreshold, cv::SIFT::CommonParams::DEFAULT_NOCTAVES, _nOctaveLayers);
detector(imgRoi, cv::Mat(), keypoints); // Opencv surf keypoints
#endif
return keypoints;
}
//////////////////////////
//StarDetector
//////////////////////////
StarDetector::StarDetector(const ParametersMap & parameters) :
KeypointDetector(parameters),
_maxSize(Parameters::defaultStarMaxSize()),
_responseThreshold(Parameters::defaultStarResponseThreshold()),
_lineThresholdProjected(Parameters::defaultStarLineThresholdProjected()),
_lineThresholdBinarized(Parameters::defaultStarLineThresholdBinarized()),
_suppressNonmaxSize(Parameters::defaultStarSuppressNonmaxSize())
{
this->parseParameters(parameters);
}
StarDetector::~StarDetector()
{
}
void StarDetector::parseParameters(const ParametersMap & parameters)
{
ULOGGER_WARN("The StarDetector parameters can't be changed on ROS (this is an issue with the default (and too old) opencv revision used in ROS)");
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kStarLineThresholdBinarized())) != parameters.end())
{
_lineThresholdBinarized = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kStarLineThresholdProjected())) != parameters.end())
{
_lineThresholdProjected = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kStarMaxSize())) != parameters.end())
{
_maxSize = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kStarResponseThreshold())) != parameters.end())
{
_responseThreshold = int(std::atof((*iter).second.c_str()));
}
if((iter=parameters.find(Parameters::kStarSuppressNonmaxSize())) != parameters.end())
{
_suppressNonmaxSize = std::atoi((*iter).second.c_str());
}
KeypointDetector::parseParameters(parameters);
}
std::vector<cv::KeyPoint> StarDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return keypoints;
}
cv::Mat img(image);
// Get keypoints with the star detector
cv::Mat imgRoi(img, roi);
cv::StarDetector detector(_maxSize, _responseThreshold, _lineThresholdProjected, _lineThresholdBinarized, _suppressNonmaxSize);
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
detector.detect(imgRoi, keypoints);
#else
detector(imgRoi, keypoints);
#endif
return keypoints;
}
//////////////////////////
//FastDetector
//////////////////////////
FASTDetector::FASTDetector(const ParametersMap & parameters) :
KeypointDetector(parameters),
_threshold(Parameters::defaultFASTThreshold()),
_nonmaxSuppression(Parameters::defaultFASTNonmaxSuppression())
{
this->parseParameters(parameters);
}
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 cv::Mat & image, const cv::Rect & roi) const
{
ULOGGER_DEBUG("");
std::vector<cv::KeyPoint> keypoints;
if(image.empty())
{
ULOGGER_ERROR("Image is null ?!?");
return keypoints;
}
cv::Mat img(image);
cv::Mat imgRoi(img, roi);
cv::FastFeatureDetector fast(_threshold, _nonmaxSuppression);
// Get keypoints with the fast detector
fast.detect(imgRoi, keypoints);
return keypoints;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,383 +0,0 @@
/*
* Micro.cpp
*
* Created on: Mar 5, 2012
* Author: MatLab
*/
#include "rtabmap/core/Micro.h"
#include "utilite/UAudioRecorderMic.h"
#include "utilite/UAudioRecorderFile.h"
#include <utilite/UEventsManager.h>
#include <utilite/UFile.h>
#include <utilite/UMath.h>
#include <fftw3.h>
namespace rtabmap {
Micro::Micro(MicroEvent::Type eventType,
int deviceId,
int fs,
int frameLength,
int channels,
int bytesPerSample,
int id) :
_eventType(eventType),
_recorder(0),
_simulateFreq(false),
_out(0),
_id(id)
{
UASSERT(eventType == MicroEvent::kTypeFrame || eventType == MicroEvent::kTypeFrameFreq || eventType == MicroEvent::kTypeFrameFreqSqrdMagn);
UASSERT(deviceId >= 0);
UASSERT(frameLength > 0 && frameLength % 2 == 0);
_recorder = new UAudioRecorderMic(deviceId, fs, frameLength, bytesPerSample, channels);
}
Micro::Micro(MicroEvent::Type eventType,
const std::string & path,
bool simulateFrameRate,
int frameLength,
int id,
bool playWhileRecording) :
_eventType(eventType),
_recorder(0),
_simulateFreq(simulateFrameRate),
_out(0),
_id(id)
{
UASSERT(eventType == MicroEvent::kTypeFrame || eventType == MicroEvent::kTypeFrameFreq || eventType == MicroEvent::kTypeFrameFreqSqrdMagn);
UASSERT(frameLength > 0 && frameLength % 2 == 0);
if(playWhileRecording)
{
simulateFrameRate = false;
}
_recorder = new UAudioRecorderFile(path, playWhileRecording, frameLength);
}
Micro::~Micro()
{
UDEBUG("");
join(true);
if(_recorder)
{
delete _recorder;
}
if(_out)
{
fftwf_destroy_plan((fftwf_plan)_p);
fftwf_free(_out);
_out = 0;
}
}
bool Micro::init()
{
if(!_recorder->init())
{
UERROR("Recorder initialization failed!");
return false;
}
// init FFTW stuff
if(_out)
{
fftwf_destroy_plan((fftwf_plan)_p);
fftwf_free(_out);
_out = 0;
_in.clear();
}
int N = _recorder->frameLength();
_in.resize(N);
_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * N);
_p = fftwf_plan_dft_r2c_1d(N, _in.data(), _out, 0);
_window = uHamming(N);
return true;
}
void Micro::stop()
{
if(this->isRunning())
{
this->kill();
}
else if(_recorder && _recorder->isRunning())
{
_recorder->join(true);
}
}
void Micro::startRecorder()
{
if(_recorder)
{
_recorder->start();
_timer.start();
}
}
void Micro::mainLoopBegin()
{
this->startRecorder();
}
void Micro::mainLoop()
{
if(!_recorder)
{
UERROR("Recorder not initialized");
this->kill();
return;
}
if(this->isRunning())
{
bool noMoreFrames = true;
if(_eventType == MicroEvent::kTypeFrame)
{
UDEBUG("");
cv::Mat data = this->getFrame();
if(!data.empty())
{
noMoreFrames = false;
UEventsManager::post(new MicroEvent(data, 2, _recorder->fs(), _recorder->channels(), _id));
}
}
else if(_eventType == MicroEvent::kTypeFrameFreq)
{
UDEBUG("");
cv::Mat freq;
cv::Mat data = this->getFrame(freq, false);
if(!data.empty())
{
noMoreFrames = false;
UEventsManager::post(new MicroEvent(MicroEvent::kTypeFrameFreq, freq, _recorder->fs(), _recorder->channels(), _id));
}
}
else if(_eventType == MicroEvent::kTypeFrameFreqSqrdMagn)
{
UDEBUG("");
cv::Mat freq;
cv::Mat data = this->getFrame(freq, true);
if(!data.empty())
{
noMoreFrames = false;
UEventsManager::post(new MicroEvent(MicroEvent::kTypeFrameFreqSqrdMagn, freq, _recorder->fs(), _recorder->channels(), _id));
}
}
else
{
UFATAL("Not supposed to be here...");
}
if(noMoreFrames)
{
if(this->isRunning())
{
UEventsManager::post(new MicroEvent(_id));
}
this->kill();
}
}
}
void Micro::mainLoopKill()
{
if(_recorder)
{
_recorder->join(true);
}
}
cv::Mat Micro::getFrame()
{
cv::Mat data;
std::vector<char> frame;
if(!_recorder)
{
UERROR("Micro is not initialized...");
return data;
}
int frameLength = _recorder->frameLength();
int fs = _recorder->fs();
int channels = _recorder->channels();
int bytesPerSample = _recorder->bytesPerSample();
if(_simulateFreq && fs)
{
int sleepTime = ((double(frameLength)/double(fs) - _timer.getElapsedTime()) * 1000.0) + 0.5;
if(sleepTime > 2)
{
uSleep(sleepTime-2);
}
// Add precision at the cost of a small overhead
while(_timer.getElapsedTime() < double(frameLength)/double(fs)-0.000001)
{
//
}
double slept = _timer.getElapsedTime();
_timer.start();
UDEBUG("slept=%fs vs target=%fs", slept, double(frameLength)/double(fs));
}
if(_recorder->getNextFrame(frame, true) && int(frame.size()) == frameLength * channels * bytesPerSample)
{
UASSERT(bytesPerSample == 1 || bytesPerSample == 2 || bytesPerSample == 4);
if(bytesPerSample == 1)
{
data = cv::Mat(channels, frameLength, CV_8S);
// Split channels in rows
for(unsigned int i = 0; i<frame.size(); i+=channels*bytesPerSample)
{
for(unsigned int j=0; j<(unsigned int)channels; ++j)
{
data.at<char>(j, i/(channels*bytesPerSample)) = *((char*)&frame[i + j*bytesPerSample]);
}
}
}
else if(bytesPerSample == 2)
{
data = cv::Mat(channels, frameLength, CV_16S);
// Split channels in rows
for(unsigned int i = 0; i<frame.size(); i+=channels*bytesPerSample)
{
for(unsigned int j=0; j<(unsigned int)channels; ++j)
{
data.at<short>(j, i/(channels*bytesPerSample)) = *((short*)&frame[i + j*bytesPerSample]);
}
}
}
else if(bytesPerSample == 4)
{
data = cv::Mat(channels, frameLength, CV_32S);
// Split channels in rows
for(unsigned int i = 0; i<frame.size(); i+=channels*bytesPerSample)
{
for(unsigned int j=0; j<(unsigned int)channels; ++j)
{
data.at<int>(j, i/(channels*bytesPerSample)) = *((int*)&frame[i + j*bytesPerSample]);
}
}
}
}
else
{
UDEBUG("No more frames...");
}
return data;
}
cv::Mat Micro::getFrame(cv::Mat & frameFreq, bool sqrdMagn)
{
cv::Mat frame = this->getFrame();
if(!frame.empty())
{
UASSERT(frame.depth() == CV_8S || frame.depth() == CV_16S || frame.depth() == CV_32S);
cv::Mat timeSample(frame.rows, frame.cols, CV_32F);
for(int i=0; i<frame.cols; ++i)
{
// for each channels
for(int j=0; j<frame.rows; ++j)
{
if(frame.depth() == CV_8S)
{
timeSample.at<float>(j, i) = _window[i] * (float)(frame.at<char>(j, i)) / float(1<<7); // between 0 and 1
}
else if(frame.depth() == CV_16S)
{
timeSample.at<float>(j, i) = _window[i] * (float)(frame.at<short>(j, i)) / float(1<<15); // between 0 and 1
}
else if(frame.depth() == CV_32S)
{
timeSample.at<float>(j, i) = _window[i] * (float)(frame.at<int>(j, i)) / float(1<<31); // between 0 and 1
}
}
}
int size = timeSample.cols/2+1;
if(sqrdMagn)
{
frameFreq = cv::Mat(timeSample.rows, size, CV_32F);
}
else
{
frameFreq = cv::Mat(timeSample.rows, size * 2, CV_32F); // [re, im, re, im, ...]
}
// for each channels
for(int j=0; j<timeSample.rows; ++j)
{
cv::Mat row = timeSample.row(j);
cv::Mat rowFreq = frameFreq.row(j);
memcpy(_in.data(), row.data, row.cols*sizeof(float));
fftwf_execute((fftwf_plan)_p); /* repeat as needed */
float re;
float im;
for(int i=0; i<size; ++i)
{
re = float(_out[i][0]);
im = float(_out[i][1]);
if(sqrdMagn)
{
frameFreq.at<float>(0, i) = re*re+im*im; // squared magnitude
}
else
{
frameFreq.at<float>(0, i*2) = re;
frameFreq.at<float>(0, i*2+1) = im;
}
}
}
}
return frame;
}
int Micro::fs()
{
int fs = 0;
if(_recorder)
{
fs = _recorder->fs();
}
return fs;
}
int Micro::bytesPerSample()
{
int bytes = 0;
if(_recorder)
{
bytes = _recorder->bytesPerSample();
}
return bytes;
}
int Micro::channels()
{
int channels = 0;
if(_recorder)
{
channels = _recorder->channels();
}
return channels;
}
int Micro::nfft()
{
int n = 0;
if(_recorder)
{
n = _recorder->frameLength();
}
return n?n/2+1:0;
}
}

View File

@@ -17,7 +17,7 @@
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rtabmap/core/NearestNeighbor.h"
#include "NearestNeighbor.h"
#include "utilite/ULogger.h"
#include <opencv2/core/core.hpp>
@@ -25,61 +25,24 @@ namespace rtabmap
{
/////////////////////////
// KdTreeNN
// FlannNN
/////////////////////////
KdTreeNN::KdTreeNN(const ParametersMap & parameters)
{
this->parseParameters(parameters);
}
KdTreeNN::~KdTreeNN()
{
}
void KdTreeNN::setData(const cv::Mat & data)
{
//(data is not copied)
_tree.build(data);
}
void KdTreeNN::search(const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax)
{
_tree.findNearest(queries, knn, emax, indices, cv::noArray(), dists);
}
void KdTreeNN::search(const cv::Mat & data, const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax) const
{
cv::KDTree tree(data);
tree.findNearest(queries, knn, emax, indices, cv::noArray(), dists);
}
void KdTreeNN::parseParameters(const ParametersMap & parameters)
{
NearestNeighbor::parseParameters(parameters);
}
/////////////////////////
// FlannKdTreeNN
/////////////////////////
FlannKdTreeNN::FlannKdTreeNN(const ParametersMap & parameters) :
FlannNN::FlannNN(Strategy strategy, const ParametersMap & parameters) :
_treeFlannIndex(0),
_strategy(kKDTree)
_strategy(strategy)
{
ULOGGER_DEBUG("");
this->parseParameters(parameters);
}
FlannKdTreeNN::~FlannKdTreeNN() {
FlannNN::~FlannNN() {
if(_treeFlannIndex)
{
delete _treeFlannIndex;
}
}
void FlannKdTreeNN::setData(const cv::Mat & data)
void FlannNN::setData(const cv::Mat & data)
{
if(_treeFlannIndex)
{
@@ -88,10 +51,9 @@ void FlannKdTreeNN::setData(const cv::Mat & data)
}
_treeFlannIndex = createIndex(data, _strategy); // using 4 randomized trees
//_treeFlannIndex = new cv::flann::Index(_dataTree, cv::flann::AutotunedIndexParams(0.9, 0.01, 0, 0.1)); // use autotuned parameters
}
void FlannKdTreeNN::search(const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax)
void FlannNN::search(const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax)
{
ULOGGER_DEBUG("");
if(_treeFlannIndex)
@@ -105,7 +67,7 @@ void FlannKdTreeNN::search(const cv::Mat & queries, cv::Mat & indices, cv::Mat &
}
}
void FlannKdTreeNN::search(const cv::Mat & data, const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax) const
void FlannNN::search(const cv::Mat & data, const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax) const
{
ULOGGER_DEBUG("");
cv::flann::Index * index = createIndex(data, _strategy);
@@ -114,13 +76,13 @@ void FlannKdTreeNN::search(const cv::Mat & data, const cv::Mat & queries, cv::Ma
delete index;
}
void FlannKdTreeNN::parseParameters(const ParametersMap & parameters)
void FlannNN::parseParameters(const ParametersMap & parameters)
{
NearestNeighbor::parseParameters(parameters);
}
enum Strategy{kLinear, kKDTree, kMeans, kComposite, kAutoTuned, kUndefined};
cv::flann::Index * FlannKdTreeNN::createIndex(const cv::Mat & data, Strategy s) const
cv::flann::Index * FlannNN::createIndex(const cv::Mat & data, Strategy s) const
{
cv::flann::Index * index = 0;
switch(s)

View File

@@ -31,92 +31,18 @@
namespace rtabmap
{
class VisualWord;
class RTABMAP_EXP NearestNeighbor
{
public:
public:
virtual ~NearestNeighbor() {}
virtual void setData(const cv::Mat & data) = 0;
virtual void search(
const cv::Mat & queries,
cv::Mat & indices,
cv::Mat & dists,
int knn = 1,
int emax = 64) = 0;
virtual void search(
const cv::Mat & data,
const cv::Mat & queries,
cv::Mat & indices,
cv::Mat & dists,
int knn = 1,
int emax = 64) const = 0;
virtual bool isDist64F() const = 0;
virtual bool isDistSquared() const = 0;
virtual void parseParameters(const ParametersMap & parameters) {}
protected:
NearestNeighbor() {}
};
/////////////////////////
// KdTreeNN
// FIXME KdTreeNN seems broken, it does not give same results as naive and FLANN
/////////////////////////
class RTABMAP_EXP KdTreeNN : public NearestNeighbor
{
public:
KdTreeNN(const ParametersMap & parameters = ParametersMap());
virtual ~KdTreeNN();
virtual void setData(const cv::Mat & data);
virtual void search(const cv::Mat & queries,
cv::Mat & indices,
cv::Mat & dists,
int knn = 1,
int emax = 64);
virtual void search(const cv::Mat & data,
const cv::Mat & queries,
cv::Mat & indices,
cv::Mat & dists,
int knn = 1,
int emax = 64) const;
virtual bool isDist64F() const {return false;}
virtual bool isDistSquared() const {return false;}
virtual void parseParameters(const ParametersMap & parameters);
private:
cv::KDTree _tree;
};
/////////////////////////
// FlannKdTreeNN
/////////////////////////
class RTABMAP_EXP FlannKdTreeNN : public NearestNeighbor
/////////////////////////
// FlannNN
/////////////////////////
class RTABMAP_EXP FlannNN
{
public:
enum dummy {d}; // Hack, to fix Eclipse complaining about not defined Strategy enum ?!
enum Strategy{kLinear, kKDTree, kMeans, kComposite, kAutoTuned, kUndefined};
public:
FlannKdTreeNN(const ParametersMap & parameters = ParametersMap());
FlannKdTreeNN(Strategy s, const ParametersMap & parameters = ParametersMap());
virtual ~FlannKdTreeNN();
FlannNN(Strategy s = kKDTree, const ParametersMap & parameters = ParametersMap());
virtual ~FlannNN();
void setStrategy(Strategy s) {if(_strategy!=kUndefined) _strategy = s;}
@@ -135,8 +61,6 @@ public:
int knn = 1,
int emax = 64) const;
virtual bool isDist64F() const {return false;}
virtual bool isDistSquared() const {return true;}
virtual void parseParameters(const ParametersMap & parameters);
private:

View File

@@ -1,98 +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/>.
*/
#ifndef NODE_H_
#define NODE_H_
namespace rtabmap {
class Node
{
public:
Node(int id, Node * parent = 0) :
_parent(parent),
_id(id)
{
if(_parent)
{
_parent->addChild(this);
}
}
virtual ~Node()
{
//We copy the set because when a child is destroyed, it is removed from its parent.
std::set<Node*> children = _children;
_children.clear();
for(std::set<Node*>::iterator iter=children.begin(); iter!=children.end(); ++iter)
{
delete *iter;
}
children.clear();
if(_parent)
{
_parent->removeChild(this);
}
}
int id() const {return _id;}
bool isAncestor(int id) const
{
if(_parent)
{
if(_parent->id() == id)
{
return true;
}
return _parent->isAncestor(id);
}
return false;
}
void expand(std::list<std::list<int> > & paths, std::list<int> currentPath = std::list<int>()) const
{
currentPath.push_back(_id);
if(_children.size() == 0)
{
paths.push_back(currentPath);
return;
}
for(std::set<Node*>::const_iterator iter=_children.begin(); iter!=_children.end(); ++iter)
{
(*iter)->expand(paths, currentPath);
}
}
private:
void addChild(Node * child)
{
_children.insert(child);
}
void removeChild(Node * child)
{
_children.erase(child);
}
private:
std::set<Node*> _children;
Node * _parent;
int _id;
};
}
#endif /* NODE_H_ */

View File

@@ -35,11 +35,6 @@ Parameters::~Parameters()
{
}
const ParametersMap & Parameters::getDefaultParameters()
{
return parameters_;
}
std::string Parameters::getDefaultWorkingDirectory()
{
std::string path = UDirectory::homeDir();

File diff suppressed because it is too large Load Diff

View File

@@ -47,14 +47,14 @@ void Statistics::addStatistic(const std::string & name, float value)
_data.insert(std::pair<std::string, float>(name, value));
}
void Statistics::setRefRawData(const std::list<Sensor> & refRawData)
void Statistics::setRefImage(const cv::Mat & image)
{
_refRawData = refRawData;
_refImage = image;
}
void Statistics::setLoopClosureRawData(const std::list<Sensor> & loopClosureRawData)
void Statistics::setLoopImage(const cv::Mat & image)
{
_loopClosureRawData = loopClosureRawData;
_loopImage = image;
}
}

View File

@@ -1,367 +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/>.
*/
#include "rtabmap/core/SMMemory.h"
#include "rtabmap/core/Signature.h"
#include "rtabmap/core/DBDriver.h"
#include "utilite/UtiLite.h"
#include "rtabmap/core/Parameters.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 "rtabmap/core/ColorTable.h"
namespace rtabmap {
SMMemory::SMMemory(const ParametersMap & parameters) :
Memory(parameters),
_useLogPolar(Parameters::defaultSMLogPolarUsed()),
_colorTable(0),
_useMotionMask(Parameters::defaultSMMotionMaskUsed()),
_dBThreshold(Parameters::defaultSMAudioDBThreshold()),
_dBIndexing(Parameters::defaultSMAudioDBIndexing()),
_magnitudeInvariant(Parameters::defaultSMMagnitudeInvariant())
{
this->parseParameters(parameters);
if(!_colorTable)
{
// index 0 = 8, index 1 = 16...
if(Parameters::defaultSMColorTable() == 8)
{
setColorTable(65536);
}
else
{
int i=1;
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::kSMMotionMaskUsed())) != parameters.end())
{
_useMotionMask = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSMAudioDBThreshold())) != parameters.end())
{
_dBThreshold = atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSMAudioDBIndexing())) != parameters.end())
{
_dBIndexing = uStr2Bool((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kSMMagnitudeInvariant())) != parameters.end())
{
_magnitudeInvariant = 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::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->getData());
}
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 std::list<Sensor> & rawSensors, bool keepRawData)
{
if(_useMotionMask)
{
UWARN("Using motion mask TODO");
}
UDEBUG("");
UTimer timer;
timer.start();
UTimer timerDetails;
timerDetails.start();
std::list<std::vector<int> > postData;
//const SMSignature * previousSignature = dynamic_cast<const SMSignature *>(this->getLastSignature());
// Process all sensors
for(std::list<Sensor>::const_iterator iter = rawSensors.begin(); iter!=rawSensors.end(); ++iter)
{
if(iter->type() == Sensor::kTypeImage)
{
UASSERT(iter->data().type() == CV_8UC3 && iter->data().channels() == 3);
const cv::Mat & image = iter->data();
UDEBUG("depth=%d, width=%d, height=%d, nChannels=%d, imageSize=%d,", image.type(), image.cols, image.rows, image.channels(), image.total());
if(_useLogPolar)
{
// Log-polar transform
int radius = image.rows < image.cols ? image.rows/2: image.cols/2;
CvSize polarSize = cvSize(64, 128);
float M = polarSize.width/std::log(radius);
IplImage * polar = cvCreateImage( polarSize, 8, 3 );
IplImage iplImg = image;
cvLogPolar(&iplImg, polar, cvPoint2D32f(image.cols/2,image.rows/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;
int k=0;
std::vector<int> sensors(polar->width*polar->height);
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;
++k;
}
}
postData.push_back(sensors);
cvReleaseImage(&polar);
UDEBUG("indexing time = %fs", timerDetails.ticks());
}
else
{
// IND transform
int k=0;
std::vector<int> sensors(image.cols*image.rows);
int sum=0;
for(int i=0; i<image.rows; ++i)
{
cv::Mat row = image.row(i); // DON'T modify row! (it refers to const data)
for(int j=0; j<row.cols; j+=3)
{
unsigned char b = row.at<unsigned char>(j+0);
unsigned char g = row.at<unsigned char>(j+1);
unsigned char r = row.at<unsigned char>(j+2);
if(b && g && r)
{
sensors[k] = (int)_colorTable->getIndex(r, g, b); // index
}
else
{
sensors[k] = 0; // null, will be ignored on likelihood computation
}
++k;
}
}
postData.push_back(sensors);
UDEBUG("sum=%d, indexing time = %fs", sum, timerDetails.ticks());
}
} // end kTypeImage
else if(iter->type() == Sensor::kTypeAudioFreqSqrdMagn)
{
UASSERT(iter->data().type() == CV_32FC1);
const cv::Mat & data = iter->data();
int k = 0;
std::vector<int> sensors(data.cols, 0);
unsigned int index;
float max = uMax((float*)data.data, data.cols, index);
int maxLimit = -1; // FIXME Must be not hard coded
float minDB = -1000;// FIXME Must be not hard coded
UDEBUG("data.rows=%d, data.cols=%d, data.type=%d, max=%f at %d", data.rows, data.cols, data.type(), max, index);
if(_dBThreshold > 0)
{
maxLimit = max / std::pow(10.0f, _dBThreshold/10);
}
for(int i=0; i<data.cols; ++i)
{
float val = data.at<float>(0, i);
if(_dBIndexing && max)
{
if(val>=0.001f)
{
val = 10*std::log(val/max);// transform to dB
}
else
{
val = minDB;
}
}
if(!_dBIndexing && val <= maxLimit)
{
val = 0;
}
else if(_dBIndexing)
{
if(val <= minDB || (_dBThreshold && val <= -_dBThreshold))
{
val = 0;
}
else if(max)
{
if(_magnitudeInvariant)
{
val = -1; // ignore magnitude, just set it not null to say this frequency is here
}
else
{
val -= 1; // make sure high values are not null
}
}
}
sensors[k] = int(val);
if((!_dBIndexing && sensors[k]<0) || (_dBIndexing && sensors[k]>0))
{
UERROR("sensors[%d]=%d %f", k, sensors[k], data.at<float>(0,i));
}
++k;
}
postData.push_back(sensors);
} // end kTypeAudioFreqSqrdMagn
else if(iter->type() == Sensor::kTypeTwist)
{
UASSERT(iter->data().type() == CV_32FC1);
const cv::Mat & data = iter->data();
std::vector<int> sensors(data.cols);
for(int i=0; i<data.cols; ++i)
{
sensors[i] = (int)(data.at<float>(0, i)*100.0f);
}
postData.push_back(sensors);
} //end kTypeTwist
else
{
UWARN("Sensor type (%d) not handled!", iter->type());
}
}
ULOGGER_DEBUG("time new signature (id=%d) %fs", id, timer.ticks());
if(keepRawData)
{
return new SMSignature(postData, id, rawSensors);
}
else
{
return new SMSignature(postData, id);
}
}
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

View File

@@ -17,176 +17,94 @@
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rtabmap/core/Signature.h"
#include "Signature.h"
#include "rtabmap/core/EpipolarGeometry.h"
#include "rtabmap/core/Memory.h"
#include <opencv2/highgui/highgui.hpp>
#include "rtabmap/core/VerifyHypotheses.h"
#include <utilite/UtiLite.h>
namespace rtabmap
{
bool NeighborLink::updateIds(int idFrom, int idTo)
{
bool modified = false;
if(_toId == idFrom)
{
_toId = 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);
}
Signature::Signature(int id) :
_id(id),
_weight(0),
_saved(false),
_modified(true)
Signature::Signature(
int id,
const std::multimap<int, cv::KeyPoint> & words,
const cv::Mat & image) :
_id(id),
_weight(0),
_saved(false),
_modified(true),
_neighborsModified(true),
_words(words),
_enabled(false),
_image(image)
{
}
Signature::Signature(int id, const std::list<Sensor> & rawData) :
_id(id),
_weight(0),
_rawData(rawData),
_saved(false),
_modified(true)
void Signature::addNeighbors(const std::set<int> & neighbors)
{
}
void Signature::addNeighbors(const NeighborsMultiMap & neighbors)
{
for(NeighborsMultiMap::const_iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
for(std::set<int>::const_iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
{
this->addNeighbor(i->second);
this->addNeighbor(*i);
}
}
void Signature::addNeighbor(const NeighborLink & neighbor)
void Signature::addNeighbor(int neighbor)
{
UDEBUG("Add neighbor %d to %d", neighbor.toId(), this->id());
if(ULogger::level() == ULogger::kDebug)
{
UTimer timer;
std::string baseIdsDebug;
const std::vector<int> & baseIds = neighbor.baseIds();
for(unsigned int i=0; i<baseIds.size(); ++i)
{
baseIdsDebug.append(uFormat("%d", baseIds[i]));
if(i+1 < baseIds.size())
{
baseIdsDebug.append(", ");
}
}
UDEBUG("Adding neighbor %d to %d with %d actions, %d baseIds = [%s] (time print=%fs)", neighbor.toId(), this->id(), neighbor.actuators().size(), neighbor.baseIds().size(), baseIdsDebug.c_str(), timer.getElapsedTime());
}
_neighbors.insert(std::pair<int, NeighborLink>(neighbor.toId(), neighbor));
if(neighbor.actuators().size())
{
_neighborsWithActuators.insert(neighbor.toId());
}
_neighborsAll.insert(neighbor.toId());
UDEBUG("Add neighbor %d to %d", neighbor, this->id());
_neighbors.insert(neighbor);
_neighborsModified = true;
}
void Signature::removeNeighbor(int neighborId)
{
int count = _neighbors.erase(neighborId);
if(count)
{
_neighborsModified = true;
}
}
void Signature::removeNeighbors()
{
if(_neighbors.size())
_neighborsModified = true;
_neighbors.clear();
}
void Signature::changeNeighborIds(int idFrom, int idTo)
{
std::pair<NeighborsMultiMap::iterator, NeighborsMultiMap::iterator> pair = _neighbors.equal_range(idFrom);
if(pair.first != _neighbors.end() && pair.first != pair.second)
if(_neighbors.find(idFrom) != _neighbors.end())
{
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);
_neighborsWithActuators.erase(idFrom);
_neighborsAll.erase(idFrom);
for(std::list<NeighborLink>::iterator iter=linksToAdd.begin(); iter!=linksToAdd.end(); ++iter)
{
_neighbors.insert(std::pair<int, NeighborLink>(iter->toId(), *iter));
if(iter->actuators().size())
{
_neighborsWithActuators.insert(iter->toId());
}
_neighborsAll.insert(iter->toId());
}
_neighbors.insert(idTo);
_neighborsModified = true;
UDEBUG("(%d) neighbor ids changed from %d to %d", _id, idFrom, idTo);
}
UDEBUG("(%d) neighbor ids changed from %d to %d", _id, idFrom, idTo);
}
//KeypointSignature
KeypointSignature::KeypointSignature(int id) :
Signature(id),
_enabled(false)
float Signature::compareTo(const Signature * s) const
{
}
KeypointSignature::KeypointSignature(const std::multimap<int, cv::KeyPoint> & words,
int id) :
Signature(id),
_words(words),
_enabled(false)
{
}
KeypointSignature::KeypointSignature(
const std::multimap<int, cv::KeyPoint> & words,
int id,
const std::list<Sensor> & rawData) :
Signature(id, rawData),
_words(words),
_enabled(false)
{
}
KeypointSignature::~KeypointSignature()
{
}
float KeypointSignature::compareTo(const Signature * s) const
{
const KeypointSignature * ss = dynamic_cast<const KeypointSignature *>(s);
float similarity = 0;
if(ss) //Compatible
float similarity = 0.0f;
const std::multimap<int, cv::KeyPoint> & words = s->getWords();
if(words.size() != 0 && _words.size() != 0)
{
const std::multimap<int, cv::KeyPoint> & words = ss->getWords();
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
int totalWords = _words.size()>words.size()?_words.size():words.size();
EpipolarGeometry::findPairs(words, _words, pairs);
if(words.size() != 0 && _words.size() != 0)
{
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
int totalWords = _words.size()>words.size()?_words.size():words.size();
findPairs(words, _words, pairs);
similarity = float(pairs.size()) / float(totalWords);
}
similarity = float(pairs.size()) / float(totalWords);
}
return similarity;
}
void KeypointSignature::changeWordsRef(int oldWordId, int activeWordId)
void Signature::changeWordsRef(int oldWordId, int activeWordId)
{
std::list<cv::KeyPoint> kps = uValues(_words, oldWordId);
if(kps.size())
@@ -200,137 +118,19 @@ void KeypointSignature::changeWordsRef(int oldWordId, int activeWordId)
}
}
bool KeypointSignature::isBadSignature() const
bool Signature::isBadSignature() const
{
return !_words.size();
}
void KeypointSignature::removeAllWords()
void Signature::removeAllWords()
{
_words.clear();
}
void KeypointSignature::removeWord(int wordId)
void Signature::removeWord(int wordId)
{
_words.erase(wordId);
}
//SMSignature
SMSignature::SMSignature(
const std::list<std::vector<int> > & data,
int id) :
Signature(id),
_data(data)
{
UDEBUG("data=%d", (int)_data.size());
}
SMSignature::SMSignature(
const std::list<std::vector<int> > & data,
int id,
const std::list<Sensor> & rawData) :
Signature(id, rawData),
_data(data)
{
UDEBUG("data=%d", (int)_data.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::list<std::vector<int> > & dataB = sm->getData();
//const std::vector<unsigned char> & motionMaskB = sm->getMotionMask();
//if(_data.size() == sensorsB.size() && _data.size()) //Compatible
if(_data.size() == dataB.size()) //Compatible
{
std::vector<float> similarities(_data.size());
// compare sensors
std::list<std::vector<int> >::const_iterator iterA = _data.begin();
std::list<std::vector<int> >::const_iterator iterB = dataB.begin();
int j=0;
while(iterA != _data.end() && iterB != dataB.end())
{
if(iterA->size() == iterB->size())
{
int sum = 0;
int notNull = 0;
for(unsigned int i=0; i<iterA->size(); ++i)
{
sum += iterA->at(i) && iterA->at(i) == iterB->at(i) ? 1 : 0;
notNull += iterA->at(i) || iterB->at(i) ? 1 : 0;
}
if(notNull)
{
similarities[j] = float(sum)/float(notNull);
}
else
{
similarities[j] = 1.0f; // example, silence == 100% silence
}
}
else
{
UERROR("Data are not the same size (%d vs %d)", (int)iterA->size(), (int)iterB->size());
}
++iterA;
++iterB;
++j;
}
similarity = uMean(similarities);
if(ULogger::level() == ULogger::kDebug)
{
std::string str;
for(unsigned int i=0; i<similarities.size(); ++i)
{
str.append(uFormat("%f", similarities[i]));
if(i<similarities.size()-1)
{
str.append(", ");
}
}
UDEBUG("similarities (%d vs %d) = [%s]", this->id(), s->id(), str.c_str());
}
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 nodes : nb sensors A=%d B=%d", (int)_data.size(), (int)dataB.size());
}
}
else if(s)
{
UWARN("Only SM signatures are compared. (type tested=%s)", s->nodeType().c_str());
}
return similarity;
}
bool SMSignature::isBadSignature() const
{
//return uSum(_data) == 0;
return !_data.size();
}
} //namespace rtabmap

View File

@@ -24,69 +24,36 @@
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "rtabmap/core/Sensor.h"
#include "rtabmap/core/Actuator.h"
#include <map>
#include <list>
#include <vector>
#include <set>
//TODO : add copy constructor
namespace rtabmap
{
class RTABMAP_EXP NeighborLink
{
public:
NeighborLink(int toId, const std::vector<int> & baseIds = std::vector<int>(), const std::list<Actuator> & actuators = std::list<Actuator>(), int actuatorId = 0) :
_toId(toId),
_actuatorId(actuatorId),
_actuators(actuators),
_baseIds(baseIds)
{}
virtual ~NeighborLink() {}
int toId() const {return _toId;}
int actuatorId() const {return _actuatorId;}
const std::list<Actuator> & actuators() const {return _actuators;}
const std::vector<int> & baseIds() const {return _baseIds;}
bool updateIds(int idFrom, int idTo);
private:
int _toId;
int _actuatorId;
std::list<Actuator> _actuators;
std::vector<int> _baseIds; // first is the nearest
};
class Memory;
typedef std::multimap<int, NeighborLink> NeighborsMultiMap;
class RTABMAP_EXP Signature
{
public:
Signature(int id,
const std::multimap<int, cv::KeyPoint> & words,
const cv::Mat & image = cv::Mat());
virtual ~Signature();
/**
* Must return a value between >=0 and <=1 (1 means 100% similarity)
* 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 nodeType() const = 0;
void setRawData(const std::list<Sensor> & rawData) {_rawData = rawData;}
const std::list<Sensor> & getRawData() const {return _rawData;}
float compareTo(const Signature * signature) const;
bool isBadSignature() const;
int id() const {return _id;}
void addNeighbors(const NeighborsMultiMap & neighbors);
void addNeighbor(const NeighborLink & neighbor);
void removeNeighbor(int neighborId) {
if(_neighbors.erase(neighborId))
_neighborsModified = true;
_neighborsWithActuators.erase(neighborId);
_neighborsAll.erase(neighborId);}
void addNeighbors(const std::set<int> & neighbors);
void addNeighbor(int neighbor);
void removeNeighbor(int neighborId);
void removeNeighbors();
bool hasNeighbor(int neighborId) const {return _neighbors.find(neighborId) != _neighbors.end();}
void setWeight(int weight) {if(_weight!=weight)_modified=true;_weight = weight;}
void setLoopClosureIds(const std::set<int> & loopClosureIds) {_loopClosureIds = loopClosureIds;_neighborsModified=true;}
@@ -99,9 +66,7 @@ public:
void setModified(bool modified) {_modified = modified; _neighborsModified = modified;}
void changeNeighborIds(int idFrom, int idTo);
const NeighborsMultiMap & getNeighbors() const {return _neighbors;}
const std::set<int> & getNeighborsWithActuators() const {return _neighborsWithActuators;}
const std::set<int> & getNeighborsAll() const {return _neighborsAll;}
const std::set<int> & getNeighbors() const {return _neighbors;}
int getWeight() const {return _weight;}
const std::set<int> & getLoopClosureIds() const {return _loopClosureIds;}
const std::set<int> & getChildLoopClosureIds() const {return _childLoopClosureIds;}
@@ -109,92 +74,35 @@ public:
bool isModified() const {return _modified || _neighborsModified;}
bool isNeighborsModified() const {return _neighborsModified;}
protected:
Signature(int id);
Signature(int id, const std::list<Sensor> & rawData);
private:
int _id;
NeighborsMultiMap _neighbors; // id, neighborLink
std::set<int> _neighborsWithActuators; // Hack, to increase efficiency of Memory::getNeighborIds()
std::set<int> _neighborsAll; // Hack, to increase efficiency of Memory::getNeighborIds()
int _weight;
std::set<int> _loopClosureIds;
std::set<int> _childLoopClosureIds;
std::list<Sensor> _rawData;
bool _saved; // If it's saved to bd
bool _modified;
bool _neighborsModified; // Optimization when updating signatures in database
};
class KeypointDetector;
class VWDictionary;
class RTABMAP_EXP KeypointSignature :
public Signature
{
public:
KeypointSignature(int id);
KeypointSignature(
const std::multimap<int, cv::KeyPoint> & words,
int id);
KeypointSignature(
const std::multimap<int, cv::KeyPoint> & words,
int id,
const std::list<Sensor> & sensors);
virtual ~KeypointSignature();
virtual float compareTo(const Signature * signature) const;
virtual bool isBadSignature() const;
virtual std::string nodeType() const {return "KeypointSignature";};
//visual words stuff
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;}
const std::map<int, int> & getWordsChanged() const {return _wordsChanged;}
void setImage(const cv::Mat & image) {_image = image;}
const cv::Mat & getImage() const {return _image;}
private:
int _id;
std::set<int> _neighbors; // id
int _weight;
std::set<int> _loopClosureIds;
std::set<int> _childLoopClosureIds;
bool _saved; // If it's saved to bd
bool _modified;
bool _neighborsModified; // Optimization when updating signatures in database
// 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>
std::map<int, int> _wordsChanged; // <oldId, newId>
bool _enabled;
cv::Mat _image;
};
class RTABMAP_EXP SMSignature :
public Signature
{
public:
SMSignature(
const std::list<std::vector<int> > & data,
int id);
SMSignature(
const std::list<std::vector<int> > & data,
int id,
const std::list<Sensor> & rawData);
SMSignature(int id);
virtual ~SMSignature();
virtual float compareTo(const Signature * signature) const;
virtual bool isBadSignature() const;
virtual std::string nodeType() const {return "SMSignature";};
void setSensors(const std::list<std::vector<int> > & data) {_data = data;}
const std::list<std::vector<int> > & getData() const {return _data;}
private:
std::list<std::vector<int> > _data;
};
} // namespace rtabmap

View File

@@ -18,11 +18,11 @@
*/
#include "rtabmap/core/VWDictionary.h"
#include "rtabmap/core/VisualWord.h"
#include "VisualWord.h"
#include "rtabmap/core/Signature.h"
#include "Signature.h"
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/NearestNeighbor.h"
#include "NearestNeighbor.h"
#include "rtabmap/core/Parameters.h"
#include "utilite/UtiLite.h"
@@ -231,15 +231,8 @@ void VWDictionary::setNNStrategy(NNStrategy strategy, const ParametersMap & para
}
switch(strategy)
{
case kNNKdTree:
//FIXME KdTreeNN is broken...
//_nn = new KdTreeNN(parameters);
//break;
UWARN("KdTree OpenCV is broken, setting nearest neighbor strategy to KdForest FLANN...");
_nn = new FlannKdTreeNN(parameters);
break;
case kNNFlannKdTree:
_nn = new FlannKdTreeNN(parameters);
_nn = new FlannNN(FlannNN::kKDTree, parameters);
break;
case kNNNaive:
default:
@@ -261,13 +254,7 @@ void VWDictionary::setNNStrategy(NNStrategy strategy, const ParametersMap & para
VWDictionary::NNStrategy VWDictionary::nnStrategy() const
{
NNStrategy strategy = kNNUndef;
KdTreeNN * kdTree = dynamic_cast<KdTreeNN*>(_nn);
FlannKdTreeNN * flannKdTree = dynamic_cast<FlannKdTreeNN*>(_nn);
if(kdTree)
{
strategy = kNNKdTree;
}
else if(flannKdTree)
if(_nn)
{
strategy = kNNFlannKdTree;
}
@@ -338,7 +325,7 @@ void VWDictionary::update()
}
// Create the kd-Tree
_dataTree = cv::Mat::zeros(_visualWords.size(), _dim, CV_32F); // SURF descriptors are CV_32F
_dataTree = cv::Mat(_visualWords.size(), _dim, CV_32F); // SURF descriptors are CV_32F
std::map<int, VisualWord*>::const_iterator iter = _visualWords.begin();
for(unsigned int i=0; i < _visualWords.size(); ++i, ++iter)
{
@@ -355,7 +342,7 @@ void VWDictionary::update()
}
}
ULOGGER_DEBUG("_mapIndexId.size() = %d, words.size()=%d",_mapIndexId.size(), _visualWords.size());
ULOGGER_DEBUG("_mapIndexId.size() = %d, words.size()=%d, _dim=%d",_mapIndexId.size(), _visualWords.size(), _dim);
ULOGGER_DEBUG("copying data = %f s", timer.ticks());
// Update the nearest neighbor algorithm
@@ -453,14 +440,8 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
cv::Mat results(descriptors.rows, k, CV_32SC1); // results index
cv::Mat dists;
if(_nn->isDist64F())
{
dists = cv::Mat(descriptors.rows, k, CV_64FC1); // Distance results are CV_64FC1;
}
else
{
dists = cv::Mat(descriptors.rows, k, CV_32FC1); // Distance results are CV_32FC1
}
dists = cv::Mat(descriptors.rows, k, CV_32FC1); // Distance results are CV_32FC1
cv::Mat newPts; // SURF descriptors are CV_32F
if(descriptors.type()!=CV_32F)
{
@@ -494,19 +475,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
for(unsigned int j=0; j<k; ++j)
{
float dist;
if(_nn->isDist64F())
{
dist = (float)dists.at<double>(i,j);
}
else
{
dist = dists.at<float>(i,j);
}
if(!_nn->isDistSquared())
{
dist*=dist;
}
dist = dists.at<float>(i,j);
fullResults.insert(std::pair<float, int>(dist, uValue(_mapIndexId, results.at<int>(i,j))));
}
}
@@ -664,16 +633,8 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws, bool
cv::Mat dists;
cv::Mat resultsNotIndexed(vws.size(), k, CV_32SC1);
cv::Mat distsNotIndexed;
if(_nn->isDist64F())
{
dists = cv::Mat(vws.size(), k, CV_64FC1); // Distance results are CV_64FC1;
distsNotIndexed = cv::Mat(vws.size(), k, CV_64FC1); // Distance results are CV_64FC1;
}
else
{
dists = cv::Mat(vws.size(), k, CV_32FC1); // Distance results are CV_32FC1
distsNotIndexed = cv::Mat(vws.size(), k, CV_32FC1); // Distance results are CV_32FC1
}
dists = cv::Mat(vws.size(), k, CV_32FC1); // Distance results are CV_32FC1
distsNotIndexed = cv::Mat(vws.size(), k, CV_32FC1); // Distance results are CV_32FC1
cv::Mat newPts(vws.size(), _dim, CV_32F); // SURF descriptors are CV_32F
// fill the request matrix
@@ -740,36 +701,12 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws, bool
float dist;
if(!_dataTree.empty())
{
if(_nn->isDist64F())
{
dist = (float)dists.at<double>(i,j);
}
else
{
dist = dists.at<float>(i,j);
}
if(!_nn->isDistSquared())
{
dist*=dist;
}
dist = dists.at<float>(i,j);
fullResults.insert(std::pair<float, int>(dist, uValue(_mapIndexId, results.at<int>(i,j))));
}
if(searchInNewlyAddedWords && unreferencedWordsCount)
{
if(_nn->isDist64F())
{
dist = (float)distsNotIndexed.at<double>(i,j);
}
else
{
dist = distsNotIndexed.at<float>(i,j);
}
if(!_nn->isDistSquared())
{
dist*=dist;
}
dist = distsNotIndexed.at<float>(i,j);
fullResults.insert(std::pair<float, int>(dist, uValue(mapIndexIdNotIndexed, resultsNotIndexed.at<int>(i,j))));
}
}
@@ -1038,7 +975,7 @@ void VWDictionary::getCommonWords(unsigned int nbCommonWords, int totalSign, std
}
else
{
commonWords = uValues(countMap);
commonWords = uValuesList(countMap);
}
ULOGGER_DEBUG("time = %f s", timer.ticks());
}

View File

@@ -1,166 +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/>.
*/
#include "rtabmap/core/VerifyHypotheses.h"
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/Signature.h"
#include "rtabmap/core/EpipolarGeometry.h"
#include <cstdlib>
#include "utilite/UtiLite.h"
namespace rtabmap
{
HypVerificator::HypVerificator(const ParametersMap & parameters)
{
this->parseParameters(parameters);
}
void HypVerificator::parseParameters(const ParametersMap & parameters)
{
}
bool HypVerificator::verify(const Signature * ref, const Signature * hyp)
{
UDEBUG("");
return ref && hyp && !ref->isBadSignature() && !hyp->isBadSignature();
}
/////////////////////////
// HypVerificatorSim
/////////////////////////
HypVerificatorSim::HypVerificatorSim(const ParametersMap & parameters) :
HypVerificator(parameters),
_similarity(Parameters::defaultVhSimilarity())
{
this->parseParameters(parameters);
}
HypVerificatorSim::~HypVerificatorSim()
{
}
void HypVerificatorSim::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kVhSimilarity())) != parameters.end())
{
_similarity = std::atof((*iter).second.c_str());
}
HypVerificator::parseParameters(parameters);
}
bool HypVerificatorSim::verify(const Signature * ref, const Signature * hyp)
{
UDEBUG("");
if(ref && hyp)
{
return ref->compareTo(hyp) >= _similarity;
}
return false;
}
/////////////////////////
// HypVerificatorEpipolarGeo
/////////////////////////
HypVerificatorEpipolarGeo::HypVerificatorEpipolarGeo(const ParametersMap & parameters) :
HypVerificator(parameters),
_matchCountMinAccepted(Parameters::defaultVhEpMatchCountMin()),
_ransacParam1(Parameters::defaultVhEpRansacParam1()),
_ransacParam2(Parameters::defaultVhEpRansacParam2())
{
this->parseParameters(parameters);
}
HypVerificatorEpipolarGeo::~HypVerificatorEpipolarGeo() {
}
void HypVerificatorEpipolarGeo::parseParameters(const ParametersMap & parameters)
{
ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kVhEpMatchCountMin())) != parameters.end())
{
_matchCountMinAccepted = std::atoi((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kVhEpRansacParam1())) != parameters.end())
{
_ransacParam1 = std::atof((*iter).second.c_str());
}
if((iter=parameters.find(Parameters::kVhEpRansacParam2())) != parameters.end())
{
_ransacParam2 = std::atof((*iter).second.c_str());
}
HypVerificator::parseParameters(parameters);
}
bool HypVerificatorEpipolarGeo::verify(const Signature * ref, const Signature * hyp)
{
UDEBUG("");
const KeypointSignature * ssRef = dynamic_cast<const KeypointSignature *>(ref);
const KeypointSignature * ssHyp = dynamic_cast<const KeypointSignature *>(hyp);
if(ssRef && ssHyp)
{
return doEpipolarGeometry(ssHyp, ssRef);
}
return false;
}
bool HypVerificatorEpipolarGeo::doEpipolarGeometry(const KeypointSignature * ssA, const KeypointSignature * ssB)
{
if(ssA == 0 || ssB == 0)
{
return false;
}
ULOGGER_DEBUG("id(%d,%d)", ssA->id(), ssB->id());
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
findPairsUnique(ssA->getWords(), ssB->getWords(), pairs);
if((int)pairs.size()<_matchCountMinAccepted)
{
return false;
}
std::vector<uchar> status;
cv::Mat f = findFFromWords(pairs, status, _ransacParam1, _ransacParam2);
int inliers = uSum(status);
if(inliers < _matchCountMinAccepted)
{
ULOGGER_DEBUG("Epipolar constraint failed A : not enough inliers (%d/%d), min is %d", inliers, pairs.size(), _matchCountMinAccepted);
return false;
}
else
{
UDEBUG("inliers = %d/%d", inliers, pairs.size());
return true;
}
}
}

View File

@@ -17,7 +17,7 @@
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rtabmap/core/VisualWord.h"
#include "VisualWord.h"
#include "utilite/ULogger.h"
#include "utilite/UStl.h"

View File

@@ -50,7 +50,7 @@ private:
int _id;
float * _descriptor;
int _dim;
bool _saved; // If it's saved to bd
bool _saved; // If it's saved to db
int _totalReferences;
std::map<int, int> _references; // (signature id , occurrence in the signature)

View File

@@ -1,5 +1,5 @@
-- *******************************************************************
-- construct_avpd_db: Script for creating the database
-- DatabaseSchema: Script for creating the database
-- Usage:
-- $ sqlite3 LTM.db < DatabaseSchema.sql
--
@@ -8,60 +8,37 @@
-- *******************************************************************
-- CLEAN
-- *******************************************************************
/*DROP TABLE Node;
DROP TABLE Link;
DROP TABLE Sensor;
DROP TABLE Actuator;
DROP TABLE Word;
DROP TABLE Map_Node_Word;
DROP TABLE Statistics;
DROP TABLE StatisticsSurf;*/
/*DROP TABLE Node;*/
-- *******************************************************************
-- CREATE
-- *******************************************************************
CREATE TABLE Node (
id INTEGER NOT NULL,
type INTEGER NOT NULL, -- 0=Keypoint, 1=Sensor
weight INTEGER,
time_enter DATE,
PRIMARY KEY (id)
);
CREATE TABLE Sensor (
CREATE TABLE Image (
id INTEGER NOT NULL,
num INTEGER NOT NULL,
type INTEGER NOT NULL, -- kTypeImage=0, kTypeImageFeatures2d, kTypeAudio, kTypeAudioFreq, kTypeAudioFreqSqrdMagn, kTypeJointState, kTypeNotSpecified
data BLOB, -- PostProcessed data (indexed integers)
raw_width INTEGER NOT NULL,
raw_height INTEGER NOT NULL,
raw_data_type INTEGER NOT NULL,
raw_compressed CHAR NOT NULL,
raw_data BLOB,
PRIMARY KEY (id, num)
time_enter DATE,
PRIMARY KEY (id)
);
CREATE TABLE Link (
from_id INTEGER NOT NULL,
to_id INTEGER NOT NULL,
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
actuator_id INTEGER,
base_ids BLOB,
FOREIGN KEY (from_id) REFERENCES Node(id),
FOREIGN KEY (to_id) REFERENCES Node(id)
);
CREATE TABLE Actuator (
id INTEGER NOT NULL,
num INTEGER NOT NULL,
type INTEGER NOT NULL, -- kTypeTwist=0, kTypeNotSpecified
width INTEGER NOT NULL,
height INTEGER NOT NULL,
data_type INTEGER NOT NULL,
data BLOB,
PRIMARY KEY (id, num)
);
--
CREATE TABLE Word (
id INTEGER NOT NULL,
@@ -92,17 +69,17 @@ CREATE TABLE Statistics (
);
CREATE TABLE StatisticsDictionary (
dictionary_size INTEGER,
time_enter DATE
dictionary_size INTEGER,
time_enter DATE
);
-- *******************************************************************
-- TRIGGERS
-- *******************************************************************
CREATE TRIGGER insert_Map_Node_Word BEFORE INSERT ON Map_Node_Word
WHEN NOT EXISTS (SELECT type FROM Node WHERE Node.id = NEW.node_id AND type=0)
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
BEGIN
SELECT RAISE(ABORT, 'Keypoint type constraint failed');
SELECT RAISE(ABORT, 'Foreign key constraint failed in Map_Node_Word table');
END;
-- Creating a trigger for time_enter
@@ -121,16 +98,10 @@ BEGIN
UPDATE Statistics SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
CREATE TRIGGER insert_StatisticsDictionary_timeEnter AFTER INSERT ON StatisticsDictionary
BEGIN
UPDATE StatisticsDictionary SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
-- *******************************************************************
-- INDEXES
-- *******************************************************************
CREATE INDEX IDX_Map_Node_Word_node_id on Map_Node_Word (node_id);
CREATE INDEX IDX_Sensor_Id on Sensor (id);
CREATE INDEX IDX_Link_from_id on Link (from_id);