gpt4 book ai didi

python - OpenCV:使用 solvePnP 确定单应性

转载 作者:太空狗 更新时间:2023-10-30 01:34:14 28 4
gpt4 key购买 nike

在过去的几周里,我尝试学习纠正图像,并且在这里的人们的帮助下,我已经设法更好地理解它。大约一周前,我设置了一个我想纠正的测试示例(查看上图)。使用函数 T = cv2.getPerspectiveTransform(UV_cp, XYZ_gcp) 可以很好地(原始:http://sitedezign.net/original.jpg 并修正:http://sitedezign.net/rectified.jpg),其中 T 成为单应性。

当我尝试对真实世界的照片执行此操作时,它失败了,因为真实世界的坐标并不完美地位于平面上(而是在空间中的 X、Y 和 Z 坐标中测量的大约 10 个控制点)。因此,我决定使用 solvePnP,并希望能够创建一个我可以使用的 Homography。

我在测试示例中尝试了这个,但没有得到我预期的结果:图像没有校正,我使用 solvePnP 计算的 Homography 不等于使用 getPerspectiveTransform 计算的 Homography。

我的代码:

# Set UV (image) and XYZ (real life)
UV_cp = np.array([[1300.0, 2544.0], # left down
[1607.0, 1000.0], # left up
[3681.0, 2516.0], # right down
[3320.0, 983.0]], np.float32) # right up

# Z is on 0 plane, so Z=0.0
XYZ_gcp = np.array([[0.0, 400.0, 0.0],
[0.0, 0.0, 0.0],
[300.0, 400.0, 0.0],
[300.0, 0.0, 0.0]], np.float32)

rvec, tvec = cv2.solvePnP(XYZ_gcp, UV_cp, K, D)
rotM_cam = cv2.Rodrigues(rvec)[0]

# calculate camera position (= translation), in mm from 0,0,0 point
cameraPosition = -np.matrix(rotM_cam).T * np.matrix(tvec)

# 3x3 Identity matrix
I = np.identity(3)

# [I|-C]
I1_extended = np.hstack((I,-cameraPosition))

# P = K*R*I
P_cam = K.dot(rotM_cam).dot(I1_extended)

# create P2 = image from above: R = 0,0,0, translation = x, y, z = 0,0,-1000 (mm)
R_rec = matr.getR(0.0,0.0,0.0)
newZ = -1000.0
new_cameraPosition = np.array([[0.0],[0.0],[newZ]])
I2_extended = np.hstack((I,new_cameraPosition))
P_rec = K.dot(R_rec).dot(I2_extended)

# correct Homography T from getPerspectiveTransform:
T = np.array([[4.70332834e-01, 9.35182514e-02, -4.24671558e+02],
[9.62104844e-03, 9.69462117e-01, -4.92461571e+02],
[3.54859924e-06, 6.80081146e-04, 1.00000000e+00]])

# Homography Matrix = H = P_rect * pinv(P) => P2 * pinv(P1)
H = P_rec.dot(np.linalg.pinv(P_cam))

结果是一张扭曲的图像,与上面显示的图像(校正后的图像)相去甚远。此外,应该正确的单应性 T(来自 getPerspectiveTransform)不接近等于使用 solvePnP (H) 的结果计算的单应性。

H from solvePnP:
[[ 1.01865631e+00 2.68683332e-01 -2.04519580e+03]
[ -3.24304366e-02 6.82672680e-01 -1.15688010e+03]
[ 2.03399902e-05 1.24191993e-04 -5.41378561e-01]]

H from getPerspectiveTransform:
[[ 4.70332834e-01 9.35182514e-02 -4.24671558e+02]
[ 9.62104844e-03 9.69462117e-01 -4.92461571e+02]
[ 3.54859924e-06 6.80081146e-04 1.00000000e+00]]

有人知道出了什么问题吗?

PS:确定 K 矩阵和畸变系数的代码(根据 Adob​​e Camera Raw,值取 self 的相机 Pentax K-5,焦距为 33mm):

# Focal length, sensor size (mm and px)
f = 33.0 # mm
pix_width = 4928.0 # sensor size has 4928px in width
pix_height = 3624.0 # sensor size has 4928px in width
sensor_width = 23.7 # mm
sensor_height = 15.7 # mm

# set center pixel
u0 = int(pix_width / 2.0)
v0 = int(pix_height / 2.0)

# determine values of camera-matrix
mu = pix_width / sensor_width # px/mm
alpha_u = f * mu # px

mv = pix_height / sensor_height # px/mm
alpha_v = f * mv # px

# Distortion coefs
D = np.array([[0.0, 0.0, 0.0, 0.0]])

# Camera matrix
K = np.array([[alpha_u, 0.0, u0],
[0.0, alpha_v, v0],
[0.0, 0.0, 1.0]])

最佳答案

您的 K 矩阵似乎很合适,但这可能不足以实现真实图像的良好精度。我认为与其给出合理的先验值(特别是光学中心像素和镜头畸变系数),不如使用 calibrateCamera 函数( documentation linktutorials )校准相机。但是,我认为您提到的问题不是由此引起的。

我认为你的问题来自P_rec的定义。

首先,请注意,如果您使用 newZ = -1000.0,您实际上是将相机平移 1000 米(而不是毫米)。

其次,您必须非常小心您正在考虑的 3D 点以及您希望它们在图像中的投影位置:

  1. 由于您在 solvePnP 函数中使用了 XYZ_gcp,这意味着您将这些坐标用作 3D 点。

  2. 由于您在 getPerspectiveTransform 函数中使用了 XYZ_gcp,这意味着您也将这些用作 2D 坐标。请注意,严格来说,您不能这样做,因为 getPerspectiveTransform 需要两个 4x2 数组(不是 4x2 和 4x3),但我假设您删除了始终为 0 的第三个坐标。

因此,您的 P_rec 应该定义为 [x;是; 1] = P_rec * [x;是; 0; 1].因此,P_rec应该定义如下:

P_rec = [ [1 0 0 0] [0 1 0 0] [0 0 0 1] ].

关于python - OpenCV:使用 solvePnP 确定单应性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22173836/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com