BundleFusion那些事儿

背景:前面几篇博客中写了很多关于BundleFusion的东西,主要包括bundlefusion的论文阅读笔记,.sens数据集的生成等,经过最近几天的工作,我对bundlefusion又有了新的技术积累,在这里整理一下,也算是理一下思路,然后开始新的工作。

1. 生成.sens文件

根据在https://graphics.stanford.edu/projects/bundlefusion/下载的.zip的数据集可知,一个数据集中包含,以frame-xxxxxx.color.png的彩色图像,有以frame-xxxxxx.depth.png命名的深度图像,以及,以frame-xxxxxx.pose.txt命名的位姿文件,该文件中存储的是一帧位姿,一个4x4的矩阵。如下图所示,所以首先你需要想办法得到这种标准格式的数据。我曾经把我使用kinectV2相机获取的深度图和彩色图对齐后的数据编辑为如下格式,所有的.pose.txt文件中我都写入单位阵。我还试着将TUM数据集和ICL-NUIM数据集编辑成下面这种格式,并且我将数据集提供的groundtruth写入到.pose.txt文件中,目的是想让bundlefusion按照groundtruth位姿来重建。由于数据集提供的groundtruth是用四元数表示的旋转,所以需要将四元数转换为旋转矩阵,由于我使用的是python脚本,这个是时候,scipy库就派上用场了,这里面有很多转换,包括,四元数,旋转矩阵,旋转向量,欧拉角之间的转换。

BundleFusion那些事儿_第1张图片

当然不要忘了,在目录的最后还有一个info.txt文件, 除了彩色图的尺寸,相机的内参数,要按照实际情况改写之后,还有很关键的一个参数就是m_depthShift,在BundleFusion官网上下载的数据集,info.txt中设置的m_depthShift =1000,而在我生成TUM和ICL的数据集时,这个值就得设置为10000,否则生成的数据集,重建不出来模型,具体的分析请阅读我的这篇博客,https://blog.csdn.net/weixin_38636815/article/details/107563959

BundleFusion那些事儿_第2张图片

 下面是我将ICL数据集整理成上述格式的python脚本

import numpy as np
from scipy.spatial.transform import Rotation as R
import associate
import os
import shutil

def copy_files(sourcefile):
    rgb_path = sourcefile+"rgb/"
    depth_path = sourcefile + "depth/"
    bf_path = sourcefile + "bf_dataset/"
    print(rgb_path)
    print(depth_path)

    rgb_images = os.listdir(rgb_path)
    depth_images = os.listdir(depth_path)
    rgb_int = []
    depth_int = []
    for rgb in rgb_images:
        rgb = rgb.replace('.png', '')
        # print(rgb)
        rgb_int.append(int(rgb))
    for depth in depth_images:
        depth = depth.replace('.png', '')
        depth_int.append(int(depth))

    rgb_id = 0
    for rgb_name in sorted(rgb_int):
        print("frame-" + str(rgb_id).zfill(6) + ".color.png" + " is writing into bf_dataset" )
        shutil.copyfile(rgb_path + "/" + str(rgb_name) + ".png",
                        bf_path + "frame-" + str(rgb_id).zfill(6) + ".color.png")
        rgb_id += 1

    depth_id = 0
    for depth_name in sorted(depth_int):
        print("frame-" + str(depth_id).zfill(6) + ".depth.png" + " is writing into bf_dataset")
        shutil.copyfile(depth_path + "/" + str(depth_name) + ".png",
                        bf_path + "frame-" + str(depth_id).zfill(6) + ".depth.png")
        depth_id += 1

    """
    transform quaternion into rotation and write them into separated pose files
    """
    gt_file = open(sourcefile + "livingRoom3n.gt.freiburg")
    gt_data =gt_file.read()
    lines = gt_data.replace(",", " ").replace("\t", " ").split("\n")
    positions = []
    quaternions = []
    lines_data = []
    for line in lines:
        line_data = []
        if len(line) > 0 and line[0] != '#':
            for v in line.split(' '):
                line_data.append(v)
            lines_data.append(line_data)
            # print(line_data)
    share_vect = np.array([0, 0, 0, 1], dtype=np.float32)[np.newaxis, :]
    pose_id = 0
    for line in lines_data:
        single_position = np.array([line[1], line[2], line[3]], dtype=np.float32)[:, np.newaxis]
        single_quaternion = np.array([line[4], line[5], line[6], line[7]], dtype=np.float32)
        positions.append(single_position)
        quaternions.append(single_quaternion)

        rotation = R.from_quat(single_quaternion)
        m34 = np.concatenate((rotation.as_matrix(), single_position), axis=1)
        m44 = np.concatenate((m34, share_vect), axis=0)
        print("frame-" + str(pose_id).zfill(6) + ".pose.txt" + "is writing into bf_dataset")
        fp = open(bf_path + "frame-" + str(pose_id).zfill(6) + ".pose.txt", 'w')
        for row in m44:
            # fp.write(" ".join(row) + "\n")
            fp.write(' '.join(str(i) for i in row) + '\n')
        pose_id += 1
    print(len(positions))
    print(len(quaternions))

if __name__ == '__main__':
    print('test')
    # copy_files("/media/yunlei/YL/DATASETS/ICL_DATABASE/lr_kt0/living_room_traj0_frei_png/")
    # copy_files("/media/yunlei/YL/DATASETS/ICL_DATABASE/lr_kt1/living_room_traj1n_frei_png/")
    # copy_files("/media/yunlei/YL/DATASETS/ICL_DATABASE/lr_kt2/living_room_traj2n_frei_png/")
    copy_files("/media/yunlei/YL/DATASETS/ICL_DATABASE/lr_kt3/living_room_traj3n_frei_png/")

假设现在已经 整理出的规范的文件格式,现在我们需要一个工具,将彩色图,深度图和位姿数据写入到.sens文件中,在BundleFusion工程中有实现将图像写入到.sens文件的函数,只需要用下面的mian函数替换你原工程 BundleFusion/FriedLiver/Source下FriedLiver.cpp中的主函数,在新的主函数中写入你自己数据的路径和名称,使用ctrl+F5的方式在vs2013中运行此时的工程,可以在saveToFile函数中加上一些打印信息,这样可以更清楚的看到数据的生成状态。不出意外的话上述方式就可以成功生成.sens文件。

int main()
{
	ml::SensorData sd;
	sd.initDefault(640, 480, 640, 480, sd.m_calibrationColor, sd.m_calibrationDepth);
	sd.loadFromImages("E:/DATASETS/ICL_DATABASE/lr_kt1/living_room_traj1n_frei_png/bf_dataset", "frame-", "png");
	sd.saveToFile("E:/DATASETS/ICL_DATABASE/lr_kt1/living_room_traj1n_frei_png.sens");
	std::cout << "generate sens data" << std::endl;
	return 0;
}

二、使用自己生成的.sens文件运行BundleFusion

如果你想通过ctrl+F5的方式运行代码,那么你就修改,位于BundleFusion-master/FriedLiver下的zParametersDefault.txt下的s_binaryDumpSensorFile,当然你也可以先在vs2013上编译工程,然后双击 BundleFusion-master/FriedLiver/x64/Release下的FriedLiver.exe可执行文件,这个时候你需要修改,FriedLiver.exe同目录下的zParametersDefault.txt文件中的s_binaryDumpSensorFile变量。两个配置文件中的其他一些参数也要调整,尤其是有关图像的宽度和高度的变量,要根据你数据集的实际大小来修改。需要注意的是,在zParametersBundingDefault.txt文件中的s_downsampledWidth和s_downsampledHeight这两变量的值设置不当,会导致系统很容易跟踪失败,大面积的跟踪失败会导致重建的模型不完整。

如果不出什么意外,自己生成的数据集就可以在bundlefusion上运行了。

 

 

你可能感兴趣的:(机器视觉,稠密重建)