據(jù)集全流程指南:從拍攝到渲染的實(shí)操經(jīng)驗(yàn))
我自己的3DGS項(xiàng)目斷斷續(xù)續(xù)搞了大半年前面六篇基本把渲染鏈路的各種細(xì)節(jié)翻了個遍位置、協(xié)方差、顏色系數(shù)、透明度混合每一個環(huán)節(jié)都拆開聊過。但這套東西真正落地時(shí)更常見的卡點(diǎn)其實(shí)是“數(shù)據(jù)從哪兒來”。網(wǎng)上開放數(shù)據(jù)集不少可一旦想做一個自己的場景、拍自己的物體很多人就懵了。這篇第七篇我把自建3DGS數(shù)據(jù)集的完整流程、踩過的坑和排查方法一次性整理出來算是給前面六篇補(bǔ)上最實(shí)操的一塊拼圖。先交代清楚本文的邊界我會從拍攝采集講起覆蓋位姿解算、數(shù)據(jù)格式整理、訓(xùn)練前檢查、手動渲染視角以及常見問題的排查思路。整個過程全部圍繞“3DGS渲染表達(dá)器”這條主線展開但視角會從“引擎內(nèi)部”挪到“喂給引擎的材料”——因?yàn)樵俸玫匿秩颈磉_(dá)器喂進(jìn)去的原始數(shù)據(jù)不對出來的效果也一定不對。1. 項(xiàng)目背景與整體思路1.1 “渲染表達(dá)器”到底在表達(dá)什么很多朋友看前面幾篇會有一個疑惑我們反復(fù)說“渲染表達(dá)器”但它指的到底是網(wǎng)絡(luò)結(jié)構(gòu)、渲染方程還是一個單獨(dú)的模塊。我在第一篇里就強(qiáng)調(diào)過3DGS沒有傳統(tǒng)渲染管線里那種“材質(zhì)球光照模型”的分工它把場景直接表達(dá)成一組高斯原語的屬性集合每個高斯帶中心位置、協(xié)方差矩陣由縮放和旋轉(zhuǎn)決定、不透明度以及球諧系數(shù)表達(dá)的顏色。所謂“表達(dá)器”其實(shí)就是把這組屬性變成屏幕上像素的過程。它在軟件層面大致分四步先把3D高斯原語投影到2D圖像平面再按深度排序然后對每個像素沿著視線做alpha混合最后把逐像素結(jié)果累積成顏色。這個表達(dá)過程高度依賴輸入數(shù)據(jù)。如果自建數(shù)據(jù)集里相機(jī)位姿誤差偏大或者場景覆蓋存在空洞表達(dá)器再怎么優(yōu)化也只能給出“殘缺”或者“抖動”的結(jié)果。所以自建數(shù)據(jù)集的本質(zhì)是在源頭控制表達(dá)質(zhì)量。1.2 為什么一定要自己做數(shù)據(jù)集市面上的公開數(shù)據(jù)大概能分兩類一類是合成場景渲染出來非常干凈位姿完全精確但和真實(shí)拍攝總覺得隔了一層另一類是真實(shí)場景掃描數(shù)量也不少可要么場景風(fēng)格和自己需求不匹配要么拍攝設(shè)備和想復(fù)現(xiàn)的流程差異太大。真到了做產(chǎn)品原型、做特定物體的展示或者驗(yàn)證自定義采集方案時(shí)公開數(shù)據(jù)往往幫不上忙。我自己做自建數(shù)據(jù)集的核心訴求有三個一是完全掌控場景內(nèi)容想拍什么就拍什么二是精確記錄采集參數(shù)為后續(xù)調(diào)優(yōu)留下完整元數(shù)據(jù)三是把從拍攝到渲染的whole chain都走一遍踩坑踩在自己項(xiàng)目里后續(xù)迭代才有底氣。這三點(diǎn)說起來簡單實(shí)際操作中每一步都有不少細(xì)節(jié)下面逐個展開。2. 自建3DGS數(shù)據(jù)集的采集環(huán)節(jié)采集是整個流程里最“容易做但很難做好”的一步。它不涉及代碼也不涉及算法邏輯卻直接決定了后面所有環(huán)節(jié)的上限。我的經(jīng)驗(yàn)是拍得好的數(shù)據(jù)訓(xùn)練出來幾乎不怎么需要調(diào)參數(shù)拍得差的數(shù)據(jù)后面補(bǔ)位姿、加約束、清浮點(diǎn)都是救火隊(duì)員的狀態(tài)。2.1 拍攝設(shè)備與場景選擇設(shè)備方面沒有統(tǒng)一標(biāo)準(zhǔn)我自己用過手機(jī)也用過運(yùn)動相機(jī)和無反相機(jī)最終建議是優(yōu)先選傳感器尺寸大、鏡頭素質(zhì)穩(wěn)定、能手動鎖參數(shù)的設(shè)備。手機(jī)確實(shí)方便但幾類問題比較常見。一是自動曝光和自動白平衡會隨著拍攝角度變化不斷跳變同一個表面在不同幀里亮暗不一訓(xùn)練出來容易出現(xiàn)“花臉”效果。運(yùn)動相機(jī)超廣角鏡頭畸變大標(biāo)定參數(shù)稍有偏差就影響位姿解算。所以如果條件允許盡量用能完全手動控制曝光、白平衡、對焦的設(shè)備哪怕只有一臺也比參數(shù)頻繁漂移的設(shè)備強(qiáng)。場景選擇上推薦從三類場景練手單物體場景一個玩偶、一臺咖啡機(jī)、一座小雕塑尺寸在三五十厘米到一兩米之間背景干凈物體表面有紋理但不過度反光。桌面小場景一盆綠植加幾個小物件覆蓋面積在一平米以內(nèi)便于完整環(huán)繞。室內(nèi)局部場景一面墻加角落里的桌椅適合驗(yàn)證大場景的視角覆蓋策略。建議新手避開全白墻面、純色地毯、大面積玻璃和強(qiáng)反光金屬因?yàn)樘卣鼽c(diǎn)不足后續(xù)COLMAP階段會出現(xiàn)稀疏點(diǎn)云斷裂或相機(jī)位姿解算失敗。2.2 拍攝參數(shù)與路徑設(shè)計(jì)鎖定參數(shù)是鐵律。光圈、快門、ISO、白平衡、對焦全部切到手動模式固定下來后整個拍攝過程中不再改動。曝光方面我習(xí)慣以主體中高光區(qū)域不過曝為基準(zhǔn)再壓半檔到一檔保證高光細(xì)節(jié)盡可能保留。這樣渲染結(jié)果雖然偏暗一點(diǎn)但后期調(diào)整空間更大避免亮部一片死白之后徹底丟失信息。拍攝路徑上最常見的錯誤是“圍著轉(zhuǎn)一圈就完事”。單圈環(huán)繞確實(shí)能覆蓋物體側(cè)面但頂部和底部容易出現(xiàn)空洞尤其是物體高度較高的時(shí)候單一水平高度的環(huán)繞會讓上下極點(diǎn)沒有有效覆蓋。正確做法可以參考下面這個模式先拍完整水平環(huán)繞每隔15到20度取一幀保證相鄰幀之間重疊度足夠。再從多個仰角、俯角補(bǔ)拍高度方向上每換一個角度也做半圈到一圈的覆蓋。如果物體擺放在轉(zhuǎn)臺上可以物體不動、人繞四周拍攝也可以物體旋轉(zhuǎn)、相機(jī)不動但務(wù)必保證每幀之間都有足夠的公共視場。幀數(shù)方面單物體場景一般控制在80到200張之間多多益善但前提是每張都是有用信息。低重疊度或者大范圍模糊的幀寧可刪掉也不要放進(jìn)數(shù)據(jù)集。桌面小場景可以適當(dāng)減少大場景則需要更多我調(diào)過動畫類場景拍過400多張室內(nèi)靜態(tài)場景一般也是200張起步。2.3 提高成功率的幾個現(xiàn)場技巧相機(jī)穩(wěn)定是最容易被低估的因素。手持拍攝時(shí)輕微晃動會讓照片產(chǎn)生運(yùn)動模糊這種模糊在單張圖片里看起來很輕微但放到三維重建里就是某塊局部位姿漂移的根源。我建議至少使用輕便三腳架或者穩(wěn)定器。如果沒有可以找固定平面依托或者把相機(jī)掛繩拉緊后屏息連拍能改善一大部分。拍攝時(shí)還要注意背景復(fù)雜度。適度復(fù)雜的背景能提供豐富特征點(diǎn)幫助位姿解算更穩(wěn)但背景里如果有運(yùn)動的行人、閃爍的屏幕、變化的光影就會引入錯誤的匹配點(diǎn)。最好選擇靜態(tài)、光照穩(wěn)定的環(huán)境如果有強(qiáng)烈直射陽光光照角度變化導(dǎo)致的陰影位移會嚴(yán)重影響訓(xùn)練結(jié)果。物體表面如果有較大反光可以在表面噴一點(diǎn)消光劑或者調(diào)整拍攝角度讓反光區(qū)域在絕大多數(shù)視角里不直接面對相機(jī)。另外拍攝前清理物體周圍的無關(guān)物品把場景內(nèi)物品固定住避免任何一個部件掉落或移動。場景中任何微小的位置變化對于需要預(yù)測相機(jī)相對位置的算法來說都是災(zāi)難級的干擾。3. 從原始照片生成相機(jī)位姿照片拍完不是直接就能用來訓(xùn)練還要先算出每張照片對應(yīng)的相機(jī)內(nèi)外參數(shù)。3DGS訓(xùn)練用得最多的是COLMAP輸出的稀疏重建結(jié)果包括相機(jī)位姿、內(nèi)參和稀疏點(diǎn)云。這一步比較硬核但流程完全可以標(biāo)準(zhǔn)化。3.1 COLMAP工作流程COLMAP的使用可以走命令行也可以用圖形界面。我推薦命令行因?yàn)檫^程中需要反復(fù)調(diào)整參數(shù)命令行可重復(fù)性好。基礎(chǔ)流程分三塊# 第一步特征提取 colmap feature_extractor \ --database_path project/database.db \ --image_path project/images \ --ImageReader.single_camera 1 \ --SiftExtraction.use_gpu 1 # 第二步特征匹配 colmap exhaustive_matcher \ --database_path project/database.db \ --SiftMatching.use_gpu 1 # 第三步稀疏重建 mkdir project/sparse colmap mapper \ --database_path project/database.db \ --image_path project/images \ --output_path project/sparse第一行的--ImageReader.single_camera 1比較關(guān)鍵它告訴COLMAP同一場景里的所有照片使用的是同一臺相機(jī)、同一套焦距。自建數(shù)據(jù)集基本都滿足這個條件開啟后內(nèi)參估計(jì)更穩(wěn)定。匹配策略上照片數(shù)少于200張時(shí)用exhaustive_matcher沒什么壓力速度也快超過這個量級建議改用vocab_tree_matcher先把圖像檢索壓縮到相似幀再在這個子集內(nèi)做匹配速度和內(nèi)存占用都會好很多。稀疏重建完成之后會在project/sparse下生成0號文件夾里面主要包含cameras.bin、images.bin、points3D.bin三個文件。這是COLMAP的二進(jìn)制格式后面訓(xùn)練框架一般都能直接讀如果遇到需要轉(zhuǎn)換的情況可以用COLMAP的模型轉(zhuǎn)換工具轉(zhuǎn)成文本格式方便查看。3.2 數(shù)據(jù)格式整理與歸一化COLMAP跑完可以先看下重建結(jié)果統(tǒng)計(jì)信息colmap model_analyzer \ --path project/sparse/0重點(diǎn)檢查注冊幀數(shù)占總輸入圖片的比例。正常場景下80%以上的圖片都能注冊成功如果低于這個值說明拍攝質(zhì)量或者場景特征有問題需要回頭檢查原始圖片。注冊失敗的幀通常出現(xiàn)在大面積模糊、嚴(yán)重遮擋、鏡頭炫光或者視角突變的照片上。確認(rèn)重建沒問題后建議做一個通用格式整理方便后續(xù)在不同訓(xùn)練框架之間切換。我自己習(xí)慣于把一個項(xiàng)目整理成如下結(jié)構(gòu)project/ ├── images/ # 原始圖片 ├── sparse/0/ # COLMAP輸出 └── dataset.yml # 記錄設(shè)備、分辨率、拍攝日期、參數(shù)等元信息dataset.yml這種元信息文件容易被忽略但到了后面調(diào)優(yōu)或者回看項(xiàng)目時(shí)非常有用。它能幫你快速確認(rèn)某次實(shí)驗(yàn)用的是哪個鏡頭、什么焦距、什么曝光參數(shù)。3.3 位姿結(jié)果檢查與常見失敗模式看到COLMAP輸出的數(shù)字不能直接訓(xùn)練我強(qiáng)烈建議先做一次可視化檢查。COLMAP自帶一個簡單的GUI加載稀疏模型后能查看相機(jī)位置和稀疏點(diǎn)云分布。重點(diǎn)看三件事相機(jī)軌跡是否連續(xù)、有沒有明顯跳躍或斷點(diǎn)所有相機(jī)的朝向是否都指向場景主體周圍稀疏點(diǎn)云是否在整個物體表面都有覆蓋有沒有大片黑色空洞。有一次我拍一個深色杯子側(cè)面紋理太少前幾次重建出來相機(jī)繞杯子的軌跡完全不連續(xù)稀疏點(diǎn)云集中在杯口和杯底中間整片面壁。后來補(bǔ)拍了一圈加裝條紋背景的圖把背景紋理加進(jìn)去位姿才穩(wěn)定下來。另一個常見失敗模式是“環(huán)閉不嚴(yán)”即相機(jī)軌跡沒有形成完整閉環(huán)。3DGS對位姿誤差比較敏感軌跡開環(huán)時(shí)容易出現(xiàn)場景漂移。解決思路是拍攝時(shí)繞場景多走一步確保首尾幀有效重疊讓COLMAP能把軌跡“縫”起來。4. 訓(xùn)練、渲染與輸出數(shù)據(jù)整理妥當(dāng)之后訓(xùn)練環(huán)節(jié)反而輕松一些。3DGS的訓(xùn)練跟傳統(tǒng)模型不太一樣它更像是在不斷調(diào)整一組高斯原語的屬性讓渲染出來的圖像逐步逼近每個視角下的真實(shí)照片。核心參數(shù)不多但有幾個地方要注意。4.1 訓(xùn)練配置要點(diǎn)用官方代碼或者gsplat這類框架常見的訓(xùn)練配置都差不多。關(guān)鍵參數(shù)包括迭代次數(shù)、學(xué)習(xí)率、SH階數(shù)以及是否開啟致密化。我一般默認(rèn)跑3萬次迭代批量大小設(shè)為1圖像分辨率在訓(xùn)練前統(tǒng)一縮放到短邊不超過1600像素長邊不超過2000像素。分辨率太高會讓訓(xùn)練時(shí)間和顯存占用劇增但對最終質(zhì)量提升其實(shí)有限。訓(xùn)練過程中要盯兩個指標(biāo)一個是在全部訓(xùn)練視角上的重建誤差我在意的不是誤差絕對值而是它是否穩(wěn)步下降另一個是每間隔500步輸出一次的可視化圖片重點(diǎn)看有沒有出現(xiàn)拖影、空洞、顏色溢出。訓(xùn)練早期出現(xiàn)少量拖影是正常的隨著迭代推進(jìn)通常會消除但如果在1萬次迭代左右還明顯就要回頭查輸入數(shù)據(jù)。SH階數(shù)我用默認(rèn)的三階球諧就夠了。更高階數(shù)能表達(dá)更復(fù)雜的光照變化適合有明顯高光或者顏色漸變明顯的物體但對多數(shù)漫反射物體低階數(shù)反而更穩(wěn)高階數(shù)容易引入抖動或偽影。4.2 手動渲染視角與相機(jī)控制訓(xùn)練完成之后除了驗(yàn)證視角的自動渲染還要學(xué)會手動控制渲染相機(jī)。這一步我建議每個自建數(shù)據(jù)集的項(xiàng)目都做一次因?yàn)樗苤庇^反映模型在訓(xùn)練視角之外的表現(xiàn)。手動渲染的核心在于定義新的相機(jī)位姿。對于轉(zhuǎn)臺類場景我會繞物體畫一條特定半徑的圓弧讓相機(jī)高度和俯仰角都做緩慢變化然后逐步輸出渲染幀。這樣生成的視頻能快速看出物體的幾何是否完整、表面顏色是否連續(xù)、有沒有視角死區(qū)。在gsplat的Python接口里手動渲染一個自定義相機(jī)位姿大概是這樣的思路import torch import gsplat from gsplat import rasterization # 假設(shè)已經(jīng)加載訓(xùn)練好的高斯參數(shù) # 構(gòu)造一個看向原點(diǎn)的相機(jī)位置在2, 1, 3焦距從訓(xùn)練數(shù)據(jù)中取中值 c2w torch.eye(4) c2w[:3, 3] torch.tensor([2.0, 1.0, 3.0]) K torch.tensor([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtypetorch.float32) # 將c2w轉(zhuǎn)為w2c后配合K傳給光柵化函數(shù) # 渲染得到2D彩色圖和alpha圖 colors, alphas rasterization( means, scales, quats, opacities, sh_coeffs, viewmatsw2c.unsqueeze(0), KsK.unsqueeze(0), widthwidth, heightheight )更省事的方式是直接用訓(xùn)練框架自帶的渲染腳本把渲染路徑寫成一段軌跡文件框架自動插值出中間幀。我自己經(jīng)常先用手動軌跡渲染出一段短視頻檢查不同角度下的模型表現(xiàn)然后再決定要不要做上層App或者Web展示。4.3 質(zhì)量評估與返工邊界渲染結(jié)果出來了怎么判斷這套自建數(shù)據(jù)集到底算不算成功我一般分三層看第一層是幾何完整性。繞物體看一周邊緣輪廓是否穩(wěn)定有沒有出現(xiàn)大面積漂浮、空洞、扭曲。如果只是某個側(cè)面輕微模糊往往可以通過增加該角度的圖片密度來彌補(bǔ)如果整個頂面完全缺失說明采集時(shí)頂部視角太少返工就得補(bǔ)拍俯視角度。第二層是紋理一致性。表面顏色在不同視角下是否一致有沒有出現(xiàn)“換角度變顏色”的斑塊。出現(xiàn)這類問題通常是曝光不統(tǒng)一或者白平衡漂移。輕微不一致可以靠后處理遮罩修嚴(yán)重影響觀感就得重新采集。第三層是細(xì)節(jié)保真度。比如織物紋理、包裝上的小字、植物葉片邊緣這種高頻細(xì)節(jié)能不能在靜止幀里看清晰。如果訓(xùn)練收斂后這些細(xì)節(jié)仍然糊且訓(xùn)練集里明明有對應(yīng)的清晰照片那大概率是定位誤差偏大導(dǎo)致高斯基元被過度平滑。這時(shí)候我建議先查看稀疏點(diǎn)云與照片的對齊情況確認(rèn)位姿無誤后再調(diào)整訓(xùn)練參數(shù)而不是盲目加迭代。返工的邊界要提前想清楚。如果只是局部區(qū)域缺失可以回歸補(bǔ)拍那個角度的圖重新跑COLMAP和訓(xùn)練如果整體漂移、大量浮點(diǎn)、紋理花掉果斷重新采集比反復(fù)調(diào)參數(shù)節(jié)約時(shí)間得多。我見過不少朋友卡在一個爛數(shù)據(jù)上反復(fù)調(diào)了幾天最后重拍兩小時(shí)就解決了。5. 自建數(shù)據(jù)集常見問題速查下面這些問題是實(shí)操中比較高頻的坑我整理成一張速查表方便按癥狀直接定位?,F(xiàn)象可能原因處理辦法COLMAP注冊幀比例過低場景紋理不足、圖片模糊、曝光跳變補(bǔ)拍帶紋理的物體或背景鎖定曝光參數(shù)剔除模糊幀相機(jī)軌跡不連續(xù)或開環(huán)相鄰幀重疊度不夠、視角跳躍太大放慢拍攝節(jié)奏保證相鄰幀重疊超過50%閉合環(huán)繞路徑訓(xùn)練出來出現(xiàn)大片空洞頂部或底部視角缺失、遮擋嚴(yán)重補(bǔ)拍俯拍和低角度視角移動遮擋物表面出現(xiàn)漂浮的高斯碎片透明/反光物體導(dǎo)致錯誤匹配拍攝時(shí)避開強(qiáng)烈反光或使用消光劑不同視角顏色不一致自動白平衡/自動曝光未鎖定手動鎖定相機(jī)參數(shù)重新采集圖像分辨率過大導(dǎo)致顯存不足訓(xùn)練分辨率設(shè)置過高短邊縮到1600像素以內(nèi)必要時(shí)用梯度裁剪我再補(bǔ)充兩個不常被提到的細(xì)節(jié)。第一個是拍攝時(shí)要留意時(shí)間跨度室外場景如果拍了兩小時(shí)光線方向已經(jīng)明顯變化建議要么壓縮采集時(shí)間要么在不同光照時(shí)段分別建模不要硬拼進(jìn)同一個模型。第二個是訓(xùn)練結(jié)果對輸入圖片數(shù)量并非越敏感越好關(guān)鍵是“均勻覆蓋”與其堆幾百張沒有差異的角度不如按球形分布均勻撒點(diǎn)每一幀都提供新的信息。排查問題的時(shí)候我喜歡先看數(shù)據(jù)和位姿再動訓(xùn)練參數(shù)。因?yàn)?DGS這套渲染表達(dá)器的底線是“數(shù)據(jù)決定表達(dá)能力的邊界”訓(xùn)練參數(shù)只是在邊界內(nèi)做優(yōu)化。數(shù)據(jù)驗(yàn)證的第一步可以畫一個包圍場景的最小球觀察相機(jī)中心和稀疏點(diǎn)在球內(nèi)的分布如果嚴(yán)重偏離球面說明某些視角的照片在重建中被錯誤估計(jì)了這時(shí)候繼續(xù)調(diào)訓(xùn)練參數(shù)意義不大。關(guān)于.COL格式的導(dǎo)出如果項(xiàng)目后續(xù)要交給Unity或者Web端展示需要把訓(xùn)練好的模型做一次格式轉(zhuǎn)換和簡化。簡化時(shí)注意不要只看頂點(diǎn)數(shù)量還要看渲染峰值顯存和三角形覆蓋密度化簡后的模型建議先在小范圍測試視角走一遍確認(rèn)沒有奇怪的破洞再上線。這組自建數(shù)據(jù)集的流程說白了我自己也是試錯試出來的。起初總以為訓(xùn)練是個技術(shù)活后來發(fā)現(xiàn)真正決定上限的永遠(yuǎn)是數(shù)據(jù)這一關(guān)。特別是自建數(shù)據(jù)時(shí)COLMAP輸出的位姿質(zhì)量會直接傳導(dǎo)到3DGS的每個高斯原語上一個好的采集習(xí)慣比一百次調(diào)參都管用。最后分享一個我每次拍攝前都會執(zhí)行的檢查清單確認(rèn)設(shè)備電量、鎖定曝光和焦距、清理場景雜物、規(guī)劃至少兩條交叉的拍攝路徑、拍攝中用監(jiān)視屏抽查關(guān)鍵幀清晰度、收尾前檢查能否閉合環(huán)繞軌跡。這六條看起來簡單但每一條我都踩過坑現(xiàn)在寫出來供大家直接抄作業(yè)。