diciembre 25, 2022

VARIOS – Visión: detección de poses con MediaPipe

Written by

En esta entrada voy a indicar dos programas que he probado para detección por visión por ordenador de manos y personas.

Tras busca por Internet bastante y probar diferentes alternativas, la opción que me ha funcionado bien, aceptablemente, es la de MediaPipe. Es una librería para visión artificial creada por Google para tareas varias de aprendizaje y ofrece herramientas para detección de caras, manos y personas previamente entrenadas, y ofrece una ejecución con poca demanda de recursos sin necesidad de tarjetas GPU específicas.

Detección de manos

Para la detección de poses de manos he usado el código que ofrece Murtaza Hassan en su web de forma gratuita, al que agradezco su trabajo. A continuación muestro el vídeo donde explica su funcionamiento.

El código contiene instrucciones para control del sonido, que no son necesarias para sólo detectar la estructura de la mano. He usado el código casi original, sólo cambiando la siguiente línea:

detector = htm.handDetector(detectionCon=1)

porque parece que la versión de librerías han cambiado y no permite números decimales. El código final lo pongo a continuación.

import cv2
import time
import numpy as np
import HandTrackingModule as htm
import math
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume

################################
wCam, hCam = 640, 480
################################

cap = cv2.VideoCapture(0)
cap.set(3, wCam)
cap.set(4, hCam)
pTime = 0

detector = htm.handDetector(detectionCon=1)

devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(
    IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
# volume.GetMute()
# volume.GetMasterVolumeLevel()
volRange = volume.GetVolumeRange()
minVol = volRange[0]
maxVol = volRange[1]
vol = 0
volBar = 400
volPer = 0
while True:
    success, img = cap.read()
    img = detector.findHands(img)
    lmList = detector.findPosition(img, draw=False)
    if len(lmList) != 0:
        # print(lmList[4], lmList[8])

        x1, y1 = lmList[4][1], lmList[4][2]
        x2, y2 = lmList[8][1], lmList[8][2]
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2

        cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
        cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
        cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
        cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)

        length = math.hypot(x2 - x1, y2 - y1)
        # print(length)

        # Hand range 50 - 300
        # Volume Range -65 - 0

        vol = np.interp(length, [50, 300], [minVol, maxVol])
        volBar = np.interp(length, [50, 300], [400, 150])
        volPer = np.interp(length, [50, 300], [0, 100])
        print(int(length), vol)
        volume.SetMasterVolumeLevel(vol, None)

        if length < 50:
            cv2.circle(img, (cx, cy), 15, (0, 255, 0), cv2.FILLED)

    cv2.rectangle(img, (50, 150), (85, 400), (255, 0, 0), 3)
    cv2.rectangle(img, (50, int(volBar)), (85, 400), (255, 0, 0), cv2.FILLED)
    cv2.putText(img, f'{int(volPer)} %', (40, 450), cv2.FONT_HERSHEY_COMPLEX,
                1, (255, 0, 0), 3)


    cTime = time.time()
    fps = 1 / (cTime - pTime)
    pTime = cTime
    cv2.putText(img, f'FPS: {int(fps)}', (40, 50), cv2.FONT_HERSHEY_COMPLEX,
                1, (255, 0, 0), 3)

    cv2.imshow("Img", img)
    if (cv2.waitKey(1) == ord('s')):
        break

cap.release()
cv2.destroyAllWindows()    

Para que funcione el programa hay que instalar varias librerías y añadir el fichero HandTrackingModule.py, que se encuentra en la web de ComputerVisionZone. La prueba se realiza ahora fácilmente.

Detección de manos

Se obtienen alrededor de 6 imágenes por segundo, lo que no está mal teniendo en cuenta que estoy usando un ordenador de gama media.

Detección de personas

Para detectar las personas he acudido a otra web, LearnOpenCV, con multitud de ejemplos y proyectos sobre visión por ordenador, y concretamente una entrada que compara detección de poses entre YOLO y MediaPipe. En el siguiente en lace está el código en Github:

https://github.com/spmallick/learnopencv/tree/master/YOLOv7-Pose-vs-MediaPipe-in-Human-Pose-Estimation

Dentro del sitio en la carpeta Experiments está el código de la prueba con MediaPipe, que es la que me interesa. Como el código original hace la prueba con vídeos en lugar de la cámara, lo he modificado un poco y lo muestro abajo:

import cv2
import time
import mediapipe as mp

mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)

mp_pose = mp.solutions.pose
pose = mp_pose.Pose(static_image_mode=False,
                    model_complexity=2,
                    enable_segmentation=False,
                    min_detection_confidence=0.5)

cap = cv2.VideoCapture(0)
fps = int(cap.get(cv2.CAP_PROP_FPS))
ret, frame = cap.read()
h,w,c = frame.shape

while True:
	ret, frame = cap.read()
	if not ret:
		print('Can\'t read frames. Exiting..')
		break

	img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
	t1 = time.time()
	results = pose.process(img)
	#print(dir(results.index.__sizeof__))
	t2 = time.time()
	fps_org = 1/(t2 - t1)
	ann_img = frame.copy()

	mp_drawing.draw_landmarks(ann_img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS,
		landmark_drawing_spec=mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2, circle_radius=1),
		connection_drawing_spec=mp_drawing.DrawingSpec(color=(255, 200, 0), 
		thickness=3, 
		circle_radius=3))

	cv2.putText(ann_img, 'FPS : {:.2f}'.format(fps_org), (200, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2, 8)
	cv2.putText(ann_img, 'MediaPipe', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2, 8)
	cv2.imshow('Annotated Image', ann_img)
	if (cv2.waitKey(1) == ord('s')):
		break

cap.release()
cv2.destroyAllWindows()

Detalle importante: la primera vez que se ejecuta tiene que descargar los modelos de TensorFlow, e intenta descargarlos en la carpeta de Python,

Preparar modelos de TensorFlow

Entonces, si se ejecuta Python de forma normal con el usuario por defecto, aunque sea administrador, va a dar error. Por tanto hay que ejecutar Python expresamente como administrador y entonces se producirá la descarga sin problemas.

En un ordenador portátil de media potencia consigue en torno a las 6 imágenes por segundo. No es mucho pero suficiente para una detección fluida. Para conseguir un vídeo en tiempo real sería necesario un ordenador potente o con tarjeta gráfica Nvidia de cierto nivel.

Detección de una persona con MediaPipe

El problema con este sistema es que sólo sirve para detectar una persona. Si en la imagen hay más de una, sólo detecta una de ellas, que puede ir cambiando de persona en persona al moverse por la imagen.

Category : VARIOS

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Proudly powered by WordPress and Sweet Tech Theme