:從標定到點云的完整Python實現(xiàn))
簡介這套源碼基于Python實現(xiàn)單目與雙目視覺三維重建覆蓋單目關(guān)鍵點估計、雙目深度恢復、圖像拼接等典型任務面向計算機視覺方向的畢業(yè)設計、課程設計或項目開發(fā)。壓縮包共42個文件整體大小約80.22MB包含3個Python腳本、1個Markdown說明、3個文本輔助文檔、34張JPG圖像及PNG示意文件。腳本按單目、雙目、圖像融合模塊拆分圖片數(shù)據(jù)可用于相機標定、特征提取與重建效果對比文檔對工程結(jié)構(gòu)、運行邏輯和依賴環(huán)境作了梳理。源碼經(jīng)過嚴格測試并保留清晰的目錄結(jié)構(gòu)便于二次開發(fā)、算法替換或數(shù)據(jù)集擴展。目前已有172人學習下載適合希望系統(tǒng)理解三維重建全流程并快速動手實踐的開發(fā)者參考。1. 單目雙目三維重建是課程設計的完整閉環(huán)不是兩個模塊的簡單拼裝如果你正在做課程設計或畢業(yè)設計看到“基于python開發(fā)的單目雙目視覺三維重建源碼”這個標題先別把它理解成“單目一套、雙目一套、各跑各的”。實際能拿到分、能寫進論文里的方案是一套從圖像采集、標定、立體匹配走到三維點云的完整工程單目負責快速測距和粗定位雙目負責稠密視差和點云重建兩者在同一個Python工程里互補。這套東西適合需要完整演示效果、又要能講清楚原理的課設和畢設也適合剛接手視覺項目開發(fā)的從業(yè)者用來建立坐標系、標定、視差、點云這條主線認知。下面按這條主線把原理、可復現(xiàn)代碼和踩坑點講透。2. 單目三維重建的真實邊界它不是重建是帶先驗的深度估計2.1 單目為什么解不出絕對深度從4個自由度和相機方程說起把三維空間里的一個點投影到二維圖像小孔成像模型寫下來是世界坐標 (X, Y, Z) 通過外參變換到相機坐標 (Xc, Yc, Zc)再通過內(nèi)參投影到像素坐標 (u, v)整個過程里已知的是像素坐標未知的是包括尺度在內(nèi)的4個自由度。單個相機只有兩條約束方程深度 Z 被直接丟掉了。所以“單目三維重建”嚴格講不成立單目只能做“帶先驗的深度估計”這也是很多畢設開題時被答辯老師追問最多的地方。常見的先驗有這么幾種已知目標尺寸比如人臉寬度、車牌寬度、ARUCO碼邊長用像素寬度反推距離已知地面平面通過消失點和相機高度估計路面上物體的距離運動視差同一目標在相機移動中出現(xiàn)視差本質(zhì)是“用時間換視角”在這個標題的項目里單目模塊最常見的角色是第一種先測出目標大概距離再指導雙目在什么深度范圍、什么圖像區(qū)域里做稠密匹配。理解了這一點你就知道標題里的“單目”不是用來輸出點云的它是雙目的前置引導。2.2 先落地一個能跑的單目測距ArUco標記加已知尺寸的快速實現(xiàn)在Python里做單目測距最簡單可靠的方式是用ArUco碼。它本身自帶角點檢測和ID識別不需要訓練模型標定一次相機內(nèi)參后就能穩(wěn)定測距。import cv2 import numpy as np # 注意OpenCV 4.7以下用Dictionary_get4.7以上建議用getPredefinedDictionary aruco_dict cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_50) params cv2.aruco.DetectorParameters_create() KNOWN_WIDTH_MM 80 # ArUco碼的實際邊長單位毫米 fx 812.34 # 相機內(nèi)參fx來自棋盤格標定單位像素 cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break corners, ids, _ cv2.aruco.detectMarkers(frame, aruco_dict, parametersparams) if ids is not None: # corners[0] 是第一個marker的四角點順序是左上、右上、右下、左下 width_px np.linalg.norm(corners[0][0][0] - corners[0][0][1]) if width_px 1e-6: distance_mm KNOWN_WIDTH_MM * fx / width_px cv2.putText(frame, fdist: {distance_mm/1000:.2f} m, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) cv2.imshow(mono_distance, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()這里的核心公式是D W * fx / w_px它來自相似三角形目標實際寬度 W在圖像里占了 w_px 像素焦距 fx 已知距離就被唯一確定。需要注意fx必須是像素單位不能拿毫米焦距直接代入width_px取的是ArUco碼上邊兩個角點的距離不是整張圖寬度測距結(jié)果對KNOWN_WIDTH_MM極其敏感貼碼之前用卡尺量準如果你沒有ArUco碼也可以打印一張黑色正方形貼在硬紙板上用輪廓檢測取邊長。但ArUco的好處是自帶ID后續(xù)做多目標定位、目標身份區(qū)分都方便在課程設計的演示環(huán)節(jié)也更完整。這個代碼跑通后單目模塊就完成了一大半。2.3 單目測距的三個參數(shù)陷阱目標寬度、觀測角度、焦距誤差單目測距看起來只有一行公式實際調(diào)參時容易翻車的地方不少。第一目標寬度不準。寬度誤差會線性傳導到距離誤差80mm的碼你量成90mm測出的距離就會虛高12.5%。所以不要用卷尺大概量一下要精確到毫米。第二觀測角度不是正對。公式假設相機光軸垂直指向ArUco碼平面。一旦目標傾斜圖像里測到的寬度會變短距離就被高估。斜著30度時誤差通常在15%以上。解決方案是在測距前用cv2.aruco.estimatePoseSingleMarkers解出旋轉(zhuǎn)向量判斷角度超過閾值就告警或不做測距。第三fx不準。很多人圖省事用圖像寬度/(2*tan(FOV/2))估算fx這種近似在畫面邊緣誤差很大。單目測距的精度上限由fx決定而fx必須來自標定。你可以在后續(xù)雙目標定階段順便把單目內(nèi)參一起標出來不要單獨省這步。這三個坑告訴我們一個結(jié)論單目測距只能給出“大概在這個深度范圍”的先驗別拿它當精密儀器。在標題這種“單目雙目”項目里單目的任務是把目標深度從完全未知縮小到某個區(qū)間剩下的事交給雙目。3. 雙目三維重建的完整鏈路從標定到點云一條命令一個節(jié)點3.1 視差與深度為什么基線越大越能看見“深度”雙目視覺能恢復深度靠的是左右相機對同一空間點的“視差”。三維點越近它在左右圖里的水平位置差越大越遠視差越小這就是人眼判斷遠近的原理。數(shù)學關(guān)系是depth fx * baseline / disparitybaseline左右相機光心之間的距離單位米disparity左右圖像的像素橫坐標差單位像素fx內(nèi)參中的焦距單位像素從這個公式能讀出兩個關(guān)鍵判斷基線越大相同視差對應的深度越大遠距離精度越好視差誤差對深度的影響與距離平方成正比所以雙目重建遠距離物體時精度掉得特別快這決定了做三維重建時的硬件選擇課設/畢設階段如果手里只有普通的USB雙攝模組基線一般只有6~12cm有效重建距離通常在0.2~3米。超出這個范圍點云會變得很稀疏這是物理限制不是代碼能完全彌補的。整個雙目三維重建流程在OpenCV里是一條固定流水線單目標定 - 立體標定 - 立體校正 - 立體匹配 - 點云生成。下面按這個順序把每一段代碼和參數(shù)說清楚。3.2 第一步棋盤格采集與相機內(nèi)參標定雙目重建的地基是內(nèi)參和畸變系數(shù)。不做標定直接跑SGBM出來的點云會扭曲得不成樣子。第一步是采集標定板圖像并計算左右相機內(nèi)參。import cv2 import numpy as np # 棋盤格的內(nèi)角點數(shù)例如打印的是10x7格子內(nèi)角點就是(9,6) CHECKERBOARD (9, 6) criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32) objp[:, :2] np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2) objpoints [] # 3D角點單位可以理解為“格數(shù)”后續(xù)需要乘實際格子邊長 imgpoints_l [] imgpoints_r [] for name_l, name_r in zip(files_left, files_right): img_l cv2.imread(name_l) img_r cv2.imread(name_r) gray_l cv2.cvtColor(img_l, cv2.COLOR_BGR2GRAY) gray_r cv2.cvtColor(img_r, cv2.COLOR_BGR2GRAY) ret_l, corners_l cv2.findChessboardCorners(gray_l, CHECKERBOARD, None) ret_r, corners_r cv2.findChessboardCorners(gray_r, CHECKERBOARD, None) if ret_l and ret_r: objpoints.append(objp) corners_l cv2.cornerSubPix(gray_l, corners_l, (11, 11), (-1, -1), criteria) corners_r cv2.cornerSubPix(gray_r, corners_r, (11, 11), (-1, -1), criteria) imgpoints_l.append(corners_l) imgpoints_r.append(corners_r) ret_l, K1, D1, _, _ cv2.calibrateCamera(objpoints, imgpoints_l, gray_l.shape[::-1], None, None) ret_r, K2, D2, _, _ cv2.calibrateCamera(objpoints, imgpoints_r, gray_r.shape[::-1], None, None) np.savez(camera_params.npz, K1K1, D1D1, K2K2, D2D2, ret_lret_l, ret_rret_r) print(left rms:, ret_l, right rms:, ret_r)這里有一個常見誤解CHECKERBOARD填的是內(nèi)角點數(shù)量不是棋盤格數(shù)量。如果打印的棋盤是10x7個小方格內(nèi)角點就是9x6寫錯的話findChessboardCorners會一直失敗。另外objp里每個角點的坐標單位是“格”不是毫米。如果你之后希望點云以米為單位需要在三角化時乘上棋盤格的實際邊長。calibrateCamera返回的ret就是重投影誤差單位是像素小于0.3說明標定質(zhì)量不錯超過0.5就需要檢查圖片數(shù)量和角度分布。3.3 第二步立體校正讓左右圖嚴格行對齊左右相機安裝時不可能完全平行直接做匹配會找不到對應點。立體校正就是把左右圖像重投影到同一個理想平面上讓同名點處于同一行。# 繼續(xù)上面的變量K1, D1, K2, D2 是單目標定結(jié)果 # R 是右相機相對左相機的旋轉(zhuǎn)矩陣T 是平移向量來自 stereocalibrate ret_stereo, K1, D1, K2, D2, R, T, E, F cv2.stereoCalibrate( objpoints, imgpoints_l, imgpoints_r, K1, D1, K2, D2, gray_l.shape[::-1], criteriacriteria, flagscv2.CALIB_FIX_INTRINSIC) R1, R2, P1, P2, Q, validPixROI1, validPixROI2 cv2.stereoRectify( K1, D1, K2, D2, gray_l.shape[::-1], R, T, alpha0, flagscv2.CALIB_ZERO_DISPARITY) map1x, map1y cv2.initUndistortRectifyMap( K1, D1, R1, P1, gray_l.shape[::-1], cv2.CV_32FC1) map2x, map2y cv2.initUndistortRectifyMap( K2, D2, R2, P2, gray_l.shape[::-1], cv2.CV_32FC1) rect_l cv2.remap(img_l, map1x, map1y, cv2.INTER_LINEAR) rect_r cv2.remap(img_r, map2x, map2y, cv2.INTER_LINEAR)這段代碼的關(guān)鍵參數(shù)是flagscv2.CALIB_ZERO_DISPARITY。它讓左右相機的主點在校正后保持不變視差只由水平位移產(chǎn)生后續(xù)Q矩陣才能正確地把視差轉(zhuǎn)成三維坐標。alpha0表示裁剪掉校正后無內(nèi)容的黑色區(qū)域會損失一部分邊緣視野但能減少無效像素。拿到rect_l和rect_r之后一定要畫幾條水平線檢查行對齊check np.hstack([rect_l, rect_r]) for y in range(0, check.shape[0], 100): cv2.line(check, (0, y), (check.shape[1], y), (0, 255, 0), 1)如果同一行上的對應點在視覺上有明顯上下偏移說明立體校正沒生效需要回去檢查標定圖像質(zhì)量而不是急著調(diào)SGBM。行對齊誤差超過1個像素視差圖質(zhì)量會明顯下降。3.4 第三步SGBM視差計算與參數(shù)調(diào)節(jié)立體匹配算法里OpenCV自帶StereoBM和StereoSGBM。BM快但噪聲大SGBM慢一點但視差圖更平滑課設畢設通常選SGBM。left_matcher cv2.StereoSGBM_create( minDisparity-1, numDisparities64, blockSize11, P18 * 3 * blockSize * blockSize, P232 * 3 * blockSize * blockSize, disp12MaxDiff1, uniquenessRatio10, speckleWindowSize100, speckleRange32, modecv2.STEREO_SGBM_MODE_SGBM) disparity left_matcher.compute( cv2.cvtColor(rect_l, cv2.COLOR_BGR2GRAY), cv2.cvtColor(rect_r, cv2.COLOR_BGR2GRAY)).astype(np.float32) / 16.0SGBM輸出的是定點數(shù)除以16才轉(zhuǎn)換成真實像素視差。這個16是算法內(nèi)部的精度縮放別漏掉否則后面轉(zhuǎn)點云時深度會整體偏差16倍。各參數(shù)的實際作用參數(shù)常見范圍作用與調(diào)參方向numDisparities16~128必須16的倍數(shù)視差搜索范圍越大能覆蓋越近的物體但耗時增加minDisparity-32~0搜索起點設為負數(shù)能減少視差圖左側(cè)空洞blockSize3~15奇數(shù)匹配窗口大小越大越平滑但邊緣細節(jié)丟失P1/P28/32 * 通道數(shù) * blockSize2平滑懲罰項P2越大越能抑制深度突變uniquenessRatio5~15唯一性約束越大誤匹配越少但過低紋理區(qū)域容易空洞disp12MaxDiff0~2左右一致性檢查閾值建議1speckleWindowSize50~200去除視差孤立小區(qū)域speckleRange8~32連通區(qū)域允許的視差波動調(diào)參順序不要亂先固定blockSize把numDisparities調(diào)到覆蓋目標深度范圍再調(diào)uniquenessRatio降噪最后用speckleWindowSize清理小噪點。如果覺得視差圖“太碎”優(yōu)先加P2而不是強行加大blockSize。3.5 第四步視差轉(zhuǎn)三維點云并輸出PLY得到視差圖后用立體校正階段的Q矩陣做重投影這一步把每個像素映射到三維坐標points3D cv2.reprojectImageTo3D(disparity, Q) # 視差為0的點是匹配失敗點直接剔除 mask disparity 0 points points3D[mask] colors rect_l[mask] # 過濾掉相機背后的點Z0和過遠的點 valid (points[:, 2] 0.1) (points[:, 2] 10.0) points points[valid] colors colors[valid] import open3d as o3d pcd o3d.geometry.PointCloud() pcd.points o3d.utility.Vector3dVector(points) pcd.colors o3d.utility.Vector3dVector(colors / 255.0) o3d.io.write_point_cloud(reconstruction.ply, pcd)Q矩陣的第4行第3列通常是1.0 / baseline所以輸出的Z軸單位由立體標定時使用的棋盤格尺寸決定。如果你在objp里用的是“格”而不是實際米數(shù)點云坐標會按格縮放。為了讓PLY文件里的尺寸和真實世界對應標定時應把objp乘上棋盤格實際邊長比如objp * 0.025表示每個格子25mm。這一段跑通后你就擁有了一套完整的雙目三維重建最小系統(tǒng)。很多課程設計做到這里就可以演示了但標題里還有“單目”下一章講怎么把單目和雙目擰成一個整體。4. 單目雙目怎么真正合起來用單目做興趣區(qū)用雙目做稠密建點4.1 為什么要讓單目先去“摸個底”直接對整幅圖跑SGBM也不是不行但在實際場景里有兩個問題算力浪費。SGBM是典型的計算密集算法視差搜索范圍越大、圖像分辨率越高耗時越長。對1080P圖像全圖搜索100像素視差普通筆記本可能跑出幾百毫秒甚至一秒以上課設演示時卡頓感很強。誤匹配。背景里的大片無紋理區(qū)域比如白墻、天空、桌面SGBM在這些區(qū)域會給出大量錯誤視差產(chǎn)生的點云像雪花一樣亂飛。如果用單目先定位目標在畫面里的位置和大概深度SGBM就可以只在目標區(qū)域、目標深度范圍內(nèi)搜索。在標題這種“單目雙目”的架構(gòu)里單目檢測模塊通常就是一個ArUco檢測器或者YOLO目標檢測器。它輸出目標在左圖中的包圍盒以及單目測距得到的深度先驗。這個深度先驗能直接換算成視差范圍。4.2 用單目距離約束SGBM的視差搜索范圍視差和深度的關(guān)系是disparity fx * baseline / depth。假設單目測出目標距離大約1.5米基線0.12米fx約800那目標處的視差大約就是64像素。這個時候把SGBM的搜索窗口設置在64附近而不是從0搜到128既能減少計算量也能避開背景干擾。import numpy as np fx 812.34 # 來自雙目標定 baseline 0.12 # 單位米來自 stereoCalibrate 得到的 T dist_guess 1.5 # 單位米來自單目測距 # 目標處的理論視差 disp_center int(fx * baseline / dist_guess) # 搜索范圍在理論值前后各留24像素余量并保證是16的倍數(shù) margin 24 num_disparities 64 if disp_center - margin 0: min_disp 0 num_disparities 128 else: min_disp disp_center - margin num_disparities 64 # 確保 num_disparities 是16的倍數(shù)且非負 num_disparities max(16, int(np.ceil(num_disparities / 16.0) * 16)) left_matcher.setMinDisparity(min_disp) left_matcher.setNumDisparities(num_disparities)這里有個容易被忽略的邊界條件minDisparity可以為負但numDisparities必須是正的16倍數(shù)。如果目標很近理論視差大于搜索窗口SGBM會匹配失敗這時要增大num_disparities而不是繼續(xù)提高min_disp。深度先驗還能用來過濾點云。單目測出1.5米雙目重建后突然出現(xiàn)一堆深度在0.5米或5米的點大概率是誤匹配直接按距離區(qū)間切掉depth points3D[:, 2] depth_mask (depth dist_guess * 0.5) (depth dist_guess * 1.5)這一步不是簡單的濾波而是把單目模塊的粗測信息和雙目的精測信息做了決策級融合論文里可以寫成“基于深度先驗的離群點剔除”。在答辯時這個點很加分的。4.3 融合后的結(jié)果檢查誰在拖慢速度誰在破壞精度單目和雙目融合后代碼運行時間大多花在三個地方圖像縮放、SGBM匹配、點云生成。要判斷瓶頸在哪最笨也最有效的方法是分別給三段代碼打時間戳。import time t0 time.time() rect_l cv2.remap(img_l, map1x, map1y, cv2.INTER_LINEAR) t1 time.time() disparity left_matcher.compute(gray_l, gray_r) t2 time.time() points3D cv2.reprojectImageTo3D(disparity, Q) t3 time.time() print(fremap: {(t1-t0)*1000:.1f}ms, sgbm: {(t2-t1)*1000:.1f}ms, reproject: {(t3-t2)*1000:.1f}ms)一般來說SGBM會占掉80%以上的時間。所以性能優(yōu)化優(yōu)先級是先縮小SGBM輸入圖像尺寸再限制視差搜索范圍最后才是換算法。如果用ROI框出目標區(qū)域把SGBM只跑在這個區(qū)域里速度還能再快一截——但這時要注意ROI外的點云會被丟棄如果你要重建整個場景就不能這么干。另外要提醒一句單目測距的誤差不要直接當成雙目的誤差。單目給出的是搜索區(qū)間真正決定點云精度的還是雙目基線、標定精度和SGBM參數(shù)。不要為了讓單目“看起來準”而拼命調(diào)ArUco寬度那是舍本逐末。5. 避坑清單標定、立體匹配與點云輸出的五個高頻翻車點5.1 標定重投影誤差居高不下內(nèi)參總覺得“飄”現(xiàn)象calibrateCamera返回的rms超過0.5或者內(nèi)參fx每次標定結(jié)果差幾十像素。原因標定圖片太少或者角度分布過于集中棋盤格在畫面里占比太小。解決重新采集20~30張左右圖像對。采集時讓棋盤格以不同傾斜角度出現(xiàn)在畫面四周和中心每張圖里棋盤格面積至少占畫面的1/3。如果某一對圖像只有單側(cè)檢測到角點直接丟棄這組數(shù)據(jù)不要硬標。標定板采集是整條重建鏈路里最像“玄學”的環(huán)節(jié)但90%的問題出在偷懶少拍了圖片。5.2 視差圖左邊大片空洞深度圖像被撕掉一塊現(xiàn)象生成的視差圖左側(cè)有大片黑色區(qū)域右側(cè)正常。原因左圖的左邊界附近匹配點在右圖上已經(jīng)超出圖像范圍SGBM找不到對應點。解決把minDisparity設為負數(shù)比如-8或-16給左邊界留出搜索余量。注意minDisparity和numDisparities是配合使用的搜索范圍是[minDisparity, minDisparitynumDisparities]。設了負值之后右側(cè)的搜索上限會變小如果右側(cè)也出現(xiàn)空洞就同時增大numDisparities。5.3 平面物體重建出來是“弧面”怎么看怎么別扭現(xiàn)象一面平整的墻或一塊標定板重建點云后變成向內(nèi)凹或向外凸的曲面。原因立體校正不徹底左右圖行對齊誤差超過1像素或者畸變標定不夠準邊緣像素的投影位置有系統(tǒng)偏差。SGBM的匹配誤差也會造成小范圍起伏但不至于整體彎曲。解決先用3.3節(jié)的方法畫橫線檢查行對齊。如果對齊沒問題檢查內(nèi)參標定時的重投影誤差。最后再用平面擬合驗證對點云跑RANSAC平面擬合看擬合誤差。如果整體呈弧面最優(yōu)先懷疑的就是標定環(huán)節(jié)不要急著調(diào)SGBM參數(shù)。5.4 低紋理區(qū)域出現(xiàn)大量錯誤匹配點云像“雪花”現(xiàn)象白墻、桌面這類區(qū)域點云稀疏且雜亂黑色噪點或飛點特別多。原因立體匹配在無紋理區(qū)域沒有足夠的灰度信息來區(qū)分同名點SGBM只能按平滑約束瞎猜。光照過強導致的反光會讓這個問題更嚴重。解決先調(diào)uniquenessRatio到10以上提升匹配唯一性要求再調(diào)speckleWindowSize到100以上把孤立的小塊噪點消掉。如果還是不行用WLS濾波對視差圖做后處理需要安裝opencv-contrib-python調(diào)用cv2.ximgproc.createDisparityWLSFilter。最后一道防線是直接用4.2節(jié)的距離先驗把明顯不合理的深度點剔除。5.5 點云顏色錯位不知道顏色從哪張圖來的現(xiàn)象點云形狀對了但顏色像“貼錯皮”邊緣有重影。原因點云顏色來自左圖但重建出的三維點坐標和左圖像素不是一一對應尤其是視差邊緣區(qū)域微小誤差會被放大成明顯的顏色錯位。還有人把右圖顏色直接賦給了左圖坐標那必然錯位。解決統(tǒng)一從reprojectImageTo3D輸出的坐標和左圖顏色生成點云不要和右圖混用。剔除disparity 0和disparity 0的點因為這些點沒有有效匹配顏色沒有意義。保存PLY后用Open3D或MeshLab打開檢查邊緣是否和圖像邊緣吻合。6. 驗證這套系統(tǒng)是否可靠的三步檢查法6.1 對標定結(jié)果做反投影誤差檢查標定完不要急著跑重建先看calibrateCamera的rms值。單目標定rms要小于0.3像素雙目標定stereoCalibrate返回的rms也要在0.3附近。如果超過0.5重建精度沒有保證。更直觀的驗證是把標定板放在已知距離用雙目視差計算的深度和實際距離對比誤差在2%以內(nèi)算正常。6.2 對單目測距做定距離驗證把ArUco碼放在1米、1.5米、2米處各測十次記錄誤差均值和波動。如果誤差超過5%檢查目標寬度是否量準、fx是否來自標定。這一項驗證至少要做否則融合方案里“單目引導雙目”的可信度不夠。6.3 用Open3D從PLY看三維結(jié)構(gòu)是否正常點云生成后用Open3D做兩步檢查。第一步統(tǒng)計點云數(shù)量太少說明匹配大面積失敗太多但有大量飛點說明參數(shù)太寬松。第二步對典型平面目標做RANSAC平面擬合看擬合內(nèi)點比例和平面法向量。如果標定板擬合出來的法向量和相機光軸明顯不垂直說明校正還有問題。import open3d as o3d pcd o3d.io.read_point_cloud(reconstruction.ply) plane_model, inliers pcd.segment_plane(distance_threshold0.005, ransac_n3, num_iterations1000) print(plane normal:, plane_model[:3]) print(inlier points:, len(inliers), /, len(pcd.points))我自己的習慣是每換一次相機或場景都先跑一輪這個三步檢查確認標定、匹配、點云三條鏈路都在正常狀態(tài)再繼續(xù)往下調(diào)參數(shù)。這套項目里最容易讓人卡住的就是標定那關(guān)圖片拍夠了、角度鋪開了后面SGBM和點云基本是水到渠成。希望這篇筆記能幫你把這條鏈路走通少交點標定學費。本文還有配套的精品資源點擊獲取