相机校准异常与立体视差图计算故障技术求助
问题描述
我正在开发一个基于立体视觉的项目,目标是计算人与物体到相机的深度和距离。硬件采用Jetson Nano开发套件搭配Waveshare IMX219-83双目相机,软件基于OpenCV实现。
运行视差计算代码时遇到以下问题:
- 已使用标定好的XML参数文件,但校正后的图像向右倾斜
- 视差图存在大量噪点,近处物体无法识别,整体呈现模糊状态
- 所有640x480分辨率的测试图像均出现该问题
相关代码
视差计算代码
from __future__ import print_function import numpy as np import cv2 def main(): cv_file = cv2.FileStorage() cv_file.open('stereoMap.xml', cv2.FILE_STORAGE_READ) stereoMapL_x = cv_file.getNode('stereoMapL_x').mat() stereoMapL_y = cv_file.getNode('stereoMapL_y').mat() stereoMapR_x = cv_file.getNode('stereoMapR_x').mat() stereoMapR_y = cv_file.getNode('stereoMapR_y').mat() imgL = cv2.imread("EpipolarGeometryAndStereoVision/left-images/left/fotoeditada.jpg", 0) imgL = cv2.resize(imgL, (640, 480)) imgL = cv2.remap(imgL, stereoMapL_x, stereoMapL_y, 0, 0, 0) imgR = cv2.imread("EpipolarGeometryAndStereoVision/right-images/right/fotoeditadaright.jpg", 0) # imgR = cv2.resize(imgR, (640, 480)) imgR = cv2.remap(imgR, stereoMapR_x, stereoMapR_y, 0, 0, 0) # StereoSGBM算法参数设置 minDisparity = 1 numDisparities = 60 - minDisparity blockSize = 5 uniquenessRatio = 1 speckleWindowSize = 3 speckleRange = 3 disp12MaxDiff = 100 P1 = 8 * 3 * blockSize ** 2 P2 = 32 * 3 * blockSize ** 2 stereo = cv2.StereoSGBM_create( minDisparity=minDisparity, numDisparities=numDisparities, blockSize=blockSize, uniquenessRatio=uniquenessRatio, speckleWindowSize=speckleWindowSize, speckleRange=speckleRange, disp12MaxDiff=disp12MaxDiff, P1=P1, P2=P2 ) # 计算视差 disparity = stereo.compute(imgL, imgR).astype(np.float32) / 16.0 cv2.imshow('leftview',imgL) cv2.imshow('rightview', imgR) cv2.imshow('disparity', (disparity - minDisparity) / numDisparities) cv2.waitKey() if __name__ == '__main__': main() cv2.destroyAllWindows()
立体相机标定代码
import numpy as np import cv2 as cv import glob ##### 查找棋盘格角点 - 物体点与图像点 chessboardSize = (8,6) frameSize = (480, 640) # 终止准则 criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 准备物体点(棋盘格方块尺寸24mm) objp = np.zeros((chessboardSize[0] * chessboardSize[1], 3), np.float32) objp[:,:2] = np.mgrid[0:chessboardSize[0],0:chessboardSize[1]].T.reshape(-1,2) objp = objp * 24 print(objp) # 存储所有图像的物体点和图像点 objpoints = [] # 真实世界中的3D点 imgpointsL = [] # 左图的2D图像点 imgpointsR = [] # 右图的2D图像点 imagesLeft = glob.glob('calibration/camera1/*.jpg') imagesRight = glob.glob('calibration/camera0/*.jpg') for imgLeft, imgRight in zip(imagesLeft, imagesRight): imgL = cv.imread(imgLeft) imgR = cv.imread(imgRight) grayL = cv.cvtColor(imgL, cv.COLOR_BGR2GRAY) grayR = cv.cvtColor(imgR, cv.COLOR_BGR2GRAY) # 查找棋盘格角点 retL, cornersL = cv.findChessboardCorners(grayL, chessboardSize, None) retR, cornersR = cv.findChessboardCorners(grayR, chessboardSize, None) # 若左右图均找到角点,添加物体点和优化后的图像点 if retL and retR: objpoints.append(objp) cornersL = cv.cornerSubPix(grayL, cornersL, (11,11), (-1,-1), criteria) imgpointsL.append(cornersL) cornersR = cv.cornerSubPix(grayR, cornersR, (11,11), (-1,-1), criteria) imgpointsR.append(cornersR) # 绘制并显示角点 cv.drawChessboardCorners(grayL, chessboardSize, cornersL, retL) cv.imshow('img left', grayL) cv.drawChessboardCorners(grayR, chessboardSize, cornersR, retR) cv.imshow('img right', grayR) cv.waitKey(1000) cv.destroyAllWindows() ####################### 单目标定 retL, cameraMatrixL, distL, rvecsL, tvecsL = cv.calibrateCamera(objpoints, imgpointsL, frameSize, None, None) heightL, widthL, channelsL = imgL.shape newCameraMatrixL, roi_L = cv.getOptimalNewCameraMatrix(cameraMatrixL, distL, (widthL, heightL), 1, (widthL, heightL)) retR, cameraMatrixR, distR, rvecsR, tvecsR = cv.calibrateCamera(objpoints, imgpointsR, frameSize, None, None) heightR, widthR, channelsR = imgR.shape newCameraMatrixR, roi_R = cv.getOptimalNewCameraMatrix(cameraMatrixR, distR, (widthR, heightR), 1, (widthR, heightR)) ############ 立体标定 ####### flags = 0 flags |= cv.CALIB_FIX_INTRINSIC # 固定内参,仅计算旋转、平移、本质矩阵和基础矩阵 criteria_stereo = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 计算两相机间的变换关系及本质/基础矩阵 retStereo, newCameraMatrixL, distL, newCameraMatrixR, distR, rot, trans, essentialMatrix, fundamentalMatrix = cv.stereoCalibrate(objpoints, imgpointsL, imgpointsR, newCameraMatrixL, distL, newCameraMatrixR, distR, grayL.shape[::-1], criteria_stereo, flags) ########## 立体校正 ################################################# rectifyScale= 1 rectL, rectR, projMatrixL, projMatrixR, Q, roi_L, roi_R = cv.stereoRectify(newCameraMatrixL, distL, newCameraMatrixR, distR, grayL.shape[::-1], rot, trans, rectifyScale,(0,0)) stereoMapL = cv.initUndistortRectifyMap(newCameraMatrixL, distL, rectL, projMatrixL, grayL.shape[::-1], cv.CV_16SC2) stereoMapR = cv.initUndistortRectifyMap(newCameraMatrixR, distR, rectR, projMatrixR, grayR.shape[::-1], cv.CV_16SC2) print("Saving parameters!") cv_file = cv.FileStorage('stereoMap.xml', cv.FILE_STORAGE_WRITE) cv_file.write('stereoMapL_x',stereoMapL[0]) cv_file.write('stereoMapL_y',stereoMapL[1]) cv_file.write('stereoMapR_x',stereoMapR[0]) cv_file.write('stereoMapR_y',stereoMapR[1]) cv_file.release()
问题排查与解决方案
图像倾斜问题
- 帧尺寸匹配修正:标定代码中
frameSize = (480, 640)格式错误,OpenCV要求frameSize为**(宽, 高)**,需改为(640, 480),重新标定生成参数文件。 - 左右图像尺寸统一:视差计算代码中仅对左图做了resize,右图注释掉了该操作,若左右图原始尺寸不一致会导致校正错位,需确保左右图在校正前均resize为640x480。
视差图噪点与模糊问题
- StereoSGBM参数优化:
numDisparities:必须是16的整数倍,当前60-1=59不符合要求,建议改为64 - minDisparity(如minDisparity设为0时用64);blockSize:从5增大到7或9,提升低纹理区域的匹配稳定性;uniquenessRatio:从1提高到5-15,过滤模糊匹配结果;speckleWindowSize和speckleRange:分别调整为50和2,减少小面积噪点;disp12MaxDiff:从100降至10-20,限制左右视差的最大差值。
- 图像预处理:在校正后添加高斯模糊(
cv2.GaussianBlur(imgL, (3,3), 0))或直方图均衡化(cv2.equalizeHist(imgL)),提升图像对比度,降低噪点干扰。 - 标定精度提升:采集至少20组不同角度、距离的棋盘格图像,确保角点识别准确,重新标定以获取更可靠的内参和外参。
内容的提问来源于stack exchange,提问作者user21221525
相关产品推荐
相关产品推荐

