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

如何用cv2.setMouseCallback提取摄像头图像区域?裁剪图像异常求助

问题修复方案

核心错误原因

  1. 鼠标拖动绘制矩形时,直接在目标图像上反复修改(反转像素+画框),导致图像残留大量拖动痕迹
  2. 裁剪ROI时使用了被修改的图像而非原始副本,最终保存的裁剪图带有叠加框
  3. 裁剪后保存的文件名与原始帧重复,覆盖了原始图像

修改后的代码

import cv2

# 打开摄像头
cap = cv2.VideoCapture(0)
i = 0
training_images = []

# 初始化全局变量
drawing = False
x_pt, y_pt = -1, -1
top_left_point, bottom_right_point = (-1, -1), (-1, -1)

def draw_bounding_box(click, x, y, flag_param, parameters):
    global x_pt, y_pt, drawing, top_left_point, bottom_right_point, image, copy
    
    if click == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        x_pt, y_pt = x, y
        top_left_point = (x_pt, y_pt)

    elif click == cv2.EVENT_MOUSEMOVE:
        if drawing:
            # 每次移动时,先从原始副本恢复图像,再绘制当前矩形
            image = copy.copy()
            bottom_right_point = (x, y)
            cv2.rectangle(image, top_left_point, bottom_right_point, (0, 255, 0), 2)
    
    elif click == cv2.EVENT_LBUTTONUP:
        drawing = False
        bottom_right_point = (x, y)
        # 最终绘制一次矩形到显示图像
        image = copy.copy()
        cv2.rectangle(image, top_left_point, bottom_right_point, (0, 255, 0), 2)
        
        # 计算ROI坐标,确保坐标合法(避免x/y顺序颠倒)
        x1, y1 = min(x_pt, x), min(y_pt, y)
        x2, y2 = max(x_pt, x), max(y_pt, y)
        
        # 从原始副本裁剪ROI,避免使用被修改的显示图像
        if x2 > x1 and y2 > y1:
            cropped_im = copy[y1:y2, x1:x2]
            training_images.append(cropped_im)
            cv2.imshow("cropped", cropped_im)
            # 用不同文件名保存裁剪图,避免覆盖原始帧
            cv2.imwrite(f'C:/Downloads/testingPictures/Frame{i}_cropped.jpg', cropped_im)
            cv2.waitKey(3000)
            cv2.destroyWindow("cropped")
        else:
            print("无效的ROI区域,请重新选择")


if __name__ == '__main__':
    # 步骤1:从摄像头捕获并保存原始图像
    while cap.isOpened() and i < 10:
        ret, frame = cap.read()
        if not ret:
            break
        cv2.imwrite(f'C:/Downloads/testingPictures/Frame{i}.jpg', frame)
        i += 1
    cap.release()
    print(f"已保存{i}张原始图像")
    
    # 步骤2:逐个处理图像,选择ROI并裁剪
    while i > 0:
        i -= 1
        # 读取原始图像,创建副本
        copy = cv2.imread(f'C:/Downloads/testingPictures/Frame{i}.jpg')
        if copy is None:
            print(f"无法读取Frame{i}.jpg")
            continue
        image = copy.copy()
        
        cv2.namedWindow('Frame')
        cv2.setMouseCallback('Frame', draw_bounding_box)
        
        # 等待用户操作,直到按下ESC或完成选择
        while True:
            cv2.imshow('Frame', image)
            k = cv2.waitKey(1) & 0xFF
            if k == 27:  # ESC键退出
                cv2.destroyAllWindows()
                exit()
            # 当完成ROI选择后,等待用户按下任意键进入下一张
            if not drawing and top_left_point != (-1, -1) and bottom_right_point != (-1, -1):
                cv2.waitKey(0)
                # 重置ROI坐标,准备处理下一张
                top_left_point, bottom_right_point = (-1, -1), (-1, -1)
                break
        
        cv2.destroyWindow('Frame')
        
    print(f"已完成{len(training_images)}张ROI裁剪")
    cv2.destroyAllWindows()

关键改动说明

  • 避免图像污染:鼠标拖动时,每次都从原始副本copy重新复制到image再绘制矩形,彻底消除拖动痕迹的叠加
  • 正确裁剪ROI:从原始图像副本copy中裁剪区域,而非被修改的显示图像,确保裁剪结果是原始内容
  • 合法坐标处理:添加了坐标顺序判断(取min和max),避免因拖动方向颠倒导致的无效裁剪
  • 文件名区分:裁剪后的图像添加_cropped后缀,避免覆盖原始捕获的帧
  • 流程优化:修改了等待逻辑,确保用户完成ROI选择后再进入下一张图像,避免超时自动跳转

内容的提问来源于stack exchange,提问作者Shruti Chakraborty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:35:17