精华内容
下载资源
问答
  • 在作SLAM时,但愿用到深度图来辅助生成场景,因此要构创建体视觉,在这里使用OpenCV的Stereo库和python来进行双目立体视觉的图像处理。python立体标定应用标定数据转换成深度图标定在开始以前,须要准备的固然是两个...

    在作SLAM时,但愿用到深度图来辅助生成场景,因此要构创建体视觉,在这里使用OpenCV的Stereo库和python来进行双目立体视觉的图像处理。python

    立体标定

    应用标定数据

    转换成深度图

    标定

    在开始以前,须要准备的固然是两个摄相头,根据你的需求将两个摄像头进行相对位置的固定,我是按平行来进行固定的(若是为了追求两个双目图像更高的生命度,也能够将其按必定钝角固定,这样作又限制了场景深度的扩展,根据实际需求选择)算法

    e7cd5a0ed3a135d590f59c0561982f65.png

    因为摄像头目前是咱们手动进行定位的,咱们如今还不知道两张图像与世界坐标之间的耦合关系,因此下一步要进行的是标定,用来肯定分别获取两个摄像头的内部参数,而且根据两个摄像头在同一个世界坐标下的标定参数来获取立体参数。注:不要使用OpenCV自带的自动calbration,其对棋盘的识别率极低,使用Matlab的Camera Calibration Toolbox更为有效,具体细节请看:摄像机标定和立体标定ide

    同时从两个摄像头获取图片spa

    import cv2

    import time

    AUTO = True # 自动拍照,或手动按s键拍照

    INTERVAL = 2 # 自动拍照间隔

    cv2.namedWindow("left")

    cv2.namedWindow("right")

    cv2.moveWindow("left", 0, 0)

    cv2.moveWindow("right", 400, 0)

    left_camera = cv2.VideoCapture(0)

    right_camera = cv2.VideoCapture(1)

    counter = 0

    utc = time.time()

    pattern = (12, 8) # 棋盘格尺寸

    folder = "./snapshot/" # 拍照文件目录

    def shot(pos, frame):

    global counter

    path = folder + pos + "_" + str(counter) + ".jpg"

    cv2.imwrite(path, frame)

    print("snapshot saved into: " + path)

    while True:

    ret, left_frame = left_camera.read()

    ret, right_frame = right_camera.read()

    cv2.imshow("left", left_frame)

    cv2.imshow("right", right_frame)

    now = time.time()

    if AUTO and now - utc >= INTERVAL:

    shot("left", left_frame)

    shot("right", right_frame)

    counter += 1

    utc = now

    key = cv2.waitKey(1)

    if key == ord("q"):

    break

    elif key == ord("s"):

    shot("left", left_frame)

    shot("right", right_frame)

    counter += 1

    left_camera.release()

    right_camera.release()

    cv2.destroyWindow("left")

    cv2.destroyWindow("right")

    下面是我拍摄的样本之一,能够肉眼看出来这两个摄像头成像都不是水平的,这更是须要标定的存在的意义

    2a225b8fa974dc15888e0959ca066e93.png.net

    在进行标定的过程当中,要注意的是在上面标定方法中没有提到的是,单个标定后,要对标定的数据进行错误分析(Analyse Error),如左图,是我对左摄像头的标定结果分析。图中天蓝色点明显与大部分点不聚敛,因此有多是标定时对这个图片标定出现的错误,要从新标定,在该点上点击并获取其图片名称索引,对其从新标定后,右图的结果看起来仍是比较满意的3d

    43a399c1adbd55259261f7a1b2ff4011.png

    在进行完立体标定后,咱们将获得以下的数据:code

    Stereo calibration parameters after optimization:

    Intrinsic parameters of left camera:

    Focal Length: fc_left = [ 824.93564 825.93598 ] [ 8.21112 8.53492 ]

    Principal point: cc_left = [ 251.64723 286.58058 ] [ 13.92642 9.11583 ]

    Skew: alpha_c_left = [ 0.00000 ] [ 0.00000 ] => angle of pixel axes = 90.00000 0.00000 degrees

    Distortion: kc_left = [ 0.23233 -0.99375 0.00160 0.00145 0.00000 ] [ 0.05659 0.30408 0.00472 0.00925 0.00000 ]

    Intrinsic parameters of right camera:

    Focal Length: fc_right = [ 853.66485 852.95574 ] [ 8.76773 9.19051 ]

    Principal point: cc_right = [ 217.00856 269.37140 ] [ 10.40940 9.47786 ]

    Skew: alpha_c_right = [ 0.00000 ] [ 0.00000 ] => angle of pixel axes = 90.00000 0.00000 degrees

    Distortion: kc_right = [ 0.30829 -1.61541 0.01495 -0.00758 0.00000 ] [ 0.06567 0.55294 0.00547 0.00641 0.00000 ]

    Extrinsic parameters (position of right camera wrt left camera):

    Rotation vector: om = [ 0.01911 0.03125 -0.00960 ] [ 0.01261 0.01739 0.00112 ]

    Translation vector: T = [ -70.59612 -2.60704 18.87635 ] [ 0.95533 0.79030 5.25024 ]

    应用标定数据

    咱们使用以下的代码来将其配置到python中,上面的参数都是手动填写至下面的内容中的,这样免去保存成文件再去读取,在托运填写的时候要注意数据的对应位置。orm

    # filename: camera_configs.py

    import cv2

    import numpy as np

    left_camera_matrix = np.array([[824.93564, 0., 251.64723],

    [0., 825.93598, 286.58058],

    [0., 0., 1.]])

    left_distortion = np.array([[0.23233, -0.99375, 0.00160, 0.00145, 0.00000]])

    right_camera_matrix = np.array([[853.66485, 0., 217.00856],

    [0., 852.95574, 269.37140],

    [0., 0., 1.]])

    right_distortion = np.array([[0.30829, -1.61541, 0.01495, -0.00758, 0.00000]])

    om = np.array([0.01911, 0.03125, -0.00960]) # 旋转关系向量

    R = cv2.Rodrigues(om)[0] # 使用Rodrigues变换将om变换为R

    T = np.array([-70.59612, -2.60704, 18.87635]) # 平移关系向量

    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)

    # 计算更正map

    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)

    这样,咱们获得了左右摄像头的两个map,并获得了立体的Q,这些参数都将应用于下面的转换成深度图中blog

    转换成深度图

    import numpy as np

    import cv2

    import camera_configs

    cv2.namedWindow("left")

    cv2.namedWindow("right")

    cv2.namedWindow("depth")

    cv2.moveWindow("left", 0, 0)

    cv2.moveWindow("right", 600, 0)

    cv2.createTrackbar("num", "depth", 0, 10, lambda x: None)

    cv2.createTrackbar("blockSize", "depth", 5, 255, lambda x: None)

    camera1 = cv2.VideoCapture(0)

    camera2 = cv2.VideoCapture(1)

    # 添加点击事件,打印当前点的距离

    def callbackFunc(e, x, y, f, p):

    if e == cv2.EVENT_LBUTTONDOWN:

    print threeD[y][x]

    cv2.setMouseCallback("depth", callbackFunc, None)

    while True:

    ret1, frame1 = camera1.read()

    ret2, frame2 = camera2.read()

    if not ret1 or not ret2:

    break

    # 根据更正map对图片进行重构

    img1_rectified = cv2.remap(frame1, camera_configs.left_map1, camera_configs.left_map2, cv2.INTER_LINEAR)

    img2_rectified = cv2.remap(frame2, camera_configs.right_map1, camera_configs.right_map2, cv2.INTER_LINEAR)

    # 将图片置为灰度图,为StereoBM做准备

    imgL = cv2.cvtColor(img1_rectified, cv2.COLOR_BGR2GRAY)

    imgR = cv2.cvtColor(img2_rectified, cv2.COLOR_BGR2GRAY)

    # 两个trackbar用来调节不一样的参数查看效果

    num = cv2.getTrackbarPos("num", "depth")

    blockSize = cv2.getTrackbarPos("blockSize", "depth")

    if blockSize % 2 == 0:

    blockSize += 1

    if blockSize < 5:

    blockSize = 5

    # 根据Block Maching方法生成差别图(opencv里也提供了SGBM/Semi-Global Block Matching算法,有兴趣能够试试)

    stereo = cv2.StereoBM_create(numDisparities=16*num, blockSize=blockSize)

    disparity = stereo.compute(imgL, imgR)

    disp = cv2.normalize(disparity, disparity, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

    # 将图片扩展至3d空间中,其z方向的值则为当前的距离

    threeD = cv2.reprojectImageTo3D(disparity.astype(np.float32)/16., camera_configs.Q)

    cv2.imshow("left", img1_rectified)

    cv2.imshow("right", img2_rectified)

    cv2.imshow("depth", disp)

    key = cv2.waitKey(1)

    if key == ord("q"):

    break

    elif key == ord("s"):

    cv2.imwrite("./snapshot/BM_left.jpg", imgL)

    cv2.imwrite("./snapshot/BM_right.jpg", imgR)

    cv2.imwrite("./snapshot/BM_depth.jpg", disp)

    camera1.release()

    camera2.release()

    cv2.destroyAllWindows()

    下面则是一附成像图,最右侧的为生成的disparity图,按照上面的代码,在图上点击则能够读取到该点的距离

    3f180ae26123e155ac6d1c27293bad5e.png索引

    Have fun.

    展开全文
  • 双目测距理论及其python实现

    万次阅读 多人点赞 2019-09-03 23:19:09
    一、双目测距基本流程 双目测距属于双目SLAM的一个应用领域。 关于双目测距的基本原理,其实并不复杂,但说起来内容也不少,其核心原理就是三角测量,三角测量在土地测量、天文测量等领域都得到了广泛应用,是一种...

    一、双目测距基本流程

            Stereo Vision, 也叫双目立体视觉,它的研究可以帮助我们更好的理解人类的双眼是如何进行深度感知的。双目视觉在许多领域得到了应用,例如城市三维重建、3D模型构建(如kinect fusion)、视角合成、3D跟踪、机器人导航(自动驾驶)、人类运动捕捉(Microsoft Kinect)等等。双目测距也属于双目立体视觉的一个应用领域,双目测距的基本原理主要是三角测量原理,即通过视差来判定物体的远近。如果读者想对双目测距的内容有一个更加深入的认识,建议去阅读《计算机视觉中的多视图几何》,这本书是视觉领域的经典之作,它的优点是内容全面,每一个定理都给出了严格的数学证明,缺点就是理论内容非常多,而且难度也非常高,读起来更像是在看一本数学书。(注:虽然一些文章中使用binocular代表双目,而stereo代表意义更为广泛的立体一词,但多数文献中仍然采用stereo来代表双目,比如stereo matching一般表示双目立体匹配)

    那么总结起来,双目测距的大致流程就是:

               双目标定 --> 立体校正(含消除畸变) --> 立体匹配 --> 视差计算 --> 深度计算/3D坐标计算

    下面将分别阐述每一个步骤并使用opencv-python来实现。本篇博客将偏重实践一些,理论方面的论述会比较少,但也会尽量写的通俗易懂。

    linux下安装opencv-python:

    pip install opencv-python

    二、双目标定

           双目标定的目标是获得左右两个相机的内参、外参和畸变系数,其中内参包括左右相机的fx,fy,cx,cy,外参包括左相机相对于右相机的旋转矩阵和平移向量,畸变系数包括径向畸变系数(k1, k2,k3)和切向畸变系数(p1,p2)。关于双目相机的标定方法,请参考这篇博客:双目相机的标定过程详解!-----MATLAB

    import cv2
    import numpy
    
    class stereoCameraCalibration():
        pass

    三、畸变校正

           光线经过相机的光学系统往往不能按照理想的情况投射到传感器上,也就是会产生所谓的畸变。畸变有两种情况:一种是由透镜形状引起的畸变称之为径向畸变。在针孔模型中,一条直线投影到像素平面上还是一条直线。可是,在实际拍摄的照片中,摄像机的透镜往往使得真实环境中的一条直线在图片中变成了曲线。越靠近图像的边缘,这种现象越明显。由于实际加工制作的透镜往往是中心对称的,这使得不规则的畸变通常径向对称。它们主要分为两大类,桶形畸变 枕形畸变(摘自《SLAM十四讲》)如图所示:

           桶形畸变是由于图像放大率随着离光轴的距离增加而减小,而枕形畸变却恰好相反。 在这两种畸变中,穿过图像中心和光轴有交点的直线还能保持形状不变。 

           除了透镜的形状会引入径向畸变外,在相机的组装过程中由于不能使得透镜和成像面 严格平行也会引入切向畸变。如图所示:

    那么消除畸变的方法就是:

    1. 将三维空间点投影到归一化图像平面。设它的归一化坐标为 [x,y]T

    2. 对归一化平面上的点进行径向畸变和切向畸变纠正。

    3. 将纠正后的点通过内参数矩阵投影到像素平面,得到该点在图像上的正确位置

    四、立体校正

           立体校正的目的是将拍摄于同一场景的左右两个视图进行数学上的投影变换,使得两个成像平面平行于基线,且同一个点在左右两幅图中位于同一行,简称共面行对准。只有达到共面行对准以后才可以应用三角原理计算距离。

    五、立体匹配与视差图计算

           立体匹配的目的是为左图中的每一个像素点在右图中找到其对应点(世界中相同的物理点),这样就可以计算出视差: disparity = x_{i} - x_{j}(xi和xj分别表示两个对应点在图像中的列坐标)。大部分立体匹配算法的计算过程可以分成以下几个阶段:匹配代价计算、代价聚合、视差优化、视差细化。立体匹配是立体视觉中一个很难的部分,主要困难在于:1.图像中可能存在重复纹理和弱纹理,这些区域很难匹配正确;2.由于左右相机的拍摄位置不同,图像中几乎必然存在遮挡区域,在遮挡区域,左图中有一些像素点在右图中并没有对应的点,反之亦然;3.左右相机所接收的光照情况不同;4.过度曝光区域难以匹配;5.倾斜表面、弯曲表面、非朗伯体表面;6.较高的图像噪声等。

           常用的立体匹配方法基本上可以分为两类:局部方法,例如BM、SGM、ELAS、Patch Match等,非局部的,即全局方法,例如Dynamic Programming、Graph Cut、Belief Propagation等,局部方法计算量小,匹配质量相对较低,全局方法省略了代价聚合而采用了优化能量函数的方法,匹配质量较高,但是计算量也比较大。目前OpenCV中已经实现的方法有BM、binaryBM、SGBM、binarySGBM、BM(cuda)、Bellief Propogation(cuda)、Constant Space Bellief Propogation(cuda)这几种方法。比较好用的是SGBM算法,它的核心是基于SGM算法,但和SGM算法又有一些不同,比如匹配代价部分用的是BT代价(原图+梯度图)而不是HMI代价等等。有关SGM算法的原理解释,可以参考另一篇博客 : 双目立体匹配算法:SGM

            在立体匹配生成视差图之后,还可以对视差图进行滤波后处理,例如Guided Filter、Fast Global Smooth Filter(一种快速WLS滤波方法)、Bilatera Filter、TDSR、RBS等。 视差图滤波能够将稀疏视差转变为稠密视差,并在一定程度上降低视差图噪声,改善视差图的视觉效果,但是比较依赖初始视差图的质量。

    六、深度图计算

    得到了视差图之后,就可以计算像素深度了,公式如下(推导略):

                                                                                                      depth =\frac{ f\times b}{d + \left(c_{xr}- c_{xl}\right )}

    其中 f 为焦距长度(像素焦距),b为基线长度,d为视差,c_{xl}c_{xr}为两个相机主点的列坐标。

    注:在opencv中使用StereoRectify()函数可以得到一个重投影矩阵Q,使用Q矩阵也可以将像素坐标转换为三维坐标。

    七、双目测距的精度

           根据上式可以看出,某点像素的深度精度取决于该点处估计的视差d的精度。假设视差d的误差恒定,当测量距离越远,得到的深度精度则越差,因此使用双目相机不适宜测量太远的目标。如果想要对与较远的目标能够得到较为可靠的深度,一方面需要提高相机的基线距离,但是基线距离越大,左右视图的重叠区域就会变小,内容差异变大,从而提高立体匹配的难度,另一方面可以选择更大焦距的相机,然而焦距越大,相机的视域则越小,导致离相机较近的物体的距离难以估计。

    八、代码实现

    最重要的就是代码了,不是么!

    首先需要引入相应的包:

    import cv2
    import numpy as np

    然后:

    # 预处理
    def preprocess(img1, img2):
        # 彩色图->灰度图
        if(img1.ndim == 3):
            img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)  # 通过OpenCV加载的图像通道顺序是BGR
        if(img2.ndim == 3):
            img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    
        # 直方图均衡
        img1 = cv2.equalizeHist(img1)
        img2 = cv2.equalizeHist(img2)
    
        return img1, img2
    
    
    # 消除畸变
    def undistortion(image, camera_matrix, dist_coeff):
        undistortion_image = cv2.undistort(image, camera_matrix, dist_coeff)
    
        return undistortion_image
    
    
    # 获取畸变校正和立体校正的映射变换矩阵、重投影矩阵
    # @param:config是一个类,存储着双目标定的参数:config = stereoconfig.stereoCamera()
    def getRectifyTransform(height, width, config):
        # 读取内参和外参
        left_K = config.cam_matrix_left
        right_K = config.cam_matrix_right
        left_distortion = config.distortion_l
        right_distortion = config.distortion_r
        R = config.R
        T = config.T
    
        # 计算校正变换
        height = int(height)
        width = int(width)
        R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(left_K, left_distortion, right_K, right_distortion, (width, height), R, T, alpha=0)
    
        map1x, map1y = cv2.initUndistortRectifyMap(left_K, left_distortion, R1, P1, (width, height), cv2.CV_32FC1)
        map2x, map2y = cv2.initUndistortRectifyMap(right_K, right_distortion, R2, P2, (width, height), cv2.CV_32FC1)
    
        return map1x, map1y, map2x, map2y, Q
    
    
    # 畸变校正和立体校正
    def rectifyImage(image1, image2, map1x, map1y, map2x, map2y):
        rectifyed_img1 = cv2.remap(image1, map1x, map1y, cv2.INTER_AREA)
        rectifyed_img2 = cv2.remap(image2, map2x, map2y, cv2.INTER_AREA)
    
        return rectifyed_img1, rectifyed_img2
    
    
    # 立体校正检验----画线
    def draw_line(image1, image2):
        # 建立输出图像
        height = max(image1.shape[0], image2.shape[0])
        width = image1.shape[1] + image2.shape[1]
    
        output = np.zeros((height, width, 3), dtype=np.uint8)
        output[0:image1.shape[0], 0:image1.shape[1]] = image1
        output[0:image2.shape[0], image1.shape[1]:] = image2
    
        # 绘制等间距平行线
        line_interval = 50  # 直线间隔:50
        for k in range(height // line_interval):
            cv2.line(output, (0, line_interval * (k + 1)), (2 * width, line_interval * (k + 1)), (0, 255, 0), thickness=2, lineType=cv2.LINE_AA)
    
        return output
    
    
    # 视差计算
    def stereoMatchSGBM(left_image, right_image, down_scale=False):
        # SGBM匹配参数设置
        if left_image.ndim == 2:
            img_channels = 1
        else:
            img_channels = 3
        blockSize = 3
        paraml = {'minDisparity': 0,
                 'numDisparities': 128,
                 'blockSize': blockSize,
                 'P1': 8 * img_channels * blockSize ** 2,
                 'P2': 32 * img_channels * blockSize ** 2,
                 'disp12MaxDiff': 1,
                 'preFilterCap': 63,
                 'uniquenessRatio': 15,
                 'speckleWindowSize': 100,
                 'speckleRange': 1,
                 'mode': cv2.STEREO_SGBM_MODE_SGBM_3WAY
                 }
    
        # 构建SGBM对象
        left_matcher = cv2.StereoSGBM_create(**paraml)
        paramr = paraml
        paramr['minDisparity'] = -paraml['numDisparities']
        right_matcher = cv2.StereoSGBM_create(**paramr)
    
        # 计算视差图
        size = (left_image.shape[1], left_image.shape[0])
        if down_scale == False:
            disparity_left = left_matcher.compute(left_image, right_image)
            disparity_right = right_matcher.compute(right_image, left_image)
    
        else:
            left_image_down = cv2.pyrDown(left_image)
            right_image_down = cv2.pyrDown(right_image)
            factor = left_image.shape[1] / left_image_down.shape[1]
    
            disparity_left_half = left_matcher.compute(left_image_down, right_image_down)
            disparity_right_half = right_matcher.compute(right_image_down, left_image_down)
            disparity_left = cv2.resize(disparity_left_half, size, interpolation=cv2.INTER_AREA)
            disparity_right = cv2.resize(disparity_right_half, size, interpolation=cv2.INTER_AREA)
            disparity_left = factor * disparity_left
            disparity_right = factor * disparity_right
    
        # 真实视差(因为SGBM算法得到的视差是×16的)
        trueDisp_left = disparity_left.astype(np.float32) / 16.
        trueDisp_right = disparity_right.astype(np.float32) / 16.
    
        return trueDisp_left, trueDisp_right

    stereoconfig.py的代码:

    import numpy as np
    
    
    ####################仅仅是一个示例###################################
    
    
    # 双目相机参数
    class stereoCamera(object):
        def __init__(self):
            # 左相机内参
            self.cam_matrix_left = np.array([[1499.641, 0, 1097.616],
                                                                 [0., 1497.989, 772.371],
                                                                  [0., 0., 1.]])
            # 右相机内参
            self.cam_matrix_right = np.array([[1494.855, 0, 1067.321],
                                                                   [0., 1491.890, 777.983],
                                                                   [0., 0., 1.]])
    
            # 左右相机畸变系数:[k1, k2, p1, p2, k3]
            self.distortion_l = np.array([[-0.1103, 0.0789, -0.0004, 0.0017, -0.0095]])
            self.distortion_r = np.array([[-0.1065, 0.0793, -0.0002,  -8.9263e-06, -0.0161]])
    
            # 旋转矩阵
            self.R = np.array([[0.9939, 0.0165, 0.1081],
                                         [-0.0157, 0.9998, -0.0084],
                                         [-0.1082, 0.0067, 0.9940]])
    
            # 平移矩阵
            self.T = np.array([[-423.716], [2.561], [21.973]])
    
            # 主点列坐标的差
            self.doffs = 0.0
    
            # 指示上述内外参是否为经过立体校正后的结果
            self.isRectified = False
    
        def setMiddleBurryParams(self):
            self.cam_matrix_left = np.array([[3997.684, 0, 225.0],
                                                                [0., 3997.684, 187.5],
                                                                [0., 0., 1.]])
            self.cam_matrix_right =  np.array([[3997.684, 0, 225.0],
                                                                    [0., 3997.684, 187.5],
                                                                    [0., 0., 1.]])
            self.distortion_l = np.zeros(shape=(5, 1), dtype=np.float64)
            self.distortion_r = np.zeros(shape=(5, 1), dtype=np.float64)
            self.R = np.identity(3, dtype= np.float64)
            self.T = np.array([[-193.001], [0.0], [0.0]])
            self.doffs = 131.111
            self.isRectified = True
    
    
    

    九、构建点云

           有了视差便可以计算深度,因此根据双目的视差图可以构建稠密点云,OpenCV中提供了reprojectImageTo3D()这个函数用于计算像素点的三维坐标,该函数会返回一个3通道的矩阵,分别存储X、Y、Z坐标(左摄像机坐标系下)。在python-pcl库中提供了用来显示点云的工具(python-pcl是PCL库的python接口,但是只提供了部分功能,且对点云的各种处理功能只限于PointXYZ格式的点云),python-pcl的下载地址:GitHub - strawlab/python-pcl: Python bindings to the pointcloud library (pcl),下载好后按步骤安装好。windows平台下的安装可以参考这两个博客:1.Windows10下PCL1.8.1以及Python-pcl1.81环境配置的掉发之路 2.win10平台python-pcl环境搭建

    下面是构建并显示点云的代码:

    # 将h×w×3数组转换为N×3的数组
    def hw3ToN3(points):
        height, width = points.shape[0:2]
    
        points_1 = points[:, :, 0].reshape(height * width, 1)
        points_2 = points[:, :, 1].reshape(height * width, 1)
        points_3 = points[:, :, 2].reshape(height * width, 1)
    
        points_ = np.hstack((points_1, points_2, points_3))
    
        return points_
    
    
    # 深度、颜色转换为点云
    def DepthColor2Cloud(points_3d, colors):
        rows, cols = points_3d.shape[0:2]
        size = rows * cols
    
        points_ = hw3ToN3(points_3d)
        colors_ = hw3ToN3(colors).astype(np.int64)
    
        # 颜色信息
        blue = colors_[:, 0].reshape(size, 1)
        green = colors_[:, 1].reshape(size, 1)
        red = colors_[:, 2].reshape(size, 1)
    
        rgb = np.left_shift(blue, 0) + np.left_shift(green, 8) + np.left_shift(red, 16)
    
        # 将坐标+颜色叠加为点云数组
        pointcloud = np.hstack((points_, rgb)).astype(np.float32)
    
        # 删掉一些不合适的点
        X = pointcloud[:, 0]
        Y = pointcloud[:, 1]
        Z = pointcloud[:, 2]
    
        # 下面参数是经验性取值,需要根据实际情况调整
        remove_idx1 = np.where(Z <= 0)
        remove_idx2 = np.where(Z > 15000)  // 注意单位是mm
        remove_idx3 = np.where(X > 10000)
        remove_idx4 = np.where(X < -10000)
        remove_idx5 = np.where(Y > 10000)
        remove_idx6 = np.where(Y < -10000)
        remove_idx = np.hstack((remove_idx1[0], remove_idx2[0], remove_idx3[0], remove_idx4[0], remove_idx5[0], remove_idx6[0]))
    
        pointcloud_1 = np.delete(pointcloud, remove_idx, 0)
    
    
        return pointcloud_1
    
    
    # 点云显示
    def view_cloud(pointcloud):
        cloud = pcl.PointCloud_PointXYZRGBA()
        cloud.from_array(pointcloud)
    
        try:
            visual = pcl.pcl_visualization.CloudViewing()
            visual.ShowColorACloud(cloud)
            v = True
            while v:
                v = not (visual.WasStopped())
        except:
            pass

    十、效果图

    下面的数据使用的是MiddleBurry双目数据,可以不用做立体校正(因为已经校正过了):

    利用SGBM算法得到视差图如下:

    点云如图所示:

    各位觉得不错的点个赞吧!

    -------------------------------------------------------------------补充完整示例代码------------------------------------------------------------------------------

    修改时间:2021.1.11(第一次)

    修改时间:2022.1.14(添加基于库open3d的点云绘制)

    # -*- coding: utf-8 -*-
    import sys
    import cv2
    import numpy as np
    import stereoconfig
    import pcl
    import pcl.pcl_visualization
    import open3d as o3d
    
    
    # 预处理
    def preprocess(img1, img2):
        # 彩色图->灰度图
        if (img1.ndim == 3):
            img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)  # 通过OpenCV加载的图像通道顺序是BGR
        if (img2.ndim == 3):
            img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    
        # 直方图均衡
        img1 = cv2.equalizeHist(img1)
        img2 = cv2.equalizeHist(img2)
    
        return img1, img2
    
    
    # 消除畸变
    def undistortion(image, camera_matrix, dist_coeff):
        undistortion_image = cv2.undistort(image, camera_matrix, dist_coeff)
    
        return undistortion_image
    
    
    # 获取畸变校正和立体校正的映射变换矩阵、重投影矩阵
    # @param:config是一个类,存储着双目标定的参数:config = stereoconfig.stereoCamera()
    def getRectifyTransform(height, width, config):
        # 读取内参和外参
        left_K = config.cam_matrix_left
        right_K = config.cam_matrix_right
        left_distortion = config.distortion_l
        right_distortion = config.distortion_r
        R = config.R
        T = config.T
    
        # 计算校正变换
        R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(left_K, left_distortion, right_K, right_distortion,
                                                          (width, height), R, T, alpha=0)
    
        map1x, map1y = cv2.initUndistortRectifyMap(left_K, left_distortion, R1, P1, (width, height), cv2.CV_32FC1)
        map2x, map2y = cv2.initUndistortRectifyMap(right_K, right_distortion, R2, P2, (width, height), cv2.CV_32FC1)
    
        return map1x, map1y, map2x, map2y, Q
    
    
    # 畸变校正和立体校正
    def rectifyImage(image1, image2, map1x, map1y, map2x, map2y):
        rectifyed_img1 = cv2.remap(image1, map1x, map1y, cv2.INTER_AREA)
        rectifyed_img2 = cv2.remap(image2, map2x, map2y, cv2.INTER_AREA)
    
        return rectifyed_img1, rectifyed_img2
    
    
    # 立体校正检验----画线
    def draw_line(image1, image2):
        # 建立输出图像
        height = max(image1.shape[0], image2.shape[0])
        width = image1.shape[1] + image2.shape[1]
    
        output = np.zeros((height, width, 3), dtype=np.uint8)
        output[0:image1.shape[0], 0:image1.shape[1]] = image1
        output[0:image2.shape[0], image1.shape[1]:] = image2
    
        # 绘制等间距平行线
        line_interval = 50  # 直线间隔:50
        for k in range(height // line_interval):
            cv2.line(output, (0, line_interval * (k + 1)), (2 * width, line_interval * (k + 1)), (0, 255, 0), thickness=2,
                     lineType=cv2.LINE_AA)
    
        return output
    
    
    # 视差计算
    def stereoMatchSGBM(left_image, right_image, down_scale=False):
        # SGBM匹配参数设置
        if left_image.ndim == 2:
            img_channels = 1
        else:
            img_channels = 3
        blockSize = 3
        paraml = {'minDisparity': 0,
                  'numDisparities': 64,
                  'blockSize': blockSize,
                  'P1': 8 * img_channels * blockSize ** 2,
                  'P2': 32 * img_channels * blockSize ** 2,
                  'disp12MaxDiff': 1,
                  'preFilterCap': 63,
                  'uniquenessRatio': 15,
                  'speckleWindowSize': 100,
                  'speckleRange': 1,
                  'mode': cv2.STEREO_SGBM_MODE_SGBM_3WAY
                  }
    
        # 构建SGBM对象
        left_matcher = cv2.StereoSGBM_create(**paraml)
        paramr = paraml
        paramr['minDisparity'] = -paraml['numDisparities']
        right_matcher = cv2.StereoSGBM_create(**paramr)
    
        # 计算视差图
        size = (left_image.shape[1], left_image.shape[0])
        if down_scale == False:
            disparity_left = left_matcher.compute(left_image, right_image)
            disparity_right = right_matcher.compute(right_image, left_image)
        else:
            left_image_down = cv2.pyrDown(left_image)
            right_image_down = cv2.pyrDown(right_image)
            factor = left_image.shape[1] / left_image_down.shape[1]
    
            disparity_left_half = left_matcher.compute(left_image_down, right_image_down)
            disparity_right_half = right_matcher.compute(right_image_down, left_image_down)
            disparity_left = cv2.resize(disparity_left_half, size, interpolation=cv2.INTER_AREA)
            disparity_right = cv2.resize(disparity_right_half, size, interpolation=cv2.INTER_AREA)
            disparity_left = factor * disparity_left
            disparity_right = factor * disparity_right
    
        # 真实视差(因为SGBM算法得到的视差是×16的)
        trueDisp_left = disparity_left.astype(np.float32) / 16.
        trueDisp_right = disparity_right.astype(np.float32) / 16.
    
        return trueDisp_left, trueDisp_right
    
    # 将h×w×3数组转换为N×3的数组
    def hw3ToN3(points):
        height, width = points.shape[0:2]
    
        points_1 = points[:, :, 0].reshape(height * width, 1)
        points_2 = points[:, :, 1].reshape(height * width, 1)
        points_3 = points[:, :, 2].reshape(height * width, 1)
    
        points_ = np.hstack((points_1, points_2, points_3))
    
        return points_
    
    
    # 深度、颜色转换为点云
    def DepthColor2Cloud(points_3d, colors):
        rows, cols = points_3d.shape[0:2]
        size = rows * cols
    
        points_ = hw3ToN3(points_3d)
        colors_ = hw3ToN3(colors).astype(np.int64)
    
        # 颜色信息
        blue = colors_[:, 0].reshape(size, 1)
        green = colors_[:, 1].reshape(size, 1)
        red = colors_[:, 2].reshape(size, 1)
    
        rgb = np.left_shift(blue, 0) + np.left_shift(green, 8) + np.left_shift(red, 16)
    
        # 将坐标+颜色叠加为点云数组
        pointcloud = np.hstack((points_, rgb)).astype(np.float32)
    
        # 删掉一些不合适的点
        X = pointcloud[:, 0]
        Y = pointcloud[:, 1]
        Z = pointcloud[:, 2]
    
        # 下面参数是经验性取值,需要根据实际情况调整
        remove_idx1 = np.where(Z <= 0)
        remove_idx2 = np.where(Z > 15000)
        remove_idx3 = np.where(X > 10000)
        remove_idx4 = np.where(X < -10000)
        remove_idx5 = np.where(Y > 10000)
        remove_idx6 = np.where(Y < -10000)
        remove_idx = np.hstack(
            (remove_idx1[0], remove_idx2[0], remove_idx3[0], remove_idx4[0], remove_idx5[0], remove_idx6[0]))
    
        pointcloud_1 = np.delete(pointcloud, remove_idx, 0)
    
        return pointcloud_1
    
    
    # 点云显示
    def view_cloud(pointcloud):
        cloud = pcl.PointCloud_PointXYZRGBA()
        cloud.from_array(pointcloud)
    
        try:
            visual = pcl.pcl_visualization.CloudViewing()
            visual.ShowColorACloud(cloud)
            v = True
            while v:
                v = not (visual.WasStopped())
        except:
            pass
    
    def getDepthMapWithQ(disparityMap : np.ndarray, Q : np.ndarray) -> np.ndarray:
        points_3d = cv2.reprojectImageTo3D(disparityMap, Q)
        depthMap = points_3d[:, :, 2]
        reset_index = np.where(np.logical_or(depthMap < 0.0, depthMap > 65535.0))
        depthMap[reset_index] = 0
    
        return depthMap.astype(np.float32)
    
    def getDepthMapWithConfig(disparityMap : np.ndarray, config : stereoconfig.stereoCamera) -> np.ndarray:
        fb = config.cam_matrix_left[0, 0] * (-config.T[0])
        doffs = config.doffs
        depthMap = np.divide(fb, disparityMap + doffs)
        reset_index = np.where(np.logical_or(depthMap < 0.0, depthMap > 65535.0))
        depthMap[reset_index] = 0
        reset_index2 = np.where(disparityMap < 0.0)
        depthMap[reset_index2] = 0
        return depthMap.astype(np.float32)
    
    
    if __name__ == '__main__':
        # 读取MiddleBurry数据集的图片
        iml = cv2.imread('Adirondack-perfect/im0.png', 1)  # 左图
        imr = cv2.imread('Adirondack-perfect/im1.png', 1)  # 右图
        if (iml is None) or (imr is None):
            print("Error: Images are empty, please check your image's path!")
            sys.exit(0)
        height, width = iml.shape[0:2]
    
        # 读取相机内参和外参
        # 使用之前先将标定得到的内外参数填写到stereoconfig.py中的StereoCamera类中
        config = stereoconfig.stereoCamera()
        config.setMiddleBurryParams()
        print(config.cam_matrix_left)
    
        # 立体校正
        map1x, map1y, map2x, map2y, Q = getRectifyTransform(height, width, config)  # 获取用于畸变校正和立体校正的映射矩阵以及用于计算像素空间坐标的重投影矩阵
        iml_rectified, imr_rectified = rectifyImage(iml, imr, map1x, map1y, map2x, map2y)
        print(Q)
    
        # 绘制等间距平行线,检查立体校正的效果
        line = draw_line(iml_rectified, imr_rectified)
        cv2.imwrite('./data/check_rectification.png', line)
    
        # 立体匹配
        iml_, imr_ = preprocess(iml, imr)  # 预处理,一般可以削弱光照不均的影响,不做也可以
        disp, _ = stereoMatchSGBM(iml, imr, False)  # 这里传入的是未经立体校正的图像,因为我们使用的middleburry图片已经是校正过的了
        cv2.imwrite('./data/disaprity.png', disp * 4)
    
        # 计算深度图
        # depthMap = getDepthMapWithQ(disp, Q)
        depthMap = getDepthMapWithConfig(disp, config)
        minDepth = np.min(depthMap)
        maxDepth = np.max(depthMap)
        print(minDepth, maxDepth)
        depthMapVis = (255.0 *(depthMap - minDepth)) / (maxDepth - minDepth)
        depthMapVis = depthMapVis.astype(np.uint8)
        cv2.imshow("DepthMap", depthMapVis)
        cv2.waitKey(0)
    
        # 使用open3d库绘制点云
        colorImage = o3d.geometry.Image(iml)
        depthImage = o3d.geometry.Image(depthMap)
        rgbdImage = o3d.geometry.RGBDImage().create_from_color_and_depth(colorImage, depthImage, depth_scale=1000.0, depth_trunc=np.inf)
        intrinsics = o3d.camera.PinholeCameraIntrinsic()
        # fx = Q[2, 3]
        # fy = Q[2, 3]
        # cx = Q[0, 3]
        # cy = Q[1, 3]
        fx = config.cam_matrix_left[0, 0]
        fy = fx
        cx = config.cam_matrix_left[0, 2]
        cy = config.cam_matrix_left[1, 2]
        print(fx, fy, cx, cy)
        intrinsics.set_intrinsics(width, height, fx= fx, fy= fy, cx= cx, cy= cy)
        extrinsics = np.array([[1., 0., 0., 0.],
                                            [0., 1., 0., 0.],
                                            [0., 0., 1., 0.],
                                            [0., 0., 0., 1.]])
        pointcloud = o3d.geometry.PointCloud().create_from_rgbd_image(rgbdImage, intrinsic=intrinsics, extrinsic=extrinsics)
        o3d.io.write_point_cloud("PointCloud.pcd", pointcloud=pointcloud)
        o3d.visualization.draw_geometries([pointcloud], width=720, height=480)
        sys.exit(0)
    
        # 计算像素点的3D坐标(左相机坐标系下)
        points_3d = cv2.reprojectImageTo3D(disp, Q)  # 参数中的Q就是由getRectifyTransform()函数得到的重投影矩阵
    
        # 构建点云--Point_XYZRGBA格式
        pointcloud = DepthColor2Cloud(points_3d, iml)
    
        # 显示点云
        view_cloud(points_3d)
    

    参考资料:

    SGBM算法详解(一)

    SGBM算法详解(二)

    双目视觉之空间坐标计算

    Stereo disparity quality problems

    Disparity map post-filtering

    OpenCV Stereo – Depth image generation and filtering

    OpenCV+OpenGL 双目立体视觉三维重建

    双目视觉测距原理,数学推导及三维重建资源

    展开全文
  • opencv-python双目测距

    千次阅读 2020-04-20 23:04:41
    双目测距原理 下图是双目摄像头成像示意图,其中P点为目标物体,O1和O2分别为左右摄像头的投影中心,x1和x2分别是目标物体在左右摄像头成像平面上的坐标,f为焦距,T为左右摄像头中心线距离,Z为摄像头投影中心到...

    双目测距原理

    下图是双目摄像头成像示意图,其中P点为目标物体,O1和O2分别为左右摄像头的投影中心,x1和x2分别是目标物体在左右摄像头成像平面上的坐标,f为焦距,T为左右摄像头中心线距离,Z为摄像头投影中心到目标物体的距离。
    在这里插入图片描述
    三维的坐标测距:在这里插入图片描述

    通过计算相似三角形我们可以得到:
    在这里插入图片描述

    程序效果

    在这里插入图片描述
    sift算法
    匹配效果:
    在这里插入图片描述
    匹配点视差数据(显示不全):
    在这里插入图片描述

    #include <opencv2/core/core.hpp>  
    #include <opencv2/highgui/highgui.hpp>  
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/features2d/features2d.hpp>
    #include <opencv2/nonfree/nonfree.hpp>
    #include <vector> 
    #include <iostream>
    #include <algorithm>
    
    using namespace cv;
    using namespace std;
    
    class parallax
    {
    public:
    	double leftX;
    	double rightX;
    	double paraValue;
    };
    
    bool ascendPara(parallax a, parallax b)
    {
    	return a.paraValue < b.paraValue;
    }
    
    int main()
    {
    	Mat leftImg, rightImg;
    	leftImg = imread("limg.jpg");
    	rightImg = imread("rimg.jpg");
    	imshow("limg", leftImg);
    	imshow("rimg", rightImg);
    
    	int minhessian = 1000;//threshold of hessian in SIFT or SURF algorithm 
    	vector<KeyPoint>l_keyPoint, r_keyPoint;
    	Mat l_descriptor, r_descriptor;
    
    	SurfFeatureDetector detector(minhessian);//define a feature detection class object
    	detector.detect(leftImg, l_keyPoint);
    	detector.detect(rightImg, r_keyPoint);
    
    	//compute descriptor (feature vector) of key points
    	SurfDescriptorExtractor extractor;
    	extractor.compute(leftImg, l_keyPoint, l_descriptor);
    	extractor.compute(rightImg, r_keyPoint, r_descriptor);
    
    	//FLANN algorithm to match feature vector
    	FlannBasedMatcher matcher;
    	vector<DMatch>matches;
    	matcher.match(l_descriptor, r_descriptor, matches);
    
    	//calculate the max and min distance between key points
    	double maxdist = 0; double mindist = 100;
    	for (int i = 0; i < l_descriptor.rows; i++)
    	{
    		double dist = matches[i].distance;
    		if (dist < mindist)mindist = dist;
    		if (dist > maxdist)maxdist = dist;
    	}
    	cout << "Matching quantity:" << matches.size() << endl;
    
    	//select the good match points
    	vector<DMatch>goodMatches;
    	for (int i = 0; i < l_descriptor.rows; i++)
    	{
    		if (matches[i].distance<2 * mindist)
    		{
    			goodMatches.push_back(matches[i]);
    		}
    	}
    	cout << "Good matching quantity:" << goodMatches.size() << endl;
    
    	//calculate parallax
    	vector<parallax>para;
    	for (int i = 0; i < goodMatches.size(); i++)
    	{
    		parallax temp;
    		temp.leftX = l_keyPoint[goodMatches[i].queryIdx].pt.x;
    		temp.rightX = r_keyPoint[goodMatches[i].trainIdx].pt.x;
    		temp.paraValue = temp.leftX - temp.rightX;
    		para.push_back(temp);
    		cout << "No." << i + 1 << ":\t l_X ";
    		cout << para[i].leftX << "\t r_X " << para[i].rightX;
    		cout << "\t parallax " << para[i].paraValue << endl;
    	}
    	sort(para.begin(), para.end(), ascendPara);
    	int idxMedian = int(para.size()/2);
    	double paraMedian = para[idxMedian].paraValue;
    	vector<parallax>::iterator it;
    	double errorRange = 0.005;
    	for (it=para.begin(); it!=para.end(); )
    	{
    		if (it->paraValue<((1 - errorRange)*paraMedian) || it->paraValue>((1 + errorRange)*paraMedian))
    			it = para.erase(it);
    		else
    			it++;
    	}
    	cout << "Final data..." << endl;
    	double paraSum = 0;
    	double paraMean;
    	for (int i = 0; i < para.size(); i++)
    	{
    		paraSum = paraSum + para[i].paraValue;
    		cout << "No." << i << "\t" << para[i].paraValue << endl;
    	}
    	paraMean = paraSum / para.size();
    	cout << "Parallax is " << paraMean << " pixel." << endl;
    
    	//draw the match image
    	Mat matchImg;
    	drawMatches(leftImg, l_keyPoint, rightImg, r_keyPoint, goodMatches, matchImg,
    		Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    	imshow("match", matchImg);
    
    	waitKey(0);
    	return 0;
    }
    
    
    

    python版本的例子
    python 双目测距

    有比我写的更好的博客 添加链接描述

    展开全文
  • 双目测距 SGBM算法 Python

    千次阅读 2021-09-16 15:26:18
    一、双目测距 效果 基于SGBM算法,生成视差图的效果 用鼠标点击视差图,程序会自动计算该点的世界坐标、距离,输出信息如下: 像素坐标 x = 523, y = 366 世界坐标xyz 是: 0.37038836669.

    前言

     首先进行双目定标,获取双目摄像头内部的参数后,进行测距。本次的双目视觉测距,基于SGBM算法。

    注意:双目定标的效果会影响测距的精准度,建议大家在做双目定标时,做好一些(尽量让误差小)

    如果不太了解双目视觉原理,建议先看看这篇文章:一篇文章认识《双目立体视觉》

    目录

    展开全文
  • 程序完全是由python3+opencv实现的,包括标定板图像采集,单目相机标定,双目相机标定,立体矫正,SGBM立体匹配,生成视差图像。测距并非采用opencv传统三维函数,通过记录实验数据,对实验数据进行多项式拟合,通过...
  • python opencv 双目测距代码

    千次阅读 2019-05-21 19:56:34
    最近高摄像头项目,顺便扩展学习python+opencv的图片处理和视频处理。 拍照效果: 代码: #!/usr/bin/python # -*- coding: utf-8 -*- import cv2 import time AUTO = True # 自动拍照,或手动按s键拍照 ...
  • OpenCV实现双目测距

    2021-01-12 04:17:54
    原理图示原理很简单,利用了相似三角形计算距离,所以双目测距的主要任务在于前期摄像头的定标、双目图像点的特征匹配上。常用做法具体步骤1.双目定标和校正,获得摄像头的参数矩阵摄像头定标一般都需要一个放在...
  • 双目测距Python-OpenCV代码及详细解释

    千次阅读 2021-12-02 16:12:29
    双目测距的基本流程 双目标定-->立体校正(含消除畸变)-->立体匹配-->视差计算-->深度计算/3D坐标计算 二 双目标定 参照之前的文章求出相册的内参,外参以及畸变函数,其中内参包括左右相机的fx...
  • importcv2importnumpy as npimportstereoconfigdefgetRectifyTransform(height, width, config):#读取矩阵参数left_K =config.cam_matrix_leftright_K=config.cam_matrix_rightleft_distortion=config.distortion_l...
  • 双目测距代码 python opencv 利用双目摄像头拍照,测距

    万次阅读 热门讨论 2018-03-19 22:33:03
    好久没有写博客了,手都感觉好生疏,最近一直在研究工控机,水下机器人等,好不容易闲下来,没办法呀,继续前行吧,前面一直说双目测距,但没有高速大家如何获得这个双目标注得图像,我在这把这代码贴一下吧,获得...
  • 双目测距 BM算法 Python

    千次阅读 2021-09-17 10:57:04
    一、双目测距 效果 基于BM算法,生成视差图的效果 用鼠标点击视差图,程序会自动计算该点的世界坐标、距离,输出信息如下: 像素坐标 x = 523, y = 366 世界坐标xyz 是: 0.37038836...
  • 基于OpenCV3.2+VS2013双目测距1、摄像头标定1.1、通查询资料和博客大概有两种方式:(1)利用OpenCV自带的校正程序(2)利用MATLAB工具来标定1.2该工程是利用MATLAB工具来标定:(1)固定好摄像头,尽量保证两个摄像头是...
  • python、opencv 双目视觉测距代码

    千次阅读 2021-02-05 07:52:25
    两个部分,一个是相机的参数设置,一个是测距运用matlab里面的stereo Camera Calibrator APP进行拍照 拍个30多张,然后拉线,留个10-20张进行计算,把双目摄像机的数据填到camera_configs.py里面camera_configs.py...
  • 为了解决被动式双目测距系统中双目摄像头光轴对准误差较大、图像匹配精确度较低、计算速度慢等问题,提出了一种基于硬件加速稳健特征(SURF)算法的自校准双目测距系统。该方案采用位置敏感探测器与伺服电机作为双目...
  • 基于C++的双摄像头的立体双目测距算法。可以实现对物体目标的捕捉 。
  • 修改内容:屏蔽了用cvblobslib实现的功能,但是主要功能标定以及测距都可以实现,而且不用安装那反人类的cvblobslib扩展库。 实现环境: 1,两个普通摄像头 2.opencv2.4.9 3.windows10 4.vs2013
  • Python-OpenCV双目测距代码实现以及参数解读

    千次阅读 多人点赞 2021-04-16 16:22:43
    1、双目相机拍照后使用Matlab进行双目标定 主要参考:https://blog.csdn.net/dulingwen/article/details/98071584 感谢大佬的分享!!!(*≧ω≦)!! Python-openCV 中cv2.StereoSGBM_create()参数的含义 参考:...
  • 双目视差匹配测距算法
  • 3,在进行测距之前,首先需要对摄像头进行标定,那么如何标定呢? 在stdafx.h中把"#define CALIBRATION 0"改成 “#define CALIBRATION 1”表示进行标定,标定之后,你就可以在工程目录下的"CalibFile" 文件夹中得到...
  • 双目测距、重构 楼主之前用的SFM来进行重构,但是得到的是视差图,点云和实物存在比例关系,单目的还是不能解决scale这个问题的。所以今天用双目的来进行重构,期间遇到了很多坑,实属难受。 双目测距过程大致可以...
  • 用C写的,但是其坐标输出有C和C++两个,鼠标点击输出三维坐标,其相机标定用的是MATLAB结果导入,用的VS2010,实际运行成功的,不出我需要修改的是相机标定的xml文件,标定过程参考前面的博文,还有就是修改左右相机...
  • 双目摄像头实现双目测距

    千次阅读 2021-12-11 11:35:20
    双目立体视觉深度相机实现双目测距功能,主要分为4个步骤:相机标定+双目校正+双目匹配+计算深度信息: (1)相机标定:需要对双目相机进行标定,得到两个相机的内外参数、单应矩阵。 (2) 双目校正:根据标定结果对...
  • 关于opencv双目标定问题,是不是可以先对两个cam分别标定,得到各自的r和t,然后直接计算可得还是通过什么方法?困扰我两天了,求大神解答,万分感谢
  • 实现双目测距功能,需要python环境,安装OpenCV,自行标定
  • 本博客将实现Python版本的双目三维重建系统,项目代码实现包含:`双目标定`,`立体校正(含消除畸变)`,`立体匹配`,`视差计算`和`深度距离计算/3D坐标计算` 的知识点。限于篇幅,本博客不会过多赘述算法原理,而是...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 379
精华内容 151
关键字:

双目测距python

python 订阅