用照片进行三维模型重建
在元宇宙的世界里,需要有大量的3D模型。
而3D模型的数量,一直是困扰从2D到3D转型的拦路虎。
以游戏角色建模为例,这些角色背后是无数的雕刻师用996加班和一地的头发换来的。
很多技术同学听说过类似于3DMax和Maya这样的建模工具,不知道是不是了解ZBrush雕刻的过程:
雕刻只是第一步,针对每个具体的领域,还需要专门的工具来辅助。
比如要给人穿上衣服,我们需要有Marvelous Designer来帮我们生成布料这样复杂的效果。
裙子的建模要更复杂一些:
虽然据说3D建模的工具比原画稍好一点点,但是也是需要美术功底的,还需要耐心。
要想低成本制作3D模型,我们的思路还是利用图像算法和深度学习来进行三维重建。
SfM的原理与应用
传统的图像方法是基于多视觉几何原理,从运动中实现3D重建。其基本方法叫作Structure-from-Motion,简称SfM,它通过无时间序列的一系列2D图像来计算三维信息。
大致的流程如下图所示:
图像首先经过解析,然后进行比对,最后通过SfM算法形成一个点云。
openMVG 多视图几何库
我们概念少讲,直接上手实战。我们使用openMVG多视图几何库来使用SfM算法。MVG是Multiple View Geometry的缩写,就是多视图几何。
首先我们要编译openMVG的库。建议使用Ubuntu 18.04系统。
首先我们要编译一个线性代数库eigen。这个是openMVG的外部依赖,还不能通过apt install来安装。
sudo apt -y install git cmake libpng-dev libjpeg-dev libtiff-dev libglu1-mesa-dev
sudo apt -y install libboost-iostreams-dev libboost-program-options-dev libboost-system-dev libboost-serialization-dev
git clone https://gitlab.com/libeigen/eigen.git --branch 3.4
mkdir eigen_build && cd eigen_build
cmake ../eigen
make && sudo make install
下面编译安装openMVG库本身:
- 安装一堆图形库:
sudo apt install libpng-dev libjpeg-dev libtiff-dev libxxf86vm1 libxxf86vm-dev libxi-dev libxrandr-dev
- 安装graphviz:
sudo apt install graphviz
- 下载openMVG代码:
git clone --recursive https://github.com/openMVG/openMVG.git
- 创建openMVG_build目录:
mkdir openMVG_Build
- 转到openMVG_build目录:
cd openMVG_Build
- 生成编译配置文件:
cmake -DCMAKE_BUILD_TYPE=RELEASE ../openMVG/src/
- 编译:
make -j
- 安装:
sudo make install
下面我们就可以找个数据集做测试了。
比如我们使用这个:https://github.com/rperrot/ReconstructionDataSet
我们随便取一个,比如第一个AvignonHotelDesMonnaies,教皇城阿维尼翁的莫奈酒店。
由11张照片组成。
我们在openMVG_Build/software/SfM目录下执行:
python SfM_SequentialPipeline.py ~/workspace/ReconstructionDataSet/AvignonHotelDesMonnaies/ ~/workspace/result/
然后会生成result/reconstruction_global/SfMReconstruction_Report.html这个报告文件:
更直观的结果我们可以通过MeshLab软件打开result/reconstruction_global/cloud_and_poses.ply来查看SFM的结果。这就是传说中的点云。
我们再换一个城堡的数据集:https://github.com/openMVG/ImageDataset_SceauxCastle
命令跟上一个一样:
python SfM_SequentialPipeline.py ~/workspace/github/ImageDataset_SceauxCastle/images/ ~/workspace/castle
点云看起来是这个样子的:
OpenMVS 从点云到模型
有了点云还不够,我们还要继续将其变成3D模型。这时候我们需要另一个库openMVS.
- 模型格式转换
上一步我们openMVG生成了一个叫sfm_data.bin的文件,我们首先将其转换成openMVS需要的格式:
openMVG_main_openMVG2openMVS -i sfm_data.bin -o scene.mvs -d scene_undistorted_images
- 重建成密集点云
通过DensifyPointCloud工具来生成密集点云:
DensifyPointCloud scene.mvs
跟上面的openMVG生成的点云图一对比,是不是差别很明显呢?
- 粗网格重建
调用ReconstructMesh工具来对上一步生成的密集点云进行网格重建:
ReconstructMesh scene_dense.mvs
生成的效果如下:
- 网格细化
调用RefineMesh工具来进行网格细化:
RefineMesh scene_dense_mesh.mvs
细化之后效果如下:
- 网格纹理
最后一步,给网格加上纹理:
TextureMesh scene_dense_mesh_refine.mvs
这一步将生成scene_dense_mesh_refine_texture.glb,我们就大功告成了。
我们来看看最终生成的效果:
注意,纹理是存放在scene_dense_mesh_refine_texture.png中的,加载glb的时候要能够在同一目录下找到,否则找不
这个glb除了要引用图片做纹理之外,跟其它的没有什么不同。
我们写个网页加载它吧:
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-sky color="#1890ff"></a-sky>
<a-assets>
<a-asset-item id="glass" src="./c.glb"></a-asset-item>
</a-assets>
<a-entity position="0 0 -4" scale="40.0 40.0 40.0" rotation="0 180 180" gltf-model="#glass"></a-entity>
</a-scene>
</body>
</html>
显示出来的效果如下:
更多细节
大致的流程大家了解了之后,我们来进一步看一些细节。
openMVS库的编译
openMVS库用到的第三方库比openMVG要更多,主要有:
- Eigen
- Boost
- OpenCV
- CGAL
- VCGLib
- Ceres
- GLFW3
- 编译Eigen
首先装一系列依赖库:
sudo apt -y install git cmake libpng-dev libjpeg-dev libtiff-dev libglu1-mesa-dev
然后下载eigen的源代码,注意是在gitlab上的,github上已经不维护了。
git clone https://gitlab.com/libeigen/eigen.git --branch 3.4
接着就是cmake的标准过程了:
cd eigen
mkdir build
cd build
cmake ..
make
sudo make install
- 安装Boost, OpenCV, CGAL
sudo apt -y install libboost-iostreams-dev libboost-program-options-dev libboost-system-dev libboost-serialization-dev
sudo apt -y install libopencv-dev
sudo apt -y install libcgal-dev libcgal-qt5-dev
- 下载VCG源代码
git clone https://github.com/cdcseacave/VCG.git vcglib
最后编译时源码引入,不用编译
- 编译Ceres-solver
先安装库:
sudo apt -y install libatlas-base-dev libsuitesparse-dev
sudo apt install libgflags-dev
sudo apt install libgoogle-glog-dev
接着下载源代码:
git clone https://github.com/ceres-solver/ceres-solver
注意,2.1以上的版本使用了std::exclusive_scan,如果你用的gcc版本较老,比如gcc7,请checkout 2.1.0版本。
cmake编译还是老套路:
mkdir build
cd build
cmake ..
make
sudo make install
- 编译openMVS
如果前面都成功了,主要是库安装都OK的话,下面就可以编译openMVS了。
git clone https://github.com/cdcseacave/openMVS.git
mkdir build2
cd build2
cmake .. -DVCG_ROOT="$main_path/vcglib"
make -j
sudo make install
再来一遍openMVS的流程
MVG的过程其实分为7步:
- Intrinsics analysis
- Compute features
- Compute matching pairs
- Compute matches
- Filter matches
- Do Sequential/Incremental reconstruction
- Colorize Structure
其中最重要的是第一步,先会做一次预测,如果不能用的话就把相关图片排除掉。比如ReconstructionDataSet/AvignonHotelDesMonnaies 这个数据集有11张图片,经过分析后可能只有7张可用。
listed #File(s): 11
usable #File(s) listed in sfm_data: 11
usable #Intrinsic(s) listed in sfm_data: 7
我们这次挑战下一个难度看起来更高的,一片大沙漠。大家可以到 https://github.com/openMVG/Image_datasets 下载,在 Image_datasets/Drone/Palm_Desert_Micro 中。
如前所述,在openMVG/build/software/SfM下运行:
python SfM_SequentialPipeline.py ~/workspace/Image_datasets/Drone/Palm_Desert_Micro/ ~/workspace/desert
生成的效果如下:
第二步,将openMVG的格式转换成openMVS的格式:
openMVG_main_openMVG2openMVS -i sfm_data.bin -o scene.mvs -d scene_undistorted_images
第三步,生成密集点云:
~/workspace/openMVS/openMVS_build/bin/DensifyPointCloud scene.mvs
这样有点地形起伏的意思了哈。
第四步,网格重建
~/workspace/openMVS/openMVS_build/bin/ReconstructMesh ./scene_dense.mvs
第五步,网络细化
~/workspace/openMVS/openMVS_build/bin/RefineMesh ./scene_dense_mesh.mvs
第六步,网络纹理
~/workspace/openMVS/openMVS_build/bin/TextureMesh ./scene_dense_mesh_refine.mvs
glb模型生成,大功告成!
完工之后的glb显示出来效果是这样的:
同样,加载时记得同目录下有scene_dense_mesh_refine_texture.png。
画廊
我们来看看默认参数下还原的一些场景的效果。