ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

开源三维重建实战:从COLMAP稀疏重建到OpenMVS稠密Mesh全流程

开源三维重建实战:从COLMAP稀疏重建到OpenMVS稠密Mesh全流程 1. 项目概述与整体思路拆解1.1 为什么选择COLMAP加OpenMVS这条技术路线在做三维重建这件事上业内可选的技术路线其实不少比如直接用商用的ContextCapture、Pix4D或者开源界的COLMAP、OpenMVS、Meshroom、AliceVision再算上传统激光扫描的方案。我的建议很直接如果你要的是“可控、可定制、能学到底层原理同时不想花几十万买商业软件授权”的方案COLMAP加OpenMVS是目前开源生态里最完整、文档最全、社区最大的一条组合拳。为什么这么说先说COLMAP。它负责从一组普通的二维照片里恢复出相机的位姿和场景的稀疏点云也就是运动恢复结构Structure from MotionSfM这一环。相机的内外参数、每张照片拍到的位置朝向全靠它算出来。这一环是后续一切重建的基础基础不牢后面全部拉胯。然后是OpenMVS。它拿着COLMAP给出的稀疏重建结果做后续的稠密点云生成、Mesh网格重建、模型细化与纹理贴图。这个管线几乎是专门为“从稀疏结果到可用模型”设计的每一步都有对应的工具DensifyPointCloud、ReconstructMesh、RefineMesh、TextureMesh。它生成的Mesh模型可以导出成OBJ、PLY等通用格式直接进入3ds Max、Blender、Unity、UE或者其他下游工具。这两者衔接得非常流畅。COLMAP的导出结果特别是稀疏重建后的模型文件可以直接被OpenMVS读进去形成一个“照片进来带纹理的Mesh出来”的标准流水线。对初学者来说这套流程最大的好处是每一步都看得见、摸得着中间出了问题你知道去哪一步排查。不像某些商业软件点一个按钮等半天给你一个结果黑盒得厉害。我见过不少人问“到底用COLMAP还是OpenMVS是不是选一个就够了”。实际上这两者根本不是替代关系而是上下游配合关系。COLMAP解决“照片之间的关系”OpenMVS解决“三维空间里到底长什么样”。少了谁都不完整当然如果你只想要稀疏点云、不追求完整Mesh单独跑COLMAP也够但想做高精度的Mesh模型这套组合基本是开源默认答案。1.2 整个重建流程的全局视图整体流程我用一张“思维地图”来理解避免了踩到顺序问题第一步是数据采集。这部分虽然听起来不入技术门但实际对结果的影响超过很多人想象。第二步是COLMAP的稀疏重建内部包含特征提取、特征匹配、增量式三维重建、Bundle Adjustment光束法平差优化。第三步是把COLMAP的结果导入OpenMVS跑稠密重建生成稠密点云。第四步是由稠密点云生成三角形网格Mesh。这步可以选择是否细化技术细节上OpenMVS的ReconstructMesh用的是Delaunay三角化和图割优化的思路。第五步是纹理贴图把原始照片的颜色、纹理映射到Mesh表面让模型从灰模变成有真实观感的完整模型。最后是导出与后处理比如导出OBJ/PLY然后在Blender或者Meshlab中做清理、补洞、简化等操作。这个流程你在敲第一行命令之前就要心里有数。因为后面每一步的参数调整、问题排查其实都是在围绕这条主线的某个环节找毛病。比如你发现Mesh有很多空洞大概率是稠密点云密度不够你发现纹理有模糊错位大概率是输入图像重叠率不足或者光照不一致。这些问题对应的修复点都在流程的“上游”先弄明白整体架构才不会在下游瞎折腾。这里也要提前提醒一句这套流程吃硬件尤其是OpenMVS的稠密重建和纹理映射阶段CPU、GPU、内存、硬盘都会有压力。数据量一旦上到几百张照片显存不够直接闪退是常见事。做之前先评估一下自己的电脑配置别等到跑到一半崩溃再来问为什么。2. 环境准备与工具链部署2.1 Windows环境下的安装细节在国内做数字媒体、测绘、建筑信息化、工业设计的人用Windows的还是占大多数。好消息是COLMAP和OpenMVS在Windows下都有比较成熟的安装方式不需要从源码折腾太多。先说COLMAP。官方GitHub的Release页面直接提供预编译的Windows版本下载解压就能用。它的主程序包括一个图形界面版和纯命令行版本两者内核是一样的。对新手来说第一次跑建议用GUI版本因为能看到每张照片的特征点提取情况、匹配结果和重建过程的实时状态熟了之后再改用命令行批处理效率会高不少。但这里有个坑官方预编译的COLMAP依赖CUDA如果电脑上没有装NVIDIA显卡驱动和CUDA运行时打开软件会提示找不到CUDA设备。即便你只想用CPU跑也建议把CUDA Toolkit装好因为OpenMVS那边同样依赖GPU加速。版本上建议CUDA 11.x系列兼容性相对稳定太新的CUDA 12.x在某些老版本OpenMVS上会报编译兼容问题。再讲OpenMVS。它没有官方Windows预编译包一般是两个来源一是GitHub上热心人编译好的二进制包二是用vcpkg或源码自己编。对绝大多数用户我建议直接找编译好的发行版省时省力。把OpenMVS的bin目录加进系统PATH环境变量命令行里就能直接敲DensifyPointCloud、ReconstructMesh这类命令了。还有个小建议把所有工具集中放在一个目录比如D:\3DRecon\tools下面分colmap和openmvs两个子目录再配一个workspace目录专门放某个重建项目的照片、数据库、中间文件和输出结果。项目一多这种“工具与工作区分离”的目录习惯会帮你省下大量找文件的时间也避免不同项目的数据互相污染。2.2 Linux环境下的源码编译如果是在Linux服务器或者开发机上跑尤其是做批量处理、自动化管线源码编译是更平滑的方案。Ubuntu 20.04/22.04是主流选择。依赖项包括CMake、Boost、Eigen、OpenCV、Ceres Solver、Cairo、SQLite等。源码编译的顺序建议是先装依赖再编译COLMAP然后编译OpenMVS。因为OpenMVS编译时要用到COLMAP的部分源码库主要是读取其模型格式和相机参数的部分所以两者的版本需要匹配。我给一个比较稳的版本组合COLMAP 3.8/3.9 配 OpenMVS 2.1/2.2这两个组合我在多个项目里验证过兼容性没问题。编译步骤大致是这样# 安装基础依赖 sudo apt-get update sudo apt-get install -y \ git cmake build-essential \ libboost-all-dev libeigen3-dev \ libopencv-dev libcgal-dev \ libceres-dev libsqlite3-dev \ libgflags-dev libgoogle-glog-dev \ libmetis-dev libgl1-mesa-dev \ libxi-dev libxmu-dev freeglut3-dev # 编译COLMAP git clone https://github.com/colmap/colmap.git cd colmap mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease -DCUDA_ENABLEDON make -j$(nproc) sudo make install编译OpenMVS时关键是要让它找到COLMAP的头文件和库。如果安装路径不是标准位置需要手动指定CMAKE_PREFIX_PATH。这一步报错率比较高常见的是找不到COLMAP的colmap/controllers/option_manager.h之类的头文件说明路径没指定对。我的经验是直接在OpenMVS的CMake配置里把COLMAP_INCLUDE_DIR和COLMAP_LIBRARY这两个变量显式指出来比依赖自动查找要省心。编译耗时看机器性能一般30分钟到两个小时不等耐心等就行这里的坑比Windows少因为Linux的依赖树相对干净不会出现DLL地狱。3. 图像采集决定Mesh精度的隐形关键3.1 拍摄规划与重叠率的控制很多人第一次做重建拿个手机随手对物体一顿拍然后丢进COLMAP里一跑发现特征点匹配稀稀拉拉、重建残缺不全。这不是软件不行是照片没拍好。图像采集的质量直接决定上游——SfM能恢复出多少有效视角进而决定稠密点云和Mesh的完整度。先说重叠率。相邻两张照片的视野重叠最好保持在60%到80%之间。低于60%特征点匹配数量不足相机的相对位姿估计容易失败高于90%意义不大还白白增加计算量。这个比例你不需要精确测量拍摄时大概保证每往前移动一段距离上一张照片边缘的内容还在下一张照片中心区域附近就差不多了。再说拍摄方式。对中小物体我推荐“环形围绕加分层俯拍”的组合。先绕物体一圈拍一圈水平视角然后从物体上方45度角再绕一圈最后补拍顶面和底面如果底面可见的话。对大型建筑或场景则采用“网格化巡查”的方式每条航线平行推进相邻轨迹间距控制好。还有一点容易被忽略焦距固定。拍摄过程中绝对不要变焦。不管你用手机还是微单把焦距锁死在某一个值手动对焦到物体主体上然后只移动设备位置来改变视角。变焦会导致相机内参变化对SfM来说等于每张照片都是不同的相机会给参数估计带来巨大麻烦。虽然COLMAP支持每张照片独立标定相机内参即“不同相机”模式但那样会显著降低重建稳定性。能用相同的相机参数一定优先用相同的。3.2 光照控制与相机参数设置光照是影响重建质量的另一个大变量。理想的光照是均匀、柔和、无大面积高光、无明显阴影。室外拍摄尽量选阴天或多云天气这时候光线最均匀物体表面的纹理细节最清楚。晴天硬光会导致物体一侧过曝、一侧死黑特征提取在过曝和死黑区域基本失效。室内拍摄或棚拍时建议用两个光源从左右两侧45度方向打光减弱单侧阴影。如果物体表面反光强比如金属、陶瓷、塑料上光面可以考虑使用偏振镜片消除反射或者干脆给物体表面喷涂消光剂——工业上做逆向工程经常这么干一次性喷剂用完可以洗掉。注意高光区域在照片里其实是“没有纹理”的白色区域特征点提不出来稠密匹配也会出问题。相机参数方面ISO尽量低100到200噪点会破坏特征提取。快门速度保证不糊手持拍摄时的安全快门要满足光圈建议在f/5.6到f/11之间保证景深足够。拍小物体的时候景深特别容易不够前后虚化会导致特征点定位不准。我自己的习惯是先用RAW格式拍一遍然后在后处理里统一调色、增加微对比度再导出为高质量JPEG。这样能最大限度保留阴影区域的细节同时压缩文件体积加速处理流程。RAW格式本身COLMAP也能读但速度慢很多而且需要额外解码库不推荐直接喂RAW。3.3 不同拍摄对象的针对性建议拍摄对象大致分三类室内小物体、室外建筑、地形级场景。它们的拍摄策略差异很大。室内小物体比如一件手办、一个工业零件、一块化石最好放在转台上拍摄相机固定物体旋转。这样能保证拍摄距离稳定相机位置固定绕物体转一圈就能拿到很均匀的视角覆盖。转台拍摄时要注意背景尽量干净纯色太花哨的背景会引入大量无关特征点加重匹配负担。我在做文物数字化时习惯铺一张灰色背景布效果很好。室外建筑比如一栋老宅、一座雕塑绕着建筑走一圈每走几步拍一张——这里的关键是“分层”。单层环绕拍出来的照片只覆盖了建筑的某一个高度视角重建出的Mesh在屋檐、二层窗户这些地方往往是空的。正确做法是每绕一圈换一个仰角从平视、仰视到俯视至少三层起步。高层建筑还要考虑无人机航拍补天顶视角。地形级场景比如矿山、遗址、大范围地貌一般靠无人机航测。航线使用“井字形”或者“航线加航线垂直接缝”的方式保证旁向重叠率不低于60%航向重叠率不低于75%。控制点GCP虽然对纯视觉重建不是必需的但如果模型要落到真实地理坐标就得布设并测量控制点。说到底拍摄环节多花半小时后面处理少花两小时模型质量还更高。数据采集偷的懒最终都会以低质量Mesh和大量后期修补的形式还回来。4. COLMAP稀疏重建实操解析4.1 特征提取与匹配的参数策略图像准备好正式进入COLMAP流程。COLMAP的完整管线分三步特征提取feature extractor、特征匹配feature matcher、增量式重建mapper。每一步都有独立的命令行入口。先看特征提取。基本命令是colmap feature_extractor \ --database_path project.db \ --image_path images \ --ImageReader.camera_model PINHOLE \ --ImageReader.single_camera 1 \ --SiftExtraction.max_image_size 4000 \ --SiftExtraction.max_num_features 16000camera_model指定相机模型。如果你用了固定焦距、照片又没带畸变信息用PINHOLE针孔模型最稳。为更精确可以选用OPENCV模型它会同时估计径向和切向畸变但参数更复杂、需要更多匹配点支撑。手机照片一般用OPENCV或PINHOLE都行前者更推荐因为手机镜头畸变不可无视。single_camera 1表示所有照片来自同一个物理相机极端重要。它告诉COLMAP所有图像共享同一套内参这样求解时参数数量大幅减少更容易收敛。除非你确实是用多台不同相机拍的混合数据集否则务必开启。max_image_size和max_num_features控制计算规模。照片分辨率太高比如5千万像素的单反照片直接全尺寸跑速度和内存都会爆炸。实践上我一般限制在3000到4000像素这对绝大多数重建项目足够用。特征点上限我一般设16000低于这个数照片多时会漏特征高于这个数计算时间涨得厉害而精度提升有限。再看特征匹配。常见两种策略穷举匹配exhaustive_matcher和顺序匹配sequential_matcher。# 无序照片集比如环绕拍摄 colmap exhaustive_matcher \ --database_path project.db \ --SiftMatching.num_threads 8 \ --SiftMatching.max_ratio 0.8 \ --SiftMatching.max_distance 0.7 # 有序照片集比如无人机航线拍摄 colmap sequential_matcher \ --database_path project.db \ --SequentialMatching.overlap 20无序数据集照片之间没有明确先后顺序用穷举匹配所有照片两两之间都尝试匹配精度最高算力最贵。对几百张照片的文件量还能接受上千张就会非常吃力这时可以用vocab_tree_matcher视觉词袋匹配来加速。顺序匹配用于照片按拍摄顺序排列的场景只匹配相邻的若干张速度极快适合无人机航测那样规律的序列影像。4.2 增量式重建的启动与参数调优匹配完成后进入核心的稀疏重建阶段命令是colmap mapper \ --database_path project.db \ --image_path images \ --output_path sparse \ --Mapper.min_num_matches 15 \ --Mapper.ba_global_function_tolerance 1e-6 \ --Mapper.ba_global_max_refinements 20这套流程的原理是增量式SfM先找一对匹配质量最好的图像作为种子恢复出初始的三维几何和相机位姿然后不断加入新图像每次加入后做一次Bundle AdjustmentBA来优化所有相机参数与三维点坐标重复直到所有可用图像都被注册。min_num_matches是每个图像对需要满足的最小匹配数门槛。默认15在多数情况下没问题图像质量差、纹理匮乏的数据可以适当降到10但低于这个值重建结果噪声会很大。跑完mapper用sparse/0目录下的模型检查注册情况。关键看两点注册成功的图像数量占比以及稀疏点云数量。如果某张照片一直注册不进去多半是拍摄时过度模糊、角度太刁钻或者光照突变。把问题照片删掉重跑比调参救回来更省时间。调优方面ba_global_function_tolerance控制BA收敛精度ba_global_max_refinements控制最大迭代次数。默认值已经比较合理不需要轻易改动。真正影响重建成败的是“图像是否成功注册”而不是那点迭代次数。我见过不少人在参数上死磕最后发现是数据本身的问题典型的捡芝麻丢西瓜。4.3 模型导出与质量评估稀疏重建的结果输出在sparse/0这个文件夹里包含三个关键文件cameras.bin相机内参、images.bin每张照片的位姿、points3D.bin三维点云。在把结果交给OpenMVS之前需要将二进制格式转换为文本或者场景文件# 导出相机和点云模型供外部检查 colmap model_converter \ --input_path sparse/0 \ --output_path sparse/0_text \ --output_type TXT # 导出为OpenMVS可用的场景通过图像位姿注册 colmap model_converter \ --input_path sparse/0 \ --output_path scene.ply \ --output_type PLY在进入OpenMVS之前有必要用GUI或Meshlab看一眼稀疏点云。如果点云结构松散、大块缺失说明图像匹配漏检严重后续Mesh也注定不完整。如果整体轮廓清晰、点云分布均匀恭喜可以放心往下走。另外一个评估指标是平均重投影误差mean reprojection errorCOLMAP的日志里会输出这个值。经验上平均重投影误差在1像素以内的项目说明标定和重建质量非常理想超过3像素就要警惕了这往往意味着相机模型选择不对或者照片本身质量太差。5. OpenMVS稠密重建与Mesh生成实战5.1 场景导入与稠密重建把COLMAP的结果导入OpenMVS需要先生成OpenMVS的工程文件.mvs格式。推荐的做法是使用OpenMVS自带的导入工具直接把COLMAP输出文件夹作为输入InterfaceCOLMAP \ --working-folder . \ --input-file sparse/0 \ --output-file scene.mvs这一步本质是把COLMAP算出的相机内参、位姿和图像列表转换整理成OpenMVS自己的数据结构。执行成功后会生成scene.mvs文件里面记录了所有图像的路径和对应位姿。稠密重建是最耗时的环节命令是DensifyPointCloud \ --working-folder . \ --input-file scene.mvs \ --resolution-level 1 \ --number-views-fused 3 \ --min-pixel-angle 1.0 \ --process-priority lowresolution-level是图像降采样级别1表示原始分辨率2表示降一半分辨率。对高精度模型用1数据量巨大时先用2跑一遍看整体效果再对局部区域用1精修这是省时间的好策略。number-views-fused是融合多少张图片的深度图来生成一个三维点。数值越高点越密也越慢推荐3到5之间。min-pixel-angle控制深度图融合时对视角差异的最低要求值越小对噪声越敏感建议1.0到2.0。稠密重建的原理再说透一点它对每张照片计算一张深度图即每个像素对应的三维点到相机中心的距离。然后用多视角的深度图做一致性检验和融合剔除误匹配点生成最终的点云。这个环节非常消耗显存处理200张全分辨率图像时8GB显存可能不够必要时调低resolution-level或分批处理。5.2 从点云到封闭Mesh的关键步骤拿到稠密点云后下一步是生成Mesh网格。OpenMVS的ReconstructMesh是一个半自动过程先用Delaunay四面体化把点云包围的空间切成很多四面体单元然后用图割优化决定哪些单元属于表面内部、哪些属于外部最终提取出等值面作为Mesh。ReconstructMesh \ --working-folder . \ --input-file scene_dense.mvs \ --resolution-level 1 \ --min-cluster-size 10 \ --smooth-iterations 2min-cluster-size用于清除面积过小的孤立网格碎片值越小保留细节越多但噪声碎片也会更多。处理有大量细碎结构的物体时设小一些处理平整建筑表面时设大一些通常5到20之间调整。smooth-iterations是网格平滑迭代次数默认2次迭代过多会抹掉表面细节。这一步输出的是一个“多块”的Mesh——同一场景可能被分成若干个连通分量。OpenMVS会把这些块合并成一个完整模型scene_dense_mesh.mvs用Meshlab打开就能看到白色或灰色的模型表面。生成Mesh后还有一个可选但非常推荐的步骤RefineMesh。它会在保持拓扑结构不变的前提下通过多视角光度一致性优化顶点的精确位置把Mesh几何质量往上拉一个档次。我一般在纹理贴图前先跑一次RefineMesh不会有坏处。RefineMesh \ --working-folder . \ --input-file scene_dense_mesh.mvs \ --resolution-level 25.3 纹理贴图的高质量处理技巧最后一步是纹理贴图这也是让Mesh从“灰模”变成“实景模型”的关键环节。TextureMesh \ --working-folder . \ --input-file scene_dense_refined.mvs \ --export-type obj \ --texture-size 8192 \ --outlier-threshold 0.1texture-size决定纹理图集的大小越大纹理保留细节越多、文件也越大。对一般项目8192够用追求极致细节可以设16384但要确保显存够吃。export-type obj导出OBJ格式附带Mtl材质文件和纹理贴图是下游兼容性最好的选择。纹理贴图的原理是Mesh上每个三角面片要确定用哪几张原始照片的哪个区域来上色。OpenMVS会计算面片在各个视角下的可见性与质量分数选择纹理信息最清晰、视角最垂直的那张照片作为贴图来源。outlier-threshold用于剔除与多数视角颜色差异过大的异常面片防止纹理颜色异常跳变。逻辑上这里最影响纹理结果的因素是光照一致性。如果原始照片在不同角度下光照差异过大纹理映射时相邻面片会呈现肉眼可见的亮暗分界。这个在拍摄阶段就要控制好后期很难完美修复。虽然可以用图像增强算法做拉普拉斯融合之类操作但治标不治本。6. 常见问题与排查技巧实录6.1 稀疏重建阶段的典型故障问题一图像注册失败率极高。表现为COLMAP mapper跑完大量图像处于未注册状态点云稀稀拉拉。排查思路首先是看照片质量——模糊、过曝、无纹理区域占比过高的照片果断删掉其次看拍摄路径——如果相邻照片之间重叠率低于一半重建算法根本找不到足够的关联点这种情况只能重拍或补拍。问题二特征匹配数量充足但BA发散。这种更棘手通常发生在相机内参初始化明显错误时。比如照片是手机拍的却指定了SIMPLE_PINHOLE这样的简化模型畸变校正无从谈起。解决方案是换用更灵活的相机模型比如OPENCV或FULL_OPENCV同时开启single_camera 0让COLMAP为每张照片单独估计内参。虽然这样变量更多但对混合机型的数据集来说更合理。问题三重建成功但坐标系扭曲严重点云弯向一侧。多半是数据存在“弱几何条件”比如所有拍摄角度过于接近同一平面。解决方法是补拍更多侧视角度的照片或者引入已知尺寸的标定尺来约束尺度。6.2 OpenMVS运行崩溃与内存不足OpenMVS的DensifyPointCloud和TextureMesh是显存消耗大户崩溃原因绝大多数是显存不足。报错信息通常是CUDA out of memory或直接崩溃无提示。处理方案按优先级排列调低resolution-level为2或4这是最立竿见影的做法。调低number-views-fused从5降到3。减少输入图像数量分区块重建然后后期拼接。检查GPU驱动和CUDA版本是否匹配。驱动过老会导致OpenMVS调用CUDA失败同样表现为不明原因崩溃。CPU端内存也要留意稠密重建时OpenMVS会把整个图片集的位置信息和深度图缓存到内存。我遇到过64GB内存都被吃满的极端情况解决方案是换用更高resolution-level设定并且不要在同时开其他内存大户软件。6.3 Mesh质量和纹理效果的常见缺陷Mesh表面出现大块空洞。这是点云缺失直接导致的。修复方法第一步排查该区域对应的照片数量是否足够不足则补拍第二步检查该区域表面是否有反光或过曝如果有拍摄时加偏振镜或调整光照第三步可以用Meshlab的“Fill Holes”功能做后期补洞但这属于“修饰”而非“重建”对精度要求不高的场景可以接受。纹理出现局部模糊或重影。通常是该区域被多张照片覆盖但每张照片的视角和分辨率差异大OpenMVS在选图时犹豫不决。处理方式是提高outlier-threshold数值让算法更严格地筛选最优质的视角或者调整texture-size让纹理分辨率更充足。Mesh表面出现“阶梯状”锯齿。多发生在模型轮廓边界和点云密度不足有关系也和平滑参数有关。可以尝试把ReconstructMesh里的smooth-iterations适当调高或者对点云先做一次Statistical Outlier Removal再重建Mesh。最后说一个很多人踩过的坑OpenMVS输出的OBJ文件带Mtl和纹理图片整个文件集要放在同一个文件夹下移动。只拷贝OBJ而漏了纹理图片在Blender里打开就是一片灰模新手会以为是导出失败实际只是路径问题。写在最后的经验谈这套COLMAP加OpenMVS的流程我前前后后跑过几十个项目从几十张照片的小物件到上千张照片的历史建筑都有。最大的体会是三维重建的瓶颈往往不在算法参数而在数据质量。你把拍摄这步做好了后面所有环节都是顺理成章的事拍得一塌糊涂再折腾参数也只是在垃圾进垃圾出的循环里打转。第二个体会是循序渐进地调参。别一上来就追求“全分辨率加最高配置”那只会让排错变得更难。先用降采样快速跑通整个流程确认每一个环节都能正常出结果再逐步提高精度、增加数据量。这个习惯能帮你省下大量排错时间尤其在处理大项目时几乎是必须的策略。另外建议养成保留中间结果的习惯。COLMAP出来的稀疏点云、OpenMVS的稠密点云、重建的Mesh、纹理贴图后的最终模型每个阶段单独存一份。因为你可能会对某个环节不满意想重跑有中间结果就不需要从头再来这对动辄跑几个小时的流程来说非常重要。这套管线不难但每一步都值得认真对待。
返回列表