计算机视觉入门(实战篇:手势数字识别)

手势数字识别

本代码基于 Advance Computer Vision with Python 进行修改,更加适合中国宝宝体质

我的相关代码及数据集已经上传GitHub仓库,欢迎使用 Advance-Computer-Vision-with-Python

FingerCounter.py

# 此脚本只能检测右手的手势
import cv2
import time
import os
import HandTrackingModule as htm

# 设置摄像头的宽度和高度,即分辨率
wCam, hCam = 640, 480

# 打开摄像头
cap = cv2.VideoCapture(0)
cap.set(3, wCam)  # 设置摄像头宽度
cap.set(4, hCam)  # 设置摄像头高度

# 指定手指图像文件夹路径
folderPath = "E:\\Advance Computer Vision with Python\\main\\Project 2 Finger Counter\\FingerImages"
myList = os.listdir(folderPath)  # 获取文件夹中的所有文件名列表
print(myList)

overlayList = []  # 用于存储手指图像的列表
for imPath in myList:
    # 读取每张手指图像
    image = cv2.imread(f"{folderPath}/{imPath}")
    overlayList.append(image)  # 将图像添加到列表中

print(len(overlayList))  # 输出图像数量

pTime = 0  # 初始化上一帧时间

# 创建手部检测器对象,设置检测置信度为0.75
detector = htm.handDetector(detectionCon=0.75)

# 手指尖的ID列表
tipIds = [4, 8, 12, 16, 20]

while True:
    success, img = cap.read()  # 从摄像头读取帧
    img = cv2.flip(img, 1)  # 水平翻转图像
    img = detector.findHands(img)  # 检测手并绘制手部关键点
    lmList = detector.findPosition(img, draw=False)  # 获取手部关键点位置列表

    if len(lmList) != 0:
        fingers = []

        # 检测拇指(根据拇指尖和拇指第二关节的x坐标判断)
        if lmList[tipIds[0]][1] < lmList[tipIds[0] - 1][1]:
            # 如果按照源代码来的话if lmList[tipIds[0]][1] > lmList[tipIds[0] - 1][1]判断的是未翻转前的右手大拇指的伸直
            # 所以如果我选择了img = cv2.flip(img, 1),此时if lmList[tipIds[0]][1] > lmList[tipIds[0] - 1][1]判断的是水平翻转后前的左手大拇指的伸直,要保持检测的是右手的话,遂变大于为小于
            # 故此脚本只能检测右手的手势
            fingers.append(1)  # 1表示该手指是伸出的
        else:
            fingers.append(0)  # 0表示该手指是弯曲的

        # 检测其他四根手指(根据手指尖和指根的y坐标判断)
        for id in range(1, 5):
            if lmList[tipIds[id]][2] < lmList[tipIds[id] - 2][2]:
                fingers.append(1)
            else:
                fingers.append(0)

        totalFingers = fingers.count(1)  # 计算伸出的手指数量
        print(totalFingers)

        # 选择对应手指数量的图像进行覆盖显示
        h, w, c = overlayList[totalFingers - 1].shape
        # totalFingers - 1 是因为列表索引是从 0 开始的,而 totalFingers 表示手指的数量(从 1 开始)。所以要减 1 来正确访问列表中对应的图像
        # 因此把0放在了列表的最后,因为此时没有手指伸直,totalFingers为0,减1得到-1,就是列表的最后一个了
        img[0:h, 0:w] = overlayList[totalFingers - 1] # 将对应数量手指的图像放置在摄像头图像的左上角

        # 绘制矩形并显示手指数量
        cv2.rectangle(img, (20, 225), (170, 425), (0, 255, 0), cv2.FILLED)
        cv2.putText(
            img,
            str(totalFingers),
            (45, 375),
            cv2.FONT_HERSHEY_PLAIN,
            10,
            (255, 0, 0),
            25,
        )

    cTime = time.time()  # 获取当前帧时间
    fps = 1 / (cTime - pTime)  # 计算帧率
    pTime = cTime  # 更新上一帧时间

    # 在图像上显示帧率
    cv2.putText(
        img, f"FPS: {int(fps)}", (400, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3
    )

    # 显示处理后的图像
    cv2.imshow("Image", img)
    cv2.waitKey(1)  # 等待按键,1毫秒

HandTrackingModule.py

"""
Hand Tracing Module
By: Murtaza Hassan
Youtube: http://www.youtube.com/c/MurtazasWorkshopRoboticsandAI
Website: https://www.computervision.zone

Modified by: Diraw
Date: 20240812
Description:
1. Modified the initialization of the `Hands` object to use named parameters for better clarity and compatibility with the latest version of the mediapipe library. This change ensures that the parameters are correctly mapped to the expected arguments in the `Hands` class.
2. Added a line to flip the image horizontally using `cv2.flip(img, 1)` to ensure the hand movements appear mirrored, which is more intuitive for user interaction
"""

import cv2
import mediapipe as mp
import time


# 手部检测器类
class handDetector:
    def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
        # 初始化参数
        self.mode = mode  # 是否为静态模式
        self.maxHands = maxHands  # 最大检测手数
        self.detectionCon = detectionCon  # 检测置信度
        self.trackCon = trackCon  # 跟踪置信度

        # 初始化MediaPipe手部模型
        self.mpHands = mp.solutions.hands
        # self.hands = self.mpHands.Hands(
        #     self.mode, self.maxHands, self.detectionCon, self.trackCon
        # )
        self.hands = self.mpHands.Hands(
            static_image_mode=self.mode,
            max_num_hands=self.maxHands,
            min_detection_confidence=self.detectionCon,
            min_tracking_confidence=self.trackCon,
        )

        # 初始化绘图工具
        self.mpDraw = mp.solutions.drawing_utils

    def findHands(self, img, draw=True):
        # 将图像转换为RGB
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # 处理图像,检测手部
        self.results = self.hands.process(imgRGB)

        # 如果检测到手部
        if self.results.multi_hand_landmarks:
            for handLms in self.results.multi_hand_landmarks:
                # 绘制手部关键点和连接
                if draw:
                    self.mpDraw.draw_landmarks(
                        img, handLms, self.mpHands.HAND_CONNECTIONS
                    )
        return img

    def findPosition(self, img, handNo=0, draw=True):
        lmList = []  # 存储手部关键点位置
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNo]
            for id, lm in enumerate(myHand.landmark):
                # 获取图像尺寸
                h, w, c = img.shape
                # 计算关键点的像素位置
                cx, cy = int(lm.x * w), int(lm.y * h)
                lmList.append([id, cx, cy])
                # 绘制关键点
                if draw:
                    cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
        return lmList


# 主函数
def main():
    pTime = 0  # 上一帧时间
    cTime = 0  # 当前帧时间
    cap = cv2.VideoCapture(0)  # 打开摄像头
    detector = handDetector()  # 创建手部检测器对象

    while True:
        success, img = cap.read()  # 读取摄像头帧
        img = cv2.flip(img, 1)  # 水平翻转图像
        img = detector.findHands(img)  # 检测手并绘制
        lmList = detector.findPosition(img)  # 获取手部关键点位置
        if len(lmList) != 0:
            print(lmList[4])  # 打印拇指尖的坐标

        cTime = time.time()  # 获取当前时间
        fps = 1 / (cTime - pTime)  # 计算帧率
        pTime = cTime  # 更新上一帧时间

        # 在图像上显示帧率
        cv2.putText(
            img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3
        )

        # 显示图像
        cv2.imshow("Image", img)
        cv2.waitKey(1)

if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值