如何在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
相关产品推荐
相关产品推荐

