在使用opencv去拖动AL虚拟的方块的时候我们分为以下的步骤
1.opencv获取视频流
2.在画面上画几个方块
3.通过mediapie获取手指关节关键点坐标
4.判断手指是否在方块上,指尖的坐标都在方块坐标里面
5.如果在方块上,方块跟着手指移动
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
AI虚拟拖动方块
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
示例:mediapipe是用于捕捉在视频中手指关键点的包。MediaPipe感知管道称为Graph。让我们以第一个solution为例,汉兹。我们输入一串图像作为输入,然后在图像上呈现手的landmarks
并且人的手指关键点为21个。
示例:numpy是用于一维数组,二维数组,甚至多维数组对象,在计算机眼里的照片都是由数组
组成的一些数字
代码如下(示例):
import cv2 #导入opencv的包 import numpy as np #导入numpy import math #后面要用到勾股定理去计算手指之间的距离,所以导入数学的包 #mediapipe的相关参数,在官网上面复制 import mediapipe as mp #导入mediapipe的包
代码如下(示例):
cap =cv2.VideoCapture(0) #定义一个变量来存放导入的视频流
while True:
#读取每一帧,ret代表的是返回值
ret,frame =cap.read()
#对图像进行处理
#镜像处理,对y轴进行翻转
frame = cv2.flip(frame,1)
#退出条件
if cv2.waitKey(10) & 0xFF == 27: #这边的27代表的是esc键退出
break
#显示图像
cv2.imshow('Virtual drag',frame) #对于第一个参数就是随便取得变量名
cap.release()
cv2.destroyAllWindows()
#mediapipe的相关参数,在官网上面复制
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
#获取手的21个关节,官网开源
hands = mp_hands.Hands(
model_complexity=0,
min_detection_confidence=0.5,
min_tracking_confidence=0.5)
#为了更方便看到我们手指之间的距离,我们这边把方块设置为半透明的
overlay = frame.copy() #给他一个遮罩
cv2.rectangle(frame,(square_x,square_y),(square_x
+square_width,square_y+square_width),square_color,-1)
#此段代码代表的是在窗口画一个方块,并且对于最后的一个参数就是把设置为-1,代表的是,设置实心的方块
frame = cv2.addWeighted(overlay,0.5,frame,0.5,0)#做一个半透明
#方块的相关参数
square_x = 100
square_y = 100
square_width = 100
square_color = (255,0,0)
因为由于opencv的颜色处理和mediapipe的颜色处理是不同的。opencv的颜色处理是RGB
而对于mediapipe的颜色处理是BGR。所以我们需要对颜色的进行的调换
#mediapipe处理颜色,在官网找,fream代表的是帧率的意思,就是变量名
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: #判断是否有手
#不断的解析遍历每一双手,并且最大为两双手
#对于下面对手解析的代码都是开源的,直接到mediapipe的官方网站进行查找即可
for hand_landmarks in results.multi_hand_landmarks:
#绘制21个关键点,先对一双手进行解析,然后在对另一双进行解析
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()
)
print(landmark.x)#看看landmark的是什么样子,我只需要食指
print(hand_landmarks)
#打印看看21个关键点长什么样子
我们只需要把其中的食指和中指的解析出来就可以了
#print(landmark.x)#看看landmark的是什么样子,我只需要食指
#这边只使用了landmarks.x代表的是值打印x坐标
但是如果你填写一个landmarks.m的话就回报错,所以只有x,y,z
因为我们是要使用21个数据,所以用python里的列表把这些数据存储起来
用来保存x,y的坐标
#保存21个x,y的坐标
x_list = []
y_list = []
for landmark in hand_landmarks.landmark:#会循环21次把手的关节弄好
#添加x坐标
x_list.append(landmark.x)#append表示添加x坐标
#添加y坐标
y_list.append(landmark.y)
#获取食指指尖,xy坐标
index_finger_x = int(x_list[8] * width)
index_finger_y = int(y_list[8] * height)
#获取中指指尖,用于退出方块
middle_finger_x = int(x_list[12] * width)
middle_finger_y = int(y_list[12] * height)
#获取画面宽度,高度,因为显示小数的原因是由于,官网原本除以了宽度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height=int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#由于小数所以要取整
#如何判断手指是获取的坐标是否正确,我们来画一个圆就知道,通过看所画的圆是否在食指手指上面
#cv2.circle(frame,(index_finger_x,index_finger_y),20,(255,
#0,255),-1)
#print(index_finger_x,index_finger_y)
if finger_len < 30:
#判断指尖是否在方块上面
if (index_finger_x > square_x) and (index_finger_x <
(square_x+square_width)) and (index_finger_y >
square_y) and (index_finger_y < (square_y
+square_width)):
if on_square ==False:
print('在方块上')
L1=abs(index_finger_x - square_x)#abs代表绝对值
L2=abs(index_finger_y - square_y)
on_square =True
square_color=(255,0,255)
else:
# print('不在方块上')
if on_square: #如果手指在方块上面
square_x = index_finger_x -L1#根据算法
square_y = index_finger_y -L2
"""
author : The sky
datw:2022-04-29
项目1步骤
1.opencv获取视频流
2.在画面上画几个方块
3.通过mediapie获取手指关节关键点坐标
4.判断手指是否在方块上,指尖的坐标都在方块坐标里面
5.如果在方块上,方块跟着手指移动
"""
import cv2
import numpy as np
import math
#mediapipe的相关参数,在官网上面复制
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
#获取手的21个关节,官网开源
hands = mp_hands.Hands(
model_complexity=0,
min_detection_confidence=0.5,
min_tracking_confidence=0.5)
#获取摄像头的视频流
cap =cv2.VideoCapture(0)
#获取画面宽度,高度,因为显示小数的原因是由于,官网原本除以了宽度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height=int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#方块的相关参数
square_x = 100
square_y = 100
square_width = 100
square_color = (255,0,0)
L1=0
L2=0
on_square = False #用于判断是否在方块上,一开始默认不在
while True:
#读取每一帧
ret,frame =cap.read()
#对图像进行处理
#镜像处理,对y轴进行翻转
frame = cv2.flip(frame,1)
#mediapipe处理颜色,在官网找
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: #判断是否有手
#不断的解析遍历每一双手,并且最大为两双手
for hand_landmarks in results.multi_hand_landmarks:
#绘制21个关键点,先对一双手进行解析,然后在对另一双进行解析
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()
)
#保存21个x,y的坐标
x_list = []
y_list = []
for landmark in hand_landmarks.landmark:#会循环21次把手的关节弄好
#添加x坐标
x_list.append(landmark.x)#append表示添加x坐标
#添加y坐标
y_list.append(landmark.y)
#获取食指指尖,xy坐标
index_finger_x = int(x_list[8] * width)
index_finger_y = int(y_list[8] * height)
#获取中指指尖,用于退出方块
middle_finger_x = int(x_list[12] * width)
middle_finger_y = int(y_list[12] * height)
#计算食指指尖和中指指尖的距离,用勾股定理
finger_len = math.hypot((index_finger_x-middle_finger_x),
(index_finger_y-middle_finger_y))
print(finger_len)
#画一个圆来验证坐标是否正确
#cv2.circle(frame,(index_finger_x,index_finger_y),20,(255,
#0,255),-1)
#print(index_finger_x,index_finger_y)
# print(landmark.x)#看看landmark的是什么样子,我只需要食指
# print(hand_landmarks)
#打印看看21个关键点长什么样子
#为x,y,z三个手指的参数位置
#如果小于30激活方块,否则不激活
if finger_len < 30:
#判断指尖是否在方块上面
if (index_finger_x > square_x) and (index_finger_x <
(square_x+square_width)) and (index_finger_y >
square_y) and (index_finger_y < (square_y
+square_width)):
if on_square ==False:
print('在方块上')
L1=abs(index_finger_x - square_x)#abs代表绝对值
L2=abs(index_finger_y - square_y)
on_square =True
square_color=(255,0,255)
else:
# print('不在方块上')
pass
else:
on_square =False
square_color=(255,0,0)
if on_square: #如果手指在方块上面
square_x = index_finger_x -L1#根据算法
square_y = index_finger_y -L2
#画一个方块,只需要左上角的点,其他的由长宽高来控制
#cv2.rectangle(frame,(square_x,square_y),(square_x
#+square_width,square_y+square_width),(255,0,0),-1)
#要使用半透明的方块,可以看手指
overlay = frame.copy() #给他一个遮罩
cv2.rectangle(frame,(square_x,square_y),(square_x
+square_width,square_y+square_width),square_color,-1)
frame = cv2.addWeighted(overlay,0.5,frame,0.5,0)#做一个半透明
#显示图像
cv2.imshow('Virtual drag',frame)
#退出条件
if cv2.waitKey(10) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()