<<< 向左挥动: 后退
<<< 向左挥动: 后退
<<< 向左挥动: 后退
向右挥动: 前进
<<< 向左挥动: 后退
<<< 向左挥动: 后退
<<< 向左挥动: 后退
<<< 向左挥动: 后退
<<< 向左挥动: 后退
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
<<< 向左挥动: 后退
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
向右挥动: 前进
<<< 向左挥动: 后退
<<< 向左挥动: 后退
import cv2
import mediapipe as mp
import pyautogui
import time
import math
# ================= 配置区域 =================
# 动作灵敏度 (0.05 - 0.2 之间,越小越灵敏)
SWIPE_THRESHOLD = 0.10
# 两次动作之间的冷却时间 (秒),防止一次挥动触发多次翻页
COOLDOWN_TIME = 1.0
# 浏览器快捷键映射
KEY_BACK = ['alt', 'left'] # Chrome 后退 (上一页)
KEY_FORWARD = ['alt', 'right'] # Chrome 前进 (下一页)
# ===========================================
class HandController:
def __init__(self):
# 初始化 MediaPipe Hands
self.mp_hands = mp.solutions.hands
self.hands = self.mp_hands.Hands(
max_num_hands=1,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
self.mp_draw = mp.solutions.drawing_utils
# 状态变量
self.prev_x = None # 上一帧的食指尖 X 坐标
self.last_action_time = 0 # 上次触发动作的时间
self.action_text = "" # 屏幕上显示的提示文字
self.action_display_timer = 0 # 文字显示计时器
def detect_gesture(self, landmarks):
"""
检测挥动手势
landmarks: 手部关键点列表
"""
current_time = time.time()
# 获取食指指尖 (关键点 8) 的 X 坐标 (范围 0.0 - 1.0)
# 0.0 是屏幕左侧,1.0 是屏幕右侧
index_finger_tip = landmarks.landmark[8]
curr_x = index_finger_tip.x
# 如果还在冷却时间内,只更新坐标,不触发动作
if current_time - self.last_action_time < COOLDOWN_TIME:
self.prev_x = curr_x
return
if self.prev_x is not None:
# 计算移动距离
diff_x = curr_x - self.prev_x
# 判断移动幅度和方向
# 向右挥动 (diff_x > 0) -> 前进
if diff_x > SWIPE_THRESHOLD:
print(">>> 向右挥动: 前进")
pyautogui.hotkey(*KEY_FORWARD)
self.last_action_time = current_time
self.action_text = "Next Page >"
self.action_display_timer = 30 # 显示约1秒(30帧)
# 向左挥动 (diff_x < 0) -> 后退
elif diff_x < -SWIPE_THRESHOLD:
print("<<< 向左挥动: 后退")
pyautogui.hotkey(*KEY_BACK)
self.last_action_time = current_time
self.action_text = "< Previous Page"
self.action_display_timer = 30
# 更新上一帧坐标
self.prev_x = curr_x
def start(self):
# 打开摄像头
cap = cv2.VideoCapture(0)
# 设置分辨率 (降低分辨率可以提高处理速度)
cap.set(3, 640)
cap.set(4, 480)
print("程序已启动!请将焦点切换到 Google Chrome 浏览器。")
print("操作说明: 食指快速向左挥动 -> 后退,向右挥动 -> 前进")
print("按 'q' 键退出程序")
while True:
success, img = cap.read()
if not success:
break
# 1. 镜像翻转图像 (让画面看起来像照镜子,符合直觉)
img = cv2.flip(img, 1)
# 2. 转换颜色空间 BGR -> RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 3. 处理手部检测
results = self.hands.process(img_rgb)
if results.multi_hand_landmarks:
for hand_lms in results.multi_hand_landmarks:
# 绘制手部骨架
self.mp_draw.draw_landmarks(img, hand_lms, self.mp_hands.HAND_CONNECTIONS)
# 检测手势
self.detect_gesture(hand_lms)
else:
# 如果没检测到手,重置位置,防止手重新出现时误判
self.prev_x = None
# 4. 在屏幕上显示反馈文字
if self.action_display_timer > 0:
cv2.putText(img, self.action_text, (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
self.action_display_timer -= 1
# 显示冷却状态
if time.time() - self.last_action_time < COOLDOWN_TIME:
cv2.circle(img, (30, 30), 10, (0, 0, 255), -1) # 红点表示冷却中
else:
cv2.circle(img, (30, 30), 10, (0, 255, 0), -1) # 绿点表示就绪
# 显示图像
cv2.imshow("Chrome Hand Controller", img)
# 按 'q' 退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
controller = HandController()
controller.start()
import cv2
import mediapipe as mp
import pyautogui
import time
import numpy as np
# ================= 配置区域 =================
# 动作灵敏度 (0.05 - 0.2 之间,越小越灵敏)
SWIPE_THRESHOLD = 0.07
# 两次动作之间的冷却时间 (秒),防止一次挥动触发多次翻页
COOLDOWN_TIME = 1.0
# 浏览器快捷键映射
KEY_BACK = ['alt', 'left'] # Chrome 后退 (上一页)
KEY_FORWARD = ['alt', 'right'] # Chrome 前进 (下一页)
# ===========================================
class HandController:
def __init__(self):
# 初始化 MediaPipe Hands
self.mp_hands = mp.solutions.hands
self.hands = self.mp_hands.Hands(
max_num_hands=1,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
self.mp_draw = mp.solutions.drawing_utils
# 状态变量
self.prev_x = None # 上一帧的食指尖 X 坐标
self.last_action_time = 0 # 上次触发动作的时间
self.action_text = "" # 屏幕上显示的提示文字
self.action_display_timer = 0 # 文字显示计时器
def detect_gesture(self, landmarks):
"""
检测挥动手势
landmarks: 手部关键点列表
"""
current_time = time.time()
# 获取食指指尖 (关键点 8) 的 X 坐标 (范围 0.0 - 1.0)
# 0.0 是屏幕左侧,1.0 是屏幕右侧
index_finger_tip = landmarks.landmark[8]
curr_x = index_finger_tip.x
# 如果还在冷却时间内,只更新坐标,不触发动作
if current_time - self.last_action_time < COOLDOWN_TIME:
self.prev_x = curr_x
return
if self.prev_x is not None:
# 计算移动距离
diff_x = curr_x - self.prev_x
# 判断移动幅度和方向
# 向右挥动 (diff_x > 0) -> 前进
if diff_x > SWIPE_THRESHOLD:
print(">>> 向右挥动: 前进")
pyautogui.hotkey(*KEY_FORWARD)
self.last_action_time = current_time
self.action_text = "Next Page >"
self.action_display_timer = 30 # 显示约1秒(30帧)
# 向左挥动 (diff_x < 0) -> 后退
elif diff_x < -SWIPE_THRESHOLD:
print("<<< 向左挥动: 后退")
pyautogui.hotkey(*KEY_BACK)
self.last_action_time = current_time
self.action_text = "< Previous Page"
self.action_display_timer = 30
# 更新上一帧坐标
self.prev_x = curr_x
def start(self):
# 打开摄像头
cap = cv2.VideoCapture(0)
# 设置分辨率 (降低分辨率可以提高处理速度)
cap.set(3, 640)
cap.set(4, 480)
print("程序已启动!请将焦点切换到 Google Chrome 浏览器。")
print("操作说明: 食指快速向左挥动 -> 后退,向右挥动 -> 前进")
print("按 'q' 键退出程序")
while True:
success, img = cap.read()
if not success:
break
# 1. 镜像翻转图像 (让画面看起来像照镜子,符合直觉)
img = cv2.flip(img, 1)
# 2. 创建一个纯色背景(黑色)
height, width = img.shape[:2]
display_img = np.zeros((height, width, 3), dtype=np.uint8) # 黑色背景
# 3. 转换颜色空间 BGR -> RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 4. 处理手部检测
results = self.hands.process(img_rgb)
if results.multi_hand_landmarks:
for hand_lms in results.multi_hand_landmarks:
# 在黑色背景上绘制手部骨架
self.mp_draw.draw_landmarks(
display_img,
hand_lms,
self.mp_hands.HAND_CONNECTIONS,
landmark_drawing_spec=mp.solutions.drawing_utils.DrawingSpec(
color=(0, 255, 0), thickness=2 # 关键点为绿色
),
connection_drawing_spec=mp.solutions.drawing_utils.DrawingSpec(
color=(255, 0, 0), thickness=2 # 连接线为蓝色
)
)
# 检测手势
self.detect_gesture(hand_lms)
else:
# 如果没检测到手,重置位置,防止手重新出现时误判
self.prev_x = None
# 5. 在屏幕上显示反馈文字
if self.action_display_timer > 0:
cv2.putText(display_img, self.action_text, (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
self.action_display_timer -= 1
# 显示冷却状态
if time.time() - self.last_action_time < COOLDOWN_TIME:
cv2.circle(display_img, (30, 30), 10, (0, 0, 255), -1) # 红点表示冷却中
cv2.putText(display_img, "Cooling", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
else:
cv2.circle(display_img, (30, 30), 10, (0, 255, 0), -1) # 绿点表示就绪
cv2.putText(display_img, "Ready", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# 显示操作提示
cv2.putText(display_img, "Swipe Left: Back", (width-200, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
cv2.putText(display_img, "Swipe Right: Forward", (width-200, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
cv2.putText(display_img, "Press 'q' to quit", (width-200, 90),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
# 显示图像(只有手部骨架在黑色背景上)
cv2.imshow("Hand Skeleton Only (No Person)", display_img)
# 按 'q' 退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
controller = HandController()
controller.start()
1860

被折叠的 条评论
为什么被折叠?



