猿问

在 Python 中使用 OpenCV 中的鱼眼相机捕获的点不失真的正确方法是什么?

信息:


我已经校准了我的相机,发现相机的内在矩阵 (K) 及其失真系数 (d) 如下:


import numpy as np

K = np.asarray([[556.3834638575809,0,955.3259939726225],[0,556.2366649196925,547.3011305411478],[0,0,1]])

d = np.asarray([[-0.05165940570900624],[0.0031093602070252167],[-0.0034036648250202746],[0.0003390345044343793]])

从这里,我可以使用以下三行来不扭曲我的图像:


final_K = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, d, (1920, 1080), np.eye(3), balance=1.0)


map_1, map_2 = cv2.fisheye.initUndistortRectifyMap(K, d, np.eye(3), final_K, (1920, 1080), cv2.CV_32FC1)


undistorted_image = cv2.remap(image, map_1, map_2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)

生成的未失真图像似乎是正确的Left image is distorted, right is undistorted,但是当我尝试使用未将cv2.remap()点映射到与图像中相应像素相同的位置来使图像点不失真时。我使用检测到左侧图像中的校准板点


ret, corners = cv2.findChessboardCorners(gray, (6,8),cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)

corners2 = cv2.cornerSubPix(gray, corners, (3,3), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1))

然后以下列方式重新映射这些点:


remapped_points = []

for corner in corners2:

    remapped_points.append(

                (map_1[int(corner[0][1]), int(corner[0][0])], map_2[int(corner[0][1]), int(corner[0][0])])

            )

在这些水平拼接的图像中,左图显示了在失真图像中检测到的点,而右图显示了右图中点的重新映射位置。


此外,我无法使用cv2.fisheye.undistortPoints(). 我有以下功能来不扭曲点:


    K = np.asarray(in_K)

    d = np.asarray(in_d)

    # Input can be list of bbox coords, poly coords, etc.

    # TODO -- Check if point behind camera?

    points_2d = np.asarray(point_list)


    points_2d = points_2d[:, 0:2].astype('float32')

    points2d_undist = np.empty_like(points_2d)

    points_2d = np.expand_dims(points_2d, axis=1)


    result = np.squeeze(cv2.fisheye.undistortPoints(points_2d, K, d))


    fx = K[0, 0]

    fy = K[1, 1]

    cx = K[0, 2]

    cy = K[1, 2]


这张图显示了使用上述函数不失真时的结果。


(这一切都在 Python 3.6.8 的 Ubuntu 18.04 上的 OpenCV 4.2.0 中运行)


问题


为什么图像坐标的重新映射不能正常工作?我是否使用map_1不map_2正确?


为什么using和using 的结果cv2.fisheye.undistortPoints()不同?map_1map_2


ibeautiful
浏览 161回答 1
1回答

开心每一天1111

回答 Q1:您没有正确使用map_1和map_2。cv2.fisheye.initUndistortRectifyMap函数生成的map应该是目标图像的像素位置到源图像的像素位置的映射,即dst(x,y)=src(mapx(x,y),mapy (x,y))。请参阅OpenCV 中的重映射。在代码中,map_1用于 x 方向像素映射,map_2用于 y 方向像素映射。例如, (X_undistorted, Y_undistorted)是未失真图像中的像素位置。map_1[Y_undistorted, X_undistorted]告诉你这个像素应该在哪里映射到扭曲图像中的x坐标,而map_2会给你相应的y坐标。因此,map_1和map_2对于从失真图像构建未失真图像很有用,并不真正适合逆向过程。remapped_points = []for corner in corners2:    remapped_points.append(              (map_1[int(corner[0][1]), int(corner[0][0])], map_2[int(corner[0][1]), int(corner[0][0])]))此代码查找角的未失真像素位置是不正确的。您将需要使用undistortPoints函数。回答 Q2:映射和不失真是不同的。您可以将映射视为基于未失真图像中的像素位置与像素图构建未失真图像,而未失真是使用镜头失真模型使用原始像素位置找到未失真像素位置。为了在未失真的图像中找到角点的正确像素位置。您需要使用新估计的 K 将未失真点的归一化坐标转换回像素坐标,在您的情况下,它是final_K,因为未失真的图像可以被视为由具有 final_K 的相机拍摄而没有失真(有小缩放效果)。这是修改后的 undistort 函数:def undistort_list_of_points(point_list, in_K, in_d, in_K_new):    K = np.asarray(in_K)    d = np.asarray(in_d)    # Input can be list of bbox coords, poly coords, etc.    # TODO -- Check if point behind camera?    points_2d = np.asarray(point_list)    points_2d = points_2d[:, 0:2].astype('float32')    points2d_undist = np.empty_like(points_2d)    points_2d = np.expand_dims(points_2d, axis=1)    result = np.squeeze(cv2.fisheye.undistortPoints(points_2d, K, d))    K_new = np.asarray(in_K_new)    fx = K_new[0, 0]    fy = K_new[1, 1]    cx = K_new[0, 2]    cy = K_new[1, 2]    for i, (px, py) in enumerate(result):        points2d_undist[i, 0] = px * fx + cx        points2d_undist[i, 1] = py * fy + cy    return points2d_undist这是我做同样事情的代码。import cv2import numpy as npimport matplotlib.pyplot as pltK = np.asarray([[556.3834638575809,0,955.3259939726225],[0,556.2366649196925,547.3011305411478],[0,0,1]])D = np.asarray([[-0.05165940570900624],[0.0031093602070252167],[-0.0034036648250202746],[0.0003390345044343793]])print("K:\n", K)print("D:\n", D.ravel())# read image and get the original image on the leftimage_path = "sample.jpg"image = cv2.imread(image_path)image = image[:, :image.shape[1]//2, :]image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)fig = plt.figure()plt.imshow(image_gray, "gray")H_in, W_in = image_gray.shapeprint("Grayscale Image Dimension:\n", (W_in, H_in))scale_factor = 1.0 balance = 1.0img_dim_out =(int(W_in*scale_factor), int(H_in*scale_factor))if scale_factor != 1.0:    K_out = K*scale_factor    K_out[2,2] = 1.0K_new = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K_out, D, img_dim_out, np.eye(3), balance=balance)print("Newly estimated K:\n", K_new)map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K_new, img_dim_out, cv2.CV_32FC1)print("Rectify Map1 Dimension:\n", map1.shape)print("Rectify Map2 Dimension:\n", map2.shape)undistorted_image_gray = cv2.remap(image_gray, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)fig = plt.figure()plt.imshow(undistorted_image_gray, "gray")  ret, corners = cv2.findChessboardCorners(image_gray, (6,8),cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)corners_subpix = cv2.cornerSubPix(image_gray, corners, (3,3), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1))undistorted_corners = cv2.fisheye.undistortPoints(corners_subpix, K, D)undistorted_corners = undistorted_corners.reshape(-1,2)fx = K_new[0,0]fy = K_new[1,1]cx = K_new[0,2]cy = K_new[1,2]undistorted_corners_pixel = np.zeros_like(undistorted_corners)for i, (x, y) in enumerate(undistorted_corners):    px = x*fx + cx    py = y*fy + cy    undistorted_corners_pixel[i,0] = px    undistorted_corners_pixel[i,1] = py    undistorted_image_show = cv2.cvtColor(undistorted_image_gray, cv2.COLOR_GRAY2BGR)for corner in undistorted_corners_pixel:    image_corners = cv2.circle(np.zeros_like(undistorted_image_show), (int(corner[0]),int(corner[1])), 15, [0, 255, 0], -1)    undistorted_image_show = cv2.add(undistorted_image_show, image_corners)fig = plt.figure()plt.imshow(undistorted_image_show, "gray")
随时随地看视频慕课网APP

相关分类

Python
我要回答