【三维重建】第1-2期作业 几何三维重建
问答题
1、编程
补全内容,以实现将三维点云或网格保存为obj格式。验证时候正确的方法是将生成的obj模型在meshlab中打开是否是三棱锥。
obj格式基础知识:
obj格式的说明该例子:
v
就是一个点,一共4个点,f
是由1、2、3、4四个顶点顺序组成的一个面。
具体含义解析:
- -0.58是第一个顶点的x坐标
- 0.84是y坐标
- 0是z坐标
四个点都没有z坐标,都是0,这里模型就刚好在x-y轴组成的平面上。
v -0.58 0.84 0
v 2.68 1.17 0
v 2.84 -2.03 0
v -1.92 -2.89 0
f 1 2 3 4
代码实现:
// 根据框架,以实现将三维点云或网格保存为obj格式,验证将生成的obj模型在meshlab中打开是否是三棱锥
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
// point3f
struct Point3f
{
float x;
float y;
float z;
Point3f(float x0, float y0, float z0) : x(x0), y(y0), z(z0) {}
};
// face(v0,v1,v2)
struct Face
{
int x;
int y;
int z;
Face(int x0, int y0, int z0) : x(x0), y(y0), z(z0) {}
};
// save pointcloud
bool save_pointcloud_obj(string name, vector<Point3f> points)
{
FILE *fpt = fopen(name.c_str(), "w");
// 判断保存路径是否有效
if (!fpt)
{
printf("Error: %s path is not exist!!!", name);
return false;
}
for (int i = 0; i < points.size(); i++)
{
// todo use fprintf
Point3f temp = points[i];
// obj中顶点标志位是V
fprintf(fpt, "v %f %f %f\n", temp.x, temp.y, temp.z);
// todo 结束
}
fclose(fpt);
return true;
}
bool save_mesh_obj(string name, vector<Point3f> points, vector<Face> faces)
{
FILE *fpt = fopen(name.c_str(), "w");
// 判断保存路径是否有效
if (!fpt)
{
printf("Error: %s path is not exist!!!", name);
return false;
}
// 保存点云
for (int i = 0; i < points.size(); i++)
{
// todo,use fprintf
Point3f temp = points[i];
fprintf(fpt, "v %f %f %f\n", temp.x, temp.y, temp.z);
// todo 结束
}
// 保存faces
for (int i = 0; i < faces.size(); i++)
{
// todo
Face temp = faces[i];
// face里面的顶点id是从0开始的,保存的时候要从1开始,故需要加1
// meshlab导出的obj face表示是 v0//v0 v1//v1 v2//v2
// 自己写的时候直接写face三个顶点也可以 v0 v1 v2 meshlab也是可以打开的
fprintf(fpt, "f %d %d %d\n", temp.x + 1, temp.y + 1, temp.z + 1);
// todo end
}
fclose(fpt);
return true;
}
// STEP
int main(int argc, char *argv[])
{
vector<Point3f> points;
vector<Face> faces;
// 生成一个四面体模型的四个顶点
points.push_back(Point3f(0, 0, 0)); // v0 id = 0
points.push_back(Point3f(10, 0, 0)); // v1 id = 1
points.push_back(Point3f(0, 10, 0)); // v2 id =2
points.push_back(Point3f(0, 0, 10)); // v2 id =3
save_pointcloud_obj("pointcloud.obj", points);
// 生成一个四面体模型的四个面
faces.push_back(Face(0, 1, 3)); // v0-v1-v3
faces.push_back(Face(0, 2, 1)); // v0-v2-v1
faces.push_back(Face(3, 2, 0)); // v3-v2-v0
faces.push_back(Face(3, 1, 2)); // v3-v1-v2
save_mesh_obj("mesh.obj", points, faces);
system("pause");
return 0;
}
问答题
2、计算视差图为什么需要对图像做极线校正,校正的好处?
三维重建是通过双目立体匹配实现的如图1,通过匹配空间中点在两个图像中的投影点,再根据三角关系得到P的Z值(意思是通过三角关系得到点P的深度值)。一般视差只有在图像行(列)对齐时才可计算即视差$ d = x_l - x_r $ 且与Z的关系是:$ Z = bf / d $。若行对齐需要对图像进行极线校正。
因为我们双目相机拍摄的时候实际情况下如下图a,两个图像做匹配时如我们图中蓝色箭头指示的匹配点那样,需要在全图中进行查找,但是如果我们对相机进行校正,使得他们成像面平行且对齐如下图b,匹配点在同一行。那么我们只需要在同行上查找,大大节约时间。因此,极线校正目的是对两幅图像的二维匹配搜索变成一维,节省计算量,排除虚假匹配点。
3、做立体匹配时,选择邻域帧时主要参考哪三个因素,为什么?如果我们的重建素材是视频序列,如何选择邻域帧更高效?
三个因素及原因:
- 共视点在两个图像的夹角,原因是:两个view的靠的越近,越不能提供一个足够大的baseline来重建高精度模型,因此,通过共视点夹角来间接判断两个view的baseline时候足够大。
- 在两个图像中分辨率的相似性,原因:两个图像的分辨率如果差别比较大,立体匹配时是有问题的。所以选择邻域帧,与当前帧分辨率是否一致也是一个重要的因素。
- 两个图像中覆盖的面积最小值,原因:重建时,图像的分辨率越高重建的效果越好,故以共视点覆盖的图像面积也作为重要参考条件。
如果是视频序列,选邻域帧只需要在选当前帧前后几帧中选择符合上面3个条件的帧即可。
选择题
4、属于光度一致性测量方式的是:NCC、Census、SAD。
SGM是视差重建方法,光度一致性测量只是其中的一步。