在Mac上使用Python和OpenCV时,DestroyWindow无法关闭窗口

57 投票
16 回答
73930 浏览
提问于 2025-04-16 18:16

我的程序用下面的代码生成了一系列窗口:

def display(img, name, fun):
    global clicked

    cv.NamedWindow(name, 1)
    cv.ShowImage(name, img)
    cv.SetMouseCallback(name, fun, img)

    while cv.WaitKey(33) == -1:
        if clicked == 1:
            clicked = 0
            cv.ShowImage(name, img)

    cv.DestroyWindow(name)

我在图形界面窗口里按“q”键想要关闭它。但是,代码还是继续执行,接着又调用了显示函数,结果又显示了第二个图形界面窗口,而第一个窗口却没有关闭。我是在Mac上使用OpenCV 2.1,通过终端运行这个程序的。请问我该怎么关闭这些图形界面窗口呢?谢谢。

16 个回答

31

Sayem2603

我试了你的解决方案,结果成功了,感谢你!我做了一些尝试和错误,发现循环4次就能解决我的问题……或者把同样的代码发4次也一样有效。

接着,我深入研究了一下:

cv2.destroyAllWindows()
cv2.waitKey(1)
cv2.waitKey(1)
cv2.waitKey(1)
cv2.waitKey(1)

或者简单地调用DestroyAllWindows,然后把waitKey()的代码循环4次:

cv2.destroyAllWindows()
for i in range (1,5):
    cv2.waitKey(1)

这样也有效。不过我不太懂为什么这样有效,我猜可能和循环代码时产生的中断和延迟有关?

Matthäus Brandl在上面提到,第三次waitKey()对他有效,所以可能在不同的系统上表现会有点不同?(我在用Linux Mint,内核是3.16.1,Python版本是2.7)

单纯的延迟并不能解释这个问题,因为仅仅增加waitKey()的延迟时间并没有解决问题。(我还尝试把print("Hello")循环打印1000次,而不是用waitKey(),只是想看看延迟是否有帮助——结果并没有。)这一定和waitKey()如何与窗口事件互动有关。

OpenCV文档上说:"这个函数是HighGUI中唯一可以获取和处理事件的方法,所以需要定期调用以正常处理事件,除非HighGUI在一个能处理事件的环境中使用。"

也许它在GUI显示中产生了一种中断,让destroyAllWindows()的操作得以执行?

J

42

你需要在打开窗口后运行 cv.startWindowThread()。我之前也遇到过这个问题,现在这样做对我有效。

希望这对未来的读者有帮助。另外,还有一个 cv2 的绑定(我建议使用这个,而不是 cv)。

这段代码对我有效:

import cv2 as cv
import time

WINDOW_NAME = "win"

image = cv.imread("ela.jpg", cv.CV_LOAD_IMAGE_COLOR)
cv.namedWindow(WINDOW_NAME, cv.CV_WINDOW_AUTOSIZE)
initialtime = time.time()

cv.startWindowThread()

while (time.time() - initialtime < 5):
  print "in first while"
cv.imshow(WINDOW_NAME, image)
cv.waitKey(1000)

cv.waitKey(1)
cv.destroyAllWindows()
cv.waitKey(1)

initialtime = time.time()
while (time.time() - initialtime < 6):
    print "in second while"

在Linux上,C++版本也会出现同样的问题:尝试关闭OpenCV窗口没有效果

39

在OpenCV的图形界面(GUI)中,有一些特别的地方需要注意。比如,destroyImage这个函数在Linux系统下(因为在2.1.0之前,默认使用的是Gtk+)不会关闭窗口,除非你先调用了waitKey来处理事件。你可以在destroyWindow后面加一个waitKey(1),这样可能会有效果。

不过,即使这样,关闭窗口也不一定能成功;因为waitKey这个函数只有在窗口有焦点的时候才会被执行。如果在你调用destroyWindow的时候,窗口没有焦点,那么它可能会一直显示,直到你下次再调用destroyWindow

我猜这可能是Gtk+的特性;在我使用Windows的时候,这个函数就没有出现过问题。

撰写回答