#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include "libmv/base/vector.h"
#include "libmv/base/vector_utils.h"
#include "libmv/base/scoped_ptr.h"
#include "libmv/correspondence/export_matches_txt.h"
#include "libmv/correspondence/feature.h"
#include "libmv/correspondence/feature_matching.h"
#include "libmv/correspondence/nRobustViewMatching.h"
#include "libmv/detector/detector_factory.h"
#include "libmv/descriptor/descriptor_factory.h"
#include "libmv/image/image.h"
#include "libmv/image/image_converter.h"
#include "libmv/image/image_drawing.h"
#include "libmv/image/image_io.h"
#include "libmv/tools/tool.h"
using namespace libmv;
using namespace std;
DEFINE_string(detector, "FAST", "select the detector (FAST,STAR,SURF,MSER)");
DEFINE_string(describer, "DIPOLE",
"select the descriptor (SIMPLIEST,SURF,DIPOLE,DAISY)");
DEFINE_bool(save_matches_results, true,
"save images with detected and matched features");
DEFINE_bool(save_matches_file, false,
"save the matches in a file");
DEFINE_string(matches_out, "matches.txt", "Matches output file");
DEFINE_bool(save_hugin, true,
"save Hugin point matches (ready to minimize Hugin project)");
DEFINE_bool(save_reconstruction, true,
"save perspective reconstruction from largest track (.ply)");
template <typename Image>
void DrawFeatures( Image & im, const libmv::vector<libmv::Feature *> & feat)
{
std::cout << feat.size() << " Detected points " <<std::endl;
for (int i = 0; i < feat.size(); ++i)
{
const libmv::PointFeature * feature =
dynamic_cast<libmv::PointFeature *>( feat[i] );
const int x = feature->x();
const int y = feature->y();
const float scale = feature->scale;
DrawCircle(x, y, scale, (unsigned char)255, &im);
const float angle = feature->orientation;
DrawLine(x, y, x + scale * cos(angle), y + scale *sin(angle),
(unsigned char) 255, &im);
}
}
std::string ExtractFilename( const std::string& path )
{
return path.substr( path.find_last_of( "\\/" ) +1 );
}
bool IsArgImage(const std::string & arg) {
string copy = arg;
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
return (arg.size()>3 &&
(copy.find_last_of (".png") == copy.size() - 1 ||
copy.find_last_of (".jpg") == copy.size() - 1 ||
copy.find_last_of (".jpeg") == copy.size()- 1 ||
copy.find_last_of (".pnm") == copy.size() - 1 ));
}
void DisplayMatches(const Matches &matches)
{
std::cout << "Matches : \t\t"<<std::endl << "\t";
for (size_t j = 0; j < matches.NumImages(); j++) {
std::cout << j << " ";
}
std::cout << std::endl;
for (size_t i = 0; i < matches.NumTracks(); i++) {
std::cout << i <<"\t";
for (size_t j = 0; j < matches.NumImages(); j++) {
const Feature * f = matches.Get(j,i);
if (f)
std::cout << "X ";
else
std::cout << " ";
}
std::cout <<std::endl;
}
}
int main(int argc, char **argv) {
gflags::SetUsageMessage("NViewMatching Demo.");
gflags::ParseCommandLineFlags(&argc, &argv, true);
libmv::vector<string> image_vector;
for (int i = 1;i < argc;++i) {
std::string arg (argv[i]);
if (IsArgImage(arg)) {
image_vector.push_back(arg);
}
}
detector::eDetector edetector = detector::FAST_DETECTOR;
if (FLAGS_detector == "FAST") {
edetector = detector::FAST_DETECTOR;
} else if (FLAGS_detector == "SURF") {
edetector = detector::SURF_DETECTOR;
} else if (FLAGS_detector == "STAR") {
edetector = detector::STAR_DETECTOR;
} else if (FLAGS_detector == "MSER") {
edetector = detector::MSER_DETECTOR;
} else {
LOG(FATAL) << "ERROR : undefined Detector !";
}
scoped_ptr<detector::Detector> spDetector = detectorFactory(edetector);
descriptor::eDescriber edescriber = descriptor::DIPOLE_DESCRIBER;
if (FLAGS_describer == "SIMPLIEST") {
edescriber = descriptor::SIMPLEST_DESCRIBER;
} else if (FLAGS_describer == "SURF") {
edescriber = descriptor::SURF_DESCRIBER;
} else if (FLAGS_describer == "DIPOLE") {
edescriber = descriptor::DIPOLE_DESCRIBER;
} else if (FLAGS_describer == "DAISY") {
edescriber = descriptor::DAISY_DESCRIBER;
} else {
LOG(FATAL) << "ERROR : undefined Describer !";
}
scoped_ptr<descriptor::Describer> spDescriber = describerFactory(edescriber);
libmv::correspondence::nRobustViewMatching nViewMatcher(spDetector.get(),
spDescriber.get());
nViewMatcher.computeCrossMatch(image_vector);
DisplayMatches(nViewMatcher.getMatches());
if (FLAGS_save_matches_file) {
ExportMatchesToTxt(nViewMatcher.getMatches(), FLAGS_matches_out);
}
if (FLAGS_save_matches_results) {
for (size_t i=0; i< nViewMatcher.getMatches().NumImages(); ++i) {
Array3Du imageA;
ReadImage( image_vector[i].c_str() , &imageA);
Array3Du imageTemp;
Rgb2Gray( imageA, &imageTemp);
Image im( new Array3Du(imageTemp) );
for (size_t j=0; j< i; ++j) {
Matches::Features<KeypointFeature> features =
nViewMatcher.getMatches().InImage<KeypointFeature>(i);
int cpt = 0;
Array3Du bigIma;
if (i!=j && features) {
Array3Du imageB;
ReadImage(image_vector[j].c_str() , &imageB);
Array3Du imageTemp2;
Rgb2Gray( imageB, &imageTemp2);
Image im2( new Array3Du(imageTemp2) );
int width = max(imageB.Width(),
imageA.Width()) + min(imageB.Width(), imageA.Width());
int height = max(imageB.Height(), imageA.Height());
bigIma = Array3Du(height,width);
for (int jj=0;jj<imageA.Height();++jj)
for (int ii=0;ii<imageA.Width();++ii) {
bigIma(jj,ii)= (*im.AsArray3Du())(jj,ii);
}
for (int jj=0;jj<imageB.Height();++jj)
for (int ii=0;ii<imageB.Width();++ii) {
bigIma(jj,ii+min(imageB.Width(), imageA.Width()))=
(*im2.AsArray3Du())(jj,ii);
}
while (features) {
Matches::TrackID id_track = features.track();
const Feature * ref = features.feature();
const Feature * f = nViewMatcher.getMatches().Get(j, id_track);
if (f && ref) {
KeypointFeature * pt0 = ((KeypointFeature*)ref);
KeypointFeature * pt1 = ((KeypointFeature*)f);
DrawCircle(pt0->x(), pt0->y(),
pt0->scale, (unsigned char)255, &bigIma);
DrawCircle(pt1->x()+min(imageA.Width(), imageB.Width()),
pt1->y(), pt1->scale, (unsigned char)255, &bigIma);
DrawLine( pt0->x(),
pt0->y(),
pt1->x()+min(imageB.Width(), imageA.Width()),
pt1->y(),
255,
&bigIma);
++cpt;
}
features.operator++();
}
}
if (cpt> 4*2) {
ostringstream os;
os<< "TOTO_" << ExtractFilename(image_vector[i].c_str()) << "_"
<< ExtractFilename(image_vector[j].c_str()) << "___"
<< cpt << "__matches" << ".jpeg";
WriteJpg(bigIma, os.str().c_str(), 100);
}
}
}
}
if (FLAGS_save_hugin) {
ofstream myFile("huginGenerated.txt");
myFile << "# oto project file generated by Libmv"<< endl << endl;
myFile << "input images :"<< endl;
for (int i = 0; i < image_vector.size(); ++i) {
ByteImage byteImage;
if ( 0 == ReadImage( image_vector[i].c_str(), &byteImage) ) {
LOG(ERROR) << "Invalid inputImage.";
continue;
}
int width = byteImage.Width();
int height = byteImage.Height();
myFile << "#-imgfile " << width << " " << height
<< " " << ExtractFilename(image_vector[i]) << endl;
myFile << "o f0 y+0.000000 r+0.000000 p+0.000000 u20 d0 e0 v50 a0 b0 c0" << endl;
}
myFile << endl << "# Control points:"<<endl;
for (size_t i=0; i< nViewMatcher.getMatches().NumImages(); ++i) {
for (size_t j=0; j<i; ++j) {
Matches::Features<KeypointFeature> features =
nViewMatcher.getMatches().InImage<KeypointFeature>(i);
while (features) {
Matches::TrackID id_track = features.track();
const Feature * ref = features.feature();
const Feature * f = nViewMatcher.getMatches().Get(j, id_track);
if (f && ref) {
KeypointFeature * pt0 = ((KeypointFeature*)ref);
KeypointFeature * pt1 = ((KeypointFeature*)f);
myFile << endl << "c "
<< "n" << i << " "
<< "N" << j << " "
<< "x" << pt0->x() << " "
<< "y" << pt0->y() << " "
<< "X" << pt1->x() << " "
<< "Y" << pt1->y();
}
features.operator++();
}
}
}
}
if (FLAGS_save_reconstruction)
{
Matches matches = nViewMatcher.getMatches();
libmv::vector<int> vec_trackLenghtHisto(matches.NumImages()+1);
fill(vec_trackLenghtHisto.begin(), vec_trackLenghtHisto.end(),0);
for (size_t i = 0; i < matches.NumTracks(); i++) {
int iCount = 0;
for (size_t j = 0; j < matches.NumImages(); j++) {
const Feature * f = matches.Get(j,i);
iCount+= (f)? 1 : 0;
}
vec_trackLenghtHisto[iCount]++;
}
copy(vec_trackLenghtHisto.begin(), vec_trackLenghtHisto.end(),
std::ostream_iterator<int>(std::cout, " "));
}
return 0;
}