0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从双目标定到立体匹配:Python实践指南

3D视觉工坊 来源:3D视觉工坊 2023-06-08 16:28 次阅读

立体匹配是计算机视觉中的一个重要领域,旨在将从不同角度拍摄的图像匹配起来,以创建类似人类视觉的3D效果。实现立体匹配的过程需要涉及许多步骤,包括双目标定、立体校正、视差计算等。在这篇文章中,将介绍如何使用Python实现立体匹配的基本步骤和技巧。

f03103a6-05d5-11ee-962d-dac502259ad0.png

下面的代码实现了从相机标定到立体匹配的完整流程,下面将分别介绍各个函数的参数和输出。

标定

首先,该程序需要用到以下库:

numpy
cv2(OpenCV)
os

在程序开头,需要定义一些变量来存储标定图片的路径、棋盘格参数、角点坐标等等。具体介绍如下:

path_left="./data/left/"
path_right="./data/right/"

path_left和path_right是左右相机标定图片文件夹的路径。

CHESSBOARD_SIZE=(8,11)
CHESSBOARD_SQUARE_SIZE=15#mm

CHESSBOARD_SIZE是棋盘格内部角点的行列数,CHESSBOARD_SQUARE_SIZE是棋盘格内部每个小正方形的大小(单位为毫米)。

objp=np.zeros((CHESSBOARD_SIZE[0]*CHESSBOARD_SIZE[1],3),np.float32)
objp[:,:2]=np.mgrid[0:CHESSBOARD_SIZE[0],0:CHESSBOARD_SIZE[1]].T.reshape(-1,2)*CHESSBOARD_SQUARE_SIZE

objp是物理坐标系下每个角点的三维坐标,即棋盘格的位置。该变量在后续的相机标定以及立体匹配中都会被用到。

criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,30,0.001)

criteria是角点检测的终止准则,一般都使用这个默认值。

img_list_left=sorted(os.listdir(path_left))
img_list_right=sorted(os.listdir(path_right))

img_list_left和img_list_right分别是左、右图像的文件名列表,使用os.listdir()函数获取。

obj_points=[]
img_points_left=[]
img_points_right=[]

obj_points、img_points_left和img_points_right分别是存储每个标定图片对应的物理坐标系下的角点坐标、左相机的像素坐标和右相机的像素坐标。这些变量同样在后续的相机标定和立体匹配中用到。

接下来,程序读取标定图片并检测角点。对于每幅图片,程序执行以下操作:

img_l=cv2.imread(path_left+img_list_left[i])
img_r=cv2.imread(path_right+img_list_right[i])
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,CHESSBOARD_SIZE,None)
ret_r,corners_r=cv2.findChessboardCorners(gray_r,CHESSBOARD_SIZE,None)

通过OpenCV的cv2.findChessboardCorners()函数检测左右图像上的棋盘格角点。这个函数的参数包括:

image:需要检测角点的灰度图像。patternSize:内部角点的行列数,即(CHESSBOARD_SIZE[1]-1, CHESSBOARD_SIZE[0]-1)。corners:用于存储检测到的角点坐标的数组。如果检测失败,则该参数为空(None)。flags:检测时使用的可选标志。这个函数的返回值包括:

ret:一个布尔值,用于指示检测是否成功。如果检测成功,则为True,否则为False。corners:用于存储检测到的角点坐标的数组。接下来是亚像素级别的角点检测。

cv2.cornerSubPix(gray_l,corners_l,(11,11),(-1,-1),criteria)
cv2.cornerSubPix(gray_r,corners_r,(11,11),(-1,-1),criteria)

这里使用了OpenCV的cv2.cornerSubPix()函数来进行亚像素级别的角点检测。这个函数的参数包括:

image:输入的灰度图像。
corners:用于存储检测到的角点坐标的数组。
winSize:每次迭代中搜索窗口的大小,即每个像素周围的搜索范围大小。通常为11x11。
zeroZone:死区大小,表示怎样的对称性(如果有的话)不考虑。通常为(-1,-1)。
criteria:定义迭代停止的误差范围、迭代次数等标准,和以上的criteria一样。

img_points_left.append(corners_l)
img_points_right.append(corners_r)

如果检测到了左右图像上的角点,则将这些角点的坐标存储到img_points_left和img_points_right中。

cv2.drawChessboardCorners(img_l,CHESSBOARD_SIZE,corners_l,ret_l)
cv2.imshow("ChessboardCorners-Left",cv2.resize(img_l,(img_l.shape[1]//2,img_l.shape[0]//2)))
cv2.waitKey(50)

cv2.drawChessboardCorners(img_r,CHESSBOARD_SIZE,corners_r,ret_r)
cv2.imshow("ChessboardCorners-Right",cv2.resize(img_r,(img_r.shape[1]//2,img_r.shape[0]//2)))
cv2.waitKey(50)

f067cae4-05d5-11ee-962d-dac502259ad0.png在图片上标出检测到的角点,并在窗口中显示。这里使用了cv2.drawChessboardCorners()函数,该函数的参数包括:

img:需要标定角点的图像。patternSize:内部角点的行列数,即(CHESSBOARD_SIZE[1]-1, CHESSBOARD_SIZE[0]-1)。
corners:存储检测到的角点坐标的数组。patternfound:检测到角点的标记,即ret。

程序接下来对双目摄像机进行标定。

ret_l,mtx_l,dist_l,rvecs_l,tvecs_l=cv2.calibrateCamera(obj_points,img_points_left,gray_l.shape[::-1],None,None)
ret_r,mtx_r,dist_r,rvecs_r,tvecs_r=cv2.calibrateCamera(obj_points,img_points_right,gray_r.shape[::-1],None,None)

flags=0
flags|=cv2.CALIB_FIX_INTRINSIC
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,30,0.001)
ret,M1,d1,M2,d2,R,T,E,F=cv2.stereoCalibrate(
obj_points,img_points_left,img_points_right,
mtx_l,dist_l,mtx_r,dist_r,
gray_l.shape[::-1],criteria=criteria,flags=flags)

这段代码首先对左右相机进行单独标定:

ret_l,mtx_l,dist_l,rvecs_l,tvecs_l=cv2.calibrateCamera(obj_points,img_points_left,gray_l.shape[::-1],None,None)
ret_r,mtx_r,dist_r,rvecs_r,tvecs_r=cv2.calibrateCamera(obj_points,img_points_right,gray_r.shape[::-1],None,None)

这里使用了OpenCV的cv2.calibrateCamera()函数对左右相机进行标定。这个函数的参数包括:

objectPoints:每幅标定图片对应的物理坐标系下的角点坐标。
imagePoints:每幅标定图片上检测到的像素坐标。
imageSize:标定图片的尺寸。
cameraMatrix:用于存储标定结果的内参数矩阵。
distCoeffs:用于存储标定结果的畸变系数。
rvecs:每幅标定图片的外参数矩阵中的旋转向量。
tvecs:每幅标定图片的外参数矩阵中的平移向量。
这个函数的返回值包括:

ret:一个标志位,表示标定是否成功。
cameraMatrix:用于存储标定结果的内参数矩阵。
distCoeffs:用于存储标定结果的畸变系数。
rvecs:每幅标定图片的外参数矩阵中的旋转向量。
tvecs:每幅标定图片的外参数矩阵中的平移向量。
然后对双目摄像机进行标定:

flags=0
flags|=cv2.CALIB_FIX_INTRINSIC
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,30,0.001)
ret,M1,d1,M2,d2,R,T,E,F=cv2.stereoCalibrate(
obj_points,img_points_left,img_points_right,
mtx_l,dist_l,mtx_r,dist_r,
gray_l.shape[::-1],criteria=criteria,flags=flags)

这里使用了OpenCV的cv2.stereoCalibrate()函数进行双目摄像机标定。这个函数的参数包括:

objectPoints:每幅标定图片对应的物理坐标系下的角点坐标。
imagePoints1:每幅标定图片的左相机上检测到的像素坐标。
imagePoints2:每幅标定图片的右相机上检测到的像素坐标。
cameraMatrix1:左相机的内参数矩阵。
distCoeffs1:左相机的畸变系数。
cameraMatrix2:右相机的内参数矩阵。
distCoeffs2:右相机的畸变系数。
imageSize:标定图片的尺寸。
criteria:定义迭代停止的误差范围、迭代次数等标准。
flags:标定的可选标志。
这个函数的返回值包括:

ret:一个标志,表示标定是否成功。
cameraMatrix1:左相机的内参数矩阵。
distCoeffs1:左相机的畸变系数。
cameraMatrix2:右相机的内参数矩阵。
distCoeffs2:右相机的畸变系数。
R:旋转矩阵。
T:平移向量。
E:本质矩阵。
F:基础矩阵。

立体匹配

通过图像标定得到的参数进行立体匹配的整个流程,如下:

首先,我们需要读取左右两张图像:

img_left=cv2.imread("./left.png")
img_right=cv2.imread("./right.png")

其中,"./left.png" 和 "./right.png" 是放置左右图像的路径。这两幅图像是未经校正和矫正的图像。

接下来,通过图像标定得到相机的参数,根据得到的参数,将图像进行去畸变:

img_left_undistort=cv2.undistort(img_left,M1,d1)
img_right_undistort=cv2.undistort(img_right,M2,d2)

在上述代码中,M1、M2、d1、d2 是从双目相机标定中获得的参数。去畸变后的图像 img_left_undistort 和 img_right_undistort 可供之后的操作使用。

然后,进行极线校正,以实现左右图像在几何上的一致性:

R1,R2,P1,P2,Q,roi1,roi2=cv2.stereoRectify(M1,d1,M2,d2,(width,height),R,T,alpha=1)
map1x,map1y=cv2.initUndistortRectifyMap(M1,d1,R1,P1,(width,height),cv2.CV_32FC1)
map2x,map2y=cv2.initUndistortRectifyMap(M2,d2,R2,P2,(width,height),cv2.CV_32FC1)
img_left_rectified=cv2.remap(img_left_undistort,map1x,map1y,cv2.INTER_LINEAR)
img_right_rectified=cv2.remap(img_right_undistort,map2x,map2y,cv2.INTER_LINEAR)

其中,R、T 是双目相机标定得到的旋转和平移矩阵, (width, height)是左右图像的尺寸。R1、R2 是左右图像的旋转矩阵,P1、P2 是左右图像的投影矩阵,Q 是视差转换矩阵,roi1、roi2 是矫正后的图像中可以使用的区域。

然后,将左右图像拼接在一起以方便观察:

img_stereo=cv2.hconcat([img_left_rectified,img_right_rectified])
f0de119a-05d5-11ee-962d-dac502259ad0.png

接下来,需要计算视差图:

minDisparity=0
numDisparities=256
blockSize=9
P1=1200
P2=4800
disp12MaxDiff=10
preFilterCap=63
uniquenessRatio=5
speckleWindowSize=100
speckleRange=32
sgbm=cv2.StereoSGBM_create(minDisparity=minDisparity,numDisparities=numDisparities,blockSize=blockSize,
P1=P1,P2=P2,disp12MaxDiff=disp12MaxDiff,preFilterCap=preFilterCap,
uniquenessRatio=uniquenessRatio,speckleWindowSize=speckleWindowSize,
speckleRange=speckleRange,mode=cv2.STEREO_SGBM_MODE_SGBM_3WAY)

disparity=sgbm.compute(img_left_rectified,img_right_rectified)

上面的代码块定义了使用的视差算法的参数,并使用了 SGBM(Semi Global Block Matching)算法计算了原始的视差图。注意,由于使用的是16位的 SGBM 输出,因此需要将它除以16。f15a6560-05d5-11ee-962d-dac502259ad0.png接下来,可以对视差图进行 WLS 滤波,减少视差空洞:

#定义WLS滤波参数
lambda_val=4000
sigma_val=1.5

#运行WLS滤波
wls_filter=cv2.ximgproc.createDisparityWLSFilterGeneric(False)
wls_filter.setLambda(lambda_val)
wls_filter.setSigmaColor(sigma_val)
filtered_disp=wls_filter.filter(disparity,img_left_rectified,None,img_right_rectified)
filtered_disp_nor=cv2.normalize(filtered_disp,filtered_disp,alpha=0,beta=255,norm_type=cv2.NORM_MINMAX,dtype=cv2.CV_8U)

上述代码块中,WLS 滤波为视差图降噪,并进行平滑处理。这里使用了 cv2.ximgproc.createDisparityWLSFilterGeneric 函数,创建一个生成 WLS 滤波器的对象 wls_filter,然后设置了滤波参数 lambda_val 和 sigma_val。filtered_disp 是经过滤波后的视差图。filtered_disp_nor 是经过归一化处理后的、用于显示的视差图。

最后,可以在窗口中显示原始视差图、预处理后的 WLS 滤波器的视差图:

cv2.imshow("disparity",cv2.resize(disparity_nor,(disparity_nor.shape[1]//2,disparity_nor.shape[0]//2)))
cv2.imshow("filtered_disparity",cv2.resize(filtered_disp_nor,(filtered_disp_nor.shape[1]//2,filtered_disp_nor.shape[0]//2)))
cv2.waitKey()
cv2.destroyAllWindows()
f166ca1c-05d5-11ee-962d-dac502259ad0.png


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 3D
    3D
    +关注

    关注

    9

    文章

    2876

    浏览量

    107496
  • 计算机视觉
    +关注

    关注

    8

    文章

    1698

    浏览量

    45985
  • python
    +关注

    关注

    56

    文章

    4795

    浏览量

    84646

原文标题:从双目标定到立体匹配:Python实践指南

文章出处:【微信号:3D视觉工坊,微信公众号:3D视觉工坊】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    双目立体视觉原理大揭秘(一)

    的三维坐标值了。把该三维坐标值输入机器人控制系统,机器人就可以智能的实现避障了。在这部分中用到了“立体匹配”算法,其实该算法是和双目标定相结合,该算法根据特征点在左右图像中的坐标点进行基础矩阵的计算并将
    发表于 11-21 16:20

    双目立体视觉原理大揭秘(二)

    图像处理(二值化、边缘提取、去噪等)后,得到一系列特征点在左右相机图像中的平面坐标X、Y。第四、根据双目立体视觉CCAS的立体匹配原理——极限约束公式。把第三步提取到的特征点在左右相机视场中的X、Y
    发表于 11-21 16:22

    维视双目产品在高校科研应用中的实例及优点分析

    包含的设备选型、系统搭建、图像获取、立体匹配,并给出标定结果,在用户需要进行开发的特征捕捉部分,也给予了丰富的支持。双目标定可以说是整套双目视觉系统的最关键技术,能够快速准确的完成
    发表于 01-19 16:59

    立体匹配SAD算法原理

    立体匹配SAD算法matlab实现
    发表于 06-05 16:08

    双目视觉立体匹配算法研究

    双日视觉是计算机视觉领域的一个重要组成部分。双目视觉研究中的关键技术摄像机标定立体匹配一直是研究的热点。本文由两部分组成,分别对双目视觉的算法和未
    发表于 08-14 16:41 0次下载

    一种快速双目立体匹配方法_梅金燕

    一种快速双目立体匹配方法_梅金燕
    发表于 03-19 11:46 0次下载

    基于颜色调整的立体匹配改进算法

    的前提,因此如何提升立体匹配算法在各种场景中的鲁棒性也是计算机视觉研究的热点问题。 立体匹配算法的目标两幅校正后的匹配图片中寻找每个像素
    发表于 11-02 11:07 0次下载
    基于颜色调整的<b class='flag-5'>立体匹配</b>改进算法

    基于HALCON的双目是相机立体视觉系统标定

    摄像机标定是机器视觉和摄像测量领域相对基础的工作,同时也是最复杂、困难的T作。摄像机标定的意义是得到立体空间中对象的几何信息,其中所使用的图像信息由双目摄像机所得。定后的
    发表于 11-06 14:41 30次下载
    基于HALCON的<b class='flag-5'>双目</b>是相机<b class='flag-5'>立体</b>视觉系统<b class='flag-5'>标定</b>

    双目立体匹配的四个步骤解析

    双目立体匹配可划分为四个步骤:匹配代价计算、代价聚合、视差计算和视差优化。
    的头像 发表于 08-31 10:08 5178次阅读

    双目立体计算机视觉的立体匹配研究综述

    双目立体视觉技术具有成本低、适用性广的优点,在物体识别、目标检测等方面应用广泛,成为计算机视觉领域的研究热点。立体匹配双目
    发表于 04-12 09:47 3次下载
    <b class='flag-5'>双目</b><b class='flag-5'>立体</b>计算机视觉的<b class='flag-5'>立体匹配</b>研究综述

    一种基于PatchMatch的半全局双目立体匹配算法

    景。因此,计算复杂度、匹配精度、匹配原理等多方面综合考虑,提出了一种基于 Patchmatch的半全局双目立体匹配算法,在路径代价计算过程
    发表于 04-20 11:31 13次下载
    一种基于PatchMatch的半全局<b class='flag-5'>双目</b><b class='flag-5'>立体匹配</b>算法

    融合边缘特征的立体匹配算法Edge-Gray

    为保证SAD算法的立体匹配效率,提高匹配精度,提出一种融合边缘特征的立体匹配算法 Edge-gray。通过边缘计算得到边缘特征图,在进行匹配的过程中,根据当前点与领域点的差值确定
    发表于 04-29 11:06 8次下载
    融合边缘特征的<b class='flag-5'>立体匹配</b>算法Edge-Gray

    双目标定是什么?为什么要进行双目标定

    在这里我们所说的双目标定是狭义的,讲解理论的时候仅指两台相机之间相互位置的标定,在代码实践的时候,我们才说完整的双目标定
    的头像 发表于 07-04 11:04 1.2w次阅读
    <b class='flag-5'>双目标定</b>是什么?为什么要进行<b class='flag-5'>双目标定</b>?

    相机之间为什么要进行双目标定呢?

    在这里我们所说的双目标定是狭义的,讲解理论的时候仅指两台相机之间相互位置的标定,在代码实践的时候,我们才说完整的双目标定
    的头像 发表于 12-28 17:17 2709次阅读

    双目立体匹配的四个步骤

    根据Schrstein和Szeliski的总结,双目立体匹配可划分为四个步骤: 匹配代价计算、代价聚合、视差计算和视差优化 。 一 、匹配代价计算
    的头像 发表于 06-28 16:59 1165次阅读
    <b class='flag-5'>双目</b><b class='flag-5'>立体匹配</b>的四个步骤