Estimaci贸n de Postura 馃毝 | Python – MediaPipe – OpenCV

Por Administrador

Hasta aqu铆 hemos hablado ya de MediaPipe hands (para la detecci贸n de manos y dedos), MediaPipe face detection (para la detecci贸n de rostros) y MediaPipe face mesh (malla facial). Cada una de estas soluciones vaya que nos ha sorprendido y adem谩s hemos aprendido como acceder a las detecciones obtenidas.En este tutorial vamos a tratar otra de las soluciones para Python, MediaPipe Pose.

CONTENIDO

  • MediaPipe Pose
    • Modelos empleados en MediaPipe Pose
      • Person/pose聽DetectionModel聽(BlazePose聽Detector)
      • Pose聽LandmarkModel聽(BlazePose聽GHUM 3D)
    • Opciones de configuraci贸n
    • Datos de salida que obtenemos al usar MediaPipe Pose
    • 隆Vamos con la programaci贸n!
      • Estimaci贸n de postura con MediaPipe en im谩genes
      • Estimaci贸n de postura con MediaPipe en videos
  • Referencias

MediaPipe Pose

Figura 1: Ejemplo del uso de MediaPipe Pose para la estimaci贸n de postura

Esta es una soluci贸n de machine learning de alta fidelidad, que permite obtener 33 puntos de referencia 3D de todo el cuerpo, teniendo como entrada, im谩genes o fotogramas en rgb. Adem谩s esta soluci贸n alcanza resultados en tiempo real en la mayor铆a de tel茅fonos m贸viles modernos, computadores o laptops, e incluso en la web.

Modelos empleados en MediaPipe Pose

Para la obtenci贸n de los 33 puntos de referencia, esta soluci贸n emplea un proceso similar al visto en MediaPpe Hands y en MediaPipe FaceMesh, trabajando con dos modelos. El primer modelo se encargar谩 de ubicar a la persona dentro de la imagen, mientras que el segundo ubicar谩 los 33 puntos claves o puntos de referencia.

Person/pose聽Detection聽Model聽(BlazePose聽Detector)

Figura 2: Ilustraci贸n del proceso de detecci贸n de una persona con MediaPipe.

Se emplea en un principio un modelo para la detecci贸n de la persona o postura, blazePose. Que por cierto est谩 basado en el modelo BlazeFace que se emplea en mediaPipe face detection. Entonces, este modelo ubica a la persona dentro de la imagen, es decir la regi贸n de inter茅s y recorta dicha regi贸n.

Pose聽Landmark聽Model聽(BlazePose聽GHUM 3D)

Figura 3: Ilustraci贸n de la obtenci贸n de 33 puntos claves con MediaPipe.

Una vez que se tiene la imagen recortada donde est谩 presente la persona, se procede a aplicar el pose landmark model, que nos permitir谩 obtener la ubicaci贸n de 33 puntos distribuidos por todo el cuerpo. Cada uno de estos tendr谩 un nombre asociado que m谩s adelante veremos como acceder.

Figura 4: 33 puntos de referencia distribuidos por el cuerpo detectado. (Fuente)

Si tenemos como entrada a un video, al igual que en anteriores tutoriales, el detector de la persona se aplicar谩 en los primeros fotogramas y luego se realizar谩 la obtenci贸n de los puntos clave, para que en fotogramas posteriores dichos puntos sean rastreados, de tal forma que solo se invoque al detector de personas cuando se hayan perdido dichos puntos.

En s铆, este es un resumen del proceso de detecci贸n que podemos encontrar en la documentaci贸n de MediaPipe Pose, por lo que si quieres una explicaci贸n m谩s extendida, te recomiendo que visites su web y su repositorio.聽

Opciones聽de configuraci贸n

STATIC_IMAGE_MODE (Por defecto false)

Si a este le asignamos False, entonces trata a las im谩genes de entrada como un video, de tal forma que intentar谩 detectar a la persona m谩s prominente y los puntos de referencia en los primeros fotogramas. Mientras que para localizar la nueva ubicaci贸n de los puntos, se proceder谩 a realizar el seguimiento o tracking de los puntos de referencia.

Si se especifica como True, el detector se aplica en cada imagen, por lo que es mejor usarlo en im谩genes que no est茅n relacionadas.

MODEL_COMPLEXITY (Por defecto 1)

Puede tomar valores de 0, 1 o 2. Que corresponden a la complejidad del modelo pose landmark. Y lo que nos dice la documentaci贸n es que la precisi贸n y latencia generalmente aumenta con la complejidad del modelo.

SMOOTH_LANDMARKS (Por defecto true)

Si se establece como True, se filtra los puntos de referencia de la postura a trav茅s de diferentes im谩genes de entrada para reducir las fluctuaciones. Este es ignorado cuando static_image_mode es igual a True.

MIN_DETECTION_CONFIDENCE (Por defecto 0.5)

Valor m铆nimo de confianza del modelo de detecci贸n de personas para que la detecci贸n se considere correcta.

MIN_TRACKING_CONFIDENCE (Por defecto 0.5)

Valor m铆nimo de confianza del modelo de seguimiento de puntos de referencia para que los pose聽landmarks聽se consideren rastreados con 茅xito, de lo contrario la detecci贸n de personas se invocar谩 autom谩ticamente en la siguiente imagen de entrada.

Este es ignorado si聽static_image_mode聽es igual a True.

Datos de salida que obtenemos al usar MediaPipe Pose

POSE_LANDMARKS

Una lista de puntos de referencia de la postura. Cada uno de ellos contar谩 con sus coordenadas x, y y z. Adem谩s tendremos visibility, este es un valor comprendido entre 0 y 1 que indica la probabilidad de que el punto de referencia sea visible (presente y no ocluido) en la imagen.

隆Vamos con la programaci贸n!

Para una explicaci贸n m谩s detallada de los programas que veremos a continuaci贸n, por favor dir铆gete al videotutorial de mi canal.

Estimaci贸n de postura con MediaPipe en im谩genes

import cv2
import mediapipe as mp

mp_drawing = mp.solutions.drawing_utils
mp_pose = mp.solutions.pose

with mp_pose.Pose(
    static_image_mode=True) as pose:

    image = cv2.imread("image_0001.jpg")
    height, width, _ = image.shape
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    results = pose.process(image_rgb)
    print("Pose landmarks:", results.pose_landmarks)

    if results.pose_landmarks is not None:
        print(int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER].x * width))
        x1 = int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER].x * width)
        y1 = int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER].y * height)

        x2 = int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_ELBOW].x * width)
        y2 = int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_ELBOW].y * height)

        x3 = int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_WRIST].x * width)
        y3 = int(results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_WRIST].y * height)

        x4 = int(results.pose_landmarks.landmark[11].x * width)
        y4 = int(results.pose_landmarks.landmark[11].y * height)

        x5 = int(results.pose_landmarks.landmark[13].x * width)
        y5 = int(results.pose_landmarks.landmark[13].y * height)

        x6 = int(results.pose_landmarks.landmark[15].x * width)
        y6 = int(results.pose_landmarks.landmark[15].y * height)

        cv2.line(image, (x1, y1), (x2, y2), (255, 255, 255), 3)
        cv2.line(image, (x2, y2), (x3, y3), (255, 255, 255), 3)
        cv2.circle(image, (x1, y1), 6, (128, 0, 255), -1)
        cv2.circle(image, (x2, y2), 6, (128, 0, 255), -1)
        cv2.circle(image, (x3, y3), 6, (128, 0, 255), -1)

        cv2.line(image, (x4, y4), (x5, y5), (255, 255, 255), 3)
        cv2.line(image, (x5, y5), (x6, y6), (255, 255, 255), 3)
        cv2.circle(image, (x4, y4), 6, (255, 191, 0), -1)
        cv2.circle(image, (x5, y5), 6, (255, 191, 0), -1)
        cv2.circle(image, (x6, y6), 6, (255, 191, 0), -1)

        '''
        mp_drawing.draw_landmarks(image, results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS,
            mp_drawing.DrawingSpec(color=(128, 0, 250), thickness=2, circle_radius=3),
            mp_drawing.DrawingSpec(color=(255, 255, 255), thickness=2))
        '''
    cv2.imshow("Image", image)
    cv2.waitKey(0)
cv2.destroyAllWindows()

Estimaci贸n de postura con MediaPipe en video

import cv2
import mediapipe as mp

mp_drawing = mp.solutions.drawing_utils
mp_pose = mp.solutions.pose

#cap = cv2.VideoCapture("video_0002.mp4")
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

with mp_pose.Pose(
    static_image_mode=False) as pose:

    while True:
        ret, frame = cap.read()
        if ret == False:
            break
        frame = cv2.flip(frame, 1)
        height, width, _ = frame.shape
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        results = pose.process(frame_rgb)

        if results.pose_landmarks is not None:
            mp_drawing.draw_landmarks(
                frame, results.pose_landmarks, mp_pose.POSE_CONNECTIONS,
                mp_drawing.DrawingSpec(color=(128, 0, 250), thickness=2, circle_radius=3),
                mp_drawing.DrawingSpec(color=(255, 255, 255), thickness=2))

        cv2.imshow("Frame", frame)
        if cv2.waitKey(1) & 0xFF == 27:
            break

cap.release()
cv2.destroyAllWindows()

Referencias