Opencv手势控制音量!附源码!

news/2024/6/23 18:09:56

效果演示:

在这里插入图片描述

废话不多说!直接上源码!下面写有所有代码注释!!

import cv2
import mediapipe as mp   #它包含了各种预训练的机器学习模型,可以用于姿势估计、手势识别等任务
from ctypes import cast, POINTER #ctypes 是 Python 的一个外部函数库,允许调用动态链接库中的函数
from comtypes import CLSCTX_ALL #用于操作 COM 对象
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume#是一个用于操作 Windows 音频控制的库。它被用于获取和控制计算机的音频音量。
import time
import math
import numpy as npclass HandControlVolume:def __init__(self):# 初始化medialpipeself.mp_drawing = mp.solutions.drawing_utilsself.mp_drawing_styles = mp.solutions.drawing_stylesself.mp_hands = mp.solutions.hands# 获取电脑音量范围devices = AudioUtilities.GetSpeakers() # 获取扬声器信息interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None) # 激活音频端点音量接口。self.volume = cast(interface, POINTER(IAudioEndpointVolume))#self.volume是指向音频端点音量接口的指针self.volume.SetMute(0, None)#0关闭静音 1打开静音self.volume_range = self.volume.GetVolumeRange()  #获取音量范围。#手势控制音量方法def recognize(self):# 计算刷新率fpsTime = time.time() #获取当前时间戳# OpenCV读取视频流cap = cv2.VideoCapture(0)# 初始化视频窗口分辨率resize_w = 640resize_h = 480# 画面显示初始化参数rect_height = 0rect_percent_text = 0#min_detection_confidence此参数设置手部检测被视为成功所需的最小置信度值(介于 0.01.0 之间)#min_tracking_confidence此参数设置手部关键点被视为成功追踪所需的最小置信度值(介于 0.01.0 之间)#max_num_hands此参数设置要检测的最大手数。with (self.mp_hands.Hands(min_detection_confidence=0.7,min_tracking_confidence=0.5,max_num_hands=2) as hands):while cap.isOpened():   #判断视频是否打开success, image = cap.read() #success是一个布尔值,表示是否成功读取了一帧图像。image是读取的图像image = cv2.resize(image, (resize_w, resize_h))  #设置视频分辨率if not success:print("空帧.")continue#将图像设置为不可写入,以保护数据image.flags.writeable = False#将图像从BGR颜色空间转换为RGB颜色空间,模型的输入是RGB图像image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 镜像,对图像进行水平翻转,可能是为了更好地适应MediaPipe模型的期望输入image = cv2.flip(image, 1)# 对输入的图像进行处理。处理后,results 包含了手部追踪的结果,可能包括检测到的手部数量、手部关键点的坐标等多种信息,results = hands.process(image)# 将图像设置为可写入,以便可以在图像上绘制标注image.flags.writeable = True# 将图像从RGB颜色空间转换为BGR颜色空间image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)# 判断是否有手掌if results.multi_hand_landmarks:# 遍历每个手掌for hand_landmarks in results.multi_hand_landmarks:# 在画面标注手掌所有关键点并连线。draw_landmarks用于在图像上标注手掌上手部关键点和手指的连接线self.mp_drawing.draw_landmarks(image,   # 待标注的图像hand_landmarks,# 在图像上标注手部所有的关键点self.mp_hands.HAND_CONNECTIONS,# 将标注的关键点连接起来self.mp_drawing_styles.get_default_hand_landmarks_style(), #修改关键点标注的样式self.mp_drawing_styles.get_default_hand_connections_style()) #修改连接线标注的样式# 解析手指,存入各个手指坐标landmark_list = []#hand_landmarks.landmark 包含了手部关键点的id以及坐标信息。通过 enumerate 函数遍历每个关键点for landmark_id, finger_axis in enumerate(hand_landmarks.landmark):landmark_list.append([landmark_id, finger_axis.x, finger_axis.y,finger_axis.z])#landmark_list中共存入21个关键点信息。#  0-手腕#  1-大拇指第一关节   2-大拇指第二关节   3-大拇指第三关节   4-大拇指指尖#  5-食指第一关节     6-食指第二关节   7-食指第三关节   8-食指指尖#  9-中指第一关节     10-中指第二关节  11-中指第三关节  12-中指指尖# 13-无名指第一关节    14-无名指第二关节 15-无名指第三关节 16-无名指指尖# 17-小指第一关节      18-小指第二关节  19-小指第三关节  20-小指指尖if landmark_list:# 获取大拇指指尖坐标thumb_finger_tip = landmark_list[4]#thumb_finger_tip也有4个信息。0-关键点ID  1-x坐标(归一化范围0-1)  2-y坐标(归一化范围0-1)  3-z坐标(归一化范围0-1)#math.ceil函数用于向上取整,确保获得的坐标是整数。thumb_finger_tip_x = math.ceil(thumb_finger_tip[1] * resize_w)thumb_finger_tip_y = math.ceil(thumb_finger_tip[2] * resize_h)# 获取食指指尖坐标index_finger_tip = landmark_list[8]index_finger_tip_x = math.ceil(index_finger_tip[1] * resize_w)index_finger_tip_y = math.ceil(index_finger_tip[2] * resize_h)# 大拇指指尖和食指指尖的之间连线的中间点坐标finger_middle_point = (thumb_finger_tip_x + index_finger_tip_x) // 2, (thumb_finger_tip_y + index_finger_tip_y) // 2#大拇指指尖坐标thumb_finger_point = (thumb_finger_tip_x, thumb_finger_tip_y)#食指指尖坐标index_finger_point = (index_finger_tip_x, index_finger_tip_y)# 画圆圈image = cv2.circle(image,thumb_finger_point,   #大拇指坐标10,            #圆圈半径(255, 0, 255),  #圆圈颜色-1)                   #实心圆image = cv2.circle(image, index_finger_point, 10, (255, 0, 255), -1)image = cv2.circle(image, finger_middle_point, 10, (255, 0, 255), -1)# 画2点连线image = cv2.line(image,thumb_finger_point,  #大拇指坐标(起点)index_finger_point,  #食指坐标(终点)(255, 0, 255), #连线颜色5)          #线宽# 勾股定理计算两点间连线的长度。 math.hypot(x,y)计算x,y平方和的平方根line_len = math.hypot((index_finger_tip_x - thumb_finger_tip_x),(index_finger_tip_y - thumb_finger_tip_y))# 获取电脑最大最小音量min_volume = self.volume_range[0]max_volume = self.volume_range[1]# # 将俩指间线的长度映射到[min_volume, max_volume]范围内的音量值vol = np.interp(line_len,[50, 300],  #line_len的范围[min_volume,#音量范围的最小值max_volume])   #音量范围的最大值# 将俩指间线的长度映射到[0, 200]范围内的 矩形高度rect_height = np.interp(line_len, [50, 300], [0, 200])# 将俩指间线的长度映射到[0, 100]范围内的 矩形高度百分比rect_percent_text = np.interp(line_len, [50, 300], [0, 100])# 设置电脑音量self.volume.SetMasterVolumeLevel(vol, None)# 在图像上添加文本cv2.putText(image,str(math.ceil(rect_percent_text)) + "%", #文本内容(10, 350),                          #文本的坐标位置cv2.FONT_HERSHEY_PLAIN,                  #字体类型,PLAIN 表示简单的字体2,                              #字体大小(255, 0, 0),                       #字体颜色3)                              #字体线宽#画音量矩形方框image = cv2.rectangle(image,(30, 100),  #矩形左上角坐标(x,y)(50, 300),  #矩形右下角坐标(x,y)(255, 0, 0),#颜色3)          #矩形线宽#画音量实心矩形image = cv2.rectangle(image,(30, math.ceil(300 - rect_height)),#矩形左上角坐标(x,y)(50, 300),                         #矩形右下角坐标(x,y)(255, 0, 0),                       #颜色-1)                                #矩形线宽,-1 表示实心矩形# 显示刷新率FPScTime = time.time()   #获取当前时间戳fps_text = 1 / (cTime - fpsTime) #计算当前帧的帧率,即每秒处理的帧数。fpsTime = cTime #将当前时间戳赋值给fpsTime,以便下一帧计算帧率。#在图像上添加文本cv2.putText(image,"FPS: " + str(int(fps_text)),#文本内容(10, 70),               #文本的坐标位置cv2.FONT_HERSHEY_PLAIN,      #字体类型,PLAIN 表示简单的字体2,                  #字体大小(255, 0, 0),           #字体颜色3)                  #字体线宽# 显示画面cv2.imshow('xyp', image)#按下q键退出if cv2.waitKey(1) & 0xFF == ord('q'):break#释放摄像头资源cap.release()control = HandControlVolume()  #创建 HandControlVolume 类的实例
control.recognize()           # 调用 recognize 方法

https://www.xjx100.cn/news/3119002.html

相关文章

(C++)移动零--双指针法

个人主页:Lei宝啊 愿所有美好如期而遇 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://le…

HTTP /1.0 /1.1 /2.0 /3.0改变和区别

HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的协议,它是Web上数据通信的基础。不同版本的HTTP协议有一些重要的变化和改进。以下是HTTP/1.0、HTTP/1.1、HTTP/2.0和HTTP/3.0的主要变化和区别: HTTP/1.0: 1.无连接性&…

根据Java的数据库实体类输出建表SQL

数据库实体类 import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode;/*** 分子公司基本信息变更代办** version 1.0* date 2023/11/21 01:01*/ EqualsAndHashCode(callSuper true) Data TableName("ent_change_t…

【Axure高保真原型】区间评分条

今天和大家分享区间评分条的原型模板,我们可以左右拖动移动滑块到指定位置,评分条上方会根据两个滑块所在的位置,自动计算出对应的区间范围;这个原型模板使用也很简单,只需要在里面填写区间的最大值,即可自…

前端如何中断请求 ( axios、原生 ajax、fetch)

使用场景 在前端开发中,我们经常需要中断请求来优化性能或处理特定的业务需求。以下是一些常见的使用场景: 比如 重复请求:当页面中多个组件并发调用同一个接口时,在第一个请求返回后,我们可能需要中断其他组件对该接…

ARM预取侧信道(Prefetcher Side Channels)攻击与防御

目录 一、预取侧信道简介 1.1 背景:预取分类 二、Arm核会受到影响吗? 2.1 先进的预取器

阿里云国际短信业务网络超时排障指南

选取一台或多台线上的应用服务器或选取相同网络环境下的机器,执行以下操作。 获取公网出口IP。 curl ifconfig.me 测试连通性。 (推荐)执行MTR命令(可能需要sudo权限),检测连通性,执行30秒。 m…

uniapp 使用 flex布局 将 图片展示 循环排列两列

将以下代码改成图片展示 循环排列两列 展示 <template><view><image v-for"(image, index) in imageList" :key"index" :src"image"></image></view> </template><script> export default {data() {…