感谢恩培大佬对项目进行了完整的实现,并将代码进行开源,供大家交流学习。
一、项目简介
本项目最终达到的效果为手势控制虚拟拖拽方块。如下所示
项目用python实现,调用opencv,mediapipe,ctypes等库,由以下四个步骤组成:
1、使用OpenCV读取摄像头视频流;
2、识别手掌关键点像素坐标;
3、根据食指和中指指尖的坐标,利用勾股定理计算距离,当距离较小且都落在矩形内,则触发拖拽(矩形变色);
4、矩形跟着手指动;
5、两指放开,则矩形停止移动
二、代码详解
# 导入OpenCV,用于图像处理,图像显示
import cv2
# 导入mediapipe,手势识别
import mediapipe as mp
# 导入其他依赖包
import time
import math
# 方块管理类
class SquareManager:
def __init__(self, rect_width):
# 可自定义方块长度
self.rect_width = rect_width
# 方块数目,用列表储存方块的x、y值
self.square_count = 0
self.rect_left_x_list = []
self.rect_left_y_list = []
self.alpha_list = []
# 中指与矩形左上角点的距离
self.L1 = 0
self.L2 = 0
# 激活移动模式,用于储存状态,表示方块是否可以移动
self.drag_active = False
# 激活的方块ID,表示哪一块方块目前处于可以移动的状态
self.active_index = -1
# 创建一个方块,将x、y值加入list里,增加方块计数器的数目
def create(self, rect_left_x, rect_left_y, alpha=0.4):
self.rect_left_x_list.append(rect_left_x)
self.rect_left_y_list.append(rect_left_y)
self.alpha_list.append(alpha)
self.square_count += 1
# 展示方块的位置
def display(self, class_obj):
for i in range(0, self.square_count):#用for循环遍历每一个方块
x = self.rect_left_x_list[i]#获取方块的x、y坐标。为左上角点的坐标
y = self.rect_left_y_list[i]
alpha = self.alpha_list[i]#此方块的透明度,用于叠加在大图像上
overlay = class_obj.image.copy()
if (i == self.active_index):#判断当前方块是否处于可移动状态
# 若方块可移动,则将此方块涂色为粉色画在图像上。rectangle函数输入的两组坐标依次为左上角和右下角坐标
cv2.rectangle(overlay, (x, y), (x + self.rect_width, y + self.rect_width), (255, 0, 255), -1)
else:
# 若方块属性为不可移动,则将此方块涂色为蓝色画在图像上。
cv2.rectangle(overlay, (x, y), (x + self.rect_width, y + self.rect_width), (255, 0, 0), -1)
# 将原图和方块相叠加,一起显示。从效果上讲,可以允许方块重叠。
class_obj.image = cv2.addWeighted(overlay, alpha, class_obj.image, 1 - alpha, 0)
# 判断落在哪个方块上,返回方块的ID
def checkOverlay(self, check_x, check_y):
for i in