(Python和OpenCV)计算对极线的正确方法

时间:2018-06-28 19:07:56

标签: python opencv

首先,是的,这只是为了锻炼,但不是,我这里不是要寻求编码解决方案。

该程序可以让我拍摄从不同角度拍摄的物体的两幅图像,并在其中一张图像上选择一个点时在另一幅图像上绘制极线

(例如:当我使用鼠标在左侧图片中选择一个点时,程序将用圆圈标记该点,然后在右侧图像上绘制一条与我标记的点相对应的极线)

练习包括2个xml文件,其中包含用于每个投影矩阵的3x3相机矩阵和每个图片的3x4投影矩阵列表(图片编号为1的投影矩阵等)

所以当我读取程序上的数据时,我有:

-相机矩阵K

-左侧图片的投影矩阵P_left

-右图的投影矩阵P_right

现在是我想做的(顺便说一下,在separte显示器上打开的图像):

  1. 通过鼠标单击选择左侧图像中的像素坐标(x,y)

  2. 计算左侧图像中的点p:K ^ -1 *(x,y,1)

  3. P + = P_left的伪逆矩阵(使用np.linalg.pinv)

  4. 右图的
  5. epipole e':P_right *(0,0,0,1)

  6. e'_skew:e的倾斜对称矩阵

  7. 基本矩阵F:e'_skew * P_right * P +

  8. 右图的
  9. 极极线l':F * p

  10. 计算右侧图像中的点p':P_right * P + * p

  11. 将p'和l转换为像素坐标(无法弄清楚)

  12. 使用cv2.line通过p'和l

到目前为止,这是我的想法,但仍然没有成功,所以我想知道它的想法本身是错的还是我只是在某个地方做错了计算。如您所见,我不太擅长此练习,因此非常感谢您的一些建议

1 个答案:

答案 0 :(得分:1)

我几天前刚刚做过,效果很好。这是我使用的方法:

  1. 校准摄像机以获取摄像机矩阵和失真矩阵(使用openCV getCornerscalibrateCamera,您可以找到很多关于此的教程,但听起来您已经有了此信息)< / li>
  2. 使用openCV stereoCalibrate()执行立体声校准。它以所有摄像机和失真矩阵为参数。您需要用它来确定两个视野之间的相关性。您将获得几个矩阵,旋转矩阵R,平移矢量T,基本矩阵E和基本矩阵F。
  3. 然后,您想使用openCV getOptimalNewCameraMatrixundistort()进行失真处理。这将消除很多相机像差(它将为您带来更好的结果)
  4. 最后,使用openCV的computeCorrespondEpilines计算线并绘制它们。我将在下面包含一些代码,您可以在Python中尝试一下。当我运行它时,我可以得到这样的图像(彩色点在其他图像中绘制了它们相应的背线)

Epiline Calculation 这是一些代码(Python 3.0)。它使用两个静态图像和静态点,但是您可以使用光标轻松选择这些点。您还可以参考有关校准和立体声校准here的OpenCV文档。

import cv2
import numpy as np

# find object corners from chessboard pattern  and create a correlation with image corners
def getCorners(images, chessboard_size, show=True):
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

    # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
    objp = np.zeros((chessboard_size[1] * chessboard_size[0], 3), np.float32)
    objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)*3.88 # multiply by 3.88 for large chessboard squares

    # Arrays to store object points and image points from all the images.
    objpoints = [] # 3d point in real world space
    imgpoints = [] # 2d points in image plane.

    for image in images:
        frame = cv2.imread(image)
        # height, width, channels = frame.shape # get image parameters
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)   # Find the chess board corners
        if ret:                                                                         # if corners were found
            objpoints.append(objp)
            corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)    # refine corners
            imgpoints.append(corners2)                                                  # add to corner array

            if show:
                # Draw and display the corners
                frame = cv2.drawChessboardCorners(frame, chessboard_size, corners2, ret)
                cv2.imshow('frame', frame)
                cv2.waitKey(100)

    cv2.destroyAllWindows()             # close open windows
    return objpoints, imgpoints, gray.shape[::-1]

# perform undistortion on provided image
def undistort(image, mtx, dist):
    img = cv2.imread(image, cv2.IMREAD_GRAYSCALE)
    image = os.path.splitext(image)[0]
    h, w = img.shape[:2]
    newcameramtx, _ = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
    dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
    return dst

# draw the provided points on the image
def drawPoints(img, pts, colors):
    for pt, color in zip(pts, colors):
        cv2.circle(img, tuple(pt[0]), 5, color, -1)

# draw the provided lines on the image
def drawLines(img, lines, colors):
    _, c, _ = img.shape
    for r, color in zip(lines, colors):
        x0, y0 = map(int, [0, -r[2]/r[1]])
        x1, y1 = map(int, [c, -(r[2]+r[0]*c)/r[1]])
        cv2.line(img, (x0, y0), (x1, y1), color, 1)

if __name__ == '__main__':

 # undistort our chosen images using the left and right camera and distortion matricies
    imgL = undistort("2L/2L34.bmp", mtxL, distL)
    imgR = undistort("2R/2R34.bmp", mtxR, distR)
    imgL = cv2.cvtColor(imgL, cv2.COLOR_GRAY2BGR)
    imgR = cv2.cvtColor(imgR, cv2.COLOR_GRAY2BGR)

    # use get corners to get the new image locations of the checcboard corners (undistort will have moved them a little)
    _, imgpointsL, _ = getCorners(["2L34_undistorted.bmp"], chessboard_size, show=False)
    _, imgpointsR, _ = getCorners(["2R34_undistorted.bmp"], chessboard_size, show=False)

    # get 3 image points of interest from each image and draw them
    ptsL = np.asarray([imgpointsL[0][0], imgpointsL[0][10], imgpointsL[0][20]])
    ptsR = np.asarray([imgpointsR[0][5], imgpointsR[0][15], imgpointsR[0][25]])
    drawPoints(imgL, ptsL, colors[3:6])
    drawPoints(imgR, ptsR, colors[0:3])

    # find epilines corresponding to points in right image and draw them on the left image
    epilinesR = cv2.computeCorrespondEpilines(ptsR.reshape(-1, 1, 2), 2, F)
    epilinesR = epilinesR.reshape(-1, 3)
    drawLines(imgL, epilinesR, colors[0:3])

    # find epilines corresponding to points in left image and draw them on the right image
    epilinesL = cv2.computeCorrespondEpilines(ptsL.reshape(-1, 1, 2), 1, F)
    epilinesL = epilinesL.reshape(-1, 3)
    drawLines(imgR, epilinesL, colors[3:6])

    # combine the corresponding images into one and display them
    combineSideBySide(imgL, imgR, "epipolar_lines", save=True)

希望这会有所帮助!