OpenCV项目2-动作识别之虚拟计算器

该文章介绍了一个使用OpenCV进行动作识别的项目,通过创建button类和handdetector检测器,实现了用摄像头捕捉手势来操作虚拟计算器的功能。用户可以通过手势点击屏幕上的按钮进行数学运算,当食指和中指的距离小于一定阈值时,视为点击操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.创建button类

class Button:
    def __init__(self, pos, width, height, value):
        self.pos = pos
        self.width = width
        self.height = height
        self.value = value
    def draw(self, img):
        # 绘制一个计算器的小格子 先画一个实心的灰色矩形
        cv2.rectangle(img, (self.pos[0], self.pos[1]), (self.pos[0] + self.width, self.pos[1] + self.height), (225, 225, 225), -1)
        # 再画矩形的边框
        cv2.rectangle(img, (self.pos[0], self.pos[1]), (self.pos[0] + self.width, self.pos[1] + self.height), (0, 0, 0), 3)
        cv2.putText(img, self.value, (self.pos[0] + 30, self.pos[1] + 70), cv2.FONT_HERSHEY_PLAIN, 2, (50, 50, 50), 2)
    def check_click(self, x, y): # 检测点击点是否小格子内
        if self.pos[0] < x < self.pos[0] +self.width and self.pos[1] < y < self.pos[1] + self.height:
            cv2.rectangle(img, (self.pos[0] + 3, self.pos[1] + 3), 
                         (self.pos[0] + self.width -3, self.pos[1]+self.height -3),
                        (255, 255, 255), -1) # 点击中的格子做放大处理
            cv2.putText(img, self.value, (self.pos[0]+25, self.pos[1] + 80), cv2.FONT_HERSHEY_PLAIN, 5, (0, 0, 0), 5)
            return True
        else:
            return False

2.摄像头打开

import numpy as np
import cv2
from cvzone.HandTrackingModule import HandDetector
import time # pip install cvzone mediapipe -i https://pypi.douban.com/simple
cap = cv2.VideoCapture(0)

3.窗口大小及符号

cap.set(3, 1280) # set:设置窗口大小
cap.set(4, 720)
button_values = [['7', '8', '9', '*'], # 按键符号
                 ['4', '5', '6', '-'],
                 ['1', '2', '3', '+'],
                 ['0', '/', '.', '=']]
button_list = []
for x in range(4):
    for y in range(4):
        x_pos = x * 100 + 800
        y_pos = y * 100 + 150
        button = Button((x_pos, y_pos), 100, 100, button_values[y][x])
        button_list.append(button)

4.hand detector检测器

detector = HandDetector(maxHands=1, detectionCon=0.8) # maxHands:手数量 detectionCon:像手概率
my_equation = ''
delay_counter = 0  # 延迟计算
while True:
    flag, img = cap.read()
    img = cv2.flip(img, 1) # 摄像头显示的画面和真实画面相反 flip:翻转
    # 检测手, 注意一定要在还没有绘制button之前去检测手
    hands, img = detector.findHands(img, flipType=False)
    if flag:
        for button in button_list:
            button.draw(img)
        cv2.rectangle(img, (800, 70), (800 + 400, 70 + 100), (225, 225, 225), -1) # 创建显示结果的窗口
        cv2.rectangle(img, (800, 70), (800 + 400, 70 + 100), (50, 50, 50), 3)
#         print(hands)
        if hands:
            lmlist = hands[0]['lmList'] # 取出食指和中值的点, 计算两者的距离
            length, _, img = detector.findDistance(lmlist[8], lmlist[12], img)
#             print(length, _, img)
            x, y = lmlist[8] # 取出手指的坐标
            # 根据食指和中指之间的距离, 如果小于50认为是进行点击操作
            if length < 50 and delay_counter == 0:
                for i, button in enumerate(button_list): # enumerate:枚举
                    if button.check_click(x, y):
                        # 说明是一个正确点击. 应该要把点中的数字显示在窗口上
                        my_value = button_values[int(i % 4)][int(i / 4)]
                        if my_value == '=': # 如果是'='说明要计算
                            try:
                                my_equation = str(eval(my_equation)) # eval:将字符串相代码一样执行
                            except Exception:
                                my_equation = '' # 非法的数学公式 重新输入
                        else:
                            my_equation += my_value # 字符串的拼接
#                             time.sleep(0.1)  # sleep并不能完全解决重复点击的问题
                        delay_counter = 1
        if delay_counter != 0: # 重置delay_counter 避免重复点击
            delay_counter += 1
            if delay_counter > 10:
                delay_counter = 0
        cv2.putText(img, my_equation, (810, 130), cv2.FONT_HERSHEY_PLAIN, 3, (0, 0, 0), 3)
        cv2.imshow('img', img)
        key = cv2.waitKey(1)
        if key == ord('q'):
            break
        elif key == ord('c'):
            my_equation = ''  # 清空输出框
    else:
        print('摄像头打开失败')
        break

5.释放资源

cap.release()

6.摧毁窗口

cv2.destroyAllWindows()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿值

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值