使用MediaPipe实时手势识别报错:NameError: name 'mp_image' is not defined
问题分析与修复
核心错误原因
NameError 是因为 mp_image 仅在检测到手部特征的代码块内定义,当某一帧没有检测到手时,这个变量未被初始化,后续调用 cv2.putText 就会报错。除此之外,代码还有几处逻辑问题需要修正:
修复步骤
- 提前初始化mp_image:将
mp_image的创建移到手部检测逻辑之外,确保每一帧都能生成该变量,避免未定义问题。 - 修正cv2.putText的操作对象:
cv2.putText只能处理OpenCV的numpy数组格式帧(即frame),不能直接操作MediaPipe的mp.Image对象。 - 补充recognize_async的时间戳参数:使用
LIVE_STREAM模式时,必须传入timestamp_ms参数,可通过cap.get(cv2.CAP_PROP_POS_MSEC)获取当前帧的时间戳。 - 避免变量名冲突:将手部检测的结果变量名改为
hand_results,防止覆盖手势识别相关数据。 - 异步结果的保存与读取:
LIVE_STREAM模式下,手势识别结果通过回调函数返回,需要用全局变量保存最新结果,再在主循环中读取并显示。
修改后的完整代码
import cv2 import mediapipe as mp from mediapipe.tasks import python from mediapipe.tasks.python import vision # 全局变量保存最新手势识别结果 latest_gesture_result = None model_path = "gesture_recognizer.task" GestureRecognizer = mp.tasks.vision.GestureRecognizer GestureRecognizerOptions = mp.tasks.vision.GestureRecognizerOptions GestureRecognizerResult = mp.tasks.vision.GestureRecognizerResult VisionRunningMode = mp.tasks.vision.RunningMode def print_result(result: GestureRecognizerResult, output_image: mp.Image, timestamp_ms: int): global latest_gesture_result latest_gesture_result = result print('gesture recognition result: {}'.format(result)) options = GestureRecognizerOptions( base_options=python.BaseOptions(model_asset_path=model_path), running_mode=VisionRunningMode.LIVE_STREAM, result_callback=print_result) recognizer = GestureRecognizer.create_from_options(options) mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands hands = mp_hands.Hands( static_image_mode=False, max_num_hands=2, min_detection_confidence=0.65, min_tracking_confidence=0.65) cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break # 转换颜色空间,处理手部检测 frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) hand_results = hands.process(frame_rgb) # 创建MediaPipe Image对象,确保每一帧都初始化 mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=frame_rgb) # 获取当前帧时间戳,传入异步识别函数 timestamp = int(cap.get(cv2.CAP_PROP_POS_MSEC)) recognizer.recognize_async(mp_image, timestamp) # 绘制手部特征点 if hand_results.multi_hand_landmarks: for hand_landmarks in hand_results.multi_hand_landmarks: mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS) # 显示手势识别结果 if latest_gesture_result and latest_gesture_result.gestures: # 获取置信度最高的手势 top_gesture = latest_gesture_result.gestures[0][0] gesture_text = f"{top_gesture.category_name} ({top_gesture.score:.2f})" cv2.putText(frame, gesture_text, (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2, cv2.LINE_AA) cv2.imshow('MediaPipe Hands', frame) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
额外说明
- 全局变量
latest_gesture_result用于存储回调函数返回的最新识别结果,确保主循环能获取到异步处理后的手势数据。 - 显示结果时,取置信度最高的手势类别和分数,让显示内容更直观。
- 最后调用
cv2.destroyAllWindows()避免程序退出后残留窗口。
内容的提问来源于stack exchange,提问作者rajtilakjee
相关产品推荐
相关产品推荐

