Channy's blog

//Description: 在cygwin下和不安装cygwin在windows下分别编译和运行Bundler

在cygwin下编译和运行Bundler

1-0 编译Bundler (在cygwin下)

(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

1-1 运行Bundler (在cygwin下)

  1. cd 到bundler目录
  2. mkdir result  存放输出结果
  3. cd result
  4. ../Runbundler.sh ../examples/kermit (注: ../examples/kermit指明用于进行多视角重建的图像所在目录)此时已经运行完Bundler, 在./bundle/bundle.out文件里有重建的稀疏点3D坐标和相机参数, 具体说明参见/bundler/readme.txt。这样/bundler会生成两个文件夹/bundle和/prepare。
  5. ../bin/Bundle2PMVS.exe prepare/list.txt bundle/bundle.out 此时生成了pmvs子目录, 编辑里边的prep_pmvs.sh(用到工具EditPlus 3,网上可以搜到), 指明BUNDLE_BIN_PATH路径来寻找RadialUndistort.exe和Bundle2Vis.exe。注意我们用的是Cygwin所以改BUNDLE_BIN_PATH要注意目录的格式,比如我的Bundler在E盘根目录,那么BUNDLER_BIN_PATH=/cygdrive/e/bundler/bin(地址不能有空格)
  6. ./pmvs/prep_pmvs.sh 在pmvs目下生成txt, visualize, models目录和bundle.rd.out, list.rd.txt, vis.dat, pmvs_options.txt文件, 这些都是PMVS2的输入。

1-2 CMVS-PMVS

将CMVS-PMVS-master\binariesWin-Linux\Win64-VS2010文件夹中的文件全部拷贝到之前的result文件夹目录下

打开cmd

  1. 进入bundler目录
  2. 进入bundler/result文件夹下(cd E:\bundler\result)
  3. 输入cmvs pmvs/
  4. 输入genOption pmvs/
  5. pmvs2 pmvs/ option-0000

这样,我们发现/pmvs/models/文件夹多了几个文件,其中*.ply文件为3D模型文件用下面的软件可以查看。

     vi   deploy.sh          
     :set fileformat=unix 
     :wq

不安装cygwin在windows下分别编译和运行Bundler

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.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


back