各位同学好,今天和大家分享一下如何使用MediaPipe完成手势调节电脑音量,先放张图看效果。

注意!!

本节需要用到手部关键点的实时跟踪,我已经在之前的文章中详细写过了,本节会直接使用,有疑问的同学可以看我的这一篇文章:【MediaPipe】(1) AI视觉,手部关键点实时跟踪,附python完整代码


1. 导入工具包,编写主程序

# 安装opencv
pip install opencv-contrib-python
# 安装mediapipe
pip install mediapipe
# pip install mediapipe --user  #有user报错的话试试这个# 安装之后导入各个包
import cv2  #opencv
import mediapipe as mp
import time

把工具包导入后,编写主程序,主程序只读取视频图像,将每一帧图像传给自定义函数。所有的手势处理均在自定义函数中完成。

handtracking是存放自定义函数的.py文件名。cap.read()读取视频帧图像,每执行一次,就读取一帧图像,返回值succes中存放视频是否成功被打开,img存放每一帧图像信息。

htm.handDetector() 中 handDetector() 是自定义的 handtracking.py 文件中定义的函数,将读取的图像数据img传给这个函数。

import cv2
import numpy as np
import time
import handtracking as htm#(1)获取摄像头
cap = cv2.VideoCapture(0) # 0代表自己电脑的摄像头
cap.set(3, 1080)  # 设置相机图像宽度1080
cap.set(4, 720)  # 设置相机图像高度720pTime = 0  # 处理第一帧图像的起始时间#(3)处理每一帧图像
while True:# 返回是否打开摄像头,以及每一帧的图像success, img = cap.read()# 调用手部关键点检测函数# 返回拇指"4"和食指"8"的坐标信息,存放在lmList中# 返回图像img,已经在食指和拇指关键点上画圈# 返回音量volimg, lmList  = htm.handDetector(img) # 记录处理每帧图像所花的时间cTime = time.time()fps = 1/(cTime-pTime)  # 计算fpspTime = cTime  # 更新下一帧图像处理的起始时间# 把fps值显示在图像上,img画板;fps变成字符串;显示的位置;设置字体;字体大小;字体颜色;线条粗细cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 3) # 显示图像,输入窗口名及图像数据cv2.imshow('image', img)    if cv2.waitKey(1) & 0xFF==27:  #每帧滞留1毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

2. 拇指和食指间的连线

新定义一个文件 handtracking.py ,放在和主程序的相同文件夹下。

下面的程序中(1)(2)部分有不明白的,可看一下我的手部关键点检测的文章:【MediaPipe】(1) AI视觉,手部关键点实时跟踪,附python完整代码

手部关键点标记如下图所示:

下面我解释一下如何绘制指尖连线,需要绘制拇指和食指间的连线,首先获取这两个关键点的坐标,每一个索引index对应一个关键点的xy坐标,每一帧图像有21个索引,也就有21个关键点坐标。由上图可知,拇指对应的索引为4,食指对应的索引为8,分别将其坐标表示为(x1, y1)和(x2, y2),接下去我们只需要处理这两个关键点即可。

使用 cv2.circle() 以这两个关键点为圆心画圆,在屏幕上突出显示出两个关键点。使用 cv2.line() 给出线段的起点和终点坐标,绘制两指间的连线。

import mediapipe as mp
import cv2#(1)创建检测手部关键点的方法
mpHands = mp.solutions.hands  #接收方法
hands = mpHands.Hands(static_image_mode=False, #静态追踪,低于0.5置信度会再一次跟踪max_num_hands=2, # 最多有2只手min_detection_confidence=0.6, # 最小检测置信度min_tracking_confidence=0.5)  # 最小跟踪置信度 # 创建检测手部关键点和关键点之间连线的方法
mpDraw = mp.solutions.drawing_utils# 存放坐标信息
lmList = []#(2)对传入的每一帧图像处理
def handDetector(img):# 把图像传入检测模型,提取信息results = hands.process(img)# 检查每帧图像是否有多只手,一一提取它们if results.multi_hand_landmarks: #如果没有手就是Nonefor handlms in results.multi_hand_landmarks:# 绘制关键点及连线,mpHands.HAND_CONNECTIONS绘制手部关键点之间的连线mpDraw.draw_landmarks(img, handlms, mpHands.HAND_CONNECTIONS) # 获取每个关键点的索引和坐标for index, lm in enumerate(handlms.landmark):# 将xy的比例坐标转换成像素坐标h, w, c = img.shape # 分别存放图像长\宽\通道数# 中心坐标(小数),必须转换成整数(像素坐标)cx ,cy =  int(lm.x * w), int(lm.y * h) #比例坐标x乘以宽度得像素坐标#(3)分别处理拇指"4"和食指"8"的像素坐标if index == 4:x1, y1 = cx, cy    if index == 8:                x2, y2 = cx, cy# 打印坐标信息print("4", x1, y1, ", 8", x2, y2)# 保存坐标点lmList.append([[x1,y1],[x2,y2]])# 在食指和拇指关键点上画圈,img画板,坐标(cx,cy),半径5,红色填充cv2.circle(img, (x1,y1), 12, (255,0,0), cv2.FILLED)cv2.circle(img, (x2,y2), 12, (255,0,0), cv2.FILLED)# 在拇指和食指中间画一条线段,img画板,起点和终点坐标,颜色,线条宽度cv2.line(img, (x1,y1), (x2,y2), (255,0,255), 3)# 拇指和食指的中点,像素坐标是整数要用//cx, cy = (x1+x2)//2, (y1+y2)//2# 在中点画一个圈cv2.circle(img, (cx,cy), 12, (255,0,0), cv2.FILLED)# 返回处理后的图像,及关键点坐标return img, lmList

效果如下:


3. 控制电脑音量

首先我们获取音量控制模块volume,音量的调节范围在[-65.25, 0]之间,音量最大为0

# 导入音量控制模块
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume# 获取音响设备
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
# volume.GetMute()  # 静音
# volume.GetMasterVolumeLevel()  # 获取主音量级
volRange = volume.GetVolumeRange()  # 音量范围(-65.25, 0.0)# 设置最值音量
minVol = volRange[0]  # 元素:-65.25
maxVol = volRange[1]  # 元素:0

接着我们修改第2节的代码内容,添加音量控制模块。通过拇指和食指之间连线的长度来调节音量。可通过勾股定理计算(x1,y1), (x2,y2)之间的长度。通过打印线段长度,发现线段最长为300,最短为50。而音量的范围是[-65,0],因此,我们将线段长度映射到音量长度使用映射函数np.interp()[50,300]==>[-65,0],该函数的用法:numpy.interp()用法_hfutdog的博客-CSDN博客_np.interp

设置音量控制器 volume.SetMasterVolumeLevel(vol, None) ,其中vol为映射后的线段长度。

#(1)创建检测手部关键点的方法
mpHands = mp.solutions.hands  #接收方法
hands = mpHands.Hands(static_image_mode=False, #静态追踪,低于0.5置信度会再一次跟踪max_num_hands=2, # 最多有2只手min_detection_confidence=0.6, # 最小检测置信度min_tracking_confidence=0.5)  # 最小跟踪置信度 # 创建检测手部关键点和关键点之间连线的方法
mpDraw = mp.solutions.drawing_utils# 存放坐标信息
lmList = []#(2)对传入的每一帧图像处理,给出音量范围
def handDetector(img):# 把图像传入检测模型,提取信息results = hands.process(img)# 检查每帧图像是否有多只手,一一提取它们if results.multi_hand_landmarks: #如果没有手就是Nonefor handlms in results.multi_hand_landmarks:# 绘制关键点及连线,mpHands.HAND_CONNECTIONS绘制手部关键点之间的连线mpDraw.draw_landmarks(img, handlms, mpHands.HAND_CONNECTIONS) # 获取每个关键点的索引和坐标for index, lm in enumerate(handlms.landmark):# 将xy的比例坐标转换成像素坐标h, w, c = img.shape # 分别存放图像长\宽\通道数# 中心坐标(小数),必须转换成整数(像素坐标)cx ,cy =  int(lm.x * w), int(lm.y * h) #比例坐标x乘以宽度得像素坐标#(3)分别处理拇指"4"和食指"8"的像素坐标if index == 4:x1, y1 = cx, cy    if index == 8:                x2, y2 = cx, cy# 打印坐标信息# print("4", x1, y1, ", 8", x2, y2)# 保存坐标点lmList.append([[x1,y1],[x2,y2]])# 在食指和拇指关键点上画圈,img画板,坐标(cx,cy),半径5,红色填充cv2.circle(img, (x1,y1), 12, (255,0,0), cv2.FILLED)cv2.circle(img, (x2,y2), 12, (255,0,0), cv2.FILLED)# 在拇指和食指中间画一条线段,img画板,起点和终点坐标,颜色,线条宽度cv2.line(img, (x1,y1), (x2,y2), (255,0,255), 3)# 拇指和食指的中点,像素坐标是整数要用//cx, cy = (x1+x2)//2, (y1+y2)//2# 在中点画一个圈cv2.circle(img, (cx,cy), 12, (255,0,0), cv2.FILLED)#(4)基于长度控制音量# 计算线段之间的长度,勾股定理计算平方和再开根length = math.hypot(x2-x1, y2-y1)# print(length)# 线段长度最大300,最小50,转换到音量范围,最小-65,最大0# 将线段长度变量length从[50,300]转变成[-65,0]vol = np.interp(length, [50,300], [minVol, maxVol])print('vol:',vol, 'length:', length)# 设置电脑主音量volume.SetMasterVolumeLevel(vol, None)  if length < 50:  # 距离小于50改变中心圆颜色绿色cv2.circle(img, (cx,cy), 12, (0,255,0), cv2.FILLED)# 返回处理后的图像,及关键点坐标return img, lmList

如下图所示,随着手部线段变化,音量也随着变化


4. 设置虚拟音量条

为了能更直观的展现出音量随着指尖距离的变化,设置虚拟的音量条,这样就不用总是打开音量控制面板看结果。因此我们在上面的代码中补充。

创建虚拟音量条的变量volBar,它的映射范围和vol不同,volBar的映射范围是虚拟音量框的高从[50,300]映射到[400,150],确保填充可以在矩形框中变动。

# 导入音量控制模块
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume# 获取音量设备
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
# volume.GetMute()  # 静音
# volume.GetMasterVolumeLevel()  # 获取主音量级
volRange = volume.GetVolumeRange()  # 音量范围(-65.25, 0.0)# 设置最小音量
minVol = volRange[0]  # 元素:-65.25
maxVol = volRange[1]  # 元素:0#(1)创建检测手部关键点的方法
mpHands = mp.solutions.hands  #接收方法
hands = mpHands.Hands(static_image_mode=False, #静态追踪,低于0.5置信度会再一次跟踪max_num_hands=2, # 最多有2只手min_detection_confidence=0.6, # 最小检测置信度min_tracking_confidence=0.5)  # 最小跟踪置信度 # 创建检测手部关键点和关键点之间连线的方法
mpDraw = mp.solutions.drawing_utils#(2)存放坐标信息
lmList = []# 对传入的每一帧图像处理,给出音量范围
def handDetector(img):# 把图像传入检测模型,提取信息results = hands.process(img)# 检查每帧图像是否有多只手,一一提取它们if results.multi_hand_landmarks: #如果没有手就是Nonefor handlms in results.multi_hand_landmarks:# 绘制关键点及连线,mpHands.HAND_CONNECTIONS绘制手部关键点之间的连线mpDraw.draw_landmarks(img, handlms, mpHands.HAND_CONNECTIONS) # 获取每个关键点的索引和坐标for index, lm in enumerate(handlms.landmark):# 将xy的比例坐标转换成像素坐标h, w, c = img.shape # 分别存放图像长\宽\通道数# 中心坐标(小数),必须转换成整数(像素坐标)cx ,cy =  int(lm.x * w), int(lm.y * h) #比例坐标x乘以宽度得像素坐标#(3)分别处理拇指"4"和食指"8"的像素坐标if index == 4:x1, y1 = cx, cy    if index == 8:                x2, y2 = cx, cy# 打印坐标信息# print("4", x1, y1, ", 8", x2, y2)# 保存坐标点lmList.append([[x1,y1],[x2,y2]])# 在食指和拇指关键点上画圈,img画板,坐标(cx,cy),半径5,红色填充cv2.circle(img, (x1,y1), 12, (255,0,0), cv2.FILLED)cv2.circle(img, (x2,y2), 12, (255,0,0), cv2.FILLED)# 在拇指和食指中间画一条线段,img画板,起点和终点坐标,颜色,线条宽度cv2.line(img, (x1,y1), (x2,y2), (255,0,255), 3)# 拇指和食指的中点,像素坐标是整数要用//cx, cy = (x1+x2)//2, (y1+y2)//2# 在中点画一个圈cv2.circle(img, (cx,cy), 12, (255,0,0), cv2.FILLED)#(4)基于长度控制音量# 计算线段之间的长度,勾股定理计算平方和再开根length = math.hypot(x2-x1, y2-y1)# print(length)# 线段长度最大300,最小50,转换到音量范围,最小-65,最大0# 将线段长度变量length从[50,300]转变成[-65,0]vol = np.interp(length, [50,300], [minVol, maxVol])print('vol:',vol, 'length:', length)# 虚拟音量调的映射,如果和vol一样音量调填充不满volBar = np.interp(length, [50,300], [400,150])  #映射到150-400# print('volbar',volBar)# 设置电脑主音量volume.SetMasterVolumeLevel(vol, None)  if length < 50:  # 距离小于50改变中心圆颜色绿色cv2.circle(img, (cx,cy), 12, (0,255,0), cv2.FILLED)#(5)画出矩形音量条,img画板,起点和终点坐标,颜色,线宽cv2.rectangle(img, (50,150), (85,400), (0,0,255), 3)# 用音量的幅度作为填充矩形条的高度,像素坐标是整数cv2.rectangle(img, (50,int(volBar)), (85,400), (0,0,255), cv2.FILLED)# 把音量值写上去,坐标(50-5,150-10)避免数字遮挡框text_vol = 100 * (volBar-150)/(400-150)   # 音量归一化再变成百分数cv2.putText(img, f'{str(int(text_vol))}%', (50-5,150-10), cv2.FONT_HERSHEY_COMPLEX, 1, (255,0,0), 2)# 返回处理后的图像,及关键点坐标return img, lmList

结果如下,24%代表的是矩形框中白色未填充部分

拇指和食指的坐标点存放在 lmList 中,把它打印出来看一下

【MediaPipe】(4) AI视觉,远程手势调节电脑音量,附python完整代码相关推荐

  1. 【机器视觉案例】(9) AI视觉,手势控制电脑键盘,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv+mediapipe 完成远程手势控制电脑键盘.感兴趣的可以看一下我前面一篇手势控制电脑鼠标:https://blog.csdn.net/dgvv4 ...

  2. 【机器视觉案例】(12) 自制AI视觉小游戏--贪吃蛇,附python完整代码

    各位同学好,今天和大家分享一下如何使用 mediapipe+opencv 自制贪吃蛇小游戏.先放张图看效果. 规则:食指指尖控制蛇头,指尖每接触到黄色方块,计数加一,蛇身变长,方块随机切换位置.如果指 ...

  3. 【机器视觉案例】(16) 自制视觉小游戏--桌上冰球,附python完整代码

    大家好,今天和各位分享一下如何使用 mediapipe+opencv 制作桌上冰球的交互式小游戏.先放张图看效果. 规则如下:左手控制白色球拍:右手控制紫色球拍:球拍只能上下移动:红色圆形就是冰球:球 ...

  4. 【机器视觉案例】(5) AI视觉,手势调节物体尺寸,附python完整代码

    各位同学好,今天和大家分享一下如何使用opencv+mediapipe完成远程手势调节图片尺寸的案例.先放张图看效果.当拇指和食指竖起时,根据食指间的连线的长度自由缩放图片尺寸.图片的中点始终位于指尖 ...

  5. 【机器视觉案例】(5) AI视觉,远程手势控制虚拟计算器,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe+Opencv完成虚拟计算器,先放张图看效果.FPS值为29,食指和中指距离小于规定阈值则认为点击按键,为避免重复数字出现,规定每20帧可点击一 ...

  6. 【机器视觉案例】(6) AI视觉,距离测量,自制AI小游戏,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv + mediapipe 创建一个AI视觉小游戏,先放图看效果. 游戏规则,用手按下屏幕上的圆形按钮,每按一次后松开,按钮就随机出现在屏幕上的一个位 ...

  7. 【机器视觉案例】(8) AI视觉,手势控制电脑鼠标,附python完整代码

    各位同学好,今天和大家分享一下如何使用 MediaPipe+Opencv 通过手势识别来控制电脑鼠标的移动和点击,如果有兴趣的话,可以代替鼠标去打游戏.先放图看效果.用画图板来测试 黄框代表电脑屏幕的 ...

  8. 【机器视觉案例】(10) AI视觉搭积木,手势移动虚拟物体,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv+mediapipe 完成手势移动虚拟物体,可自定义各种形状的物体,通过手势搭积木.先放张图看效果. 规则:当食指在某个物体内部,并且中指指尖和食指 ...

  9. 【MediaPipe】(1) AI视觉,手部关键点实时跟踪,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe完成手部关键点实时检测跟踪.先放张图看效果,15代表FPS值. 1. 导入工具包 # 安装opencv pip install opencv-c ...

最新文章

  1. 优化算法之手推遗传算法(Genetic Algorithm)的详细步骤图解
  2. 中国物流供应链“零的突破”!阿里路径规划算法入围运筹学“奥斯卡”
  3. ITK:将具有RGB像素的vtkImageData转换为itk :: Image
  4. 用 ABAP 读取本地文本文件内容
  5. mac vim 配置文件
  6. 使用FileUpload组件上传文件
  7. 45.MySQL Cluster
  8. 数据挖掘:原理与实践(基础篇)(进阶篇)
  9. C中字符串常量字符数组字符常量
  10. C语言自己写代码实现的strcmp函数
  11. 名义利率、实际利率、名义贴现率
  12. Java 同时替换 字符串中子串
  13. 什么是物联网?定义和解释
  14. Python——Flask基础学习
  15. DevOps到底是什么意思?-小白收藏
  16. Verilog HDL四位加法器
  17. mklink建立软链接
  18. WireShark 无法抓取以太帧前序和FCS或出现IP报头校验和错误 -- 原因
  19. echars地图---显示到乡镇街道级别
  20. 呼叫中心客服IVR语音导航和电销自动外呼

热门文章

  1. 微信小程序点击右下角的图片移动到当前位置
  2. pip安装拓展包--网络超时/Read timed out问题
  3. 2022-2028年中国三网融合产业深度调研及投资前景预测报告
  4. 机器学习概念 — 线性感知机、线性回归、单个神经元、多层次神经元
  5. 【云安全与同态加密_调研分析(3)】国内云安全组织及标准——By Me
  6. linux系统操作常见问题(ubuntu和opensuse)
  7. OpenCV+python:色彩空间转换及色彩通道的分离和合并
  8. svn的代码提交到git服务器_svn服务器代码仓库,数据迁移到git仓库
  9. java 泛型 父子,Java泛型-mb601cf8a78cc07的博客-51CTO博客
  10. 处理字典值是把字典放内存还是用sql处理_SQL索引及其底层实现