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

news2024/11/20 18:35:55

效果演示:

在这里插入图片描述

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

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 np


class HandControlVolume:
    def __init__(self):
        # 初始化medialpipe
        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles
        self.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 = 640
        resize_h = 480

        # 画面显示初始化参数
        rect_height = 0
        rect_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 表示实心矩形
                # 显示刷新率FPS
                cTime = 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 方法


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1269402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

P8649 [蓝桥杯 2017 省 B] k 倍区间(前缀和+优化(桶分类))

分析: (1)任意连续子序列可用两个前缀和的差来表示 (2)判断该子序列是否为k的倍数 p1-p2 模 0 (mod k) 等价于:前缀和模 k 是否同余 (3)同余的任意两前缀和组合的序列均满足…

[React] 2023年最新面试题

[React] 2023年最新面试题 1. class 组件与函数组件的区别2. react 18 新特性有那些?新增 createRoot API自动批处理过渡更新新的Hook 3. redux 和 react-redux 的区别4. redux 中间件的原理5. setState 发生了什么 ,render 函数做了什么6. 虚拟DOM, Fi…

【面试】typescript

目录 为什么用TypeScript? TS和JS的区别 控制类成员可见性的访问关键字? public protected),该类及其子类都可以访问它们。 但是该类的实例无法访问。 私有(private),只有类的成员可以访问…

JSON.stringify方法详解 后端接受JSON数据格式

1、方法定义:JSON.stringify(value, replacer, space) 参数说明: value:js对象 replacer:替换对象,可以是一个方法、对象或数组,将value按照替换规则展示。 space:填充参数,可以是数…

LVS+Keepalived实验

实验前准备 主DR服务器:(ens33)192.168.188.11 ipvsadm、keepalived (ens33:0)192.168.188.188 备DR服务器:(ens33)192.168.188.12 ipvsadm、keepalived (ens33:0)192.168.188.188 Wbe服务器1:(ens33)192.168.188.13 (lo:0)192.168.188.188 W…

selenium使用记录

本文记录python环境下使用selenium的一些步骤 Step1:安装并配置驱动 pip install selenium # 使用pip在对应python中安装selenium包为了让selenium能调用指定的浏览器,需要下载对应浏览器的驱动程序(这里以edge为例子) #Firefo…

【Openstack Train安装】四、MariaDB/RabbitMQ 安装

本章介绍了MariaDB/RabbitMQ的安装步骤,MariaDB/RabbitMQ仅需要在控制节点安装。 在安装MariaDB/RabbitMQ前,请确保您按照以下教程进行了相关配置: 【Openstack Train安装】一、虚拟机创建 【Openstack Train安装】二、NTP安装 【Opensta…

改善厦门城市内涝积水问题,实时监测城市易涝积水点

近年来,城市内涝积水问题已成为中国许多城市面临的严峻挑战。特别是在厦门这样的海滨城市,由于其特殊的地理环境和气候条件,内涝问题尤为突出。传统的解决方法主要依赖于人工排查,然而,这种方式存在许多缺陷。 WITBEE万…

BEVFormer【人工智能】

BEVFormer 是一篇今年中稿 ECCV 2022 的论文,其中提出了一种纯视觉(camera)感知任务的算法模型,用于实现3D目标检测和地图分割任务。该算法通过提取环视相机(Bird’s Eye View Camera)采集到的图像特征&…

【产品设计】SaaS产品数据分析之指标与标签

数据分析能够应用到各个领域和岗位,那么在SaaS产品中的应用会是如何?本文将探索SaaS产品在数据分析中的应用,并对其指标与标签的设计进行总结分析,一起来看看吧。 数据分析是业务开展过程中,收集记录各种行为产生的数据…

vue2+element-ui npm run build打包后,在服务器打开报错

报错 页面的图标也显示不出来,如下 解决: 在build->utils.js文件里面加上publicPath: ../../,再打包发布一下就可以了 // Extract CSS when that option is specified// (which is the case during production build)if (options.extrac…

数据挖掘之时间序列分析

一、 概念 时间序列(Time Series) 时间序列是指同一统计指标的数值按其发生的时间先后顺序排列而成的数列(是均匀时间间隔上的观测值序列)。 时间序列分析的主要目的是根据已有的历史数据对未来进行预测。 时间序列分析主要包…

re:Invent 构建未来:云计算生成式 AI 诞生科技新局面

文章目录 前言什么是云计算云计算类型亚马逊云科技云计算最多的功能最大的客户和合作伙伴社区最安全最快的创新速度最成熟的运营专业能力 什么是生成式 AI如何使用生成式 AI后记 前言 在科技发展的滚滚浪潮中,我们见证了云计算的崛起和生成式 AI 的突破&#xff0c…

客服管理者如何有效管理客服团队,有哪些高效方式?

在如今的市场竞争中,客户服务是企业成功的关键因素之一。因此,客服团队的有效管理至关重要。客服管理者需要了解如何有效地管理客服团队,以确保客户的满意度和忠诚度,从而提高企业的竞争力。 以下是客服管理者如何有效管理客服团队…

【AI】Segment-Anything本地部署

Segment-Anything是Meta开源的图像分割模型,顾名思义,可以分割所有东西,感觉这东西可以用于遥感影像分割,于是找来源码测试一下。 项目地址:https://github.com/facebookresearch/segment-anything 1. 构建环境 首先…

论文笔记:Confidential Assets

Confidential Assets 描述了一种称为“保密交易”的方案,该方案模糊了所有UTXO的金额,同时保持了不创建或销毁硬币的公共可验证性。进一步将此方案扩展到“保密资产”,一种单一的基于区块链的分类帐可以跟踪多种资产类型的方案。将保密交易扩…

VSCode编译多个文件

打开tasks.json文件,找到"$ {file}“这一行。然后在其后面添加你想要编译的文件即可。 比如我这里是想要编译当前文件夹下的所有.cpp文件,那么我就直接把”$ {file}"给注释掉了,然后再使用通配符来代表所有.cpp文件。 最后解释以下…

支持向量机,硬间隔,软间隔,核技巧,超参数设置,分类与回归

SVM(Support Vector Machine,支持向量机)是一种非常常用并且有效的监督学习算法,在许多领域都有广泛应用。它可以用于二分类问题和多分类问题,并且在处理高维数据和特征选择方面非常强大。SVM算法的核心思想是通过找到…

vue3项目安装vite-plugin-mock 项目报错

vue3vite项目安装了vite-plugin-mock之后,根据官网配置使用,vscode会出现波浪线,启动项目,发现运行不了 解决办法: 安装vite-plugin-mock2.9.6的版本即可 pnpm install mockjs vite-plugin-mock2.9.6 -D

RabbitMQ的Web管理页面

访问页面 http://IP:15672/账号密码默认都是:guest 主页概览 Overview 显示当前RabbitMQ Broker的运行信息、连接信息、集群信息以及配置信息等。 连接 Connections 无论生产者还是消费者,都需要与RabbitMQ建立连接后才可以完成消息的生产和消费&#…