python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > opencv手势控制音量

基于opencv实现手势控制音量(案例详解)

作者:计算机小混子

这篇文章主要介绍了基于opencv的手势控制音量和ai换脸,通过定义了一个名为 handDetector 的类,用于检测和跟踪手部,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下

基于opencv的手势控制音量和ai换脸

HandTrackingModule.py

import cv2
import mediapipe as mp
import time
class handDetector():
    def __init__(self, mode = False, maxHands = 2, model_complexity = 1, detectionCon = 0.5, trackCon = 0.5):
        self.mode = mode
        self.maxHands = maxHands
        self.model_complexity = model_complexity
        self.detectionCon = detectionCon
        self.trackCon = trackCon
        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.model_complexity, self.detectionCon, self.trackCon)
        self.mpDraw = mp.solutions.drawing_utils
    def findHands(self, img, draw = True):
        # Hand类的对象只能使用RGB图像
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)
        # print(results.multi_hand_landmarks)
        # 如果存在手
        if self.results.multi_hand_landmarks:
            # 如果存在多个手
            for handLms in self.results.multi_hand_landmarks:
                if draw:
                    # 设置连接线等属性
                    self.connection_drawing_spec = self.mpDraw.DrawingSpec(color=(0, 255, 0), thickness=2)
                    # 绘制
                    self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS, connection_drawing_spec=self.connection_drawing_spec)
        return img
    def findPosition(self, img, handNum=0, draw=True):
        lmList = []
        # 每个点的索引和它的像素比例,若知道窗口的宽度和高度可以计算位置
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNum]
            for id, lm in enumerate(myHand.landmark):
                # print(id, lm)
                h, w, c = img.shape
                cx, cy = int(lm.x * w), int(lm.y * h)
                # print(id, cx, cy)
                lmList.append([id, cx, cy])
                if draw:
                    cv2.circle(img, (cx, cy), 7, (255, 0, 0), cv2.FILLED)
            # 绘制每一只手
        return lmList

定义了一个名为 handDetector 的类,用于检测和跟踪手部。下面是代码的详细分析:

导入库

handDetector

初始化方法 __init__

该方法用于初始化 handDetector 类的对象,并设置一些参数。

此外,还创建了 MediaPipe 手部解决方案的实例,并初始化了绘图工具。

方法 findHands

该方法用于在给定图像中找到手,并根据需要绘制手部标记。

该方法首先将图像从 BGR 转换为 RGB,然后处理图像以找到手部标记。如果找到了手部标记,并且 draw 参数为 True ,则会在图像上绘制手部标记和连接线。

方法 findPosition

该方法用于在给定图像中找到手部标记的位置,并返回一个包含每个标记位置的列表。

该方法遍历给定手的每个标记,并计算其在图像中的位置。如果 draw 参数为 True ,则在每个标记的位置上绘制一个圆圈。

总结

handDetector 类是一个用于检测和跟踪手部的工具。它使用了 MediaPipe 的手部解决方案,并提供了在图像上绘制手部标记和连接线的功能。通过调用这些方法,你可以在视频流或静态图像中跟踪手部,甚至找到特定手部标记的位置。

VolumeHandControl.py

import cv2
import time
import numpy as np
import HandTrackingModule as htm
import math
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
wCam, hCam = 640, 480
cap = cv2.VideoCapture(0)
# 设置摄像头的宽度
cap.set(3, wCam)
# 设置摄像头的高度
cap.set(4, hCam)
pTime = 0
tiga_img = cv2.imread("tiga.jpg", cv2.IMREAD_UNCHANGED)
detector = htm.handDetector(detectionCon=0.7)
face_Cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
# volume.GetMute()
# volume.GetMasterVolumeLevel()
# 音量范围
volRange = volume.GetVolumeRange()
print(volRange)
# 最小音量
minVol = volRange[0]
# 最大音量
maxVol = volRange[1]
vol = 0
volBar = 400
volPer = 0
def overlay_img(img, img_over, img_over_x, img_over_y):
    # 背景图像高宽
    img_w, img_h, img_c = img.shape
    # 覆盖图像高宽通道数
    img_over_h, img_over_w, img_over_c = img_over.shape
    # 转换成4通道
    if img_over_c == 3:
        img_over = cv2.cvtColor(img_over, cv2.COLOR_BGR2BGRA)
    # 遍历列
    for w in range(0, img_over_w):
        #遍历行
        for h in range(0, img_over_h):
            if img_over[h, w, 3] != 0:
                # 遍历三个通道
                for c in range(0, 3):
                    x = img_over_x + w
                    y = img_over_y + h
                    if x >= img_w or y >= img_h:
                        break
                    img[y-40, x, c] = img_over[h, w, c]
    return img
while True:
    success, img = cap.read()
    gray_frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    height, width, channel = img.shape
    faces = face_Cascade.detectMultiScale(gray_frame, 1.15, 5)
    for (x, y, w, h) in faces:
        gw = w
        gh = int(height * w / width)
        tiga_img = cv2.resize(tiga_img, (gw, gh+gh))
        print(gw, gh)
        if 0 <= x < img.shape[1] and 0 <= y < img.shape[0]:
            overlay_img(img, tiga_img, x, y)
    img = detector.findHands(img)
    lmList = detector.findPosition(img, draw=False)
    if len(lmList) != 0:
        # print(lmList[4], lmList[8])
        x1, y1 = lmList[4][1], lmList[4][2]
        x2, y2 = lmList[8][1], lmList[8][2]
        cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
        cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
        cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
        cx, cy = (x1+x2)//2, (y1+y2)//2
        cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
        length = math.hypot(x2 - x1, y2 - y1)
        print(length)
        # Hand rang 130 25
        # Vomume Range -65 0
        vol = np.interp(length, [25, 175], [minVol, maxVol])
        volBar = np.interp(length, [25, 175], [400, 150])
        volPer = np.interp(length, [25, 175], [0, 100])
        print(int(length), vol)
        volume.SetMasterVolumeLevel(vol, None)
        if length<25:
            cv2.circle(img, (cx, cy), 15, (0, 255, 0), cv2.FILLED)
    cv2.rectangle(img, (50, 150), (85, 400), (255, 0, 0), 3)
    cv2.rectangle(img, (50, int(volBar)), (85, 400), (255, 0, 0), cv2.FILLED)
    cv2.putText(img, f'{int(volPer)} %', (40, 450), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 3)
    cTime = time.time()
    fps = 1/(cTime - pTime)
    pTime = cTime
    cv2.putText(img, f'FPS:{int(fps)}', (40, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 3)
    cv2.imshow("img", img)
    cv2.waitKey(1)

1. 导入必要的库

2. 初始化参数和对象

3. 定义图像叠加函数 overlay_img

该函数负责将一个图像叠加到另一个图像上的特定位置。它遍历覆盖图像的每个像素,并将非透明像素复制到背景图像的相应位置。

4. 主循环

在无限循环中,代码执行以下任务:

a. 人脸检测和图像叠加

b. 手部检测和音量控制

c. 可视化

d. 显示结果

总结

这个代码集成了多个功能:通过摄像头捕获图像,检测人脸并在人脸上叠加图像,检测手部并通过手指之间的距离控制系统音量,然后通过 OpenCV 实时显示结果。它结合了图像处理、人脸和手部检测、系统交互和实时可视化,展示了计算机视觉和人机交互的强大功能。

效果

(B站演示视频)[https://www.bilibili.com/video/BV1Xu41177Gz/?spm_id_from=333.999.0.0]

到此这篇关于基于opencv的手势控制音量的文章就介绍到这了,更多相关opencv手势控制音量内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文