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 <xx1.pgm >xx1.key
其中参数2和3是图像名称(貌似涉及到pgm和jpg等的转换)这些.key文件需要在KeyMatchFull.exe的参数1中罗列
--------------------------------------------------------------------------
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
--------------------------------------------------------------------------