用Python编程识别手势数字
谷歌出了一个开源的、跨平台的、可定制化的机器学习解决方案工具包,给在线流媒体(当然也可以用于普通的视频、图像等)提供了机器学习解决方案。感兴趣的同学可以打开这个网址了解详情:mediapipe.dev/
它提供了手势、人体姿势、人脸、物品等识别和追踪功能,并提供了C++、Python、JavaScript等编程语言的工具包以及iOS、Android平台的解决方案,今天我们就来看一下如何使用MediaPipe提供的手势识别来写一个Python代码识别手势中的数字:0-5 。
准备工作
电脑需要安装Python3,建议安装Python3.8.x的版本。除此之外,还需要安装Opencv-Python、MediaPipe以及numpy几个工具包,可以使用pip进行安装:
pip install mediapipe numpy opencv-python
复制代码
我的电脑是Python3.8.3,各工具包版本是:
mediapipe==0.8.3.1
numpy==1.20.2
opencv-python==4.5.1.48
复制代码
准备6张图片,分别是6张手的图片。
编写程序
- 编写一个handutil.py模块,这个handutil模块有一个HandDetector类,提供了检测手势、获取手势数据的方法。代码如下,详细解释看代码注释:
import cv2
import mediapipe as mp
class HandDetector():
'''
手势识别类
'''
def __init__(self, mode=False, max_hands=2, detection_con=0.5, track_con=0.5):
'''
初始化
:param mode: 是否静态图片,默认为False
:param max_hands: 最多几只手,默认为2只
:param detection_con: 最小检测信度值,默认为0.5
:param track_con: 最小跟踪信度值,默认为0.5
'''
self.mode = mode
self.max_hands = max_hands
self.detection_con = detection_con
self.track_con = track_con
self.hands = mp.solutions.hands.Hands(self.mode, self.max_hands, self.detection_con, self.track_con)
def find_hands(self, img, draw=True):
'''
检测手势
:param img: 视频帧图片
:param draw: 是否画出手势中的节点和连接图
:return: 处理过的视频帧图片
'''
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 处理图片,检测是否有手势,将数据存进self.results中
self.results = self.hands.process(imgRGB)
if draw:
if self.results.multi_hand_landmarks:
for handlms in self.results.multi_hand_landmarks:
mp.solutions.drawing_utils.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS)
return img
def find_positions(self, img, hand_no=0):
'''
获取手势数据
:param img: 视频帧图片
:param hand_no: 手编号(默认第1只手)
:return: 手势数据列表,每个数据成员由id, x, y组成,代码这个手势位置编号以及在屏幕中的位置
'''
self.lmslist = []
if self.results.multi_hand_landmarks:
hand = self.results.multi_hand_landmarks[hand_no]
for id, lm in enumerate(hand.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
self.lmslist.append([id, cx, cy])
return self.lmslist
复制代码
- 编写另一个fingercount.py代码,在这个代码中,调用handutil.py的HandDetector类提供的方法,获取手势数据,每个手势数据由3个数字组成:id, x, y,分别代表手势中某个点以及这个点的x\y坐标位置。下图是手势识别中每个id对应手的部位说明。
从上图可知:4, 8, 12, 16, 20分别代表大拇指、食指、中指、无名指和小指的指尖。完整代码如下:
import cv2
from handutil import HandDetector
# 打开摄像头
cap = cv2.VideoCapture(1)
# 创建一个手势识别对象
detector = HandDetector()
# 6张手的图片,分别代表0~5
finger_img_list = [
'fingers/0.png',
'fingers/1.png',
'fingers/2.png',
'fingers/3.png',
'fingers/4.png',
'fingers/5.png',
]
finger_list = []
for fi in finger_img_list:
i = cv2.imread(fi)
finger_list.append(i)
# 指尖列表,分别代表大拇指、食指、中指、无名指和小指的指尖
tip_ids = [4, 8, 12, 16, 20]
while True:
success, img = cap.read()
if success:
# 检测手势
img = detector.find_hands(img, draw=True)
# 获取手势数据
lmslist = detector.find_positions(img)
if len(lmslist) > 0:
fingers = []
for tid in tip_ids:
# 找到每个指尖的位置
x, y = lmslist[tid][1], lmslist[tid][2]
cv2.circle(img, (x, y), 10, (0, 255, 0), cv2.FILLED)
# 如果是大拇指,如果大拇指指尖x位置大于大拇指第二关节的位置,则认为大拇指打开,否则认为大拇指关闭
if tid == 4:
if lmslist[tid][1] > lmslist[tid - 1][1]:
fingers.append(1)
else:
fingers.append(0)
# 如果是其他手指,如果这些手指的指尖的y位置大于第二关节的位置,则认为这个手指打开,否则认为这个手指关闭
else:
if lmslist[tid][2] < lmslist[tid - 2][2]:
fingers.append(1)
else:
fingers.append(0)
# fingers是这样一个列表,5个数据,0代表一个手指关闭,1代表一个手指打开
# 判断有几个手指打开
cnt = fingers.count(1)
# 找到对应的手势图片并显示
finger_img = finger_list[cnt]
w, h, c = finger_img.shape
img[0:w, 0:h] = finger_img
cv2.rectangle(img, (200, 0), (300, 100), (0, 255, 0), cv2.FILLED)
cv2.putText(img, str(cnt), (200, 100), cv2.FONT_HERSHEY_DUPLEX, 5, (0, 0, 255))
cv2.imshow('Image', img)
k = cv2.waitKey(1)
if k == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
复制代码
运行代码,我们可以看到能够识别手势中的数字,并显示对应的图片和数字了。
欢迎关注”编程玩家俱乐部“公众号,学习更多好玩又有趣的编程。
作者:编程玩家俱乐部
链接:https://juejin.cn/post/6957303775857999909
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦