社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python玩人工智能:识别手势数字

编程玩家俱乐部 • 3 年前 • 587 次点击  
阅读 53

Python玩人工智能:识别手势数字

用Python编程识别手势数字

谷歌出了一个开源的、跨平台的、可定制化的机器学习解决方案工具包,给在线流媒体(当然也可以用于普通的视频、图像等)提供了机器学习解决方案。感兴趣的同学可以打开这个网址了解详情:mediapipe.dev/

image-20210422112313073

它提供了手势、人体姿势、人脸、物品等识别和追踪功能,并提供了C++、Python、JavaScript等编程语言的工具包以及iOS、Android平台的解决方案,今天我们就来看一下如何使用MediaPipe提供的手势识别来写一个Python代码识别手势中的数字:0-5 。

hand_crops.png

准备工作

电脑需要安装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张手的图片。

image-20210424155201904.png

编写程序

  1. 编写一个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
复制代码
  1. 编写另一个fingercount.py代码,在这个代码中,调用handutil.py的HandDetector类提供的方法,获取手势数据,每个手势数据由3个数字组成:id, x, y,分别代表手势中某个点以及这个点的x\y坐标位置。下图是手势识别中每个id对应手的部位说明。

hand_landmarks.png

从上图可知: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()

复制代码

运行代码,我们可以看到能够识别手势中的数字,并显示对应的图片和数字了。

image-20210424155406430.png

image-20210424155433600.png

image-20210424155459651.png

image-20210424155517619.png

image-20210424155550759.png

image-20210424155607893.png

欢迎关注”编程玩家俱乐部“公众号,学习更多好玩又有趣的编程。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/113752
 
587 次点击