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

在Python中,在OpenCV中使用鱼眼相机捕获点时,正确的方法是什么?,python,opencv,camera-calibration,calibration,fisheye,Python,Opencv,Camera Calibration,Calibration,Fisheye,信息: 我已经校准了我的相机,发现相机的内部矩阵(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.003403664825020274

信息:

我已经校准了我的相机,发现相机的内部矩阵(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)
生成的未失真图像看起来是正确的,但是当我尝试使用
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()
获得正确的结果。我有以下功能来消除点的扭曲:

def undistort_list_of_points(point_list, in_K, in_d):
    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]

    for i, (px, py) in enumerate(result):
        points2d_undist[i, 0] = px * fx + cx
        points2d_undist[i, 1] = py * fy + cy

    return points2d_undist
显示使用上述函数取消失真时的结果

(这些都是在Python3.6.8版本的Ubuntu18.04上的OpenCV 4.2.0中运行的)

问题

为什么图像坐标的重新映射不能正常工作?我是否错误地使用了
map\u 1
map\u 2

为什么使用
cv2.fisheye.undistortPoints()
的结果与使用
map_1
map_2
的结果不同?

回答问题1: 您没有正确使用map_1map_2

cv2.fisheye.initundistortic整流map函数生成的映射应该是目标图像的像素位置到源图像的像素位置的映射,即dst(x,y)=src(mapx(x,y),mapy(x,y))。请参见OpenCV中的

在代码中,map_1用于x方向像素映射,map_2用于y方向像素映射。例如 (X\u未失真,Y\u未失真)是未失真图像中的像素位置map_1[Y_未失真,X_未失真]提供此像素应映射到扭曲图像中X坐标的位置,而map_2将提供相应的Y坐标

因此,map_1map_2对于从失真图像构建未失真图像非常有用,但并不真正适用于反向处理

重新映射的_点=[]
对于拐角中的拐角2:
重新映射的_points.append(
(map_1[int(corner[0][1])、int(corner[0][0])、map_2[int(corner[0][1])、int(corner[0][0]))
这段代码查找未变形的像素角点位置不正确。您需要使用无失真点功能


对问题2的答复: 映射和不失真是不同的

可以将贴图视为基于像素贴图的未失真图像中的像素位置构建未失真图像,而未失真是使用镜头失真模型使用原始像素位置查找未失真的像素位置

以便在未失真图像中找到角点的正确像素位置。您需要使用新估计的K将未失真点的标准化坐标转换回像素坐标,在您的情况下,这是最终的_K,因为未失真的图像可以被视为是由具有最终的_K的相机拍摄的,没有失真(有一个小的缩放效果)

以下是修改后的不失真函数:

def取消点列表(点列表、输入、输出、输入新):
K=np.asarray(单位:K)
d=np.asarray(in_d)
#输入可以是bbox坐标、poly坐标等的列表。
#TODO——检查摄像机后面的点是否正确?
点2d=np.asarray(点列表)
points_2d=points_2d[:,0:2].aType('float32')
点2d\u undis=np.空类(点2d)
点\u 2d=np。展开\u dims(点\u 2d,轴=1)
结果=np.挤压(cv2.鱼眼.不变形点(点2d,K,d))
K_new=np.asarray(in_K_new)
fx=K_新[0,0]
fy=K_新[1,1]
cx=K_新[0,2]
cy=K_新[1,2]
对于枚举(结果)中的i,(px,py):
点2d_undis[i,0]=px*fx+cx
点2d_undis[i,1]=py*fy+cy
返回点2d_undis

这是我做同样事情的代码。
导入cv2
将numpy作为np导入
将matplotlib.pyplot作为plt导入
K=np.asarray([556.3834638575809,0955.3259939726225],[0556.2366649196925547.3011305411478],[0,0,1])
D=np.asarray([-0.05165940570900624],[0.00310936020705167],-0.0034036648250202746],[0.00033903450443793])
打印(“K:\n”,K)
打印(“D:\n”,D.ravel())
#读取图像并获取左侧的原始图像
image\u path=“sample.jpg”
image=cv2.imread(图像路径)
image=image[:,:image.shape[1]//2,:]
图像\u灰度=cv2.CVT颜色(图像,cv2.COLOR\u BGR2GRAY)
图=plt.图()
plt.imshow(图像为灰色,“灰色”)
H_in,W_in=图像的灰度形状
打印(“灰度图像尺寸:\n”,(W_英寸,H_英寸))
比例系数=1.0
余额=1.0
img_dim_out=(int(W_in*比例系数),int(H_in*比例系数))
如果比例系数!=1.0:
K_out=K*比例系数
K_out[2,2]=1.0
K_new=cv2.fisheye.EstimateMewCameraTrix不失真校正(K_out,D,img_dim_out,np.eye(3),balance=balance)
打印(“新估计的K:\n”,K\u新)
map1,map2=cv2.fisheye.initundistortionrectiveymap(K,D,np.eye(3),K_new,img_dim_out,cv2.CV_32FC1)
打印(“纠正Map1尺寸:\n”,Map1.shape)
打印(“纠正Map2尺寸:\n”,Map2.shape)
未失真图像灰度=cv2.重新映射(图像灰度,map1,map2,插值=cv2.内部线性,边界模式=cv2.边界常数)
图=plt.图()
plt.imshow(未失真图像“灰色”)
ret,corners=cv2。findChessboardCorners(图像灰度,(6,8),cv2。校准校准校准CB校准自适应阈值+cv2。校准校准CB校准快速检查+cv2。校准校准CB校准标准化图像)
角点_子项=cv2.corne