欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > OpenCV--项目:虚拟计数器

OpenCV--项目:虚拟计数器

2024/12/22 0:02:33 来源:https://blog.csdn.net/GamBleout/article/details/144448204  浏览:    关键词:OpenCV--项目:虚拟计数器

OpenCV--项目:虚拟计数器

  • 代码和笔记

代码和笔记

import cv2
import numpy as np
import time
from cvzone.HandTrackingModule import HandDetector"""
项目:虚拟计数器
cvzone:cv任务开源库
mediapipe:姿态估计开源库(在cvzone里面)
"""# 打开摄像头,显示每一帧图片 0表示只有一个摄像头
# 如果是读取视频文件,则0改为视频的地址就行
cap = cv2.VideoCapture(0)# 设置窗口大小 ID+value
# 属性ID 3 和 4 来设置视频的宽度和高度
cap.set(3, 1280)
cap.set(4, 720)# 定义计数器的每一个按键
# pos坐标,width, height宽度和高度,value按键值
class Button:def __init__(self, pos, width, height, value):self.pos = posself.width = widthself.height = heightself.value = value# 在视频上画出计数器的每一个按键def draw(self, _img):# 绘制一个计数器的一个小格子# 先绘制一个实心的灰色矩形# 第一个是起始点坐标,第二个是起始点对角的那个坐标# 然后是颜色和线宽, -1表示填充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 Trueelse:return False# 因为计数器有多个按键,用循环画出按键
button_values = [['7', '8', '9', '*'],['4', '5', '6', '-'],['1', '2', '3', '+'],['0', '/', '.', '=']]button_list = []
# 开始画,先画第一列,然后是第二列.....
# 注意OpenCV中纵轴的正方向是往下,先遍历列后遍历行
for x in range(4):for y in range(4):x_pos = x * 100 + 800y_pos = y * 100 + 150button = Button((x_pos, y_pos), 100, 100, button_values[y][x])button_list.append(button)# 创建手势识别器
# maxHands:最大能够识别的手数。detectionCon:检测到是手的概率
detector = HandDetector(maxHands=1, detectionCon=0.8)# 计数器公式显示
equation = ''
# 缓冲器,避免重复点击
delay_count = 0while True:# 读取每一帧图片,返回标记和图片flag, img = cap.read()# 摄像头和真实画面反了,要调整,图片翻转# 大于0,左右翻转;等于0,上下翻转;小于0,左右上下都翻转img = cv2.flip(img, 1)# 检测手,返回手和检测的图片,返回的手是一个列表(字典类型),在lmList里面,里面是手的坐标# 因为我们在摄像头就反转了,这里就不用了# 注意要先检测手,后按键hands, img = detector.findHands(img, flipType=False)# 如果flag为True,显示图片if flag:# 调用buttonfor button in button_list:button.draw(img)# 创建显示结果的窗口cv2.rectangle(img, (800, 70), (800 + 400, 70 + 80), (225, 225, 225), -1)cv2.rectangle(img, (800, 70), (800 + 400, 70 + 80), (50, 50, 50), 3)if hands:# 取出食指和中指的点,并计算两者的距离lmList = hands[0]['lmList']# lmList[8], lmList[12]代表的是食指和中指的点# 返回距离,线的描述,图片# # 最新版本的cvzone中,lmList坐标是三个值x,y,z,取出前两个值。lmList = [x[:2] for x in lmList]length, _, img = detector.findDistance(lmList[8], lmList[12], img)# 取出手指的坐标x, y = lmList[8]# 如果食指和中指之间的距离小于50,我们认为进行了点击操作# 为了防止频繁输入,设置延缓delay_countif length < 50 and delay_count == 0:for i, button in enumerate(button_list):if button.check_click(x, y):# 如果正确点击,把点中的数字显示在窗口上# 我们用枚举得到的i来算values的索引values = button_values[int(i % 4)][int(i / 4)]# 如果是'='说明要计算了# eval可以直接把字符串里面的公式或者变量,通过整合或者计算变成数字# eval计算结果 如:'1 + 2',eval后得到3if values == '=':try:equation = str(eval(equation))except Exception:# 非法数学公式,重新输出equation = ''else:# 字符串拼接equation += values# 不要频繁的输入,睡眠一下# time.sleep(0.5) 但睡眠不能完全解决问题还会导致卡顿delay_count = 1# 重置delay_count,避免重复点击if delay_count != 0:delay_count += 1if delay_count > 10:delay_count = 0# 计数器的计算公式cv2.putText(img, equation, (810, 130), cv2.FONT_HERSHEY_PLAIN, 3, (0, 0, 0), 3)cv2.imshow('img', img)# 1ms,1帧key = cv2.waitKey(1)if key == ord('q'):breakelif key == ord('c'):# 清空输出框equation = ''else:print('摄像头打开失败')breakcap.release()
cv2.destroyAllWindows()

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com