估計落地指南:從點云生成到PnP/回歸/ICP選型)
簡介結(jié)合深度圖像的三維信息來識別俯仰角、翻滾角與偏航角是頭部姿態(tài)估計的核心思路相比二維圖像深度數(shù)據(jù)在遮擋和光照變化下更具魯棒性。圍繞這一思路資源包以Visual Studio工程形式呈現(xiàn)共66個文件、約11.09MB主要包含C源碼、工程配置、編譯生成的dll/exe/obj/bin以及cal標(biāo)定數(shù)據(jù)并保留了Debug目錄結(jié)構(gòu)適合計算機(jī)視覺初學(xué)者或算法工程師直接打開工程從預(yù)處理、特征提取到姿態(tài)預(yù)測逐層梳理實現(xiàn)。內(nèi)容覆蓋特征點檢測HOG、SURF、模板匹配、傳統(tǒng)機(jī)器學(xué)習(xí)SVM、隨機(jī)森林以及基于CNN的多任務(wù)深度網(wǎng)絡(luò)等不同技術(shù)路線既展示經(jīng)典算法又包含可運行可調(diào)試的工程示例便于理解深度圖歸一化、模型加載等關(guān)鍵環(huán)節(jié)。資源包已吸引288人學(xué)習(xí)可作為理解深度圖像姿態(tài)估計原理、遷移到實際項目的實用參考。1. 深度圖像做頭部姿態(tài)估計為什么比RGB多一個維度就多一條出路要做頭部姿態(tài)估計常見做法是拿普通RGB圖像直接喂給卷積網(wǎng)絡(luò)可一旦遇到室內(nèi)暗光、逆光或者夜間車內(nèi)場景RGB方案就會明顯掉點?;谏疃葓D像的頭部姿態(tài)估計把深度圖當(dāng)作主輸入從像素級距離信息里恢復(fù)頭部yaw、pitch、roll三個自由度天然不吃光照也更容易拿到真實尺度。你在做駕駛分心檢測、人機(jī)交互、睡眠監(jiān)測這類近景視覺任務(wù)時遇到RGB調(diào)不過去的暗光case換成深度圖往往是更省力的一個分支。這篇實踐記錄不聊論文指標(biāo)講落地深度圖怎么轉(zhuǎn)點云PnP、回歸、ICP三條路線怎么選數(shù)據(jù)集怎么準(zhǔn)備和評估以及我在真機(jī)上踩過的幾個坑。適合手里已經(jīng)有深度相機(jī)、想把頭部姿態(tài)從demo推到產(chǎn)線的工程師。2. 先把深度圖變成能算的東西相機(jī)模型、坐標(biāo)系與點云生成深度圖本身不是圖像它更像一張“距離表”。這一步做不對后面再怎么調(diào)網(wǎng)絡(luò)都是白費。很多復(fù)現(xiàn)項目效果差問題往往不在模型而在點云生成時的單位、內(nèi)參和無效像素沒處理好。2.1 深度圖到底長什么樣三種常見數(shù)據(jù)格式拿到RealSense、Kinect或者手機(jī)ToF相機(jī)的數(shù)據(jù)先看保存格式。常見的有三種。第一種是16位無符號整數(shù)uint16單位是毫米RealSense的z16和Kinect都默認(rèn)這一類導(dǎo)出PNG時也大多是它。第二種是浮點深度圖單位是米一些SDK的原始回調(diào)直接給float32。第三種是歸一化深度圖取值范圍0到255或者0到1這類最坑因為尺度信息已經(jīng)被吃掉了只適合做可視化不適合做姿態(tài)回歸。提示先打印一下像素值分布。無效像素在不同相機(jī)里可能是0、2047、65535如果不先統(tǒng)計直方圖就統(tǒng)一置零后期點云里會出現(xiàn)一批離群點。我一般會在代碼里強(qiáng)制統(tǒng)一成毫米的uint16或者米的float32再做歸一化。否則同一個模型在RealSense上調(diào)好了換到另一家模組上直接崩。2.2 從二維像素到三維點內(nèi)參、深度值與尺度要把深度圖變成點云只需要相機(jī)內(nèi)參fx、fy、cx、cy。對每個有效像素(u, v)深度值為z_raw尺度為scale毫米轉(zhuǎn)米就是1000.0三維坐標(biāo)是z z_raw / scalex (u - cx) * z / fxy (v - cy) * z / fy。這里的(x, y, z)是三維點在相機(jī)坐標(biāo)系下的位置。頭部姿態(tài)估計一般也把相機(jī)坐標(biāo)系作為基準(zhǔn)輸出yaw、pitch、roll就是頭部模型相對于相機(jī)的旋轉(zhuǎn)角。要注意的是OpenCV里x向右、y向下、z向前和你數(shù)學(xué)課上的右手系不完全一樣但視覺領(lǐng)域都按這個約定走坐標(biāo)符號不要自己改。外參(R, t)在深度圖到點云這一步用不上只有需要把頭部姿態(tài)換算到世界坐標(biāo)、或者融合多臺相機(jī)時才引入外參。多數(shù)項目前期可以完全忽略外參先把內(nèi)參和尺度管住。2.3 生成點云的最小實現(xiàn)下面這段代碼把一張16位毫米深度圖轉(zhuǎn)成(N, 3)的相機(jī)系點云import numpy as np def depth_to_pointcloud(depth_raw, fx, fy, cx, cy, scale1000.0, mask_depth2047): # depth_raw: uint16單位mm無效像素通常為0或超出量程 # mask_depth: 深度上限超過該值的像素考慮丟棄避免紅外噪聲點 valid (depth_raw 0) (depth_raw mask_depth) rows, cols np.nonzero(valid) z depth_raw[rows, cols].astype(np.float32) / scale x (cols - cx) * z / fx y (rows - cy) * z / fy pts np.stack([x, y, z], axis-1) # (N, 3) return pts, valid邏輯說明先用掩碼把0值和超量程像素剔掉再把有效像素的行列索引取出來。深度值除以scale得到米之后用針孔相機(jī)模型反投影。這里用NumPy全量索引而不是for循環(huán)一張640x480的深度圖在毫秒級出結(jié)果。參數(shù)說明fx、fy一般取深度相機(jī)的出廠內(nèi)參也可以用棋盤格標(biāo)定得到cx、cy是主點部分SDK會隨分辨率變化換了分辨率要重新拿。mask_depth不要拍腦袋設(shè)先看統(tǒng)計直方圖再定用2047是因為很多ToF相機(jī)的最大有效測量值接近這一檔。這段代碼我的用法是先在離線上跑一遍整段視頻畫一下深度直方圖確認(rèn)無效值分布后再落到訓(xùn)練和推理流程里。2.4 點云不是必須的什么時候直接歸一化深度喂網(wǎng)絡(luò)點云適合PnP和ICP這類幾何求解但如果你走回歸路線直接把裁剪后的深度圖歸一化喂給卷積網(wǎng)絡(luò)就行不需要生成點云。歸一化有個常用做法先把深度clip到0.3到1.5米再縮放到0到1這樣能避免不同安裝距離對網(wǎng)絡(luò)的干擾。這里也給出后面選路線的一個判斷依據(jù)如果你有可靠的人臉關(guān)鍵點就走PnP如果你只想用一個輕量網(wǎng)絡(luò)端到端出角度就走回歸如果你的任務(wù)是跟蹤且頭部運動范圍小ICP可以作為后端優(yōu)化。我見過不少團(tuán)隊一開始就往深度學(xué)習(xí)上堆結(jié)果發(fā)現(xiàn)連深度圖的單位都沒統(tǒng)一這屬于典型的“地基沒打就砌墻”。3. 三條落地路線PnP、回歸、ICP我建議怎么選很多剛接觸這個方向的人會直接去搜“頭部姿態(tài)估計開源模型”拿一個現(xiàn)成模型回來跑。真到項目里你會發(fā)現(xiàn)選路線比選模型更重要因為每條路線對輸入、算力和數(shù)據(jù)的要求差得很遠(yuǎn)。3.1 PnP路線2D人臉關(guān)鍵點 3D人臉模型求解在位姿估計里PnPPerspective-n-Point是把3D點和2D像素對應(yīng)起來求相機(jī)位姿的標(biāo)準(zhǔn)方法。做頭部姿態(tài)估計時3D點來自一個人臉模型的關(guān)鍵點坐標(biāo)鼻尖、眼角、嘴角等2D點來自RGB或深度圖上檢測到的對應(yīng)關(guān)鍵點相機(jī)內(nèi)參已知求解結(jié)果就是頭部相對于相機(jī)的R和t。這條路的好處是幾何可解釋、數(shù)據(jù)量要求低關(guān)鍵點檢測器質(zhì)量夠、3D模型定義不歪角度結(jié)果就可靠。壞處是它對大姿態(tài)不友好——轉(zhuǎn)頭超過50度自遮擋會讓關(guān)鍵點檢測器丟點或錯點。import cv2 import numpy as np fx, fy, cx, cy 525.0, 525.0, 320.0, 240.0 # 從相機(jī)標(biāo)定結(jié)果讀取 # 3D 人臉模型關(guān)鍵點單位米原點在頭部中心附近 face_model_3d np.array([ [0.000, 0.000, 0.000], # 鼻尖 [-0.031, -0.031, -0.052], # 左眼外角 [0.031, -0.031, -0.052], # 右眼外角 [-0.031, 0.028, -0.052], # 左嘴角 [0.031, 0.028, -0.052], # 右嘴角 ], dtypenp.float32) # 同一幀由關(guān)鍵點檢測器給出的 2D 像素坐標(biāo) face_2d np.array([ [320.0, 240.0], [283.0, 221.0], [359.0, 221.0], [291.0, 281.0], [351.0, 281.0], ], dtypenp.float32) camera_matrix np.array([ [fx, 0.0, cx], [0.0, fy, cy], [0.0, 0.0, 1.0], ], dtypenp.float32) dist_coeffs np.zeros((5, 1)) ok, rvec, tvec cv2.solvePnP( face_model_3d, face_2d, camera_matrix, dist_coeffs, flagscv2.SOLVEPNP_ITERATIVE ) R, _ cv2.Rodrigues(rvec) # 旋轉(zhuǎn)矩陣邏輯說明cv2.solvePnP輸入3D點、2D點、內(nèi)參和畸變系數(shù)輸出旋轉(zhuǎn)向量rvec和平移向量tvec。rvec是三維向量軸角表達(dá)必須用Rodrigues公式轉(zhuǎn)成3x3旋轉(zhuǎn)矩陣再從R按你定的歐拉角順序拆出yaw、pitch、roll。注意歐拉角順序和旋轉(zhuǎn)矩陣定義必須和后續(xù)可視化、打標(biāo)工具保持一致否則會出現(xiàn)“模型輸出10度看起來像轉(zhuǎn)了80度”的錯位。參數(shù)說明SOLVEPNP_ITERATIVE是最常用的迭代解法適合5個點以上點數(shù)少且不共面時改用SOLVEPNP_EPNP更可靠。3D模型的最小要求是至少4個不共線點實際我用5到7個關(guān)鍵點就夠點太多反而會把檢測誤差帶進(jìn)來。3D模型坐標(biāo)的符號約定也要注意比如左眼外角到底取x正還是負(fù)決定了yaw的正負(fù)最好先拿一張正面臉驗證。3.2 回歸路線深度圖直接出角度回歸路線的思路簡單把裁剪好的深度圖輸入一個卷積網(wǎng)絡(luò)輸出三個角度或者輸出六個值讓模型自己學(xué)習(xí)sin、cos。它的上限取決于數(shù)據(jù)集的覆蓋度和網(wǎng)絡(luò)容量優(yōu)勢是推理鏈路短不需要關(guān)鍵點檢測器夜間和遮擋場景也相對皮實。常見做法是用輕量主干MobileNetV3、EfficientNet-lite替換ImageNet主干輸出頭改成3個神經(jīng)元。訓(xùn)練時注意幾點輸入深度先做歸一化和隨機(jī)裁剪損失函數(shù)不要直接對角度做L1因為角度在±90度邊界會有跳變建議把角度轉(zhuǎn)為sin、cos輸出推理時用atan2還原或者加一個離散角度分類輔助頭幫助收斂?;貧w路線的坑在于對數(shù)據(jù)分布特別敏感真想上線要用目標(biāo)場景的數(shù)據(jù)做微調(diào)。3.3 ICP路線點云與頭部模板對齊ICPIterative Closest Point把當(dāng)前點云和一個預(yù)先準(zhǔn)備好的頭部模板點云對齊通過迭代尋找旋轉(zhuǎn)平移使得兩組點云距離最小。好處是不需要標(biāo)定人臉關(guān)鍵點用的是整個頭部幾何信息壞處是必須有一個好的初始位姿否則容易落到局部最優(yōu)。我一般在跟蹤場景這樣用上一幀的PnP結(jié)果作為當(dāng)前幀ICP的初值再限定迭代次數(shù)這樣能把抖動壓下去。單獨拿ICP做全范圍姿態(tài)搜索不太現(xiàn)實計算量大且容易跑飛。如果你只有一個單幀、沒有任何初始信息不要選這條路。3.4 選型建議先看你的輸入條件下面是我做選型時常用的判斷表不是標(biāo)準(zhǔn)答案但能幫你少走彎路。路線輸入依賴精度上限算力適合場景PnP關(guān)鍵點檢測器 相機(jī)內(nèi)參中高關(guān)鍵點質(zhì)量決定很低有RGB或深度人臉檢測、需可解釋中間結(jié)果回歸網(wǎng)絡(luò)大量標(biāo)注深度圖高依賴數(shù)據(jù)分布中固定安裝、環(huán)境可覆蓋、端到端部署ICP模板點云 初始位姿高但怕局部最優(yōu)偏高近景跟蹤、頭戴設(shè)備姿態(tài)校正如果你的現(xiàn)場有強(qiáng)紅外干擾深度圖噪聲大PnP比回歸更容易通過幾何約束剔除壞點如果你的深度圖干凈、距離變化范圍小回歸更省心。有的項目我最后把PnP和回歸做了個簡單融合回歸給初值PnP做精調(diào)效果比單一方案扎實。4. 數(shù)據(jù)集與評估用 Biwi 和 ICT-3DHP 把模型調(diào)到能上線深度圖像頭部姿態(tài)估計的開源數(shù)據(jù)不如RGB人臉數(shù)據(jù)多選錯數(shù)據(jù)集等于白訓(xùn)練。這章講數(shù)據(jù)集標(biāo)注長什么樣、怎么預(yù)處理、評估指標(biāo)怎么定以及一份能直接復(fù)制的評估代碼。4.1 數(shù)據(jù)集標(biāo)注格式與適用場景業(yè)內(nèi)常用來做深度圖像頭部姿態(tài)估計的開源數(shù)據(jù)主要是Biwi Head Pose Database和ICT-3DHP。Biwi是單臺Kinect采集的近景RGB-D序列包含頭部中心和旋轉(zhuǎn)矩陣標(biāo)注用來做PnP校驗和回歸訓(xùn)練起點都比較合適。ICT-3DHP提供多視角RGB-D序列與頭部姿態(tài)真值適合做跨視角評估和仿真增強(qiáng)的參考。還有一個更實際的來源是自采真機(jī)數(shù)據(jù)雖然標(biāo)注貴但它的分布和你上線環(huán)境最一致。數(shù)據(jù)集傳感器標(biāo)注形式我一般拿它做什么BiwiKinect RGB-D頭部中心 旋轉(zhuǎn)矩陣PnP驗證、回歸訓(xùn)練ICT-3DHP多視角RGB-D姿態(tài)真值跨視角評估、仿真參考自采數(shù)據(jù)目標(biāo)深度相機(jī)手動標(biāo)角度或旋轉(zhuǎn)矩陣上線前微調(diào)和真機(jī)回歸測試用的時候注意這些數(shù)據(jù)集的相機(jī)內(nèi)參、深度單位、姿態(tài)定義都不一樣先寫一個轉(zhuǎn)換層統(tǒng)一到“相機(jī)坐標(biāo)系 毫米深度 yaw/pitch/roll順序”再進(jìn)訓(xùn)練或評測。4.2 數(shù)據(jù)準(zhǔn)備裁剪、縮放到統(tǒng)一尺寸回歸網(wǎng)絡(luò)和PnP的輸入不同但第一步都是把頭部區(qū)域從整幀里切出來。深度圖像不像RGB有成熟的目標(biāo)檢測模型常見做法是先用距離閾值或人體檢測結(jié)果定位頭部中心然后以中心向四周擴(kuò)展一個固定尺寸的矩形再從深度圖裁剪出對應(yīng)像素。def crop_depth_head(depth_raw, head_center, crop_size): # head_center: (u, v) 頭部中心像素坐標(biāo) # crop_size: 裁剪半徑單位像素 h, w depth_raw.shape[:2] u0, v0 int(head_center[0]), int(head_center[1]) u_min max(0, u0 - crop_size) u_max min(w, u0 crop_size) v_min max(0, v0 - crop_size) v_max min(h, v0 crop_size) crop depth_raw[v_min:v_max, u_min:u_max] return crop邏輯說明這個函數(shù)只做裁剪不做縮放避免引入插值誤差。裁剪后統(tǒng)一resize到64x64或者128x128再除以深度尺度并歸一化。裁剪半徑要根據(jù)相機(jī)安裝距離來定比如0.5到1米距離下crop_size取40到60像素比較合適距離遠(yuǎn)了頭部占的像素少要適當(dāng)加大半徑。參數(shù)說明歸一化不要直接用整幀min-max而是用預(yù)設(shè)深度范圍比如clip到0.3到1.5米。直接用min-max會讓深度變化不大的頭部區(qū)域?qū)Ρ榷缺粔嚎s模型學(xué)不到距離差這是一些復(fù)現(xiàn)模型在原數(shù)據(jù)集上效果好、換場景就失效的重要原因。4.3 回歸網(wǎng)絡(luò)的評估指標(biāo)MAE 與 N 度準(zhǔn)確率評估指標(biāo)主要看兩個平均絕對誤差MAE和N度準(zhǔn)確率。MAE就是預(yù)測角度與真值的平均絕對差N度準(zhǔn)確率是預(yù)測與真值最大誤差小于N度的樣本比例N一般取5或10。真實項目里我會兩個一起看MAE低但5度準(zhǔn)確率不高說明模型在大部分樣本上不錯但在大姿態(tài)樣本上系統(tǒng)性偏大這時候要補(bǔ)大角度樣本。import numpy as np def evaluate_pose(pred, gt): # pred, gt: [N, 3]順序為 yaw, pitch, roll單位度 diff pred - gt diff (diff 180.0) % 360.0 - 180.0 # 角度回繞 mae np.mean(np.abs(diff), axis0) max_err np.max(np.abs(diff), axis1) acc_5 np.mean(max_err 5.0) * 100.0 acc_10 np.mean(max_err 10.0) * 100.0 return mae, acc_5, acc_10邏輯說明角度回繞那行很關(guān)鍵否則yaw從179度到-179度真實只差2度會被算成358度。max_err取每個樣本三個角度的最大誤差N度準(zhǔn)確率用這個最大誤差判斷比單獨看每個軸的指標(biāo)更貼近實際。參數(shù)說明5度準(zhǔn)確率適合要求精細(xì)的場景比如人機(jī)交互的視線估算10度準(zhǔn)確率更適合廣角粗定位比如車內(nèi)人員行為分析。如果看到acc_5因為少數(shù)大姿態(tài)樣本突然掉到80%以下先看是不是歐拉角符號定義和大姿態(tài)分布的問題。4.4 訓(xùn)練集和測試集要按人劃分這算是我吃過大虧的地方按幀隨機(jī)劃分?jǐn)?shù)據(jù)集模型會記住人臉換個人就掉點。正確的做法是按人頭subject_id劃分訓(xùn)練測試集保證測試集里的人沒有出現(xiàn)在訓(xùn)練集里。這個細(xì)節(jié)在頭部姿態(tài)估計里比在一般圖像分類里更敏感因為深度人臉結(jié)構(gòu)相似度很高模型很容易把面孔本身當(dāng)作特征。5. 頭部姿態(tài)估計常見問題排查現(xiàn)象、原因與對策這一章記的是我在真機(jī)上翻車后總結(jié)的排查思路。深度圖像頭部姿態(tài)估計的難點不在算法本身而在傳感器和場景的坑里。5.1 現(xiàn)象深度圖邊緣跳動導(dǎo)致姿態(tài)角每幀都在抖距離一超過量程深度圖邊緣會出現(xiàn)空洞和跳動頭部貼臉邊緣尤其明顯PnP或ICP結(jié)果就會跟著抖。 原因ToF深度相機(jī)在物體邊界處存在多路徑干擾和低置信度像素深度不連續(xù)區(qū)域的噪聲比平面區(qū)域大得多。 解決先做深度置信度過濾把無效和低置信度像素置零再做時域濾波比如對連續(xù)3到5幀的深度取像素級中值。一個小實現(xiàn)import numpy as np def temporal_median(depth_frames): # depth_frames: list/array [T, H, W]T一般取3或5 depth_stack np.stack(depth_frames, axis0) return np.median(depth_stack, axis0).astype(np.uint16)這個濾波能有效去掉跳變點而不會像均值濾波那樣把邊緣搞糊。訓(xùn)練時也可以隨機(jī)給深度圖加椒鹽噪聲讓網(wǎng)絡(luò)學(xué)會忽略邊緣跳變。5.2 現(xiàn)象換一臺相機(jī)誤差從 3 度漲到 8 度同一個模型在實驗室RealSense上很好到了產(chǎn)線上另一家的模組就掉點。 原因不同深度相機(jī)的內(nèi)參、深度尺度、分辨率甚至紅外投影圖案都不一樣模型學(xué)到的尺度信息沒有對齊。 解決把所有輸入統(tǒng)一到米制的三維空間而非原始像素深度。訓(xùn)練時把深度隨機(jī)縮放0.9到1.1倍模擬不同相機(jī)的尺度差異推理時根據(jù)新相機(jī)內(nèi)參重新裁剪和歸一化。這樣換相機(jī)的遷移損失會明顯變小。5.3 現(xiàn)象頭部旋轉(zhuǎn)超過 45 度PnP 關(guān)鍵點頻繁丟失大姿態(tài)下側(cè)臉、低頭會導(dǎo)致人臉關(guān)鍵點檢測器漏檢PnP退化成只有兩三個點可用的病態(tài)求解。 原因自遮擋加關(guān)鍵點模型的訓(xùn)練數(shù)據(jù)以正臉為主大姿態(tài)本身是長尾。 解決不要只依賴RGB人臉關(guān)鍵點深度圖上可以用整個頭部的點云去擬合橢圓或頭部模板給PnP提供更多幾何約束或者在跟蹤場景下用上一幀的位姿做外推限制當(dāng)前幀的搜索范圍。訓(xùn)練關(guān)鍵點檢測器時大姿態(tài)樣本要故意保留一部分遮擋。5.4 現(xiàn)象yaw 在 ±90 度附近輸出跳變甚至符號反轉(zhuǎn)回歸模型輸出yaw連續(xù)角度時在邊界處容易出現(xiàn)90度到-90度的跳變這會讓評估指標(biāo)突然惡化。 原因歐拉角本身存在周期性角度空間不是歐幾里得空間用L1或MSE直接回歸角度模型無法處理179與-179的等價性。 解決輸出sin、cos而不是角度推理用atan2還原或者把分類和回歸結(jié)合起來先判斷離散角度區(qū)間再回歸區(qū)間內(nèi)的偏移。評估時也要按前面寫的角度回繞邏輯先處理差值否則指標(biāo)失真。5.5 現(xiàn)象訓(xùn)練集指標(biāo)很高真機(jī)一跑就廢模型在Biwi測試集上MAE不到5度接到真實相機(jī)上各種跑偏。 原因數(shù)據(jù)分布差異包括相機(jī)高度、頭部到相機(jī)距離、安裝角度、人的坐姿習(xí)慣這些在數(shù)據(jù)集里是固定的在真機(jī)上是變化的。 解決離線階段留一部分真機(jī)采集數(shù)據(jù)做驗證訓(xùn)練時做域隨機(jī)化把深度值偏移、隨機(jī)裁剪、隨機(jī)縮放、隨機(jī)遮擋都加上。還有一個后悔藥不要在項目一開始就迷信精度指標(biāo)先搭一個包含“采集—標(biāo)注—訓(xùn)練—真機(jī)回灌”的閉環(huán)數(shù)據(jù)管道后面迭代會順很多。6. 上線前先做一輪仿真閉環(huán)最小驗證方案與角度編碼技巧最后這個技巧我?guī)缀趺總€項目都用。真機(jī)數(shù)據(jù)少、標(biāo)注貴我習(xí)慣先用仿真深度圖把算法鏈路跑通確認(rèn)坐標(biāo)系、角度定義、網(wǎng)絡(luò)輸出都沒有問題再上真機(jī)。第一步用Blender或Unity放一個頭部模型隨機(jī)擺yaw、pitch、roll渲染深度圖導(dǎo)出一張圖和對應(yīng)的角度真值。第二步在仿真數(shù)據(jù)上跑一遍你的PnP或回歸模型看誤差是不是在預(yù)期范圍。如果仿真都能跑出明顯錯誤多半是代碼里坐標(biāo)系定義反了而不是數(shù)據(jù)問題。第三步給仿真深度加噪聲和隨機(jī)裁剪模擬低質(zhì)量深度相機(jī)提前暴露算法短板。角度編碼這里再給一個挽救性的代碼段。回歸網(wǎng)絡(luò)不要在最后一層直接輸出角度而是輸出sin和cos# 訓(xùn)練時把角度轉(zhuǎn)成兩個值 angle_rad np.deg2rad(yaw_true) yaw_target np.array([np.sin(angle_rad), np.cos(angle_rad)]) # 推理時從兩個值還原角度 yaw_pred np.arctan2(yaw_sin, yaw_cos) * 180.0 / np.pi這樣訓(xùn)練目標(biāo)連續(xù)且沒有回繞邊界比直接回歸角度省去不少邊界對齊的功夫。pitch、roll同理輸出6個值推理時各自atan2還原。我的習(xí)慣是在動真機(jī)數(shù)據(jù)之前先用仿真把兩條最容易出問題的地方校驗掉——旋轉(zhuǎn)矩陣到歐拉角的符號定義以及深度尺度是否統(tǒng)一?,F(xiàn)在不管模型多復(fù)雜我都會先跑一遍這個閉環(huán)再去碰產(chǎn)線數(shù)據(jù)。希望幫到你。本文還有配套的精品資源點擊獲取