系列文章目录
在使用opencv去拖动AL虚拟的方块的时候我们分为以下的步骤
1.opencv获取视频流
2.在画面上画几个方块
3.通过mediapie获取手指关节关键点坐标
4.判断手指是否在方块上,指尖的坐标都在方块坐标里面
5.如果在方块上,方块跟着手指移动
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
AI虚拟拖动方块
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、mediapipe是什么?
示例:mediapipe是用于捕捉在视频中手指关键点的包。MediaPipe感知管道称为Graph。让我们以第一个solution为例,汉兹。我们输入一串图像作为输入,然后在图像上呈现手的landmarks
并且人的手指关键点为21个。
二、numpy是什么
示例:numpy是用于一维数组,二维数组,甚至多维数组对象,在计算机眼里的照片都是由数组
组成的一些数字
1.引入库
代码如下(示例):
import cv2 #导入opencv的包 import numpy as np #导入numpy import math #后面要用到勾股定理去计算手指之间的距离,所以导入数学的包 #mediapipe的相关参数,在官网上面复制 import mediapipe as mp #导入mediapipe的包
2.使用opencv都要先导入视频流
代码如下(示例):
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()
3.导入mediapipe来获取视频流里的手指关节
#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)
4.对于使用后opencv来画一个方块,用于我们的拖动
#为了更方便看到我们手指之间的距离,我们这边把方块设置为半透明的
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)#做一个半透明
5.当然还需要对方块的位置进行设置
#方块的相关参数
square_x = 100
square_y = 100
square_width = 100
square_color = (255,0,0)
6.对mediapipe颜色的处理
因为由于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)
7.使用mediapipe来对手的21个关键进行遍历解析,在加入以下的代码就可以在视频上面看到视屏中我们手指的21个关键点。(但是我们的重点是在于对食指和中指的识别,使用这两很手指之间的距离来拖动)
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()
)
8.整个项目的核心代码即使上一段代码里的hand_landmarks代表的是
21个关键点的信息,我们打印出来看看hand_landmarks是什么东西
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)
9.在我们使用食指的时候要确保食指的坐标是准确的
#获取画面宽度,高度,因为显示小数的原因是由于,官网原本除以了宽度
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)
10.判断手指是否在方块上面。在我们确定方块的位置的时候,我们只需要知道方块的对角的那两个点的坐标左上角坐标(x,y),右下角坐标(x+w,y+w)即可确认方块的位置,于是我们把手指看成一个坐标点,如果手指的横坐标点小于右下角的横坐标并且大于左上角的横坐标,手指的纵坐标小于左上角的纵坐标,大于右下角的纵坐标,即可表示出手指在方块上面
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('不在方块上')
11.接下来的一步就是当我们的手指在方块上的时候如何使方块的移动,实际上就是当手指在方块的时候,只要不断的改变方块的坐标,并且食指之间的坐标也是在不断的改变即可实现这个功能。算法的图我也给大家整理出
12.最后一步就是当我们的手指在方块上面的时候要激活方块就是用到勾股定理(大家在熟悉不过的345)
if on_square: #如果手指在方块上面
square_x = index_finger_x -L1#根据算法
square_y = index_finger_y -L2
13.最后的全部代码
"""
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()