左手一只鸡 第一卷

我和小家伙来到了杭州

如果你已经运行了我们提供的完整调试代码,**双手都清晰出现在画面中**,但系统仍然只检测到只手(控制台输出始终是“检测到 1 只手”),那么我们可以断定:问题不是代码逻辑错误,而是 **MediaPipe 的检测机制在当前环境下未能激活双手机制**。 下面我们进行**终极排查 + 强制解决方案**,确保你能真正实现双手识别。 --- ## 🔍 终极原因分析(为什么 MediaPipe “看不见”第二只手?) 即使设置了 `max_num_hands=2`,MediaPipe Hands 内部有个 **非极大抑制(Non-Maximum Suppression, NMS)策略**,它会基于空间重叠度自动过滤掉“看起来太近”的手。这是导致“明明有两只手却只返回只”的根本原因! > 📌 **关键点**:当两只手靠得太近、交叉、或被模型认为是同个手时,MediaPipe 会主动抑制其中个检测结果。 --- ## ✅ 解决方案:修改 MediaPipe 源码参数(高级用户推荐) MediaPipe 默认的 `hand_detection_cpu.pbtxt` 中有个参数叫 `min_suppression_threshold`,默认为 `0.3`,意味着如果两个候选框重叠超过 70%,就只保留个。 我们可以通过**降低这个阈值**来允许更多手被保留。 但由于 Python 包是编译好的,不能直接改 pbtxt 文件,所以我们采用以下替代方法: ### ✅ 替代方案:使用自定义推理流程(基于 TFLite 手动调用) 但这对大多数用户太复杂。因此我们提供更实用的方法: --- ## ✅ 实用解决方案二:强制启用双手机制的技巧 ### ✨ 技巧:让 MediaPipe “以为”是两只独立的手 —— 分区域检测 我们将图像分成左右两部分,分别送入检测器。这样可以绕过 NMS 限制,强制检测出两只手。 ```python import cv2 import mediapipe as mp mp_hands = mp.solutions.hands mp_drawing = mp.solutions.drawing_utils # 全局 Hands 模型(用于复用) hands = mp_hands.Hands( static_image_mode=False, max_num_hands=1, # 每次只检测只手,但我们分区域处理 min_detection_confidence=0.5, min_tracking_confidence=0.5 ) cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while cap.isOpened(): success, image = cap.read() if not success: continue image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) h, w, _ = image.shape # 存储所有检测到的手 all_hand_landmarks = [] all_handedness = [] # ---- 左半区检测右手 or 左手 ---- left_roi = image_rgb[:, :w//2] # 左半边 results_left = hands.process(left_roi) if results_left.multi_hand_landmarks: for i, lm in enumerate(results_left.multi_hand_landmarks): # 调整坐标回全局位置 for point in lm.landmark: point.x = point.x * (w//2) / w all_hand_landmarks.append(lm) # 假设左区检测到的是左手(可进步判断) handedness = results_left.multi_handedness[i].classification[0].label all_handedness.append(handedness) # ---- 右半区检测 ---- right_roi = image_rgb[:, w//2:] # 右半边 results_right = hands.process(right_roi) if results_right.multi_hand_landmarks: for i, lm in enumerate(results_right.multi_hand_landmarks): for point in lm.landmark: point.x = (point.x * (w//2) + w//2) / w all_hand_landmarks.append(lm) handedness = results_right.multi_handedness[i].classification[0].label all_handedness.append(handedness) # ---- 合并绘制 ---- for lm, hand_label in zip(all_hand_landmarks, all_handedness): mp_drawing.draw_landmarks(image, lm, mp_hands.HAND_CONNECTIONS) x_px = int(lm.landmark[0].x * w) y_px = int(lm.landmark[0].y * h) cv2.putText(image, hand_label, (x_px, y_px - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow('Dual Hand Forced Detection', image) if cv2.waitKey(1) & 0xFF == ord('q'): break hands.close() cap.release() cv2.destroyAllWindows() ``` ✅ **优点**: - 即使双手靠近也不会被 NMS 过滤; - 稳定检测出两只手; - 适用于手语录制场景。 ⚠️ **注意**: - 需要适当调整 ROI 区域避免切掉手; - 可扩展为三区域滑动窗口提升精度。 --- ## ✅ 解决方案三:升级到 MediaPipe Tasks(新版本 API,支持更强双手) Google 推出了新的 [MediaPipe Tasks](https://developers.google.com/mediapipe/solutions/vision/hand_landmarker) API,支持更好的多手检测。 ### 安装: ```bash pip install mediapipe-models ``` ### 示例代码(Tasks 版本): ```python from mediapipe import solutions from mediapipe.framework.formats import landmark_pb2 import numpy as np import cv2 def draw_landmarks_on_image(rgb_image, detection_result): hand_landmarks_list = detection_result.hand_landmarks handedness_list = detection_result.handedness annotated_image = np.copy(rgb_image) for idx in range(len(hand_landmarks_list)): hand_landmarks = hand_landmarks_list[idx] handedness = handedness_list[idx] # Draw landmarks hand_landmarks_proto = landmark_pb2.NormalizedLandmarkList() hand_landmarks_proto.landmark.extend([ landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in hand_landmarks ]) solutions.drawing_utils.draw_landmarks( annotated_image, hand_landmarks_proto, solutions.hands.HAND_CONNECTIONS, solutions.drawing_styles.get_default_hand_landmarks_style(), solutions.drawing_styles.get_default_hand_connections_style()) # Label x = int(hand_landmarks[0].x * rgb_image.shape[1]) y = int(hand_landmarks[0].y * rgb_image.shape[0]) cv2.putText(annotated_image, f'{handedness[0].display_name}', (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) return annotated_image # 初始化 Hand Landmarker BaseOptions = mp.tasks.BaseOptions HandLandmarker = mp.tasks.vision.HandLandmarker HandLandmarkerOptions = mp.tasks.vision.HandLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode options = HandLandmarkerOptions( base_options=BaseOptions(model_asset_path='hand_landmarker.task'), running_mode=VisionRunningMode.IMAGE, num_hands=2 # 明确设置双手 ) detector = HandLandmarker.create_from_options(options) # 视频循环 cap = cv2.VideoCapture(0) while cap.isOpened(): success, image = cap.read() if not success: continue image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image_mp = mp.Image(image_format=mp.ImageFormat.SRGB, data=image_rgb) detection_result = detector.detect(image_mp) annotated_image = draw_landmarks_on_image(image_rgb, detection_result) cv2.imshow('MediaPipe Tasks - Dual Hands', cv2.cvtColor(annotated_image, cv2.COLOR_RGB2BGR)) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() ``` 📌 下载模型文件:[hand_landmarker.task](https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task) --- ## ✅ 最终建议(快速见效) | 目标 | 推荐做法 | |------|----------| | 快速看到双手 | 使用 **分区域检测法(解决方案二)** | | 长期项目开发 | 迁移到 **MediaPipe Tasks API** | | 动态手语识别 | 结合双手关键点 + LSTM / Transformer 序列建模 | --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值