web-dev-qa-db-fra.com

DestroyWindow ne ferme pas la fenêtre sur Mac avec Python et OpenCV

Mon programme génère une série de fenêtres en utilisant le code suivant:

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)

J'appuie sur "q" dans la fenêtre de l'interface graphique pour la fermer. Cependant, le code continue jusqu'au prochain appel de la fonction d'affichage et affiche une seconde fenêtre d'interface graphique sans fermer la première. J'utilise un Mac avec OpenCV 2.1, en exécutant le programme dans Terminal. Comment puis-je fermer les fenêtres de l'interface graphique? Merci.

27
Arthur

Il y a quelques particularités avec l'interface graphique dans OpenCV. L'appel destroyImage ne parvient pas à fermer une fenêtre (du moins sous Linux, où le système par défaut était Gtk + jusqu'à la version 2.1.0), à moins que waitKey ne soit appelé pour afficher les événements. L'ajout d'un appel waitKey(1) juste après destroyWindow peut fonctionner.

Même dans ce cas, la fermeture n’est pas garantie; la fonction waitKey n'est interceptée que si une fenêtre a le focus, et donc si la fenêtre n'avait pas le focus au moment où vous avez invoqué destroyWindow, il est probable qu'elle restera visible jusqu'au prochain appel destroyWindow.

Je suppose que c'est un comportement qui découle de Gtk +; la fonction ne m'a pas posé de problème lorsque je l'ai utilisée sous Windows.

18
susmits

Vous devez exécuter cv.startWindowThread() après avoir ouvert la fenêtre .J'ai eu le même problème et maintenant cela fonctionne pour moi.

J'espère que cela aidera les futurs lecteurs. Et il y a aussi une liaison cv2 (je conseille de l'utiliser à la place de cv).

Ce code fonctionne pour moi:

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"

Le même problème se produit avec la version C++, sous Linux: Essayer de fermer la fenêtre OpenCV n'a aucun effet

26
elaRosca

Sayem2603

J'ai essayé votre solution et cela a fonctionné pour moi - merci! J'ai fait des essais et des erreurs et découvert que boucler 4 fois a fait l'affaire pour moi ... ou poster le même code 4 fois de la même manière ..

De plus, j'ai creusé jusqu'à:

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

ou simplement en appelant DestroyAllWindows puis en bouclant le code waitKey () 4 fois:

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

A travaillé aussi bien. Je ne suis pas assez averti pour savoir pourquoi cela fonctionne exactement, même si je suppose que cela a quelque chose à voir avec l'interruption et le retard créés par la mise en boucle de ce code (?) 

Matthäus Brandl a dit, ci-dessus, que le troisième waitKey () fonctionnait pour lui, alors peut-être est-il légèrement différent sur chaque système? (J'utilise Linux Mint avec le noyau 3.16.1 et python 2.7)

Le délai, seul, ne l'explique pas, car augmenter le temps de délai sur waitKey () ne fait pas l'affaire. (Également en boucle une impression ("Hello") 1000 fois au lieu d’utiliser wiatKey () pour voir si le retard créé a aidé quelque chose - ce n’est pas le cas.) Doit avoir quelque chose de plus à voir avec la façon dont waitKey () interagit avec les événements de fenêtre.

Les documents OpenCV Docs disent: "Cette fonction est la seule méthode dans HighGUI capable d'extraire et de gérer les événements. Elle doit donc être appelée périodiquement pour le traitement normal des événements, à moins que HighGUI ne soit utilisé dans un environnement prenant en charge le traitement des événements."

Peut-être que cela crée une interruption dans l’interface graphique qui permet à l’action destroyAllWindows () de traiter?

J

15
Jay

Cette solution fonctionne pour moi (sous Ubuntu 12.04 avec python ouvert dans le shell):

Réinvoquez cv.ShowImage après que la fenêtre soit "détruite".

4
Marco Centin

J'ai résolu le problème en appelant cv2.waitKey(1) dans une boucle for, je ne sais pas pourquoi cela a fonctionné mais mon travail est terminé, donc je ne me suis plus ennuyé.

for i in range(1,10):
    cv2.destroyAllWindows()
    cv2.waitkey(1)

vous êtes invités à expliquer.

3
sayem2603

Si vous utilisez Spyder (Anaconda Package), le problème se pose.

Aucune des solutions n’a fonctionné pour moi… j’ai découvert que le problème n’était pas lié aux fonctions mais bien à un problème sur Spyder. Essayez d’utiliser un éditeur de texte et de courir sur un terminal et vous irez très bien en utilisant simplement:

WINDOW_NAME = "win"
image = cv.imread("foto.jpg", 0)
cv.namedWindow(WINDOW_NAME, cv.CV_WINDOW_AUTOSIZE)

cv.startWindowThread()

cv.imshow(WINDOW_NAME, image)
cv.waitKey()
cv.destroyAllWindows()
2
Michelcyc

Voici ce qui a fonctionné pour moi:

cv2.namedWindow("image")
cv2.imshow('image', img)
cv2.waitKey(0) # close window when a key press is detected
cv2.destroyWindow('image')
cv2.waitKey(1)
2
Hassan Alshehri

En parcourant ce problème dans la console python, j'ai observé le comportement suivant:

  • l'émission d'un cv2.imshow après cv2.destroyWindowparfois ferme la fenêtre. Bien que l'ancienne fenêtre réapparaisse avec le prochain appel highgui, par exemple, cv2.namedWindow
  • le troisième appel de cv2.waitKey après cv2.destroyWindow a fermé la fenêtre à chaque fois que j'ai essayé. De plus, la fenêtre fermée est restée fermée, même si vous avez utilisé cv2.namedWindow après

J'espère que ça aide quelqu'un.

(J'ai utilisé Ubuntu 12.10 avec Python 2.7.3 mais OpenCV 2.4.2 à partir des versions 13.04)

1
Matthäus Brandl

Après avoir cherché pendant un certain temps, aucune des solutions fournies ne fonctionnait pour moi. Comme il y avait un bogue dans cette fonction et que je n'avais pas le temps de le réparer, je n'ai pas eu à utiliser la fenêtre cv2 pour afficher les cadres. Une fois que quelques images ont été enregistrées, vous pouvez ouvrir le fichier dans une autre visionneuse, telle que VLC ou MoviePlayer (pour Linux).

Voici comment j'ai fait le mien.

 import cv2

 threadDie = True # change this to false elsewhere to stop getting the video
 def getVideo(Message):
          print Message
          print "Opening url"
          video = cv2.VideoCapture("rtsp://username:passwordp@IpAddress:554/axis-media/media.amp")

          print "Opened url"
          fourcc = cv2.cv.CV_FOURCC('X','V','I','D')
          fps = 25.0 # or 30.0 for a better quality stream
          writer = cv2.VideoWriter('out.avi', fourcc,fps, (640,480),1)
          i = 0

          print "Reading frames "
          while threadDie:
                  ret, img = video.read()
                  print "frame number: ",i
                  i=i+1
                  writer.write(img)
          del(video)


          print "Finished capturing video"

Ensuite, ouvrez le fichier avec une autre visionneuse, probablement dans une autre fonction, comme si vous aimez vlc, vous pouvez le démarrer et transmettre le fichier enregistré en tant que paramètre. Sur le terminal, je le ferais

vlc out.avi #out.avi is my video file being saved by the function above.

Cela a fonctionné pour moi sur Arch Linux.

1
Telewa

Il semble qu'aucune des solutions ci-dessus ne fonctionne pour moi si je l'exécute sur Jupyter Notebook (la fenêtre se bloque lors de la fermeture et vous devez forcer la fermeture de Python pour la fermer). 

Je suis sur macOS High Sierra 10.13.4, Python 3.6.5, OpenCV 3.4.1.

Le code ci-dessous fonctionne si vous l'exécutez en tant que fichier .py (source: https://www.learnopencv.com/read-write-and-display-a-video-using-opencv-cpp-python/ ). Il ouvre la caméra, enregistre la vidéo, ferme la fenêtre en appuyant sur 'q' et enregistre la vidéo au format .avi. 

import cv2
import numpy as np

# Create a VideoCapture object
cap = cv2.VideoCapture(0)

# Check if camera opened successfully
if (cap.isOpened() == False): 
  print("Unable to read camera feed")

# Default resolutions of the frame are obtained.The default resolutions are system dependent.
# We convert the resolutions from float to integer.
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))

# Define the codec and create VideoWriter object.The output is stored in 'outpy.avi' file.
out = cv2.VideoWriter('outpy.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height))

while(True):
  ret, frame = cap.read()

  if ret == True: 

    # Write the frame into the file 'output.avi'
    out.write(frame)

    # Display the resulting frame    
    cv2.imshow('frame',frame)

    # Press Q on keyboard to stop recording
    if cv2.waitKey(1) & 0xFF == ord('q'):
      break

  # Break the loop
  else:
    break 

# When everything done, release the video capture and video write objects
cap.release()
out.release()

# Closes all the frames
cv2.destroyAllWindows() 
0
yl_low

Cela a fonctionné pour moi dans spyder:

import cv2 as cv
cv.namedWindow("image")
img = cv.imread("image_name.jpg")
cv.imshow("image",img)

cv.waitKey(5000) # 5 sec delay before image window closes
cv.destroyWindow("image")

N'oubliez pas utilisez uniquement cv.waitKey(positive Integer) pour que cela fonctionne

0
Dinesh jain