OpenCV 手控光标(实现过程)

#第一版
import cv2
import mediapipe as mp

# 初始化MediaPipe手势识别模块
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
    static_image_mode=False,  # 实时视频流模式
    max_num_hands=2,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5
)
mp_drawing = mp.solutions.drawing_utils


# 手势判断函数应定义在循环外部
def is_fist(hand_landmarks):
    wrist = hand_landmarks.landmark[mp_hands.HandLandmark.WRIST]
    tips = [
        mp_hands.HandLandmark.THUMB_TIP,
        mp_hands.HandLandmark.INDEX_FINGER_TIP,
        mp_hands.HandLandmark.MIDDLE_FINGER_TIP,
        mp_hands.HandLandmark.RING_FINGER_TIP,
        mp_hands.HandLandmark.PINKY_TIP
    ]

    total_distance = 0
    for tip in tips:
        tip_point = hand_landmarks.landmark[tip]
        distance = ((tip_point.x - wrist.x) ** 2 + (tip_point.y - wrist.y) ** 2) ** 0.5
        total_distance += distance
    avg_distance = total_distance / len(tips)
    return avg_distance < 0.15  # 根据实际效果调整阈值


# 调用摄像头
cap = cv2.VideoCapture(0)

while cap.isOpened():
    success, frame = cap.read()
    if not success:
        break

    # 转换颜色空间
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = hands.process(rgb_frame)

    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 绘制关键点
            mp_drawing.draw_landmarks(
                frame, hand_landmarks, mp_hands.HAND_CONNECTIONS
            )

            # 调用手势判断函数并显示结果
            if is_fist(hand_landmarks):
                cv2.putText(frame, "Fist", (10, 50),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            else:
                cv2.putText(frame, "open", (10, 50),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    cv2.imshow('Hand Tracking', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

#第二版
import cv2
import mediapipe as mp
import math

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
with mp_hands.Hands(
        static_image_mode=False,
        max_num_hands=2,
        min_detection_confidence=0.7,
        min_tracking_confidence=0.5
) as hands:
    while cap.isOpened():
        success, frame = cap.read()
        if not success:
            break

        # 转换颜色空间并处理
        rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        results = hands.process(rgb_frame)

        if results.multi_hand_landmarks:
            for hand_landmarks in results.multi_hand_landmarks:
                # 绘制关键点(修复括号问题)
                mp_drawing.draw_landmarks(
                    frame,
                    hand_landmarks,
                    mp_hands.HAND_CONNECTIONS,
                    mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),  # 关键点
                    mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)  # 连接线
                )

                # ---------------------- 优化后的手指计数逻辑 ----------------------

                finger_count = 0
                h, w = frame.shape[:2]

                # 修复列表生成式括号问题
                landmark_points = [(int(lm.x * w), int(lm.y * h))
                                   for lm in hand_landmarks.landmark]

                # 拇指判断(优化角度计算)
                thumb_tip = landmark_points[mp_hands.HandLandmark.THUMB_TIP.value]
                thumb_ip = landmark_points[mp_hands.HandLandmark.THUMB_IP.value]
                thumb_mcp = landmark_points[mp_hands.HandLandmark.THUMB_MCP.value]

                # 向量点积计算角度(添加分母保护)
                vec1 = (thumb_ip[0] - thumb_mcp[0], thumb_ip[1] - thumb_mcp[1])
                vec2 = (thumb_tip[0] - thumb_ip[0], thumb_tip[1] - thumb_ip[1])
                dot_product = vec1[0] * vec2[0] + vec1[1] * vec2[1]
                denominator = (math.hypot(*vec1) * math.hypot(*vec2)) + 1e-6
                angle = math.degrees(math.acos(dot_product / denominator))

                # 其他手指判断(示例:食指)
                index_tip_y = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_TIP.value][1]
                index_pip_y = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_PIP.value][1]
                if index_tip_y < index_pip_y:  # 指尖在PIP关节上方
                    finger_count += 1
                index_tip_y1 = landmark_points[mp_hands.HandLandmark.MIDDLE_FINGER_TIP.value][1]
                index_pip_y1= landmark_points[mp_hands.HandLandmark.MIDDLE_FINGER_PIP.value][1]
                if index_tip_y1 < index_pip_y1:  # 指尖在PIP关节上方
                    finger_count += 1
                index_tip_y2= landmark_points[mp_hands.HandLandmark.RING_FINGER_TIP.value][1]
                index_pip_y2 = landmark_points[mp_hands.HandLandmark.RING_FINGER_PIP.value][1]
                if index_tip_y2 < index_pip_y2:  # 指尖在PIP关节上方
                    finger_count += 1

                # 显示计数结果
                cv2.putText(frame, f"Fingers: {finger_count}", (10, 30),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

        cv2.imshow('Hand Tracking', frame)
        cv2.imshow('Hand Tracking', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        if cv2.waitKey(5) & 0xFF == 27:
            break

cap.release()
cv2.destroyAllWindows()
#第三版
import cv2
import mediapipe as mp
import math

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
with mp_hands.Hands(
        static_image_mode=False,
        max_num_hands=2,
        min_detection_confidence=0.7,
        min_tracking_confidence=0.5
) as hands:
    while cap.isOpened():
        success, frame = cap.read()
        if not success:
            break

        # 转换颜色空间并处理
        rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        results = hands.process(rgb_frame)

        if results.multi_hand_landmarks:
            for hand_landmarks in results.multi_hand_landmarks:
                # 绘制关键点(修复括号问题)
                mp_drawing.draw_landmarks(
                    frame,
                    hand_landmarks,
                    mp_hands.HAND_CONNECTIONS,
                    mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),  # 关键点
                    mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)  # 连接线
                )

                # ---------------------- 优化后的手指计数逻辑 ----------------------

                finger_count1 = 0
                finger_count2= 0
                h, w = frame.shape[:2]

                # 修复列表生成式括号问题
                landmark_points = [(int(lm.x * w), int(lm.y * h))
                                   for lm in hand_landmarks.landmark]

                # 拇指判断(优化角度计算)
                thumb_tip = landmark_points[mp_hands.HandLandmark.THUMB_TIP.value]
                thumb_ip = landmark_points[mp_hands.HandLandmark.THUMB_IP.value]
                thumb_mcp = landmark_points[mp_hands.HandLandmark.THUMB_MCP.value]

                # 向量点积计算角度(添加分母保护)
                vec1 = (thumb_ip[0] - thumb_mcp[0], thumb_ip[1] - thumb_mcp[1])
                vec2 = (thumb_tip[0] - thumb_ip[0], thumb_tip[1] - thumb_ip[1])
                dot_product = vec1[0] * vec2[0] + vec1[1] * vec2[1]
                denominator = (math.hypot(*vec1) * math.hypot(*vec2)) + 1e-6
                angle = math.degrees(math.acos(dot_product / denominator))

                # 其他手指判断(示例:食指)

                index_tip_y = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_TIP.value][1]
                index_pip_y = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_PIP.value][1]
                if index_tip_y < index_pip_y:  # 指尖在PIP关节上方
                    finger_count1 += 1
                index_tip_y1 = landmark_points[mp_hands.HandLandmark.MIDDLE_FINGER_TIP.value][1]
                index_pip_y1= landmark_points[mp_hands.HandLandmark.MIDDLE_FINGER_PIP.value][1]
                if index_tip_y1 < index_pip_y1:  # 指尖在PIP关节上方
                    finger_count2 += 1

                # 显示计数结果
                cv2.putText(frame, f"index: {finger_count1}", (10, 30),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
                cv2.putText(frame, f"middle: {finger_count2}", (10, 60),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
        cv2.imshow('Hand Tracking', frame)
        # cv2.imshow('Hand Tracking', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        if cv2.waitKey(5) & 0xFF == 27:
            break

cap.release()
cv2.destroyAllWindows()

#第四版
import cv2
import mediapipe as mp
import math

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
with mp_hands.Hands(
        static_image_mode=False,
        max_num_hands=2,
        min_detection_confidence=0.7,
        min_tracking_confidence=0.5
) as hands:
    while cap.isOpened():
        success, frame = cap.read()
        if not success:
            break

        # 转换颜色空间并处理
        rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        results = hands.process(rgb_frame)

        if results.multi_hand_landmarks:
            for hand_index, hand_landmarks in enumerate(results.multi_hand_landmarks):
                # 获取手部标签(左手或右手)
                handedness = results.multi_handedness[hand_index].classification[0].label

                # 绘制关键点
                mp_drawing.draw_landmarks(
                    frame,
                    hand_landmarks,
                    mp_hands.HAND_CONNECTIONS,
                    mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),  # 关键点
                    mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)  # 连接线
                )

                # 初始化手指计数
                finger_count = 0
                h, w = frame.shape[:2]

                # 获取所有关键点的像素坐标
                landmark_points = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]

                # ---------------------- 大拇指判断优化 ----------------------
                thumb_tip = landmark_points[mp_hands.HandLandmark.THUMB_TIP.value]
                thumb_ip = landmark_points[mp_hands.HandLandmark.THUMB_IP.value]
                thumb_mcp = landmark_points[mp_hands.HandLandmark.THUMB_MCP.value]

                # 判断大拇指是否伸展
                if handedness == "Right":
                    # 对于右手,如果 TIP 在 MCP 的左侧,则认为大拇指是伸展的
                    if thumb_tip[0] < thumb_mcp[0]:
                        finger_count += 1
                else:
                    # 对于左手,如果 TIP 在 MCP 的右侧,则认为大拇指是伸展的
                    if thumb_tip[0] > thumb_mcp[0]:
                        finger_count += 1

                # ---------------------- 其他手指判断 ----------------------
                fingers = [
                    mp_hands.HandLandmark.INDEX_FINGER_TIP,
                    mp_hands.HandLandmark.MIDDLE_FINGER_TIP,
                    mp_hands.HandLandmark.RING_FINGER_TIP,
                    mp_hands.HandLandmark.PINKY_TIP
                ]
                for finger in fingers:
                    tip_y = landmark_points[finger.value][1]
                    pip_y = landmark_points[finger.value - 2][1]  # PIP关节是TIP的前两个点
                    if tip_y < pip_y:  # 指尖在PIP关节上方
                        finger_count += 1

                # 显示计数结果
                if handedness == "Right":
                    y = 30  # 右手结果显示在 y=40 的位置
                else:
                    y = 70  # 左手结果显示在 y=60 的位置

                cv2.putText(frame, f"{handedness} Hand: {finger_count}", (10, y),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

        # 显示画面
        cv2.imshow('Hand Tracking', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

cap.release()
cv2.destroyAllWindows()
#---------------------------------------------------------------------------------------------------------------------------
#第五版
import cv2
import mediapipe as mp
import pyautogui
import math
import time
import threading

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)  # 降低分辨率以提高帧率
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 设置窗口名称并调整窗口大小
cv2.namedWindow('Hand Gesture Control', cv2.WINDOW_NORMAL)
cv2.resizeWindow('Hand Gesture Control', 640, 480)  # 设置窗口大小为 1280x720

# 初始化pyautogui
pyautogui.FAILSAFE = False  # 禁用pyautogui的故障保护功能

# 全局变量用于多线程
frame = None
results = None
fps = 0

# 图像捕获线程
def capture_frame():
    global frame
    while cap.isOpened():
        success, img = cap.read()
        if not success:
            break
        frame = img  # 更新全局帧

# 图像处理线程
def process_frame():
    global results, fps
    with mp_hands.Hands(
            static_image_mode=False,
            max_num_hands=1,  # 只检测一只手
            min_detection_confidence=0.7,
            min_tracking_confidence=0.5
    ) as hands:
        while cap.isOpened():
            if frame is None:
                continue

            # 镜像模式:水平翻转帧
            flipped_frame = cv2.flip(frame, 1)

            # 转换颜色空间并处理
            rgb_frame = cv2.cvtColor(flipped_frame, cv2.COLOR_BGR2RGB)
            start_time = time.time()
            results = hands.process(rgb_frame)
            end_time = time.time()

            # 计算FPS
            fps = 1 / (end_time - start_time)

# 启动图像捕获线程
capture_thread = threading.Thread(target=capture_frame)
capture_thread.daemon = True
capture_thread.start()

# 启动图像处理线程
process_thread = threading.Thread(target=process_frame)
process_thread.daemon = True
process_thread.start()

while cap.isOpened():
    if frame is None or results is None:
        continue

    # 镜像模式:水平翻转帧
    flipped_frame = cv2.flip(frame, 1)

    # 绘制手势识别结果
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 绘制关键点
            mp_drawing.draw_landmarks(
                flipped_frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),  # 关键点
                mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)  # 连接线
            )

            # 获取所有关键点的像素坐标
            h, w = flipped_frame.shape[:2]
            landmark_points = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]

            # 获取关键点坐标
            thumb_tip = landmark_points[mp_hands.HandLandmark.THUMB_TIP.value]
            index_tip = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_TIP.value]
            middle_tip = landmark_points[mp_hands.HandLandmark.MIDDLE_FINGER_TIP.value]
            ring_tip = landmark_points[mp_hands.HandLandmark.RING_FINGER_TIP.value]
            pinky_tip = landmark_points[mp_hands.HandLandmark.PINKY_TIP.value]
            wrist = landmark_points[mp_hands.HandLandmark.WRIST.value]

            # 计算手指是否伸展
            fingers = [
                (index_tip[1] < landmark_points[mp_hands.HandLandmark.INDEX_FINGER_PIP.value][1]),  # 食指
                (middle_tip[1] < landmark_points[mp_hands.HandLandmark.MIDDLE_FINGER_PIP.value][1]),  # 中指
                (ring_tip[1] < landmark_points[mp_hands.HandLandmark.RING_FINGER_PIP.value][1]),  # 无名指
                (pinky_tip[1] < landmark_points[mp_hands.HandLandmark.PINKY_PIP.value][1])  # 小指
            ]

            # 判断手势
            if all(fingers):  # 所有手指都伸展(手掌张开)
                # 模拟鼠标移动
                x, y = index_tip[0], index_tip[1]
                screen_width, screen_height = pyautogui.size()
                target_x = int((x / w) * screen_width)
                target_y = int((y / h) * screen_height)
                pyautogui.moveTo(target_x, target_y, duration=0.1)
                cv2.putText(flipped_frame, "Mouse Move", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

            elif not any(fingers):  # 所有手指都弯曲(握拳)
                # 模拟鼠标左键点击
                pyautogui.click()
                cv2.putText(flipped_frame, "Click", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

            elif fingers[0] and not any(fingers[1:]):  # 只有食指伸展
                # 模拟按下空格键
                pyautogui.press('space')
                cv2.putText(flipped_frame, "Space", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

            elif not fingers[0] and not fingers[1] and not fingers[2] and fingers[3]:  # 只有大拇指伸展
                # 模拟按下Alt+Tab切换窗口
                pyautogui.hotkey('alt', 'tab')
                cv2.putText(flipped_frame, "Alt+Tab", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 显示FPS
    cv2.putText(flipped_frame, f"FPS: {int(fps)}", (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 显示画面
    cv2.imshow('Hand Gesture Control', flipped_frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
#----------------------------------------------------------------------------------------------------------------------------
#第六版
import cv2
import mediapipe as mp
import pyautogui
import time
import threading

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)  # 降低分辨率以提高帧率
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 设置窗口名称并调整窗口大小
cv2.namedWindow('Hand Gesture Control', cv2.WINDOW_NORMAL)
cv2.resizeWindow('Hand Gesture Control', 640, 480)  # 设置窗口大小为 1280x720

# 初始化pyautogui
pyautogui.FAILSAFE = False  # 禁用pyautogui的故障保护功能

# 全局变量用于多线程
frame = None
results = None
fps = 0

# 初始化点击时间记录
last_click_time = 0

# 图像捕获线程
def capture_frame():
    global frame
    while cap.isOpened():
        success, img = cap.read()
        if not success:
            break
        frame = img  # 更新全局帧

# 图像处理线程
def process_frame():
    global results, fps
    with mp_hands.Hands(
            static_image_mode=False,
            max_num_hands=1,  # 只检测一只手
            min_detection_confidence=0.7,
            min_tracking_confidence=0.5
    ) as hands:
        while cap.isOpened():
            if frame is None:
                continue

            # 镜像模式:水平翻转帧
            flipped_frame = cv2.flip(frame, 1)

            # 转换颜色空间并处理
            rgb_frame = cv2.cvtColor(flipped_frame, cv2.COLOR_BGR2RGB)
            start_time = time.time()
            results = hands.process(rgb_frame)
            end_time = time.time()

            # 计算FPS
            fps = 1 / (end_time - start_time)

# 启动图像捕获线程
capture_thread = threading.Thread(target=capture_frame)
capture_thread.daemon = True
capture_thread.start()

# 启动图像处理线程
process_thread = threading.Thread(target=process_frame)
process_thread.daemon = True
process_thread.start()

while cap.isOpened():
    if frame is None or results is None:
        continue

    # 镜像模式:水平翻转帧
    flipped_frame = cv2.flip(frame, 1)

    # 绘制手势识别结果
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 绘制关键点
            mp_drawing.draw_landmarks(
                flipped_frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),  # 关键点
                mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)  # 连接线
            )

            # 获取所有关键点的像素坐标
            h, w = flipped_frame.shape[:2]
            landmark_points = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]

            # 获取关键点坐标
            index_tip = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_TIP.value]
            index_pip = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_PIP.value]

            # 判断食指是否伸展
            if index_tip[1] < index_pip[1]:  # 食指伸展
                # 模拟鼠标移动
                x, y = index_tip[0], index_tip[1]
                screen_width, screen_height = pyautogui.size()
                target_x = int((x / w) * screen_width)
                target_y = int((y / h) * screen_height)
                pyautogui.moveTo(target_x, target_y, duration=0.1)
                cv2.putText(flipped_frame, "Mouse Move", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            else:  # 食指弯曲
                current_time = time.time()
                if current_time - last_click_time > 0.5:  # 每隔 0.5 秒才触发一次点击
                    # 模拟鼠标左键点击
                    pyautogui.click()
                    last_click_time = current_time  # 更新上次点击时间
                    cv2.putText(flipped_frame, "Click", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 显示FPS
    cv2.putText(flipped_frame, f"FPS: {int(fps)}", (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 显示画面
    cv2.imshow('Hand Gesture Control', flipped_frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
#-------------------------------------------------------------------------------------------------------------------------------
#第七版
import cv2
import mediapipe as mp
import pyautogui
import time
import threading
from collections import deque

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)  # 提高分辨率
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 初始化pyautogui
pyautogui.FAILSAFE = False  # 禁用pyautogui的故障保护功能

# 全局变量用于多线程
frame = None
results = None
fps = 0

# 初始化点击时间记录
last_click_time = 0

# 防抖参数
smooth_factor = 5  # 移动平均滤波的帧数
position_history = deque(maxlen=smooth_factor)  # 用于存储历史位置
dead_zone_threshold = 10  # 死区阈值,小于该值的移动将被忽略

# 图像捕获线程
def capture_frame():
    global frame
    while cap.isOpened():
        success, img = cap.read()
        if not success:
            break
        frame = img  # 更新全局帧

# 图像处理线程
def process_frame():
    global results, fps
    with mp_hands.Hands(
            static_image_mode=False,
            max_num_hands=1,  # 只检测一只手
            min_detection_confidence=0.7,
            min_tracking_confidence=0.5
    ) as hands:
        while cap.isOpened():
            if frame is None:
                continue

            # 关闭镜像模式
            flipped_frame = cv2.flip(frame, 1)  # 直接使用原始帧

            # 转换颜色空间并处理
            rgb_frame = cv2.cvtColor(flipped_frame, cv2.COLOR_BGR2RGB)
            start_time = time.time()
            results = hands.process(rgb_frame)
            end_time = time.time()

            # 计算FPS
            fps = 1 / (end_time - start_time)

# 启动图像捕获线程
capture_thread = threading.Thread(target=capture_frame)
capture_thread.daemon = True
capture_thread.start()

# 启动图像处理线程
process_thread = threading.Thread(target=process_frame)
process_thread.daemon = True
process_thread.start()

while cap.isOpened():
    if frame is None or results is None:
        continue

    # 关闭镜像模式
    flipped_frame = frame  # 直接使用原始帧

    # 绘制手势识别结果
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 绘制关键点
            mp_drawing.draw_landmarks(
                flipped_frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),  # 关键点
                mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)  # 连接线
            )

            # 获取所有关键点的像素坐标
            h, w = flipped_frame.shape[:2]
            landmark_points = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]

            # 获取关键点坐标
            index_tip = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_TIP.value]
            index_pip = landmark_points[mp_hands.HandLandmark.INDEX_FINGER_PIP.value]

            # 判断食指是否伸展
            if index_tip[1] < index_pip[1]:  # 食指伸展
                # 模拟鼠标移动
                x, y = index_tip[0], index_tip[1]
                screen_width, screen_height = pyautogui.size()

                # 缩放因子,用于放大控制范围
                scale_factor = 1.5  # 例如,放大2倍

                # 计算目标鼠标位置
                target_x = int((x / w) * screen_width * scale_factor)
                target_y = int((y / h) * screen_height * scale_factor)

                # 确保目标位置在屏幕范围内
                target_x = max(0, min(target_x, screen_width - 1))
                target_y = max(0, min(target_y, screen_height - 1))

                # 添加当前位置到历史记录
                position_history.append((target_x, target_y))

                # 计算移动平均值
                if len(position_history) == smooth_factor:
                    avg_x = sum(p[0] for p in position_history) / smooth_factor
                    avg_y = sum(p[1] for p in position_history) / smooth_factor

                    # 死区控制:忽略微小移动
                    if abs(avg_x - target_x) > dead_zone_threshold or abs(avg_y - target_y) > dead_zone_threshold:
                        pyautogui.moveTo(int(avg_x), int(avg_y), duration=0.1)
                        cv2.putText(flipped_frame, "Mouse Move", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            else:  # 食指弯曲
                current_time = time.time()
                if current_time - last_click_time > 0.5:  # 每隔 0.5 秒才触发一次点击
                    # 模拟鼠标左键点击
                    pyautogui.click()
                    last_click_time = current_time  # 更新上次点击时间
                    cv2.putText(flipped_frame, "Click", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 显示FPS
    cv2.putText(flipped_frame, f"FPS: {int(fps)}", (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 显示画面
    cv2.imshow('Hand Gesture Control', flipped_frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
#-----------------------------------------------------------------------------------------------------------------------
#第八版
import cv2
import mediapipe as mp
import pyautogui
import time
import threading
from collections import deque

# 初始化MediaPipe手势模块
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils

# 配置摄像头
cap = cv2.VideoCapture(0)
if not cap.isOpened():
    raise Exception("无法打开摄像头,请检查摄像头连接。")

cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 初始化pyautogui
pyautogui.FAILSAFE = False  # 禁用故障保护

# 全局变量与线程锁
frame = None
results = None
fps = 0
frame_lock = threading.Lock()
results_lock = threading.Lock()

# 控制板参数
control_board_width = 400  # 控制板宽度
control_board_height = 300  # 控制板高度
control_board_x = 100  # 控制板左上角x坐标
control_board_y = 100  # 控制板左上角y坐标

# 防抖参数
smooth_factor = 5
position_history = deque(maxlen=smooth_factor)
dead_zone_threshold = 10

# 图像捕获线程
def capture_frame():
    global frame
    while cap.isOpened():
        success, img = cap.read()
        if not success:
            print("警告: 无法读取摄像头帧")
            break
        with frame_lock:
            frame = img

# 图像处理线程
def process_frame():
    global results, fps
    with mp_hands.Hands(
        static_image_mode=False,
        max_num_hands=1,
        min_detection_confidence=0.7,
        min_tracking_confidence=0.5
    ) as hands:
        while cap.isOpened():
            # 获取并翻转帧
            with frame_lock:
                if frame is None:
                    continue
                working_frame = cv2.flip(frame, 1)

            # 处理手势识别
            rgb_frame = cv2.cvtColor(working_frame, cv2.COLOR_BGR2RGB)
            start_time = time.time()
            processed_results = hands.process(rgb_frame)
            end_time = time.time()

            # 更新结果
            with results_lock:
                results = processed_results
                fps = 1 / (end_time - start_time)

# 启动线程
capture_thread = threading.Thread(target=capture_frame, daemon=True)
process_thread = threading.Thread(target=process_frame, daemon=True)
capture_thread.start()
process_thread.start()

try:
    while cap.isOpened():
        # 获取当前帧
        with frame_lock:
            if frame is None:
                continue
            display_frame = cv2.flip(frame, 1).copy()

        # 获取处理结果
        with results_lock:
            current_results = results
            current_fps = fps

        # 绘制控制板区域
        cv2.rectangle(display_frame,
                      (control_board_x, control_board_y),
                      (control_board_x + control_board_width, control_board_y + control_board_height),
                      (0, 255, 0), 2)

        # 手势识别处理
        if current_results and current_results.multi_hand_landmarks:
            for hand_landmarks in current_results.multi_hand_landmarks:
                # 绘制关键点
                mp_drawing.draw_landmarks(
                    display_frame,
                    hand_landmarks,
                    mp_hands.HAND_CONNECTIONS,
                    mp_drawing.DrawingSpec(color=(0,255,0), thickness=2),  # 关键点
                    mp_drawing.DrawingSpec(color=(0,0,255), thickness=2)   # 连接线
                )

                # 获取食指坐标
                h, w = display_frame.shape[:2]
                landmarks = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]
                tip = landmarks[mp_hands.HandLandmark.INDEX_FINGER_TIP]

                # 检查食指是否在控制板区域内
                if (control_board_x <= tip[0] <= control_board_x + control_board_width and
                    control_board_y <= tip[1] <= control_board_y + control_board_height):
                    # 计算控制板内相对位置
                    relative_x = tip[0] - control_board_x
                    relative_y = tip[1] - control_board_y

                    # 计算屏幕坐标
                    screen_w, screen_h = pyautogui.size()
                    target_x = int((relative_x / control_board_width) * screen_w)
                    target_y = int((relative_y / control_board_height) * screen_h)

                    # 防抖处理
                    position_history.append((target_x, target_y))
                    if len(position_history) == smooth_factor:
                        avg_x = sum(p[0] for p in position_history) // smooth_factor
                        avg_y = sum(p[1] for p in position_history) // smooth_factor

                        # 死区控制:忽略微小移动
                        if abs(avg_x - target_x) > dead_zone_threshold or \
                           abs(avg_y - target_y) > dead_zone_threshold:
                            pyautogui.moveTo(avg_x, avg_y, duration=0.1)
                            cv2.putText(display_frame, "Moving", (10,50),
                                      cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)

        # 显示FPS
        cv2.putText(display_frame, f"FPS: {int(current_fps)}", (10,100),
                  cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)

        # 显示窗口
        cv2.imshow('Gesture Mouse Control', display_frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

except Exception as e:
    print(f"程序异常: {e}")

finally:
    cap.release()
    cv2.destroyAllWindows()
    print("程序已正常退出")
#---------------------------------------------------------------------------------------------------------------------------
#第九版
import cv2
import mediapipe as mp
import pyautogui
import time
import threading
from collections import deque
import math

class GestureMouseControl:
    def __init__(self):
        self.cap = cv2.VideoCapture(0)
        if not self.cap.isOpened():
            raise Exception("无法打开摄像头,请检查摄像头连接。")

        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        self.mp_hands = mp.solutions.hands
        self.mp_drawing = mp.solutions.drawing_utils
        self.hands = self.mp_hands.Hands(
            static_image_mode=False,
            max_num_hands=1,
            min_detection_confidence=0.7,
            min_tracking_confidence=0.5
        )

        self.frame = None
        self.results = None
        self.fps = 0
        self.frame_lock = threading.Lock()
        self.results_lock = threading.Lock()

        # 控制板参数
        self.control_board_width = 340
        self.control_board_height = 240
        self.control_board_x = 150
        self.control_board_y = 130

        # 边缘缓冲区域宽度
        self.edge_buffer = 50

        self.smooth_factor = 5
        self.position_history = deque(maxlen=self.smooth_factor)
        self.dead_zone_threshold = 10

        # 点击阈值(手指距离小于该值时触发点击)
        self.click_threshold = 30
        # 防抖标志
        self.left_clicked = False
        self.right_clicked = False

        self.running = True

        # 平滑滤波参数
        self.smoothing_factor = 0.5
        self.last_x, self.last_y = pyautogui.position()

    def capture_frame(self):
        while self.running:
            success, img = self.cap.read()
            if not success:
                print("警告: 无法读取摄像头帧")
                break
            with self.frame_lock:
                self.frame = img

    def process_frame(self):
        while self.running:
            with self.frame_lock:
                if self.frame is None:
                    continue
                working_frame = cv2.flip(self.frame, 1)

            rgb_frame = cv2.cvtColor(working_frame, cv2.COLOR_BGR2RGB)
            start_time = time.time()
            processed_results = self.hands.process(rgb_frame)
            end_time = time.time()

            with self.results_lock:
                self.results = processed_results
                self.fps = 1 / (end_time - start_time)

    def run(self):
        capture_thread = threading.Thread(target=self.capture_frame, daemon=True)
        process_thread = threading.Thread(target=self.process_frame, daemon=True)
        capture_thread.start()
        process_thread.start()

        try:
            while self.running:
                with self.frame_lock:
                    if self.frame is None:
                        continue
                    display_frame = cv2.flip(self.frame, 1).copy()

                with self.results_lock:
                    current_results = self.results
                    current_fps = self.fps

                self.draw_control_board(display_frame)
                self.process_gestures(display_frame, current_results)
                self.display_fps(display_frame, current_fps)

                cv2.imshow('Gesture Mouse Control', display_frame)
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    self.running = False

        except Exception as e:
            print(f"程序异常: {e}")

        finally:
            self.cap.release()
            cv2.destroyAllWindows()
            print("程序已正常退出")

    def draw_control_board(self, frame):
        # 绘制控制板
        cv2.rectangle(frame,
                      (self.control_board_x, self.control_board_y),
                      (self.control_board_x + self.control_board_width, self.control_board_y + self.control_board_height),
                      (0, 255, 0), 2)

        # 绘制边缘缓冲区域
        cv2.rectangle(frame,
                      (self.control_board_x - self.edge_buffer, self.control_board_y - self.edge_buffer),
                      (self.control_board_x + self.control_board_width + self.edge_buffer, self.control_board_y + self.control_board_height + self.edge_buffer),
                      (0, 0, 255), 1)

    def process_gestures(self, frame, results):
        if results and results.multi_hand_landmarks:
            for hand_landmarks in results.multi_hand_landmarks:
                self.draw_landmarks(frame, hand_landmarks)
                self.move_mouse(frame, hand_landmarks)
                self.detect_clicks(frame, hand_landmarks)

    def draw_landmarks(self, frame, hand_landmarks):
        self.mp_drawing.draw_landmarks(
            frame,
            hand_landmarks,
            self.mp_hands.HAND_CONNECTIONS,
            self.mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2),
            self.mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)
        )

    def move_mouse(self, frame, hand_landmarks):
        h, w = frame.shape[:2]
        landmarks = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]
        tip = landmarks[self.mp_hands.HandLandmark.INDEX_FINGER_TIP]

        # 检查手指是否在控制板或边缘缓冲区域内
        if (self.control_board_x - self.edge_buffer <= tip[0] <= self.control_board_x + self.control_board_width + self.edge_buffer and
            self.control_board_y - self.edge_buffer <= tip[1] <= self.control_board_y + self.control_board_height + self.edge_buffer):

            # 计算相对位置(包括缓冲区域)
            relative_x = tip[0] - (self.control_board_x - self.edge_buffer)
            relative_y = tip[1] - (self.control_board_y - self.edge_buffer)

            # 计算目标位置
            screen_w, screen_h = pyautogui.size()
            target_x = int((relative_x / (self.control_board_width + 2 * self.edge_buffer)) * screen_w)
            target_y = int((relative_y / (self.control_board_height + 2 * self.edge_buffer)) * screen_h)

            # 使用指数平滑滤波
            smoothed_x = self.last_x + self.smoothing_factor * (target_x - self.last_x)
            smoothed_y = self.last_y + self.smoothing_factor * (target_y - self.last_y)

            self.last_x, self.last_y = smoothed_x, smoothed_y

            # 检查是否超过死区阈值
            if abs(smoothed_x - target_x) > self.dead_zone_threshold or \
               abs(smoothed_y - target_y) > self.dead_zone_threshold:
                pyautogui.moveTo(int(smoothed_x), int(smoothed_y), duration=0.1)
                cv2.putText(frame, "Moving", (10, 50),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    def detect_clicks(self, frame, hand_landmarks):
        h, w = frame.shape[:2]
        landmarks = [(int(lm.x * w), int(lm.y * h)) for lm in hand_landmarks.landmark]

        # 获取指尖坐标
        index_tip = landmarks[self.mp_hands.HandLandmark.INDEX_FINGER_TIP]
        thumb_tip = landmarks[self.mp_hands.HandLandmark.THUMB_TIP]
        middle_tip = landmarks[self.mp_hands.HandLandmark.MIDDLE_FINGER_TIP]

        # 计算食指和拇指的距离
        index_thumb_distance = math.hypot(index_tip[0] - thumb_tip[0], index_tip[1] - thumb_tip[1])
        # 计算中指和拇指的距离
        middle_thumb_distance = math.hypot(middle_tip[0] - thumb_tip[0], middle_tip[1] - thumb_tip[1])

        # 左键点击(食指和拇指接触)
        if index_thumb_distance < self.click_threshold:
            if not self.left_clicked:
                pyautogui.click(button='left')
                self.left_clicked = True
                cv2.putText(frame, "Left Click", (10, 150),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        else:
            self.left_clicked = False

        # 右键点击(中指和拇指接触)
        if middle_thumb_distance < self.click_threshold:
            if not self.right_clicked:
                pyautogui.click(button='right')
                self.right_clicked = True
                cv2.putText(frame, "Right Click", (10, 200),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        else:
            self.right_clicked = False

    def display_fps(self, frame, fps):
        cv2.putText(frame, f"FPS: {int(fps)}", (10, 100),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

if __name__ == "__main__":
    gesture_mouse_control = GestureMouseControl()
    gesture_mouse_control.run()

免责:中间代码可能有错误(新人创作,轻点喷)

安装库可以转上一篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值