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

如何在OpenCV Python中对鼠标选中的图像区域做自适应阈值处理?

问题分析与修正方案

你的代码存在几个关键问题,导致无法正确实现选中区域的自适应阈值操作:

1. 选中区域的坐标切片错误

直接使用img2[y: iy, x: ix]截取区域时,若用户从右下角往左上角拖动鼠标,会出现y > iy或x > ix的情况,此时切片会得到空数组,后续处理完全失效。必须先计算坐标的最小和最大值,确保切片范围有效:

x1, x2 = min(ix, x), max(ix, x)
y1, y2 = min(iy, y), max(iy, y)
roi = img2[y1:y2, x1:x2]

2. 单通道结果直接替换三通道原图

自适应阈值处理后的th是单通道灰度图,而原图img是三通道彩色图。直接将img = th会导致整个窗口变为单通道灰度显示,且丢失原图其他区域内容。正确做法是将处理后的灰度图转为三通道,再替换回原图的对应区域:

# 将单通道阈值图转为三通道格式
th_color = cv2.cvtColor(th, cv2.COLOR_GRAY2BGR)
# 把处理后的区域替换回原图
img[y1:y2, x1:x2] = th_color

3. 重复读取图片效率低下

每次鼠标拖动都重新读取test.png属于冗余操作,可在程序开头保存原图副本,后续直接复制副本使用,避免重复IO开销:

original_img = cv2.imread("test.png")
img = original_img.copy()

之后在拖动和松开鼠标时,用img2 = original_img.copy()代替重新读取图片。

修正后的完整代码

import cv2

original_img = cv2.imread("test.png")
img = original_img.copy()

# 全局变量
ix = -1
iy = -1
drawing = False


def draw_rectangle_with_drag(event, x, y, flags, param):
    global ix, iy, drawing, img
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        ix = x
        iy = y

    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing == True:
            img2 = original_img.copy()
            cv2.rectangle(img2, pt1=(ix, iy), pt2=(x, y),
                          color=(0, 255, 255), thickness=1)
            img = img2

    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        img2 = original_img.copy()
        cv2.rectangle(img2, pt1=(ix, iy), pt2=(x, y),
                      color=(0, 255, 255), thickness=1)

        # 计算有效选中区域的坐标
        x1, x2 = min(ix, x), max(ix, x)
        y1, y2 = min(iy, y), max(iy, y)
        
        # 截取选中区域并转为灰度图
        roi = img2[y1:y2, x1:x2]
        gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

        # 执行自适应阈值处理
        th = cv2.adaptiveThreshold(gray,
                                   255,
                                   cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                   cv2.THRESH_BINARY,
                                   5,
                                   3)
        # 转为三通道后替换回原图
        th_color = cv2.cvtColor(th, cv2.COLOR_GRAY2BGR)
        img2[y1:y2, x1:x2] = th_color
        img = img2


cv2.namedWindow(winname="Title of Popup Window")
cv2.setMouseCallback("Title of Popup Window", draw_rectangle_with_drag)

while True:
    cv2.imshow("Title of Popup Window", img)
    if cv2.waitKey(10) == 27:
        break
cv2.destroyAllWindows()

内容的提问来源于stack exchange,提问作者Emad Younan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:25:23