使用Python和Pycharm创建一个手势音量控制器
本教程将讨论如何使用Python来跟踪手势,以及如何创建一个手势音量控制器。
在本教程结束时,你将能够使用你的手指并将计算机的音量调整到你满意的程度。
前提条件
要跟上本教程,你需要。
- 熟悉Python编程语言。
- 在你的电脑上安装Pycharm。
推荐人的手图像

上面的图片显示了MediaPipe用来指代手的不同点的数字。本教程将使用点4 和点8 ,它们分别是拇指和食指。
创建一个手势音量控制器
设置
首先,我们要准备我们的工作空间。启动Pycharm应用程序。点击创建一个新的项目。

在接下来出现的窗口中点击创建按钮。
我们需要安装我们将在项目中使用的库。
numpy 将帮助我们处理数组。要安装它,打开终端并运行以下命令。
pip install numpy
对其他库重复同样的过程。
pip install opencv-python
我们将把这个库作为cv2 。我们将用它来捕捉使用网络摄像头的图像,并将其转换为RGB 。
pip install mediapipe
它是一个由谷歌开发的开源库。我们用它来进行人脸和手势识别。在本教程中,我们将把它用于手势识别。
pip install pycaw
我们将需要这个库来访问设备的扬声器和它的主音量。
pip install python-math
我们将使用这个库,用斜线找到点号4 (拇指)和点号8 (食指)之间的距离。
pip install gpib-ctypes, comtypes
pycaw Ctypes 提供 语言兼容的数据类型。 基于C Comtypes ctypes FFI(外国函数接口)库。
现在,让我们开始编码。在pycharm自动为你创建的main.py 文件中,键入以下代码。
第1步:导入我们需要的库
import cv2
import mediapipe as mp
from math import hypot
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
import numpy as np
在上面的代码段中,我们导入我们在项目中安装的每个库。
cap = cv2.VideoCapture(0)
然后我们从电脑的主摄像头获取视频输入。如果你使用的是其他摄像头,请将数字0 ,替换为你所使用的摄像头的数字。
第2步:检测、初始化和配置双手
mpHands = mp.solutions.hands
hands = mpHands.Hands()
mpDraw = mp.solutions.drawing_utils
在上面的代码中,我们正在调用mediapipe 手部模块,从我们的主摄像头得到的视频输入中检测手部。然后MpHands.Hands() ,完成对检测到的手部的初始化和配置。最后我们使用mp.solutions.drawing_utils ,在检测到的手上画出连接和地标。
第3步:使用pycaw访问说话者
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
这些是我们需要的初始化,以使pycaw 顺利地运行。开发者将这个库与初始化一起提供。我们不打算改变任何东西。
第4步:找到最小和最大体积之间的体积范围
volMin, volMax = volume.GetVolumeRange()[:2]
上面的代码找到了最小和最大音量之间的音量范围。我们把它放在while循环之外,因为我们只需要找到一次体积范围。
第5步:从我们的相机捕捉图像并将其转换为RGB图像
while True:
success, img = cap.read()
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
results = hands.process(imgRGB)
上面的代码检查我们所指定的相机是否工作。如果它能工作,我们将捕获一个图像。然后我们将图像转换为RGB ,并完成图像的处理。
我们现在需要检查我们捕获的图像中是否有多只手。
第6步:检查我们的输入中是否有多只手
lmList = []
if results.multi_hand_landmarks:
这段代码创建了一个空列表,它将存储由mediapipe 手模块检测到的手的元素列表,即手的点数。它还会检查输入是否有多只手。
我们现在将创建一个for循环来处理输入中的每一只手。
第7步:创建一个for循环来操作每一只手
for handlandmark in results.multi_hand_landmarks:
for id, lm in enumerate(handlandmark.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
lmList.append([id, cx, cy])
mpDraw.draw_landmarks(img, handlandmark, mpHands.HAND_CONNECTIONS)
-
在上面的代码中,我们使用第一个for循环来与结果中的每只手进行交互。我们使用第二个for循环来获取每只手的地标
id(ID号码)和lm(地标信息)。地标信息将给我们提供x和y的坐标。id号是分配给各个手部点的数字。 -
h, w, c = img.shape检验:这行代码检验我们图像的高度、宽度和通道。这将给我们提供图像的宽度和高度。 -
cx, cy = int(lm.x * w), int(lm.y * h)这一行代码将找到我们图像的中心位置。我们将通过将lm.x乘以宽度并将得到的值赋给cx。然后将lm.y乘以高度并将得到的值赋给cy。lm代表地标。 -
lmList.append([id, cx, cy]): 然后我们将使用这一行将id,cx和cy的值加到lmList。 -
最后我们将调用mpDraw.draw_landmarks,用最后一行代码画出手的所有地标。
第8步:指定我们要使用的拇指和中指的点
if lmList != []:
x1, y1 = lmList[4][1], lmList[4][2]
x2, y2 = lmList[8][1], lmList[8][2]
在上面的代码中,我们指定了lmlist 中的元素数量。它不应该是空的。我们给变量x1 和y1 分别指定点x 和y 的坐标4 。这就是拇指尖。然后我们在最后一行对食指重复同样的操作。
第9步:在拇指尖和食指尖之间画一个圆形
cv2.circle(img, (x1, y1), 15, (255, 0, 0), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (255, 0, 0), cv2.FILLED)
上面的代码在拇指尖和食指尖上画了一个圆。
-
(x1, y1)15是圆的半径。 是圆的(255, 0, 0)颜色。 是指 像素的厚度,它将用我们指定的颜色填充圆。cv2.FILLED-1 -
我们将对食指重复同样的步骤。
第10步:在4点和8点之间画一条线
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 3)
在上面的代码中,我们使用cv2.line 函数在手的四点和点8 之间画一条线。这条线将连接点4 (x1, y1) ,也就是大拇指的尖端,和点8 (x2, y2) ,也就是食指的尖端。(255, 0, 0) 是线的颜色,3 是它的厚度。
第11步:寻找4号和8号点之间的距离
length = hypot(x2 - x1, y2 - y1)
在上面的代码中,我们用斜线找到拇指尖和食指尖之间的距离。我们通过调用数学函数hypot ,然后传递x2 和x1 之间的差值以及y2 和y1 之间的差值来实现。
第12步:将手的范围转换为体积范围
vol = np.interp(length, [15, 220], [volMin, volMax])
print(vol, length)
我们调用NumPy函数np.interp ,将手部范围转换为体积范围。使用的参数是。
length:这是我们要转换的数值。[15 - 220]:这是手的范围。[volMin, volMax]:给出我们要转换的范围。
第13步:设置主音量
volume.SetMasterVolumeLevel(vol, None)
我们要根据手的范围来设置主音量水平。我们通过传递vol ,这是我们转换为音量范围的手部范围的值来实现。
第14步:显示用于与用户互动的视频输出
cv2.imshow('Image', img)
上面的代码显示了用户与程序互动的实时视频,即用户用拇指和食指来控制音量。
第15步:终止程序
if cv2.waitKey(1) & 0xff == ord('q'):
break
上面的代码将在用户按下q 键时终止程序。
结果
当我们在没有任何错误的情况下运行该代码时,结果将是。

结论
你现在已经掌握了创建一个手势音量控制器所需的所有技能。如果你在工作时听你最喜欢的音乐,只需用手势控制音乐的音量,你就能控制音乐的音量。