Bootstrap

opencv-python立体匹配(极线校正)


前言

  对照片进行光学畸变矫正后,因为是在研究双目视觉,所以就要进行立体矫正了。


一、立体校正是什么?

  标定后得到了左右相机的内参数:焦距、主点坐标以及径向畸变和切向畸变,通过相机的内参数和畸变系数可校正左右拍摄图像的畸变,得到对应环境场景正确的图像。同时实验还得到了相机外参,外参用于立体校正,使左右图像处于同一平面内,且实现行对准,这一过程被称为极线校正。

二、校准步骤

1.照片准备

因为还没有实地拍摄照片,只能先用opencv的自带实例。
在这里插入图片描述

2.立体匹配

   stereoCalibrate() 是用来标定一个立体摄像头的,也就是同时标定两个摄像头。标定的结果除了能够求出两个摄像头的内外参数矩阵,跟能够得出两个摄像头的位置关系R,T。R– 输出第一和第二相机坐标系之间的旋转矩阵,T– 输出第一和第二相机坐标系之间的旋转矩阵平移向量。
  flag-CV_CALIB_FIX_INTRINSIC 如果该标志被设置,那么就会固定输入的cameraMatrix和distCoeffs不变,只求解R,T,E,F。
   initUndistortRectifyMap()是计算无畸变和修正转换映射。

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

# 终止标准
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 准备对象点,(0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

# 用于存储所有图像对象点与图像点的矩阵
objpoints = [] # 在真实世界中的 3d 点
imgpointsR = [] # 在图像平面中的 右2d 点
imgpointsL = [] # 在图像平面中的 左2d 点
#左图13张右图13for i in range(1, 14):
    t = str(i)
    ChessImaR = cv.imread(r'D:\test\venv\data\right' + t + '.jpg', 0)  # 右视图
    ChessImaL = cv.imread(r'D:\test\venv\data\left' + t + '.jpg', 0)  # 左视图
    # 提取每一张图片的角点
    retR, cornersR = cv.findChessboardCorners(ChessImaR, (7, 6), None)  
    retL, cornersL = cv.findChessboardCorners(ChessImaL, (7, 6), None)  
    if (True == retR) & (True == retL):
        objpoints.append(objp)
        # 亚像素精确化,对粗提取的角点进行精确化
        cv.cornerSubPix(ChessImaR, cornersR, (11, 11), (-1, -1), criteria)  
        cv.cornerSubPix(ChessImaL, cornersL, (11, 11), (-1, -1), criteria)
        imgpointsR.append(cornersR)
        imgpointsL.append(cornersL)
#通过多个视角的2D/3D对应,求解出该相机的内参数和每一个视角的外参数
retR, mtxR, distR, rvecsR, tvecsR = cv.calibrateCamera(objpoints, imgpointsR, ChessImaR.shape[::-1], None, None)
hR, wR = ChessImaR.shape[:2]
OmtxR, roiR = cv.getOptimalNewCameraMatrix(mtxR, distR, (wR, hR), 1, (wR, hR))

retL, mtxL, distL, rvecsL, tvecsL = cv.calibrateCamera(objpoints, imgpointsL, ChessImaL.shape[::-1], None, None)
hL, wL = ChessImaL.shape[:2]
OmtxL, roiL = cv.getOptimalNewCameraMatrix(mtxL, distL, (wL, hL), 1, (wL, hL))

retS, MLS, dLS, MRS, dRS, R, T, E, F = cv.stereoCalibrate(objpoints,imgpointsL,imgpointsR,OmtxL,distL,OmtxR,distR,
                                                           ChessImaR.shape[::-1], criteria,0) #ChessImaR.shape[::-1]是图像的大小

# 利用stereoRectify()计算立体校正的映射矩阵
rectify_scale = 1  # 设置为0的话,对图片进行剪裁,设置为1则保留所有原图像像素
RL, RR, PL, PR, Q, roiL, roiR = cv.stereoRectify(MLS, dLS, MRS, dRS,
                                                  ChessImaR.shape[::-1], R, T,
                                                  rectify_scale, (0, 0))
# 利用initUndistortRectifyMap函数计算畸变矫正和立体校正的映射变换,实现极线对齐。
Left_Stereo_Map = cv.initUndistortRectifyMap(MLS, dLS, RL, PL,
                                              ChessImaR.shape[::-1], cv.CV_16SC2)

Right_Stereo_Map = cv.initUndistortRectifyMap(MRS, dRS, RR, PR,
                                               ChessImaR.shape[::-1], cv.CV_16SC2)

# 立体校正效果显示
for i in range(1, 13): 
    t = str(i)
    frameR = cv.imread(r'D:\test\venv\data\right' + t + '.jpg', 0)
    frameL = cv.imread(r'D:\test\venv\data\left' + t + '.jpg', 0)

    Left_rectified = cv.remap(frameL, Left_Stereo_Map[0], Left_Stereo_Map[1], cv.INTER_LANCZOS4, cv.BORDER_CONSTANT,
                               0)  # 使用remap函数完成映射
    im_L = Image.fromarray(Left_rectified)  # numpy 转 image类

    Right_rectified = cv.remap(frameR, Right_Stereo_Map[0], Right_Stereo_Map[1], cv.INTER_LANCZOS4,
                                cv.BORDER_CONSTANT, 0)
    im_R = Image.fromarray(Right_rectified)  # numpy 转 image 类

    # 创建一个能同时并排放下两张图片的区域,后把两张图片依次粘贴进去
    width = im_L.size[0] * 2
    height = im_L.size[1]

    img_compare = Image.new('RGBA', (width, height))
    img_compare.paste(im_L, box=(0, 0))
    img_compare.paste(im_R, box=(640, 0))

    # 在已经极线对齐的图片上均匀画线
    for i in range(1, 20):
        len = 480 / 20
        plt.axhline(y=i * len, color='r', linestyle='-')
    plt.imshow(img_compare)
    plt.savefig(r'D:\test\venv\result\result' + t + '.jpg')
    plt.show()

在这里插入图片描述
在这里插入图片描述

总结

参考了opencv官方中文手册,https://blog.csdn.net/qq_22059843/article/details/103400094大佬的代码,以及https://docs.opencv.org/3.4/dc/dbb/tutorial_py_calibration.html官方例子。

;