BM算法实现双目视觉测距--python实现

BM算法
1 篇文章0 订阅
订阅专栏
在完成对双目摄像头的标定之后,获得标定的矩阵包括左右相机的内参数矩阵、畸变矩阵、旋转矩阵和平移矩阵。将其放入代码中,如下所示:

import cv2
import numpy as np
 
# 左相机内参
left_camera_matrix = np.array([(426.61499943, 0, 337.77666426),
                   (0, 426.50296492, 254.57967858),
                   (0, 0, 1)])
 
 
# 左相机畸变系数:[k1, k2, p1, p2, k3]
left_distortion = np.array([[1.64160258e-02 ,1.90313751e-02  ,3.85843636e-05 ,-6.81027605e-04,  -7.77682876e-02]])
 
# 右相机内参
right_camera_matrix = np.array([( 428.37039364, 0, 335.14944239),
                   (0, 428.26149388, 253.70369704),
                   (0, 0, 1)])
 
# 右相机畸变系数:[k1, k2, p1, p2, k3]
right_distortion = np.array([[1.18624707e-02 , 2.92395356e-02 , 7.84349618e-04 ,-4.59924352e-05,  -8.34482148e-02]])
 
# om = np.array([-0.00009, 0.02300, -0.00372])
# R = cv2.Rodrigues(om)[0]
 
# 旋转矩阵
R = np.array([(9.99999401e-01 ,-1.08818183e-03 , 1.21838861e-04),
                   (1.08825693e-03 , 9.99999217e-01, -6.18081935e-04),
                   (-1.21166180e-04 , 6.18214157e-04 , 9.99999802e-01)])
 
# 平移向量
T = np.array([[-59.98598553], [-0.81926245], [0.12784464]])
doffs = 0.0
 
size = (640, 480)
 
R1, R2, P1, P2, Q, validPixROI1, validPixROI2 = cv2.stereoRectify(left_camera_matrix, left_distortion,
                                                                  right_camera_matrix, right_distortion, size, R,
                                                                  T)
 
left_map1, left_map2 = cv2.initUndistortRectifyMap(left_camera_matrix, left_distortion, R1, P1, size, cv2.CV_16SC2)
right_map1, right_map2 = cv2.initUndistortRectifyMap(right_camera_matrix, right_distortion, R2, P2, size, cv2.CV_16SC2)


在进行立体标定和平行校正。代码如下:

 

   img1_rectified = cv2.remap(frame1, left_map1, left_map2, cv2.INTER_LINEAR,
                               cv2.BORDER_CONSTANT)
    img2_rectified = cv2.remap(frame2, right_map1, right_map2, cv2.INTER_LINEAR,
                               cv2.BORDER_CONSTANT)


也可以不用,如果你的相机的平行相机的话,这一步做不做都可以。

完成之后在看一下BM算法:

    # BM
    numberOfDisparities = ((640 // 8) + 15) & -16  # 640对应是分辨率的宽
 
    stereo = cv2.StereoBM_create(numDisparities=16*10, blockSize=7)  # 立体匹配
    stereo.setROI1(camera_configs.validPixROI1)
    stereo.setROI2(camera_configs.validPixROI2)
    stereo.setPreFilterCap(50)
    stereo.setBlockSize(9)
    stereo.setMinDisparity(0)
    stereo.setNumDisparities(numberOfDisparities)
    stereo.setTextureThreshold(10)
    stereo.setUniquenessRatio(15)
    stereo.setSpeckleWindowSize(200)
    stereo.setSpeckleRange(32)
    stereo.setDisp12MaxDiff(8)
 
    disparity = stereo.compute(img1_rectified, img2_rectified)  # 计算视差
 
    disp = cv2.normalize(disparity, disparity, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)  # 归一化函数算法
 
    threeD = cv2.reprojectImageTo3D(disparity, camera_configs.Q, handleMissingValues=True)  # 计算三维坐标数据值
    threeD = threeD * 16


这块就是计算三维坐标了,其中stereo里的都是算法的参数,可以进行调节,找到一种效果好的参数组合即可,当然建议设置一个滑块调节,这样调节起来比较方便,如何设置滑块进行参数调节,我将在另一篇博客中介绍。

 

  cv2.setMouseCallback(WIN_NAME, onmouse_pick_points, threeD)
 
    cv2.imshow("left", frame1)
    cv2.imshow(WIN_NAME, disp)  # 显示深度图的双目画面


这样就可以进行展示了,是建立在左相机的坐标系下进行计算和展示。

通过鼠标点击输入像素坐标信息,通过BM算法进行对应点的匹配,再根据平行视图的计算公式进行计算,即可得三维坐标了,这样需要乘以16进行换算才是真实坐标。

鼠标点击输入函数如下,其中xy也可以自己设置输入,进行对应坐标的计算:

def onmouse_pick_points(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        threeD = param
        print('\n像素坐标 x = %d, y = %d' % (x, y))
        print("世界坐标xyz 是:", threeD[y][x][0] / 1000.0, threeD[y][x][1] / 1000.0, threeD[y][x][2] / 1000.0, "m")
 
        distance = math.sqrt(threeD[y][x][0] ** 2 + threeD[y][x][1] ** 2 + threeD[y][x][2] ** 2)
        distance = distance / 1000.0  # mm -> m
        print("距离是:", distance, "m")
    cv2.setMouseCallback(WIN_NAME, onmouse_pick_points, threeD)


把这些函数组合一下就可以得到整个函数了,图片输入识别深度和摄像头实时识别都是可以的,计算速度快,实际测量的话,感觉精度还行,当然是短距离。效果的话没有SGBM算法好的,但是胜在计算速度快。

完整的代码如下了,最重要的就是。

# -*- coding: utf-8 -*-
 
import numpy as np
import cv2
import camera_configs
import random
import math
 
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 480)  # 打开并设置摄像头
 
 
# 鼠标回调函数
def onmouse_pick_points(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        threeD = param
        print('\n像素坐标 x = %d, y = %d' % (x, y))
        # print("世界坐标是:", threeD[y][x][0], threeD[y][x][1], threeD[y][x][2], "mm")
        print("世界坐标xyz 是:", threeD[y][x][0] / 1000.0, threeD[y][x][1] / 1000.0, threeD[y][x][2] / 1000.0, "m")
 
        distance = math.sqrt(threeD[y][x][0] ** 2 + threeD[y][x][1] ** 2 + threeD[y][x][2] ** 2)
        distance = distance / 1000.0  # mm -> m
        print("距离是:", distance, "m")
 
 
WIN_NAME = 'Deep disp'
cv2.namedWindow(WIN_NAME, cv2.WINDOW_AUTOSIZE)
 
while True:
    ret, frame = cap.read()
    frame1 = frame[0:480, 0:640]
    frame2 = frame[0:480, 640:1280]  # 割开双目图像
 
    imgL = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)  # 将BGR格式转换成灰度图片
    imgR = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
 
    # cv2.remap 重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。
    # 依据MATLAB测量数据重建无畸变图片
    img1_rectified = cv2.remap(imgL, camera_configs.left_map1, camera_configs.left_map2, cv2.INTER_LINEAR)
    img2_rectified = cv2.remap(imgR, camera_configs.right_map1, camera_configs.right_map2, cv2.INTER_LINEAR)
 
    imageL = cv2.cvtColor(img1_rectified, cv2.COLOR_GRAY2BGR)
    imageR = cv2.cvtColor(img2_rectified, cv2.COLOR_GRAY2BGR)
 
    # BM
    numberOfDisparities = ((640 // 8) + 15) & -16  # 640对应是分辨率的宽
 
    stereo = cv2.StereoBM_create(numDisparities=16*10, blockSize=7)  # 立体匹配
    stereo.setROI1(camera_configs.validPixROI1)
    stereo.setROI2(camera_configs.validPixROI2)
    stereo.setPreFilterCap(50)
    stereo.setBlockSize(9)
    stereo.setMinDisparity(0)
    stereo.setNumDisparities(numberOfDisparities)
    stereo.setTextureThreshold(10)
    stereo.setUniquenessRatio(15)
    stereo.setSpeckleWindowSize(200)
    stereo.setSpeckleRange(32)
    stereo.setDisp12MaxDiff(8)
 
    disparity = stereo.compute(img1_rectified, img2_rectified)  # 计算视差
 
    disp = cv2.normalize(disparity, disparity, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)  # 归一化函数算法
 
    threeD = cv2.reprojectImageTo3D(disparity, camera_configs.Q, handleMissingValues=True)  # 计算三维坐标数据值
    threeD = threeD * 16
 
    # threeD[y][x] x:0~640; y:0~480;   !!!!!!!!!!
    cv2.setMouseCallback(WIN_NAME, onmouse_pick_points, threeD)
 
    cv2.imshow("left", frame1)
    cv2.imshow(WIN_NAME, disp)  # 显示深度图的双目画面
 
    key = cv2.waitKey(1)
    if key == ord("q"):
        break
 
cap.release()
cv2.destroyAllWindows()

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Python中进行双目视觉测距,可以使用OpenCV库。首先需要安装OpenCV-Python库,可以使用命令"pip install opencv-python"进行安装。 双目视觉测距的主要代码包括两个文件:main.py和camera_config.py。main.py是主函数,用于实现双目视觉测距,而camera_config.py用于表示相机参数。通过调用camera_config.py中的相机参数,可以进行双目视觉测距的计算。 双目视觉测距的基本原理是三角测量原理,即通过视差来判定物体的远近。在实际实现中,可以通过对左右两个相机获取的图像进行处理和匹配,得到视差图像。然后,通过根据相机参数和视差图像的像素坐标计算出物体的实际距离。这样就可以实现双目视觉测距的功能。双目视觉测距在许多领域得到了应用,例如城市三维重建、3D模型构建、机器人导航等等。 如果你对双目测距的内容想要有更深入的了解,可以阅读《计算机视觉中的多视图几何》,这本书是视觉领域的经典之作。它包含了丰富的理论内容和数学证明,但也需要一定的数学基础和阅读能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [双目测距理论及其python实现](https://blog.csdn.net/dulingwen/article/details/98071584)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [双目测距 BM算法 Python版](https://blog.csdn.net/qq_41204464/article/details/120344636)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值