OpenCV调用destroyAllWindows()时随机触发段错误问题求助
解决OpenCV点击4点后随机段错误的问题
问题原因分析
- 全局变量状态污染:
calibrate.py中的全局变量cnt没有重置,多次调用main时会残留之前的计数,导致鼠标回调逻辑混乱,触发窗口销毁的时机错误。 - 窗口销毁时序冲突:在鼠标回调中直接调用
cv2.destroyWindow,此时cv2.waitKey(0)仍处于阻塞状态,窗口资源未正确释放就被销毁,引发内存访问错误(段错误)。 - 按键判断逻辑错误:
test.py中ord('q' or 'Q')的写法无效,实际只会响应小写q;且break后的cv2.destroyWindow("output")永远无法执行。
修复方案及代码
修复后的calibrate.py
import cv2 def main(img): cnt = 0 window_name = 'image' def click_event(event, x, y, flags, params): nonlocal cnt current_img = params['img'] # 仅在点击次数未满4次时处理左键点击 if event == cv2.EVENT_LBUTTONDOWN and cnt < 4: cnt += 1 cv2.circle(current_img, (x, y), 5, (0, 0, 255), -1) cv2.imshow(window_name, current_img) print(x, y) cv2.imshow(window_name, img) # 通过params传递图片对象,供回调修改 cv2.setMouseCallback(window_name, click_event, {'img': img}) # 循环等待,直到点击满4次或按ESC退出 while True: key = cv2.waitKey(1) & 0xFF if cnt >= 4: break if key == 27: # ESC键提前退出 break # 退出循环后安全销毁窗口 cv2.destroyWindow(window_name)
修复后的test.py
import cv2 import calibrate path = "crowd.mp4" cap = cv2.VideoCapture(path) while cap.isOpened(): ret, frame = cap.read() if not ret or frame is None: continue frame = cv2.resize(frame, (640, 480), cv2.INTER_AREA) cv2.imshow("output", frame) key = cv2.waitKey(1) & 0xFF # 同时响应大小写Q键 if key == ord('q') or key == ord('Q'): # 传递帧的副本,避免原帧被修改 calibrate.main(frame.copy()) cv2.destroyWindow("output") break cap.release() # 确保所有OpenCV窗口都被关闭 cv2.destroyAllWindows()
关键修复点说明
- 消除全局状态:将计数变量
cnt放在main函数内部,用nonlocal让回调函数访问,避免多次调用时的状态残留。 - 安全销毁窗口:通过循环检测点击计数,在退出
waitKey循环后再销毁窗口,避免事件循环与窗口销毁的时序冲突。 - 修正按键逻辑:单独判断大小写Q键,确保输入响应正确;调整窗口销毁代码位置,保证执行。
- 资源清理:添加
cv2.destroyAllWindows()确保所有OpenCV窗口资源被正确释放。
内容的提问来源于stack exchange,提问作者MUSTANGBOSS8055
相关产品推荐
相关产品推荐

