COLMAP+OPENMVS进行三维重建

COLMAP+OPENMVS进行三维重建

1、COLMAP安装

​ 只需要在windows下安装已经编译好的可执行文件就行,还可以使用命令行,但是命令行不太好用,用UI界面转换比较方便。

github地址:

colmap/README.md at main · colmap/colmap · GitHub

将解压的COLMAP的根目录添加到系统环境变量中,可以使用cmd或者powershell完成

2、OPENMVS安装

OpenMVS GitHub网站

GitHub - cdcseacave/openMVS: open Multi-View Stereo reconstruction library

第一种方法,在Ubuntu中,最快捷的方法就是使用docker镜像,省去安装各种库的麻烦,前提是拉取docker镜像时需要使用国内镜像,使用代理也不太管用。

具体步骤:

1、ubuntu下创建一个/etc/docker/daemon.json文件。填入以下信息

{
    "registry-mirrors": [
        "https://docker.m.daocloud.io",
        "https://dockerproxy.com",
        "https://docker.mirrors.ustc.edu.cn",
        "https://docker.nju.edu.cn",
        "https://do.nark.eu.org"
    ]
}

重启docker服务,使用纯ubuntu系统可以执行

systemctl restart docker 

使用wsl子系统,由于子系统中systemctl 不可用,使用service可以重启。

service docker restart 

2、拉取openmvs镜像

docker pull openmvs/openmvs-ubuntu

第二种方法,下载编译好的windows版本,将解压的openmvs根目录添加到系统环境变量中可以在CMD或者powershell中通过命令行执行openmvs的运行。

Releases · cdcseacave/openMVS (github.com)

3、COLMAP重建得到稠密点云

新建一个文件夹,在其中新建images文件夹,以及一个Database.db的空文件,注意文件路径不要出现中文。images文件夹中放入需要重建的图片,图片越多重建时间越长,图片过少可能会重建失败.

自建数据集要求:

尽量使用单反相机或专业数码相机进行数据采集,如果要用手机进行采集,请使用单摄像头的手机进行数据采集。
尽量选择纹理丰富的外界环境进行数据采集,避免玻璃围墙、瓷砖和打蜡地板等强反光材料环境
尽量选择光照明亮,且光照条件变化不剧烈的环境,最好选择室内环境。如室内客厅,开启客厅大灯进行灯光补偿。
尽量围绕重建物体或环境采集较多的影像,且在采集过程中控制快门速度,避免模糊。

打开colmap程序(COLMAP.bat),点击File-New Project,在Database栏点击open,选择刚才新建的Database.db文件,在Images栏选择刚才新建的存放图片的images文件夹,点击save保存。

点击Processing-Feature Extraction,默认参数即可,点击Extract,等待程序运行完毕可看到右侧有log信息输出。

点击Processing-Feature matching,默认参数即可,点击Run,等待程序运行完毕可看到右侧有log信息输出。

点击Reconstruncion-Start reconstruction,等待执行完毕,即可得到重建的结果。

在之前images的同级目录下,新建一个文件夹dense。点击Reconstruncion-Dense reconstrction,点击select,选择刚才新建的dense文件夹用来保存稠密点云结果。依次点击Undistorion、Stereo、Fusion,执行完毕。

在程序中点击File-export model as txt,选择dense文件夹下的sparse文件夹(由于openmvs支支持txt格式的,所以需要将重建的文件转成txt文件) 软件自带的转换工具有bug,使用以下python代码实现转换功能。

import os
import collections
import numpy as np
import struct
import argparse
 
 
CameraModel = collections.namedtuple(
    "CameraModel", ["model_id", "model_name", "num_params"])
Camera = collections.namedtuple(
    "Camera", ["id", "model", "width", "height", "params"])
BaseImage = collections.namedtuple(
    "Image", ["id", "qvec", "tvec", "camera_id", "name", "xys", "point3D_ids"])
Point3D = collections.namedtuple(
    "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"])
 
 
class Image(BaseImage):
    def qvec2rotmat(self):
        return qvec2rotmat(self.qvec)
 
 
CAMERA_MODELS = {
   
    CameraModel(model_id=0, model_name="SIMPLE_PINHOLE", num_params=3),
    CameraModel(model_id=1, model_name="PINHOLE", num_params=4),
    CameraModel(model_id=2, model_name="SIMPLE_RADIAL", num_params=4),
    CameraModel(model_id=3, model_name="RADIAL", num_params=5),
    CameraModel(model_id=4, model_name="OPENCV", num_params=8),
    CameraModel(model_id=5, model_name="OPENCV_FISHEYE", num_params=8),
    CameraModel(model_id=6, model_name="FULL_OPENCV", num_params=12),
    CameraModel(model_id=7, model_name="FOV", num_params=5),
    CameraModel(model_id=8, model_name="SIMPLE_RADIAL_FISHEYE", num_params=4),
    CameraModel(model_id=9, model_name="RADIAL_FISHEYE", num_params=5),
    CameraModel(model_id=10, model_name="THIN_PRISM_FISHEYE", num_params=12)
}
CAMERA_MODEL_IDS = dict([(camera_model.model_id, camera_model)
                         for camera_model in CAMERA_MODELS])
CAMERA_MODEL_NAMES = dict([(camera_model.model_name, camera_model)
                           for camera_model in CAMERA_MODELS])
 
 
def read_next_bytes(fid, num_bytes, format_char_sequence, endian_character="<"):
    """Read and unpack the next bytes from a binary file.
    :param fid:
    :param num_bytes: Sum of combination of {2, 4, 8}, e.g. 2, 6, 16, 30, etc.
    :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}.
    :param endian_character: Any of {@, =, <, >, !}
    :return: Tuple of read and unpacked values.
    """
    data = fid.read(num_bytes)
    return struct.unpack(endian_character + format_char_sequence, data)
 
 
def write_next_bytes(fid, data, format_char_sequence, endian_character="<"):
    """pack and write to a binary file.
    :param fid:
    :param data: data to send, if multiple elements are sent at the same time,
    they should be encapsuled either in a list or a tuple
    :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}.
    should be the same length as the data list or tuple
    :param endian_character: Any of {@, =, <, >, !}
    """
    if isinstance(data, (list, tuple)):
        bytes = struct.pack(endian_character + format_char_sequence, *data)
    else:
        bytes = struct.pack(endian_character + format_char_sequence, data)
    fid.write(bytes)
 
 
def read_cameras_text(path):
    """
    see: src/base/reconstruction.cc
        void Reconstruction::WriteCamerasText(const std::string& path)
        void Reconstruction::ReadCamerasText(const std::string& path)
    """
    cameras = {
   }
    with open(path, "r") as fid:
        while True:
            line = fid.readline()
            if not line:
                break
            line = line.strip()
            if len(line) > 0 and line[0] != "#":
                elems = line.split()
                camera_id = int(elems[0])
                model = elems[1]
                width = int(elems[2])
                height = int(elems[3])
                params = np.array(tuple(map(float, elems[4:])))
                cameras[camera_id] = Camera(id=camera_id, model=model,
                                            width=width, height=height,
                                            params=params)
    return cameras
 
 
def read_cameras_binary(path_to_model_file):
    """
    see: src/base/reconstruction.cc
        void Reconstruction::WriteCamerasBinary(const std::string& path)
        void Reconstruction::ReadCamerasBinary(const std::string& path)
    """
    cameras = {
   }
    with open(path_to_model_file, "rb") as fid:
        num_cameras = read_next_bytes(fid, 8, "Q")[0]
        for _ in 
  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值