背景:前面几篇博客中写了很多关于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库就派上用场了,这里面有很多转换,包括,四元数,旋转矩阵,旋转向量,欧拉角之间的转换。
当然不要忘了,在目录的最后还有一个info.txt文件, 除了彩色图的尺寸,相机的内参数,要按照实际情况改写之后,还有很关键的一个参数就是m_depthShift,在BundleFusion官网上下载的数据集,info.txt中设置的m_depthShift =1000,而在我生成TUM和ICL的数据集时,这个值就得设置为10000,否则生成的数据集,重建不出来模型,具体的分析请阅读我的这篇博客,https://blog.csdn.net/weixin_38636815/article/details/107563959
下面是我将ICL数据集整理成上述格式的python脚本
import numpy as np
from scipy.spatial.transform import Rotation as R
import associate
import os
import shutildef 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 = 0for 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 += 1depth_id = 0for 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 = 0for 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 += 1print(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上运行了。