Skip to content

Commit

Permalink
better integration with OpenCv: API allows describing an image as a s…
Browse files Browse the repository at this point in the history
…ingle matrix of descriptors, one per row
  • Loading branch information
rmsalinas committed Sep 5, 2016
1 parent b72029c commit 7a5d97a
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 37 deletions.
19 changes: 19 additions & 0 deletions src/Database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ Database& Database::operator=

// --------------------------------------------------------------------------

EntryId Database::add(
const cv::Mat &features,
BowVector *bowvec, FeatureVector *fvec)
{
std::vector<cv::Mat> vf(features.rows);
for(int r=0;r<features.rows;r++) vf[r]=features.rowRange(r,r+1);
add(vf,bowvec,fvec);
}

EntryId Database::add(
const std::vector<cv::Mat> &features,
Expand Down Expand Up @@ -221,6 +229,17 @@ void Database::allocate(int nd, int ni)

// --------------------------------------------------------------------------

void Database::query(
const cv::Mat &features,
QueryResults &ret, int max_results, int max_id) const
{

std::vector<cv::Mat> vf(features.rows);
for(int r=0;r<features.rows;r++) vf[r]=features.rowRange(r,r+1);
query(vf, ret, max_results, max_id);
}



void Database::query(
const std::vector<cv::Mat> &features,
Expand Down
21 changes: 20 additions & 1 deletion src/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ class DBOW_API Database
*/
EntryId add(const std::vector<cv::Mat> &features,
BowVector *bowvec = NULL, FeatureVector *fvec = NULL);
/**
* Adds an entry to the database and returns its index
* @param features features of the new entry, one per row
* @param bowvec if given, the bow vector of these features is returned
* @param fvec if given, the vector of nodes and feature indexes is returned
* @return id of new entry
*/
EntryId add(const cv::Mat &features,
BowVector *bowvec = NULL, FeatureVector *fvec = NULL);

/**
* Adss an entry to the database and returns its index
Expand Down Expand Up @@ -172,7 +181,17 @@ class DBOW_API Database
*/
void query(const std::vector<cv::Mat> &features, QueryResults &ret,
int max_results = 1, int max_id = -1) const;

/**
* Queries the database with some features
* @param features query features,one per row
* @param ret (out) query results
* @param max_results number of results to return. <= 0 means all
* @param max_id only entries with id <= max_id are returned in ret.
* < 0 means all
*/
void query(const cv::Mat &features, QueryResults &ret,
int max_results = 1, int max_id = -1) const;

/**
* Queries the database with a vector
* @param vec bow vector already normalized
Expand Down
21 changes: 20 additions & 1 deletion src/Vocabulary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,21 @@ Vocabulary::operator=
return *this;
}

// --------------------------------------------------------------------------


void Vocabulary::create(
const std::vector< cv::Mat > &training_features)
{
std::vector<std::vector<cv::Mat> > vtf(training_features.size());
for(int i=0;i<training_features.size();i++){
vtf[i].resize(training_features[i].rows);
for(int r=0;r<training_features[i].rows;r++)
vtf[i][r]=training_features[i].rowRange(r,r+1);
}
create(vtf);

}

void Vocabulary::create(
const std::vector<std::vector<cv::Mat> > &training_features)
{
Expand Down Expand Up @@ -616,6 +628,13 @@ WordId Vocabulary::transform

// --------------------------------------------------------------------------

void Vocabulary::transform(
const cv::Mat& features, BowVector &v) const
{
std::vector<cv::Mat> vf(features.rows);
for(int r=0;r<features.rows;r++) vf[r]=features.rowRange(r,r+1);
transform(vf,v);
}

void Vocabulary::transform(
const std::vector<cv::Mat>& features, BowVector &v) const
Expand Down
19 changes: 16 additions & 3 deletions src/Vocabulary.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,21 @@ class DBOW_API Vocabulary
Vocabulary& operator=(
const Vocabulary &voc);

/**
/**
* Creates a vocabulary from the training features with the already
* defined parameters
* @param training_features
*/
virtual void create
(const std::vector<std::vector<cv::Mat> > &training_features);

/**
* Creates a vocabulary from the training features with the already
* defined parameters
* @param training_features. Each row of a matrix is a feature
*/
virtual void create
(const std::vector<cv::Mat> &training_features);

/**
* Creates a vocabulary from the training features, setting the branching
* factor and the depth levels of the tree
Expand Down Expand Up @@ -121,7 +128,13 @@ class DBOW_API Vocabulary
*/
virtual void transform(const std::vector<cv::Mat>& features, BowVector &v)
const;

/**
* Transforms a set of descriptores into a bow vector
* @param features, one per row
* @param v (out) bow vector of weighted words
*/
virtual void transform(const cv::Mat & features, BowVector &v)
const;
/**
* Transform a set of descriptors into a bow vector and a feature vector
* @param features
Expand Down
3 changes: 2 additions & 1 deletion utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src )
LINK_LIBRARIES(${PROJECT_NAME})
IF(OPENCV_VERSION_3)
ADD_EXECUTABLE(demo_general demo_general.cpp)
INSTALL(TARGETS demo_general RUNTIME DESTINATION bin)
ADD_EXECUTABLE(create_voc create_voc.cpp)
INSTALL(TARGETS demo_general create_voc RUNTIME DESTINATION bin)
ENDIF()
3 changes: 3 additions & 0 deletions utils/create_voc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int main(){

}
61 changes: 30 additions & 31 deletions utils/demo_general.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <opencv2/xfeatures2d.hpp>
#endif

#include "DescManip.h"

using namespace DBoW3;
using namespace std;
Expand All @@ -31,8 +31,6 @@ class CmdLineParser{int argc; char **argv; public: CmdLineParser(int _argc,char

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// number of training images
const int NIMAGES = 4;
// extended surf gives 128-dimensional vectors
const bool EXTENDED_SURF = false;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand All @@ -43,7 +41,14 @@ void wait()
getchar();
}

void loadFeatures(vector<vector<cv::Mat> > &features,string path_to_images,string descriptor="") throw (std::exception){

vector<string> readImagePaths(int argc,char **argv,int start){
vector<string> paths;
for(int i=start;i<argc;i++) paths.push_back(argv[i]);
return paths;
}

vector< cv::Mat > loadFeatures( std::vector<string> path_to_images,string descriptor="") throw (std::exception){
//select detector
cv::Ptr<cv::Feature2D> fdetector;
if (descriptor=="orb") fdetector=cv::ORB::create();
Expand All @@ -57,33 +62,28 @@ void loadFeatures(vector<vector<cv::Mat> > &features,string path_to_images,strin

else throw std::runtime_error("Invalid descriptor");
assert(!descriptor.empty());
features.clear();
features.reserve(NIMAGES);
vector<cv::Mat> features;

vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;

cout << "Extracting features..." << endl;
for(int i = 0; i < NIMAGES; ++i)
for(int i = 0; i < path_to_images.size(); ++i)
{
stringstream ss;
ss << path_to_images<<"image" << i << ".png";
cout<<"reading image: "<<ss.str()<<endl;
cv::Mat image = cv::imread(ss.str(), 0);
if(image.empty())throw std::runtime_error("Could not open image"+ss.str());
vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
cout<<"reading image: "<<path_to_images[i]<<endl;
cv::Mat image = cv::imread(path_to_images[i], 0);
if(image.empty())throw std::runtime_error("Could not open image"+path_to_images[i]);
cout<<"extracting features"<<endl;
fdetector->detectAndCompute(image, cv::Mat(), keypoints, descriptors);
features.push_back(descriptors);
cout<<"done detecting features"<<endl;

//turn descriptor into a set of matries, one per row and store in the vector
features.push_back(vector<cv::Mat >(descriptors.rows));
for(int i = 0; i < descriptors.rows; i++) features.back()[i]=descriptors.rowRange(i,i+1);
}
return features;
}

// ----------------------------------------------------------------------------

void testVocCreation(const vector<vector<cv::Mat > > &features)
void testVocCreation(const vector<cv::Mat> &features)
{
// branching factor and depth levels
const int k = 9;
Expand All @@ -103,10 +103,10 @@ void testVocCreation(const vector<vector<cv::Mat > > &features)
// lets do something with this vocabulary
cout << "Matching images against themselves (0 low, 1 high): " << endl;
BowVector v1, v2;
for(int i = 0; i < NIMAGES; i++)
for(int i = 0; i < features.size(); i++)
{
voc.transform(features[i], v1);
for(int j = 0; j < NIMAGES; j++)
for(int j = 0; j < features.size(); j++)
{
voc.transform(features[j], v2);

Expand All @@ -121,9 +121,9 @@ void testVocCreation(const vector<vector<cv::Mat > > &features)
cout << "Done" << endl;
}

//// ----------------------------------------------------------------------------
////// ----------------------------------------------------------------------------

void testDatabase(const vector<vector<cv::Mat > > &features)
void testDatabase(const vector<cv::Mat > &features)
{
cout << "Creating a small database..." << endl;

Expand All @@ -137,10 +137,8 @@ void testDatabase(const vector<vector<cv::Mat > > &features)
// db creates a copy of the vocabulary, we may get rid of "voc" now

// add images to the database
for(int i = 0; i < NIMAGES; i++)
{
for(int i = 0; i < features.size(); i++)
db.add(features[i]);
}

cout << "... done!" << endl;

Expand All @@ -150,7 +148,7 @@ void testDatabase(const vector<vector<cv::Mat > > &features)
cout << "Querying the database: " << endl;

QueryResults ret;
for(int i = 0; i < NIMAGES; i++)
for(int i = 0; i < features.size(); i++)
{
db.query(features[i], ret, 4);

Expand Down Expand Up @@ -185,14 +183,15 @@ int main(int argc,char **argv)
try{
CmdLineParser cml(argc,argv);
if (cml["-h"] || argc==1){
cerr<<"Usage: [-i path_to_image_dir] [-d descriptor_name] \n\t descriptors:brisk,surf,orb(default),akaze(only if using opencv 3)"<<endl;
cerr<<"Usage: descriptor_name image0 image1 ... \n\t descriptors:brisk,surf,orb(default),akaze(only if using opencv 3)"<<endl;
return -1;
}
vector<vector<cv::Mat > > features;

string path_to_images=cml("-i","");//read param -i if present. If not, returns emtpy string
string descriptor=cml("-d","orb");//read param -d if present. If not, returns "orb"
string descriptor=argv[1];

loadFeatures(features,path_to_images,descriptor);
auto images=readImagePaths(argc,argv,2);
vector< cv::Mat > features= loadFeatures(images,descriptor);
testVocCreation(features);

wait();
Expand Down

0 comments on commit 7a5d97a

Please sign in to comment.