【三维重建】第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

https://blog.csdn.net/huqinweI987/article/details/119247523

代码实现:

// 根据框架,以实现将三维点云或网格保存为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是视差重建方法,光度一致性测量只是其中的一步。

posted @ 2022-09-22 17:14  乞力马扎罗山的雪  阅读(114)  评论(0编辑  收藏  举报