//Description: 在cygwin下和不安装cygwin在windows下分别编译和运行Bundler
(1) 在编译之前请大家在/src打开Bundle2PMVS.cpp将217行的
fprintf(f_scr, "mv pmvs/%s.rd.jpg %s/visualize/%08d.jpg\n", 修改为 fprintf(f_scr, "mv %s.jpg %s/visualize/%08d.jpg\n"。原因后面第(6)步大家会知道。
$ cd 到bundler的目录下
$ make
(在编译到BundlerApp.h文件第620行, 出现错误: 不能直接调用构造函数'SkeletalApp::BundlerApp')该头文件在/bundler/src目录中, 注释掉该行, 继续make, 可以通过编译此次make共生成bundler.exe, Bundle2PMVS,exe, BundleVis.exe, KeyMatchFull.exe, RadialUndistort.exe, libANN_char.dll, 都放置在/bundler/bin目录下。
(2) 下载SIFT获取siftWin32.exe
将CMVS-PMVS-master\binariesWin-Linux\Win64-VS2010文件夹中的文件全部拷贝到之前的result文件夹目录下
打开cmd
这样,我们发现/pmvs/models/文件夹多了几个文件,其中*.ply文件为3D模型文件用下面的软件可以查看。
vi deploy.sh
:set fileformat=unix
:wq
bundler是个挺强大的三维重建库,具体的就不介绍了,上其主页上看去。
这里主要记录一下怎么在windows下运行这东西。网上搜索的都要安装cygwin,但这东西太大了,安装下来1个G以上。空间宝贵,故想不安装它直接在windows下跑。
借助了opencv和Qt,其中opencv是用来将.jpg图像转换成.pgm格式的,因为bunder其中用到的特征检测siftWin32只能用P5开头的.pgm格式的图像;而Qt是用来遍历文件夹下的图像路径的,这个如果熟悉其它如MFC的也可以用其它的代替,反正只要能运行就Ok了是吧。
话不多说,上代码。
bundlerInWin.h
#ifndef BUNDLERINWIN_H
#define BUNDLERINWIN_H
#include <QtWidgets/QWidget>
#include "ui_bundlerinwin.h"
#include <QPushButton>
#include <QLineEdit>
#include <QString>
#include <QSlider>
#include <QSpinBox>
namespace Ui
{
class bundlerInWin;
};
class bundlerInWin : public QWidget
{
Q_OBJECT
public:
bundlerInWin(QWidget *parent = 0);
~bundlerInWin();
void initwidgets();
void initconnects();
public slots :
bool choosedir();
void GenListFile();
void changeImage();
void runbundler();
void setLcdvalue(int);
void setSlidervalue(int);
private:
Ui::bundlerInWin *ui;
QLineEdit *dirlineedit;
QPushButton *dirbtn;
QString dirname;
QPushButton *genlistbtn, *changeimgbtn, *runbtn;
int focal_length;
QSpinBox *paramedit;
QSlider *slider;
};
#endif // BUNDLERINWIN_H
bundlerInWin.cpp
#include "bundlerinwin.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
using namespace cv;
string StringRepalceSub(string &str, const string oldSub, const string newSub)
{
int oldSubLen = oldSub.size();//替换的长度
unsigned int p = string::npos;
p = str.find(oldSub, 0);//查找替换的位置
if (p == string::npos) {
return str;
}
else {
string restr = str;
return restr.replace(p, oldSubLen, newSub);
}
}
bundlerInWin::bundlerInWin(QWidget *parent)
:ui(new Ui::bundlerInWin), QWidget(parent)
{
ui->setupUi(this);
initwidgets();
initconnects();
focal_length = 5;
QHBoxLayout *dirlayout = new QHBoxLayout();
dirlayout->addWidget(dirlineedit);
dirlayout->addWidget(dirbtn);
QHBoxLayout *paramlayout = new QHBoxLayout();
paramlayout->addWidget(paramedit);
paramlayout->addWidget(slider);
QVBoxLayout *btnlayout = new QVBoxLayout();
btnlayout->addWidget(genlistbtn);
btnlayout->addWidget(changeimgbtn);
btnlayout->addWidget(runbtn);
QVBoxLayout *mainlayout = new QVBoxLayout();
mainlayout->addLayout(dirlayout);
mainlayout->addLayout(paramlayout);
mainlayout->addLayout(btnlayout);
setLayout(mainlayout);
}
bundlerInWin::~bundlerInWin()
{
delete ui;
}
void bundlerInWin::initwidgets()
{
dirbtn = new QPushButton("choose dir");
dirlineedit = new QLineEdit();
genlistbtn = new QPushButton("genlistfile");
changeimgbtn = new QPushButton("changeImage");
runbtn = new QPushButton("run");
slider = new QSlider(Qt::Horizontal);
slider->setMinimum(0);
slider->setMaximum(10000);
slider->setValue(0);
paramedit = new QSpinBox();
paramedit->setRange(0, 10000);
paramedit->setValue(5);
}
void bundlerInWin::initconnects()
{
connect(dirbtn, SIGNAL(clicked()), this, SLOT(choosedir()));
connect(genlistbtn, SIGNAL(clicked()), this, SLOT(GenListFile()));
connect(changeimgbtn, SIGNAL(clicked()), this, SLOT(changeImage()));
connect(runbtn, SIGNAL(clicked()), this, SLOT(runbundler()));
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(setLcdvalue(int)));
connect(paramedit, SIGNAL(valueChanged(int)), this, SLOT(setSlidervalue(int)));
}
bool bundlerInWin::choosedir()
{
dirname = QFileDialog::getExistingDirectory(this);
if (dirname.isEmpty()) {
QMessageBox::warning(NULL, "warning:", "No such directory!");
return false;
}
dirlineedit->setText(dirname);
return true;
}
void bundlerInWin::GenListFile()
{
QDir dir(dirname);
dir.setFilter(QDir::Files);
QFileInfoList list = dir.entryInfoList();
ofstream listfile("result/list.txt");
int i = 0;
do {
QFileInfo fileInfo = list.at(i);
if (fileInfo.fileName() == "." || fileInfo.fileName() == "..") {
i++;
continue;
}
listfile << fileInfo.absoluteFilePath().toStdString() << " 0 " << focal_length << endl;
i++;
} while (i < list.size());
listfile.close();
}
void bundlerInWin::changeImage()
{
ifstream listfile("result/list.txt");
ofstream keyfile("result/list_keys.txt");
string str, new_imagename, keyname, comm;
int len = 0, i = 0;
QDir dir;
string tmpstr;
vector<string> str_list;
while (getline(listfile, tmpstr)) {
int pos = tmpstr.find_first_of(" ");
str = tmpstr.substr(0, pos);
i++;
Mat image = imread(str);
Mat img_gray;
cvtColor(image, img_gray, CV_RGB2GRAY);
new_imagename = StringRepalceSub(str, "testImage", "pgmImage");
keyname = StringRepalceSub(str, "jpg", "key");
new_imagename = StringRepalceSub(new_imagename, "jpg", "pgm");
// keyname = StringRepalceSub(str, "png", "key");
// new_imagename = StringRepalceSub(new_imagename, "png", "pgm");
imwrite(new_imagename, img_gray);
keyfile << keyname << endl;
comm = dir.currentPath().toStdString() + "/bin/siftWin32.exe <" + new_imagename + " >" + keyname;
system(comm.c_str());
}
listfile.close();
keyfile.close();
}
void bundlerInWin::runbundler()
{
system("cls");
QDir dir;
string comm;
comm = dir.currentPath().toStdString() + "/bin/KeyMatchFull.exe result/list_keys.txt result/matches.init.txt";
system(comm.c_str());
comm = dir.currentPath().toStdString() + "/bin/bundler.exe result/list.txt --options_file result/options.txt";
system(comm.c_str());
}
void bundlerInWin::setLcdvalue(int value)
{
focal_length = slider->value();
paramedit->setValue(focal_length);
}
void bundlerInWin::setSlidervalue(int value)
{
focal_length = paramedit->value();
slider->setValue(focal_length);
}
main.cpp
#include "bundlerinwin.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
bundlerInWin w;
w.show();
return a.exec();
}
换种说法,就是:
Windows下调用bundler(有点麻烦,建议写个脚本或程序衔接中间的参数变换什么的)
bundler.exe list.txt –options_file options.txt
其中参数2是图像名称列表,参数4是配置信息(主要包括匹配点文件名matches.init.txt[由KeyMatchFull.exe生成]及其路径)
KeyMatchFull.exe list_keys.txt matches.init.txt
其中参数1是特征点的文件列表,特征点文件(xx.key)由siftWin32.exe生成,参数2是输出文件
siftWin32.exe
list.txt 文件样例
../mytest/test0000.jpg ../mytest/test0001.jpg ../mytest/test0002.jpg ../mytest/test0003.jpg ../mytest/test0004.jpg ../mytest/test0005.jpg
options.txt 文件样例(主要修改第一行第二个参数,其它可以不改)
–match_table ../result/matches.init.txt –output bundle.out –output_all bundle_ –output_dir bundle –variable_focal_length –use_focal_estimate –constrain_focal –constrain_focal_weight 0.0001 –estimate_distortion –run_bundle
list_keys.txt 文件样例
../mytest/test0000.key ../mytest/test0001.key ../mytest/test0002.key ../mytest/test0003.key ../mytest/test0004.key ../mytest/test0005.key