proyecto de práctica openCV: arrastrar y soltar bloques virtuales

1. Efecto del proyecto:

El dormitorio de la escuela se movió hoy, estaba cansado y de repente descubrí que el manejo de la pantalla también era muy duro, así que eso es todo, jeje ~~~

En segundo lugar, el proceso central:

1. openCV lee el flujo de video y dibuja un rectángulo en cada cuadro de la imagen.

2. Utilice mediapipe para obtener las coordenadas de los puntos clave del dedo.

3. De acuerdo con la posición de las coordenadas del dedo y la posición de las coordenadas del rectángulo, determine si la punta del dedo está en el rectángulo y, de ser así, el rectángulo se mueve con el dedo.

3. Proceso de código:

Preparación del entorno:

  • pitón: 3.8.8
  • cv abierto: 4.2.0.32
  • mediapipe: 0.8.10.1

Nota:

1. Si la versión de opencv es demasiado alta o demasiado baja, puede haber algunos problemas, como que la cámara no se pueda encender, flashback, etc. La versión de python afecta la versión seleccionable de opencv.

2. Después de pip install mediapipe, es posible que openCV no se use normalmente. Desinstálelo y descárguelo nuevamente, solo acostúmbrese.

1. Lea el video de la cámara y dibuje un rectángulo:

import cv2
import time
import numpy as np


# 调用摄像头 0 默认摄像头 
cap = cv2.VideoCapture(0)

# 初始方块数据
x = 100
y = 100
w = 100
h = 100

# 读取一帧帧照片
while True:
    # 返回frame图片
    rec,frame = cap.read()
    
    # 镜像
    frame = cv2.flip(frame,1)
    
    # 画矩形 
    cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 255), -1)

    # 显示画面
    cv2.imshow('frame',frame)
    
    # 退出条件
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    
cap.release()
cv2.destroyAllWindows() 

Esta es una operación muy básica de un solo paso. En este momento, ejecutamos este código, la cámara está encendida y nos sorprenderá ver su hermoso rostro, y hay un rectángulo morado de 100 * 100 en la esquina superior izquierda. .

2. Importar mediapipe para procesar las coordenadas de los dedos

pip install mediapipe

Puede haber algunos problemas en este momento, como que openCV de repente no se puede usar, no importa, desinstálelo y descárguelo nuevamente.

detalles de mediapipe: Manos - mediapipe (google.github.io)

En resumen, nos devolverá las coordenadas de 21 puntos clave del dedo, es decir, su relación de posición en la pantalla de video (0~1), multiplicamos el ancho y el alto de la pantalla correspondiente para obtener las coordenadas correspondientes al dedo.

Esta vez usaré las puntas de mis dedos índice y medio, que son del tamaño 8 y 12.

2.1 Configure algunos datos básicos:

import cv2
import time
import numpy as np
import mediapipe as mp


mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands

hands =  mp_hands.Hands(
    static_image_mode=True,
    max_num_hands=2,
    min_detection_confidence=0.5)

2.2 Al procesar cada cuadro de imagen, agregue:

    frame.flags.writeable = False
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 返回结果
    results = hands.process(frame)

    frame.flags.writeable = True
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

Cuando leemos cada fotograma de la imagen en la transmisión de video, lo convertimos de BGR a RGB para que lo lea el objeto de manos generado por mediapipe, devolverá la información de los puntos clave del dedo en esta imagen, solo necesitamos continuar pintando , dibujado en cada marco de la imagen.

    # 如果结果不为空
    if results.multi_hand_landmarks:

        # 遍历双手(根据读取顺序,一只只手遍历、画画)
        for hand_landmarks in results.multi_hand_landmarks:
            mp_drawing.draw_landmarks(
                frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing_styles.get_default_hand_landmarks_style(),
                mp_drawing_styles.get_default_hand_connections_style())

2.3 Código completo para este paso

import cv2
import time
import numpy as np
import mediapipe as mp


mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands

hands =  mp_hands.Hands(
    static_image_mode=True,
    max_num_hands=2,
    min_detection_confidence=0.5)


# 调用摄像头 0 默认摄像头 
cap = cv2.VideoCapture(0)

# 方块初始数组
x = 100
y = 100
w = 100
h = 100


# 读取一帧帧照片
while True:
    # 返回frame图片
    rec,frame = cap.read()
    
    # 镜像
    frame = cv2.flip(frame,1)
    
    
    
    frame.flags.writeable = False
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 返回结果
    results = hands.process(frame)

    frame.flags.writeable = True
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
    
    
    # 如果结果不为空
    if results.multi_hand_landmarks:

        # 遍历双手(根据读取顺序,一只只手遍历、画画)
        # results.multi_hand_landmarks n双手
        # hand_landmarks 每只手上21个点信息
        for hand_landmarks in results.multi_hand_landmarks:
            mp_drawing.draw_landmarks(
                frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing_styles.get_default_hand_landmarks_style(),
                mp_drawing_styles.get_default_hand_connections_style())
    
    
    # 画矩形 
    cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 255), -1)

    # 显示画面
    cv2.imshow('frame',frame)
    
    # 退出条件
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    
cap.release()
cv2.destroyAllWindows() 

En este punto, es interesante correr y ver:

3. Cálculo de posición

Nuestro experimento requiere arrastrar el cuadrado, y debe haber momentos en que no se arrastre, por lo tanto, también podríamos obtener la posición del dedo índice (8) y el dedo medio (12) de acuerdo con el paso anterior . Si los dos están cerca, estaremos entre él y el cuadrado.Al superponerse, las coordenadas del bloque se cambian según la posición del dedo.

Código completo:

import cv2
import time
import math
import numpy as np
import mediapipe as mp

# mediapipe配置
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
hands =  mp_hands.Hands(
    static_image_mode=True,
    max_num_hands=2,
    min_detection_confidence=0.5)


# 调用摄像头 0 默认摄像头 
cap = cv2.VideoCapture(0)

# cv2.namedWindow("frame", 0)
# cv2.resizeWindow("frame", 960, 640)


# 获取画面宽度、高度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))


# 方块初始数组
x = 100
y = 100
w = 100
h = 100

L1 = 0
L2 = 0

on_square = False
square_color = (0, 255, 0)

# 读取一帧帧照片
while True:
    # 返回frame图片
    rec,frame = cap.read()
    
    # 镜像
    frame = cv2.flip(frame,1)
    
    
    
    frame.flags.writeable = False
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 返回结果
    results = hands.process(frame)

    frame.flags.writeable = True
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
    
    
    # 如果结果不为空
    if results.multi_hand_landmarks:


        # 遍历双手(根据读取顺序,一只只手遍历、画画)
        # results.multi_hand_landmarks n双手
        # hand_landmarks 每只手上21个点信息
        for hand_landmarks in results.multi_hand_landmarks:
            mp_drawing.draw_landmarks(
                frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing_styles.get_default_hand_landmarks_style(),
                mp_drawing_styles.get_default_hand_connections_style())
            
            # 记录手指每个点的x y 坐标
            x_list = []
            y_list = []
            for landmark in hand_landmarks.landmark:
                x_list.append(landmark.x)
                y_list.append(landmark.y)
                
            
            # 获取食指指尖
            index_finger_x, index_finger_y = int(x_list[8] * width),int(y_list[8] * height)

            # 获取中指
            middle_finger_x,middle_finger_y = int(x_list[12] * width), int(y_list[12] * height)


            # 计算两指尖距离
            finger_distance = math.hypot((middle_finger_x - index_finger_x), (middle_finger_y - index_finger_y))

            # 如果双指合并(两之间距离近)
            if finger_distance < 60:

                # X坐标范围 Y坐标范围
                if (index_finger_x > x and index_finger_x < (x + w)) and (
                        index_finger_y > y and index_finger_y < (y + h)):

                    if on_square == False:
                        L1 = index_finger_x - x
                        L2 = index_finger_y - y
                        square_color = (255, 0, 255)
                        on_square = True

            else:
                # 双指不合并/分开
                on_square = False
                square_color = (0, 255, 0)

            # 更新坐标
            if on_square:
                x = index_finger_x - L1
                y = index_finger_y - L2
            
            

    # 图像融合 使方块不遮挡视频图片
    overlay = frame.copy()
    cv2.rectangle(frame, (x, y), (x + w, y + h), square_color, -1)
    frame = cv2.addWeighted(overlay, 0.5, frame, 1 - 0.5, 0)
    

    # 显示画面
    cv2.imshow('frame',frame)
    
    # 退出条件
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    
cap.release()
cv2.destroyAllWindows() 

Supongo que te gusta

Origin blog.csdn.net/suic009/article/details/126534975
Recomendado
Clasificación