Use la función solvepnp() de OpenCV para resolver el problema PnP

Manav Narula 30 enero 2023
  1. Entender el problema PnP
  2. Utilice la función opencv.solvepnp() para resolver el problema PnP
  3. Conclusión
Use la función solvepnp() de OpenCV para resolver el problema PnP

La biblioteca OpenCV es una biblioteca de código abierto desarrollada para ayudar con las tareas de Computer Vision. Esta biblioteca es compatible con Python y se puede utilizar para implementar y resolver diferentes problemas de procesamiento de imágenes.

Este tutorial demostrará el uso de la función solvepnp() de la biblioteca OpenCV en Python. Esta función se utiliza para resolver el problema de estimación de pose.

Entender el problema PnP

El problema PnP es muy común en Computer Vision y representa el problema Perspective n-Points. En este problema, no podemos determinar la pose de un objeto con respecto a la cámara después de recibir las coordenadas 2D y 3D.

Esto se puede entender con el ejemplo del seguimiento facial durante un examen en línea. La pose de un objeto con respecto puede cambiar con el cambio de dirección.

Los siguientes dos tipos de mociones facilitan este cambio:

  1. El primer tipo de movimiento es el movimiento de traslación, que puede ocurrir a lo largo de cualquiera de los tres ejes. El objeto se mueve con un movimiento uniforme en cualquier dirección particular, cambiando así sus coordenadas.
  2. El segundo tipo de movimiento es el movimiento de rotación, en el que el objeto puede girar alrededor de cualquiera de los tres ejes.

Utilice la función opencv.solvepnp() para resolver el problema PnP

La función solvepnp() de la biblioteca OpenCV se utiliza para estimar la pose de un objeto dado con respecto a la cámara, resolviendo así el problema PnP. Devuelve vectores de rotación y traslación.

Utiliza las coordenadas 2D y 3D del objeto con la matriz de la cámara. Las coordenadas proporcionadas son de los diferentes rasgos del rostro.

Estas características son la nariz, las comisuras de la boca, el mentón y ambos ojos.

Analicemos todos los parámetros necesarios para utilizar esta función.

  1. El parámetro objectPoints toma los puntos 3D de todas las características mencionadas anteriormente.
  2. El parámetro imagePoints se utiliza para especificar los puntos 2D de las características del objeto.
  3. La cameraMatrix se utiliza para especificar el valor intrínseco de la cámara. Esta matriz se crea utilizando el punto central y la distancia focal de la cámara.
  4. Para abordar la distorsión provocada por la cámara, usamos el parámetro distCoeffs. Este vector puede ser NULO si hay una distorsión insignificante en la cámara.
  5. Podemos usar el resultado de salida para los cálculos iniciales usando el parámetro useExtrinsicGuess, que puede ser verdadero o falso. Aparte de eso, solo existe el parámetro flags.

Los vectores de rotación y traslación devueltos por esta función se pueden usar para trazar la línea de la pose del objeto.

Por ejemplo, determinaremos la pose de la siguiente imagen.

imagen de muestra para determinar la pose

El código para determinar la pose de esta imagen se muestra a continuación.

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()

Producción:

pose determinada usando solvepnp

Están sucediendo muchas cosas en el código mencionado anteriormente. Entendámoslo paso a paso.

Primero, leemos la imagen requerida usando la función imread(). Los puntos de los rasgos faciales se mencionan en 2D y 3D.

Los puntos y la matriz de la cámara se proporcionan a la función solvepnp(), que devuelve los vectores de rotación y traslación para las coordenadas 3D de la pose.

Después trazamos visualmente la línea de la pose. Primero, trazamos las características faciales.

Usamos los puntos 2D y trazamos cada punto usando la función circle().

projectPoints() se usa para determinar la proyección de los vectores devueltos por la función solvepnp() en el plano de la imagen. También necesitamos pasar el parámetro de la cámara en esta función para obtener la proyección.

Trazamos una línea desde la nariz de la cara en línea con los puntos proyectados usando la función line() para visualizar la pose determinada por el método solvepnp().

Conclusión

Este tutorial nos enseñó a usar la función solvepnp() para resolver el problema PnP en Computer Vision. Necesitamos conocer los parámetros necesarios para utilizar este método.

Los parámetros principales son los puntos 2D y 3D de los rasgos faciales de la imagen y la matriz de la cámara. Utilizando estos valores, devuelve los vectores que determinan los puntos 3D de la pose.

Obtenemos una proyección de estos puntos en 2D con respecto a la cámara usando la función projectPoints(). Finalmente, trazamos una línea para representar la pose determinada en la imagen utilizando estos puntos.

Manav Narula avatar Manav Narula avatar

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

Artículo relacionado - Python OpenCV