OpenCV の solvepnp()関数を使用して PnP の問題を解決する
OpenCV ライブラリは、ComputerVision タスクを支援するために開発されたオープンソースライブラリです。このライブラリは Python と互換性があり、さまざまな画像処理の問題を実装および解決するために使用できます。
このチュートリアルでは、Python の OpenCV ライブラリの solvepnp()
関数の使用方法を示します。この関数は、ポーズ推定の問題を解決するために使用されます。
PnP 問題を理解する
PnP の問題は、Computer Vision で非常に一般的であり、Perspectiven-Points 問題の略です。この号では、2D および 3D 座標が提供された後、カメラに対するオブジェクトのポーズを特定できません。
これは、オンライン試験中の顔追跡の例で理解できます。オブジェクトの姿勢は、方向の変化に応じて変化する可能性があります。
次の 2 種類のモーションにより、この変更が容易になります。
- 最初のタイプのモーションは並進モーションであり、3つの軸のいずれかに沿って発生する可能性があります。オブジェクトは特定の方向に均一な動きで移動し、それによってその座標が変化します。
- 2 番目のタイプのモーションは回転モーションで、オブジェクトは 3つの軸のいずれかを中心に回転できます。
opencv.solvepnp()
関数を使用して PnP 問題を解決する
OpenCV ライブラリの solvepnp()
関数は、カメラに対する特定のオブジェクトのポーズ推定に使用され、PnP の問題を解決します。回転ベクトルと並進ベクトルを返します。
これは、カメラマトリックスでオブジェクトの 2D および 3D 座標を使用します。提供される座標は、顔のさまざまな特徴のものです。
これらの特徴は、鼻、口の角、あご、そして両方の目です。
この関数を使用するために必要なすべてのパラメーターについて説明します。
objectPoints
パラメータは、前述のすべての機能の 3D ポイントを取得します。imagePoints
パラメーターは、オブジェクトの特徴の 2D ポイントを指定するために使用されます。cameraMatrix
は、カメラの固有の値を指定するために使用されます。このマトリックスは、カメラの中心点と焦点の長さを使用して作成されます。- カメラによって発生する歪みに対処するために、
distCoeffs
パラメーターを使用します。カメラにごくわずかな歪みがある場合、このベクトルは NULL になる可能性があります。 useExtrinsicGuess
パラメーターを使用して、出力結果を初期計算に使用できます。これは、true または false の場合があります。それ以外は、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 で言及されています。
ポイントとカメラマトリックスは、ポーズの 3D 座標の回転ベクトルと並進ベクトルを返す solvepnp()
関数に提供されます。
ポーズの線を視覚的にプロットした後。まず、顔の特徴をプロットします。
2D ポイントを使用し、circle()
関数を使用して各ポイントをプロットします。
projectPoints()
は、solvepnp()
関数によって返されるベクトルの画像平面への投影を決定するために使用されます。また、投影を取得するには、この関数でカメラパラメータを渡す必要があります。
line()
関数を使用して、投影されたポイントに沿って顔の鼻から線をプロットし、solvepnp()
メソッドによって決定されたポーズを視覚化します。
まとめ
このチュートリアルでは、コンピュータビジョンの PnP 問題を解くために solvepnp()
関数を使用する方法を学びました。このメソッドを使用するために必要なパラメータについて知っておく必要があります。
主なパラメータは、画像の顔の特徴とカメラマトリックスの 2D および 3D ポイントです。これらの値を使用して、ポーズの 3D ポイントを決定するベクトルを返します。
projectPoints()
関数を使用して、カメラに関して 2D でこれらのポイントの投影を取得します。最後に、これらのポイントを使用して、画像内で決定されたポーズを表す線をプロットします。
Manav is a IT Professional who has a lot of experience as a core developer in many live projects. He is an avid learner who enjoys learning new things and sharing his findings whenever possible.
LinkedIn