gada888 发表于 2024-9-10 17:27:28

用Mediapipe来通过手势实现灯光调光

本帖最后由 gada888 于 2024-9-23 17:29 编辑

通过手势实现灯光调光前言:完成这样一个项目的意义在于什么呢,在于你会发现整个项目的核心居然是两个数学计算公式。所以有人说‘’AI的尽头是数学‘’不无道理。当下在AI代码助手的帮助下,学习代码这个工作的意义其实在弱化了。我们更多的关注点应该在创意和数学上。

mediapipe是机器视觉的一个套件。在opencv的框架下,可以利用mediapipe的高互动性来做一些有趣的项目。今天我们用个简化的mediapipe库文件。cvzone来完成一个手势控制灯光的项目。

为了让大家对这个项目的核心内容有个快速的了解。这里发布一个教学视频。视频里有对核心代码部分的解释。因为时间关系,也因为代码注释很完整,视频讲解就不对mediapipe和opencv部分进行解释,因此它不是初学者项目。需要学习者有python,opencv和机器视觉知识的基础储备。

下面是视频链接:
https://www.bilibili.com/video/BV1pQ4heXEDu/
下面是源代码:并且提供了代码注释。
from cvzone.HandTrackingModule import HandDetector
import cv2
#Arduino Declare
import time
from pinpong.board import Board,Pin
Board("uno","COM3").begin()
pwm0 = Pin(Pin.D7, Pin.PWM)

# Initialize the webcam to capture video
# The '2' indicates the third camera connected to your computer; '0' would usually refer to the built-in camera
cap = cv2.VideoCapture(0)
length = 0
# Initialize the HandDetector class with the given parameters
detector = HandDetector(staticMode=False, maxHands=2, modelComplexity=1, detectionCon=0.5, minTrackCon=0.5)

# Continuously get frames from the webcam
while True:
    # Capture each frame from the webcam
    # 'success' will be True if the frame is successfully captured, 'img' will contain the frame
    success, img = cap.read()

    # Find hands in the current frame
    # The 'draw' parameter draws landmarks and hand outlines on the image if set to True
    # The 'flipType' parameter flips the image, making it easier for some detections
    hands, img = detector.findHands(img, draw=True, flipType=True)

    # Check if any hands are detected
    if hands:
      # Information for the first hand detected
      hand1 = hands# Get the first hand detected
      lmList1 = hand1["lmList"]# List of 21 landmarks for the first hand
      bbox1 = hand1["bbox"]# Bounding box around the first hand (x,y,w,h coordinates)
      center1 = hand1['center']# Center coordinates of the first hand
      handType1 = hand1["type"]# Type of the first hand ("Left" or "Right")

      # Count the number of fingers up for the first hand
      fingers1 = detector.fingersUp(hand1)
      print(f'H1 = {fingers1.count(1)}', end=" ")# Print the count of fingers that are up

      # Calculate distance between specific landmarks on the first hand and draw it on the image
      length, info, img = detector.findDistance(lmList1, lmList1, img, color=(255, 0, 255),
                                                scale=10)

      # Check if a second hand is detected
      if len(hands) == 2:
            # Information for the second hand
            hand2 = hands
            lmList2 = hand2["lmList"]
            bbox2 = hand2["bbox"]
            center2 = hand2['center']
            handType2 = hand2["type"]

            # Count the number of fingers up for the second hand
            fingers2 = detector.fingersUp(hand2)
            print(f'H2 = {fingers2.count(1)}', end=" ")

            # Calculate distance between the index fingers of both hands and draw it on the image
            length, info, img = detector.findDistance(lmList1, lmList2, img, color=(255, 0, 0),
                                                      scale=10)
      length = int((length // 10) * 10 - 30)

      if length < 0: length = 0
      if length > 100: length = 100
      print(length)
      pwm0.write_analog(length)

    #lengthConverted = int(np.interp(length, , ))

    print(" ")# New line for better readability of the printed output

    # Display the image in a window
    cv2.imshow("Image", img)

    # Keep the window open and update it for each frame; wait for 1 millisecond between frames
    cv2.waitKey(1)

这个项目主要用食指和拇指的缩放来进行灯的明暗控制。软件控制硬件是用的DFRobot的pinpong库。感谢pinpong库,让我们能够完成软硬件互动项目。程序通过摄像头来对双手进行辨识。它会提取并且绘制手型框。它能识别左右手,用H1和H2表示。它可以识别手指。最关键是识别缩放。因为缩放是变量值。需要计算和公式才能达到我们的目的。
关于软件部分,我是参考了cvzone的官方手势识别案例,换句话说,人家把框架搭好了。我可以按照自己的意图去实现更个性化的目的。在这个案例里,我调用了pinpong库的pwm0函数功能。那问题来了。我怎么知道它的功能是怎么使用的呢?我是在下列地址找到了pinpong原始档案。https://pypi.org/project/pinpong/#files
找到pwm文件。------------------------------
根据下面两条语句:
from pinpong.board import Board,Pin #导入PWM类实现模拟输出
pwm0.write_analog(i) #设置模拟输出值
----------------------
从而知道了取值范围是0-100和模拟输出的值范围0-255,0-255也就是0-5V之间的电压。通过AD转换,就是0-1023.这个不断变化的值给到Arduino的PWM引脚,这个引脚通过了mosfet进行了放大。给到了12V的灯泡。于是呈现了我视频里要呈现的0-12V电压变压的效果。==========

[*]下面是官方提供的pinpong pwm源文件
# -*- coding: utf-8 -*-

#实验效果:使用按钮控制LED模块亮度
#接线:使用windows或linux电脑连接一块arduino主控板,主控板D6接一个LED灯模块
import time
from pinpong.board import Board,Pin #导入PWM类实现模拟输出

Board("uno").begin()#初始化,选择板型和端口号,不输入端口号则进行自动识别
#Board("uno","COM36").begin()#windows下指定端口初始化
#Board("uno","/dev/ttyACM0").begin()   #linux下指定端口初始化
#Board("uno","/dev/cu.usbmodem14101").begin()   #mac下指定端口初始化

pwm0 = Pin(Pin.D6, Pin.PWM)

while True:
for i in range(100): #从0到255循环
    pwm0.write_analog(i)#设置模拟输出值
    print(i)
    time.sleep(0.05)



[*]下面讲一讲场效应模块mosfet的连线方式。先看照片




[*]下面是连线图。
[*]从5V到12V,三极管已经无法应对,需要能应付大功率的场效应管登场了。灯泡选的是12V的灯泡。arduino uno无法直接点亮,它需要通过场效应管放大5V电压到12V才能实现。



[*]下面是场效应管模块原理图












页: [1]
查看完整版本: 用Mediapipe来通过手势实现灯光调光