You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV目标跟踪代码中鼠标与准星对齐异常问题求助

Python目标跟踪:摄像头帧下准星与鼠标偏移问题解决及ROI跟踪实现

问题分析

你遇到的准星偏移问题,核心原因是摄像头捕获帧的分辨率与OpenCV显示窗口的尺寸不匹配,导致鼠标事件获取的窗口坐标和帧的实际像素坐标错位。黑屏帧下窗口尺寸和绘制尺寸完全一致,所以准星能正常跟随;但摄像头帧有固定分辨率,若窗口被缩放(或默认显示尺寸与帧分辨率不同),直接用鼠标坐标绘制准星就会出现偏移。

解决方案

1. 先解决准星与鼠标对齐问题

方案A:统一帧与窗口尺寸

强制摄像头输出固定分辨率,且窗口不做缩放,确保鼠标坐标与帧坐标一一对应:

import cv2

# 初始化摄像头并固定分辨率
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 存储鼠标实时位置
mouse_pos = (0, 0)

def update_mouse(event, x, y, flags, param):
    global mouse_pos
    mouse_pos = (x, y)

cv2.namedWindow("Tracker")
cv2.setMouseCallback("Tracker", update_mouse)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    # 直接在帧上绘制准星
    cv2.circle(frame, mouse_pos, 5, (0, 255, 0), -1)
    cv2.line(frame, (mouse_pos[0]-15, mouse_pos[1]), (mouse_pos[0]+15, mouse_pos[1]), (0,255,0), 2)
    cv2.line(frame, (mouse_pos[0], mouse_pos[1]-15), (mouse_pos[0], mouse_pos[1]+15), (0,255,0), 2)
    
    cv2.imshow("Tracker", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

方案B:坐标转换(适配窗口缩放)

如果必须缩放窗口,将鼠标的窗口坐标转换为帧的实际坐标:

import cv2

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
mouse_pos = (0, 0)

def update_mouse(event, x, y, flags, param):
    global mouse_pos
    mouse_pos = (x, y)

cv2.namedWindow("Tracker")
cv2.setMouseCallback("Tracker", update_mouse)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    # 获取当前窗口尺寸
    win_rect = cv2.getWindowImageRect("Tracker")
    win_w, win_h = win_rect[2], win_rect[3]
    # 计算帧与窗口的缩放比例
    frame_h, frame_w = frame.shape[:2]
    scale_x = frame_w / win_w
    scale_y = frame_h / win_h
    # 转换鼠标坐标到帧坐标系
    frame_x = int(mouse_pos[0] * scale_x)
    frame_y = int(mouse_pos[1] * scale_y)
    # 绘制准星
    cv2.circle(frame, (frame_x, frame_y), 5, (0, 255, 0), -1)
    cv2.line(frame, (frame_x-15, frame_y), (frame_x+15, frame_y), (0,255,0), 2)
    cv2.line(frame, (frame_x, frame_y-15), (frame_x, frame_y+15), (0,255,0), 2)
    
    cv2.imshow("Tracker", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

2. 实现点击ROI跟踪目标

基于上述坐标修正,集成高精度CSRT跟踪器,实现点击准星中心选择目标并跟踪:

import cv2

tracker = cv2.TrackerCSRT_create()
is_tracking = False
mouse_pos = (0, 0)

def mouse_callback(event, x, y, flags, param):
    global is_tracking
    if event == cv2.EVENT_LBUTTONDOWN:
        # 获取当前帧和窗口尺寸
        frame = param
        win_rect = cv2.getWindowImageRect("Tracker")
        win_w, win_h = win_rect[2], win_rect[3]
        frame_h, frame_w = frame.shape[:2]
        scale_x = frame_w / win_w
        scale_y = frame_h / win_h
        # 转换鼠标坐标到帧坐标系
        frame_x = int(x * scale_x)
        frame_y = int(y * scale_y)
        # 以准星为中心创建20x20的ROI
        roi_size = 20
        bbox = (frame_x - roi_size//2, frame_y - roi_size//2, roi_size, roi_size)
        tracker.init(frame, bbox)
        is_tracking = True

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cv2.namedWindow("Tracker")
cv2.setMouseCallback("Tracker", mouse_callback)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    win_rect = cv2.getWindowImageRect("Tracker")
    win_w, win_h = win_rect[2], win_rect[3]
    frame_h, frame_w = frame.shape[:2]
    scale_x = frame_w / win_w
    scale_y = frame_h / win_h

    if is_tracking:
        # 更新跟踪结果
        success, bbox = tracker.update(frame)
        if success:
            x, y, w, h = [int(v) for v in bbox]
            # 计算跟踪框中心并绘制准星
            center_x = x + w//2
            center_y = y + h//2
            cv2.circle(frame, (center_x, center_y), 5, (0, 255, 0), -1)
            cv2.line(frame, (center_x-15, center_y), (center_x+15, center_y), (0,255,0), 2)
            cv2.line(frame, (center_x, center_y-15), (center_x, center_y+15), (0,255,0), 2)
            # 绘制跟踪边界框
            cv2.rectangle(frame, (x,y), (x+w,y+h), (255,0,0), 2)
    else:
        # 未跟踪时,准星跟随鼠标
        frame_x = int(mouse_pos[0] * scale_x)
        frame_y = int(mouse_pos[1] * scale_y)
        cv2.circle(frame, (frame_x, frame_y), 5, (0, 255, 0), -1)
        cv2.line(frame, (frame_x-15, frame_y), (frame_x+15, frame_y), (0,255,0), 2)
        cv2.line(frame, (frame_x, frame_y-15), (frame_x, frame_y+15), (0,255,0), 2)
    
    cv2.imshow("Tracker", frame)
    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break
    elif key == ord('r'):
        # 重置跟踪状态
        is_tracking = False

cap.release()
cv2.destroyAllWindows()

关键提示

  • 若需要更高跟踪速度,可将CSRT替换为MOSSE跟踪器(cv2.TrackerMOSSE_create());
  • 准星样式可通过修改cv2.circle和cv2.line的半径、颜色、线宽参数调整;
  • 如果摄像头不支持设置的分辨率,可注释掉cap.set相关代码,改用摄像头默认分辨率。

内容的提问来源于stack exchange,提问作者Joseph z

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 02:35:03