Один из способов распознать жесты рук — это пометить руки ориентирами в каждом суставе.

Используя предварительно обученную модель Google MediaPipe Hand Landmarks, мы можем использовать эту функциональность в наших собственных приложениях. Для каждого изображения модель создает 20 ориентиров, соответствующих разным точкам на руке.

Для начала откройте новый блокнот или редактор кода!

Установить пакеты и модель вывода

!pip install -q mediapipe==0.10.0
!wget -q <https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task>

Первая строка устанавливает mediapipe в нашу среду, а другая устанавливает предварительно обученную модель Google под названием «hand_landmarker.task».

Установить зависимости

import os
import numpy as np
import cv2
import time

import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
from mediapipe import solutions
from mediapipe.framework.formats import landmark_pb2

Функция отображения

Этот код точно такой же, как в примере кода Google.

Функция получает изображение и набор точек, идентифицированных на изображении. Затем он перебирает каждую точку и рисует как точки, так и соединительные линии между ними. Наконец, он пишет текст «левый» и/или «правый», чтобы указать, является ли ориентир левой или правой рукой.

MARGIN = 10  # pixels
FONT_SIZE = 1
FONT_THICKNESS = 1
HANDEDNESS_TEXT_COLOR = (88, 205, 54) # vibrant green

def draw_landmarks_on_image(rgb_image, detection_result):
    hand_landmarks_list = detection_result.hand_landmarks
    handedness_list = detection_result.handedness
    annotated_image = np.copy(rgb_image)
    # Loop through the detected hands to visualize.
    for idx in range(len(hand_landmarks_list)):
        hand_landmarks = hand_landmarks_list[idx]
        handedness = handedness_list[idx]
        # Draw the hand landmarks.
        hand_landmarks_proto = landmark_pb2.NormalizedLandmarkList()
        hand_landmarks_proto.landmark.extend([
          landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in hand_landmarks
        ])
        solutions.drawing_utils.draw_landmarks(
          annotated_image,
          hand_landmarks_proto,
          solutions.hands.HAND_CONNECTIONS,
          solutions.drawing_styles.get_default_hand_landmarks_style(),
          solutions.drawing_styles.get_default_hand_connections_style())
        # Get the top left corner of the detected hand's bounding box.
        height, width, _ = annotated_image.shape
        x_coordinates = [landmark.x for landmark in hand_landmarks]
        y_coordinates = [landmark.y for landmark in hand_landmarks]
        text_x = int(min(x_coordinates) * width)
        text_y = int(min(y_coordinates) * height) - MARGIN
        # Draw handedness (left or right hand) on the image.
        cv2.putText(annotated_image, f"{handedness[0].category_name}",
                    (text_x, text_y), cv2.FONT_HERSHEY_DUPLEX,
                    FONT_SIZE, HANDEDNESS_TEXT_COLOR, FONT_THICKNESS, cv2.LINE_AA)
    return annotated_image

Обнаружение ориентира руки

Этот код адаптирован из примера кода Google.

Во-первых, мы указываем, какую модель использовать (наша загруженная и предварительно обученная модель). Затем мы указываем, чтобы использовать базовые параметры и что модель должна найти максимум две руки. Наконец, мы создаем детектор, чтобы делать выводы.

Я извлек часть предсказания в свою собственную функцию.

Одним из дополнений является первая строка в функции get_annotation_from, которая преобразует кадр OpenCV в объект изображения MediaPipe.

# Setup options
base_options = python.BaseOptions(model_asset_path='hand_landmarker.task')
options = vision.HandLandmarkerOptions(base_options=base_options,
                                       num_hands=2)
detector = vision.HandLandmarker.create_from_options(options)

# Get inference
def get_annotation_from(frame):
    image = mp.Image(image_format=mp.ImageFormat.SRGB, data=frame)
    detection_result = detector.detect(image)
    annotated_image = draw_landmarks_on_image(image.numpy_view(), detection_result)
    
    return detection_result, annotated_image

Захват видео

Используя OpenCV, мы можем захватывать кадры, анализировать их, а затем отображать окончательное аннотированное изображение.

Возможно, вам придется поэкспериментировать со значением внутри функции VideoCapture, чтобы найти камеру. Мы запускаем цикл while True для непрерывного получения кадров, пока не решим нажать клавишу «q» и выйти.

# define a video capture object
cap = cv2.VideoCapture(0)
  
while True:
    # capture image
    ret, frame = cap.read()
    
    if ret:
        detection_result, annotation = get_annotation_from(cv2.flip(frame, 1))
    
        cv2.imshow('', annotation)  
    else:
        print("! No frame")
        
    time.sleep(0.05)
     
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
        
# After the loop release the cap object
cap.release()

# Destroy all the windows
cv2.destroyAllWindows()

Вот и все!

Потрясающая работа! Теперь вы сможете запустить программу и получить вывод о наземных ориентирах в реальном времени! 😄