Reconocimiento de gestos basado en opencv-mediapipe

El artículo anterior introdujo el reconocimiento de gestos basado en opencv. Si ejecuta mi código, encontrará que el efecto de encontrar el contorno de la mano en el código no es ideal. En ese momento, estaba buscando una solución en Internet y encontré la biblioteca mediapip, y luego usé las dos bibliotecas de opencv y mediapipe para reescribir el código para el reconocimiento de gestos. El efecto no es malo, escribe un artículo para registrarlo.

1. Introducción a mediapipe

Mediapipe es un proyecto de código abierto de Google, que puede proporcionar soluciones comunes de aprendizaje automático (aprendizaje automático) multiplataforma y de código abierto. Mediapipe es en realidad una biblioteca de herramientas de algoritmos de visión de aprendizaje automático integrados, que incluye varios modelos, como detección de rostros, puntos clave de rostros, reconocimiento de gestos, segmentación de avatares y reconocimiento de poses.

Dado que principalmente hago reconocimiento de gestos, explicaré brevemente el módulo de detección de manos de la biblioteca, para que todos puedan comprender mejor el código fuente del reconocimiento de gestos final. (Si desea conocer otros módulos, puede hacer clic aquí para obtener más información: introducción oficial de mediapipe

Primero, inicialice el módulo de detección de manos
mphand = mp.solutions.hands
hands = mphand.Hands()
Parámetro mpHand.Hands Parámetros detallados
static_image_mode=Falso Si se establece en Falso, reduce la latencia, ideal para procesar cuadros de video. Si se establece en True, es adecuado para procesar un lote de imágenes estáticas potencialmente irrelevantes. El valor predeterminado es falso.
max_num_hands=2 El tamaño de lote máximo a detectar. El valor predeterminado es 2
modelo_complejidad=1 Complejidad del modelo de puntos de referencia de la mano: 0 o 1. La precisión de los puntos de referencia y la latencia de inferencia generalmente aumentan con la complejidad del modelo. El valor predeterminado es 1
min_detection_confidence=0.5 El valor de confianza mínimo en el modelo de detección manual para que una detección se considere exitosa. El valor predeterminado es 0,5
min_tracking_confidence=0.5 El valor de confianza mínimo en el modelo de seguimiento de puntos de referencia, que indica que el punto de referencia de la mano se considera rastreado con éxito; de lo contrario, la detección de la mano se invoca automáticamente en la siguiente imagen de entrada. Establecerlo en un valor más alto puede mejorar la solidez de la solución a costa de una mayor latencia. Se ignora si static_image_mode es True, donde la detección manual simplemente se ejecuta en cada imagen. El valor predeterminado es 0,5

Si no comprende del todo el significado de los parámetros anteriores, no importa, solo prefijelos. Creo que siempre que sepa el significado de los dos parámetros max_num_hands y min_detection_confidence

Luego está el proceso de detección de gestos.
hand = hands.process(img)

El parámetro img es la imagen que se va a detectar. Dado que la imagen leída por opencv está en modo BGR, la img aquí debe convertirse al modo RGB.

Finalmente, lea los resultados de la prueba.
 finger = []
    for handlms in hand.multi_hand_landmarks:
        for lm in handlms.landmark:
        	img_height,img_width,_ =  img.shape
        	#这里检测返回的x,y的坐标是基于原图像大小的比例坐标,
        	#所以要与原图像相乘得到真实的坐标
            x, y = int(lm.x * img_width), int(lm.y * img_height)
            finger.append([x, y])

Si imprime la lista de dedos, verá 21 valores de coordenadas. Estas 21 coordenadas son la detección de midiapipe basada en las coordenadas de posición de 21 puntos clave de la mano humana en la imagen original. Los puntos clave de detección de manos correspondientes a estos 21 valores de coordenadas son los siguientes:

inserte la descripción de la imagen aquí

2. Ideas de reconocimiento de gestos

Todos ya han entendido el uso básico de mediapipe, ahora explique las ideas y las habilidades clave

tren de pensamiento

Primero use opencv para llamar a la cámara, lea la imagen de la cámara, invierta la imagen (la imagen leída por la cámara es opuesta a la realidad) y convierta la imagen al modo RGB. Luego use mediapipe para la detección manual y guárdelo en una lista. El ángulo formado por los dedos se usa luego para determinar si los dedos están doblados.

Puntos clave explicados

Todo el programa parece no tener dificultad, la clave principal es cómo detectar si el dedo está doblado.

Leí en el libro que la yema del dedo se resta de la raíz del dedo, y los resultados positivos y negativos de la observación se usan para juzgar la flexión del dedo. Por ejemplo, en la imagen de arriba, resto el valor de y de 6 puntos de coordenadas del valor de y de 8 puntos de coordenadas (si el valor de y no se entiende aquí, haga clic aquí), si el resultado es positivo , significa que el dedo está doblado, y si es negativo, significa Dedos estirados.
Pero aquí hay dos problemas :
primero , la flexión del pulgar es diferente a la flexión de los otros cuatro dedos (aquí puedes estirar la mano para observarlo, puedes entender), por ejemplo, uso 4 coordenadas en el imagen de arriba Reste el valor y de la coordenada 1 (aquí el valor y es el mismo que el anterior), pero el valor y de la coordenada 4 de todos no debe ser mayor que el valor y de la coordenada 1 cuando todos tienen el pulgar doblado. tiempo, es imposible juzgar si el pulgar está doblado.
Para este problema, una vez quise establecer un umbral para resolverlo, pero necesito depurar constantemente el tamaño de este umbral, y el tamaño del dedo de cada persona es diferente. Este umbral puede ser adecuado para usted, pero no para otros.
En segundo lugar , no sé si descubrió que los ejemplos anteriores se basan en la situación en la que las yemas de los dedos de las manos están hacia arriba, si las yemas de los dedos de las manos están hacia abajo, hacia la izquierda y hacia la derecha. ¿Qué hacer en estas situaciones? ¿Es necesario escribir más condiciones de juicio y analizarlas una por una? Esta es una gran cantidad de código, por lo que no lo recomiendo mucho.

Introducir ángulos para resolver problemas
Introducir funciones trigonométricas y usar los ángulos formados por los dedos para juzgar
Por ejemplo, aquí uso las coordenadas 5, 6 y 7 como vértices para formar un triángulo, y aquí uso las
coordenadas 5 y 6 como los lados. ,
el lado formado por las coordenadas 6 y 7 es b,
el lado formado por las coordenadas 5 y 7 es c,
y luego usa la función coseno para calcular el ángulo del vértice 6, la fórmula es:
a 2 + b 2 − c 2 / 2 aba^ 2+b^2-c^2/2aba2+b2C2/2 ab
Luego establezca un umbral de 155 para juzgar si el dedo está doblado.

3. Código completo

Aquí he comentado el código para ayudarte a leer el programa.

import cv2
import numpy
import mediapipe as mp
import math

#创建手部检测的对象
mphand = mp.solutions.hands
hands = mphand.Hands()
mpdraw = mp.solutions.drawing_utils

cap = cv2.VideoCapture(0)

while cap.isOpened():
	#对读取的图像进行反转,转换为RGB模式,读出图片大小
    ret,frame = cap.read()
    frame = cv2.flip(frame,1)
    img =cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
     h,w,_ = frame.shape
     
     #进行手部的检测
    hand = hands.process(img)
    
   #判断是否检测到了手部
    if hand.multi_hand_landmarks:
        count = 0	#统计手指的伸出个数
        for handlms in hand.multi_hand_landmarks:
            finger = []
            finger_point = []
            
            #这里我将每一根手指的四个坐标整合到一个列表中,大家可以打印finger,进行详细的查看
            for id,lm in enumerate(handlms.landmark):
                x,y = int(lm.x*w),int(lm.y*h)
                if id == 0:
                    pass
                elif id % 4 == 0:
                    finger_point.append([x,y])
                    finger.append(finger_point)
                    finger_point = []
                else:
                    finger_point.append([x,y])

			#遍历每一根手指列表,计算其构成的三角形的三边长,这里使用26101418所对应的角进行判断
            for id,point in enumerate(finger):
                a = math.hypot((point[0][0]-point[1][0]),(point[0][1]-point[1][1]))
                b = math.hypot((point[1][0]-point[2][0]),(point[1][1]-point[2][1]))
                c = math.hypot((point[0][0]-point[2][0]),(point[0][1]-point[2][1]))

              #在计算value值的时候,除数可能为零,以及当三点在一点直线上,都会抛出异常,所以要捕获异常
                try :   
                	value = (a**2+b**2-c**2)/(2*a*b)
                	#这里的value为弧度制,乘上57转换为角度制,当然你也可以选择直接使用弧度制
                    angle = math.acos(value)*57
                except ValueError:
                    angle = 180
                except ZeroDivisionError:
                    angle = 0
                print(angle)   
				
				#当角度大于155的时候记为手指伸出
                if angle >= 155:
                    count += 1
                else:
                    pass
                    
            #在手部绘制关键点位置
            mpdraw.draw_landmarks(frame,handlms,mphand.HAND_CONNECTIONS)
		
		#将手指检测的结果显示在图像上
        cv2.putText(frame,str(count),(int((1/9)*w),int((1/9)*h)),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),1)
     
     #展示图片   
    cv2.imshow('img',frame)
    
    #按下Esc退出循环
    c = cv2.waitKey(25)
    if c == 27:
        break
cap.release()
cv2.destroyAllWindows()

4. Terminando

Utilizar la librería mediapipe para detectar manos, lo que nos permite hacer muchas cosas interesantes mediante gestos, como controlar el ratón del ordenador mediante gestos, dibujar con gestos, etc. También estoy tratando de hacer esto, y compartiré con ustedes mis ideas y dificultades encontradas después de que termine.
La creación final no es fácil, espero que todos apoyen y les guste. Espero poder compartir y aprender con ustedes y progresar juntos.
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/m0_59151709/article/details/129120958
Recomendado
Clasificación