使用 OpenCV solvepnp() 函数解决 PnP 问题
OpenCV 库是一个开源库,旨在帮助完成计算机视觉任务。该库与 Python 兼容,可用于实现和解决不同的图像处理问题。
本教程将演示如何在 Python 中使用 OpenCV 库中的 solvepnp()
函数。该函数用于解决姿态估计问题。
了解 PnP 问题
PnP 问题在计算机视觉中非常常见,代表 Perspective n-Points 问题。在这个问题中,我们无法在提供 2D 和 3D 坐标后确定物体相对于相机的位姿。
这可以通过在线考试期间的面部跟踪示例来理解。物体的姿态可以随着方向的改变而改变。
以下两种类型的运动促进了这种变化:
- 第一种运动是平移运动,可以沿三个轴中的任何一个发生。物体沿任何特定方向匀速运动,从而改变其坐标。
- 第二种运动是旋转运动,物体可以围绕三个轴中的任何一个旋转。
使用 opencv.solvepnp()
函数解决 PnP 问题
OpenCV 库中的 solvepnp()
函数用于给定对象相对于相机的位姿估计,从而解决 PnP 问题。它返回旋转和平移向量。
它使用相机矩阵的对象的 2D 和 3D 坐标。提供的坐标是面部的不同特征。
这些特征是鼻子、嘴角、下巴和双眼。
让我们讨论使用此功能所需的所有参数。
-
objectPoints
参数采用前面提到的所有特征的 3D 点。 -
imagePoints
参数用于指定对象特征的 2D 点。 -
cameraMatrix
用于指定相机的内在价值。该矩阵是使用相机的中心点和焦距创建的。 -
为了解决相机引起的失真,我们使用了
distCoeffs
参数。如果相机中的失真可以忽略不计,则该向量可以为 NULL。 -
我们可以使用
useExtrinsicGuess
参数将输出结果用于初始计算,该参数可以为真或假。除此之外,只有flags
参数。
此函数返回的旋转和平移向量可用于绘制对象姿势的线。
例如,我们将确定下图的位姿。
确定此图像姿势的代码如下所示。
import cv2
import numpy as np
img = cv2.imread("img.jpg")
size = img.shape
image_points_2D = np.array(
[
(196, 141), # Nose tip
(190, 202), # Chin
(196, 124), # Left eye corner
(236, 128), # Right eye corner
(186, 175), # Left mouth
(214, 177), # Right mouth
],
dtype="double",
)
figure_points_3D = np.array(
[
(0.0, 0.0, 0.0), # Nose tip
(0.0, -330.0, -65.0), # Chin
(-225.0, 170.0, -135.0), # Left eye left corner
(225.0, 170.0, -135.0), # Right eye right corne
(-150.0, -150.0, -125.0), # Left Mouth corner
(150.0, -150.0, -125.0), # Right mouth corner
]
)
distortion_coeffs = np.zeros((4, 1))
focal_length = size[1]
center = (size[1] / 2, size[0] / 2)
matrix_camera = np.array(
[[focal_length, 0, center[0]], [0, focal_length, center[1]], [0, 0, 1]],
dtype="double",
)
success, vector_rotation, vector_translation = cv2.solvePnP(
figure_points_3D, image_points_2D, matrix_camera, distortion_coeffs, flags=0
)
nose_end_point2D, jacobian = cv2.projectPoints(
np.array([(0.0, 0.0, 1000.0)]),
vector_rotation,
vector_translation,
matrix_camera,
distortion_coeffs,
)
for p in image_points_2D:
cv2.circle(img, (int(p[0]), int(p[1])), 3, (0, 0, 255), -1)
point1 = (int(image_points_2D[0][0]), int(image_points_2D[0][1]))
point2 = (int(nose_end_point2D[0][0][0]), int(nose_end_point2D[0][0][1]))
cv2.line(img, point1, point2, (255, 255, 255), 2)
cv2.imshow("Final", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
上面提到的代码中发生了很多事情。让我们一步一步来理解它。
首先,我们使用 imread()
函数读取所需的图像。面部特征的点在 2D 和 3D 中提到。
点和相机矩阵被提供给 solvepnp()
函数,该函数返回姿势 3D 坐标的旋转和平移向量。
在我们直观地绘制姿势线之后。首先,我们绘制面部特征。
我们使用 2D 点并使用 circle()
函数绘制每个点。
projectPoints()
用于确定 solvepnp()
函数返回的向量在图像平面上的投影。我们还需要在这个函数中传递相机参数来获取投影。
我们使用 line()
函数从面部鼻子绘制一条与投影点对齐的线,以可视化由 solvepnp()
方法确定的姿势。
结论
本教程教我们如何使用 solvepnp()
函数来解决计算机视觉中的 PnP 问题。我们需要了解使用此方法所需的参数。
主要参数是图像的人脸特征的 2D 和 3D 点以及相机矩阵。使用这些值,它返回确定姿势的 3D 点的向量。
我们使用 projectPoints()
函数获得这些点相对于相机的 2D 投影。最后,我们使用这些点绘制一条线来表示图像中确定的姿势。
相关文章
Python 中 NumPy 数组的滑动平均值
发布时间:2023/12/24 浏览次数:145 分类:Python
-
本教程演示了如何在 python 中计算 numpy 数组的滑动平均值。滑动平均值通常用于通过计算特定时间间隔的数据平均值来研究时间序列数据。
在 Python 中计算马氏距离
发布时间:2023/12/24 浏览次数:125 分类:Python
-
有两个主要方法可用于在 Python 中查找两个 NumPy 数组之间的马氏距离,scipy 库中的 cdist() 函数和 numpy 包中的 numpy.einsum() 函数。
在 Python 中实现 ReLU 函数
发布时间:2023/12/24 浏览次数:62 分类:Python
-
本教程讨论 Relu 函数以及如何在 Python 中实现它。Relu 函数是机器学习的基础,在使用深度学习时必不可少。
杀死一个 Python 进程
发布时间:2023/12/24 浏览次数:103 分类:Python
-
本文讨论了杀死 Python 进程的三种方法。在使用 Python 编程时,有时我们的程序会陷入无限循环。
在 Python 中获取文件扩展名
发布时间:2023/12/24 浏览次数:79 分类:Python
-
它演示了如何在 Python 中获取文件扩展名。本教程将介绍如何在 Python 中从文件名中获取文件扩展名。
在 Python 中读取文件的第一行
发布时间:2023/12/24 浏览次数:156 分类:Python
-
本教程演示了如何在 Python 中读取文本文件的第一行。在 Python 中,我们有内置的函数可以处理不同的文件操作。
在 Python 中读取二进制文件
发布时间:2023/12/24 浏览次数:175 分类:Python
-
本教程演示了如何在 Python 中读取二进制文件。程序或内部处理器对二进制文件进行解释。它包含字节作为内容。
用 Python 向文件写入字节
发布时间:2023/12/24 浏览次数:69 分类:Python
-
本教程演示了如何在 Python 中向二进制文件写入字节。本教程中,我们将介绍在 Python 中如何向二进制文件写入字节。
Python 从路径获取不带扩展名的文件名
发布时间:2023/12/24 浏览次数:55 分类:Python
-
本教程演示了如何在 Python 中从文件路径中获取不带扩展名的文件名。本教程将演示在 Python 中从文件路径中获取不带扩展名的文件名的各种方法。