2016-05-04 28 views
5

Per il mio algoritmo di elaborazione delle immagini sto usando python/OpenCV. L'output del mio algoritmo deve essere aggiornato sempre nella stessa finestra.Opencv imshow() si blocca durante l'aggiornamento

Tuttavia a volte la finestra si blocca e non si aggiorna affatto, ma l'algoritmo è ancora in esecuzione e ha aggiornato l'immagine più volte nel frattempo. La finestra diventa grigio scuro su questa macchina Ubuntu.

Ecco un estratto del codice coinvolti:

for i in range(0,1000): 
    img = loadNextImg() 
    procImg = processImg(img) 
    cv2.imshow("The result", procImg) 
    cv2.waitKey(1) 

N.B.: processImg() richiede circa 1-2 s per le sue procedure. La riga cv2.imshow(procImg) crea la finestra in prima istanza (cioè non c'è invocazione precedente)

+1

È 'cv2.waitKey' che in realtà pompa i messaggi affinché la GUI funzioni. Deve essere chiamato abbastanza frequentemente affinché l'interfaccia utente risponda effettivamente a tutti gli eventi necessari (come i ripetuti, ecc.). Se l'elaborazione richiede molto tempo e si desidera avere un'interfaccia utente reattiva allo stesso tempo, è necessario eseguire l'elaborazione in un thread separato. –

+0

@ DanMašek In un programma a thread singolo che funziona in sequenza mi aspettavo prima di eseguire un altro comando, dopo che è stata completata un'attività corrente (in questo caso aggiorna l'immagine). Grazie per il suggerimento con il threading, ma per essere onesti questo rende inutile il complicato – user3085931

+1

Se non vuoi trattare i thread (anche se non è quello che considererei complicato, ma capisco che YMMV), l'altra possibilità è per fornire un modo per pompare i messaggi (chiama waitKey) mentre stai facendo l'elaborazione (tra i singoli passaggi). Sarà maldestro, ma almeno in questo modo la finestra rimarrà abbastanza reattiva. –

risposta

1

Quindi quello che penso stia succedendo è che la finestra, (un elemento del highGUI) che è ancora attiva dopo la prima chiamata a imshow, è in attesa di una sorta di risposta dalla funzione waitKey, ma sta diventando inattiva poiché il programma è bloccato nel calcolo delle funzioni processImg di loadNextImg. Se non ti preoccupi di un leggero spreco di efficienza (cioè non stai lavorando su un sistema embedded dove ogni operazione conta), dovresti semplicemente distruggere la finestra dopo waitKey, e ricrearla prima di imshow. Poiché la finestra non esiste più durante il tempo in cui si elaborano e si caricano le immagini, l'highGUI non si bloccherà in attesa di una chiamata da waitKey e non si bloccherà.

+0

Ho provato ad abbattere la finestra a destra ** prima ** aggiornando (o in questo caso creando nuovamente una nuova finestra). Il risultato è che invece di diventare grigio rimane semplicemente bianco.Un altro problema con questa soluzione: la finestra viene generata in un luogo casuale e se voglio spostarla, dopo il prossimo aggiornamento la nuova finestra viene creata nuovamente nella vecchia posizione. Potrebbe ostacolare il lavoro rimanente. – user3085931

+0

Per risolvere il problema con Windows in posizioni casuali, basta chiamare moveWindow subito dopo aver creato la finestra ed è possibile specificare la posizione x, y della finestra desiderata. Inoltre, la tua finestra rimane bianca vuota indica che è ancora attiva, solo che potresti passargli un'immagine bianca da visualizzare. Vorrei controllare gli algoritmi stessi a questo punto. Un buon modo per farlo sarebbe quello di scrivere l'immagine che si sta tentando di visualizzare in un file e quindi visualizzare il file. Se il file è tutto bianco, si tratta di un problema algoritmico. – bstadt

+0

l'algoritmo è ok, ho solo aumentato il carico di lavoro, prima che funzionasse bene - voglio dire quando una finestra diventa grigia in ubuntu significa che questa applicazione non risponde. Dato che si tratta di una routine di programma sequenziale, la nuova immagine è già finita quando si tratta di aggiornare - e in effetti inizia a elaborare il fotogramma successivo quando viene mostrata la nuova immagine. Questo è il motivo per cui mi aspetto che l'errore sia sul lato OpenCV. In altre parole OpenCV sembra iniziare un po 'di threading da solo, quando sta tornando, ma non ha nemmeno finito – user3085931

3

Aumentare il tempo di attesa risolve questo problema. Comunque a mio avviso questo è un tempo non necessario speso per dormire (20 ms/frame), anche se non è molto.

Modifica

cv2.waitKey(1) 

a

cv2.waitKey(20) 

impedisce la finestra dal gelo nel mio caso. La durata di questo tempo di attesa richiesto può variare su diverse macchine.

3

Ho lo stesso problema e ho notato che il fps che la finestra viene aggiornata sta diventando più lento e lento fino a quando non si blocca completamente. Aumentare il waitKey (x) a qualcosa di più alto aumenta solo la durata di aggiornamento delle immagini, ma quando il tempo che cv2.imshow() deve calcolare supera il tempo di attesa (chiave), si interrompe semplicemente l'aggiornamento.

(Salta questo reclamo :) Penso che la combinazione cv2.imshow() with waitKey() sia un errore di progettazione completo, perché non è imshow() che blocca fino a quando l'interfaccia utente non viene aggiornata? Ciò renderebbe la vita molto più facile, senza dover chiamare WAITKEY) ogni volta (...

PS: C'è la possibilità di avviare un proprio thread per le finestre OpenCV OpenCV all'interno:

import cv2 
img = cv2.imread("image.jpg") 
cv2.startWindowThread() 
cv2.namedWindow("preview") 
cv2.imshow("preview", img) 

fonte: cv2.imshow command doesn't work properly in opencv-python

Beh questo non funziona per me, perché ho sempre questo errore quando l'eseguo:

(python3:1177): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed 
Attempt to unlock mutex that was not locked 
Aborted 

Forse si potrebbe provare e riferire se è lavoro per te?

Edit: Ok ho risolto il problema per me con la creazione di un imshow.py script separato:

import cv2 
import os.path 

while True: 
    if os.path.exists("image.pgm"): 
     image = cv2.imread("image.pgm") 
     if not image is None and len(image) > 0: 
      cv2.imshow("Frame", image) 
      cv2.waitKey(20) 

E sto scrivendo l'immagine nel mio altro programma con: cv2.imwrite("image.pgm", image) E io sono chiamando lo script come questo:

import subprocess 
subprocess.Popen(["python3", "imshow.py"]) 

Anche se questa è la creazione di un po 'di sporco letture a volte è sufficiente per me, una soluzione migliore potrebbe essere quella di utilizzare pipe o code tra i due processi.

+0

.. ma ancora una volta hai a che fare con un ciclo di 20 ms, vero? – user3085931

+0

Correttamente, attualmente non c'è modo che io conosca per sbarazzarsi di quella funzione waitkey. Ma quello che proverò è sostituire opencv imshow con un'altra soluzione non opencv per mostrare le immagini. Sai qualcosa in quella direzione? – ElDani

+0

Quindi non ottengo il guadagno di informazioni del post. Dai un'occhiata a 'Tkinter' e' PIL' per Python – user3085931

1

Il mio suggerimento è di utilizzare il pyplot Matplotlib per visualizzare l'immagine. Lo faccio nel modo seguente.

import matplotlib.pyplot as plt 
# load image using cv2....and do processing. 
plt.imshow(cv2.cvtColor(image, cv2.BGR2RGB)) 
# as opencv loads in BGR format by default, we want to show it in RGB. 
plt.show() 

So che non risolve il problema di cv2.imshow, ma risolve il nostro problema.

0

Se la finestra diventa grigia, potrebbe richiedere più potenza di elaborazione. Quindi prova a ridimensionare l'immagine in un'immagine di dimensioni più piccole ed eseguirla. A volte le volte si blocca durante l'esecuzione nei notebook ipython a causa della pressione di qualsiasi tasto durante l'esecuzione dell'operazione. Avevo eseguito personalmente il tuo problema ma non ho ottenuto lo schermo grigio mentre lo facevo. Ho eseguito direttamente utilizzando il terminale. Codice e passaggi sono mostrati di seguito.

import argparse 
import cv2 
import numpy as np 

# construct the argument parser and parse the arguments 
ap = argparse.ArgumentParser() 
ap.add_argument("-i", "--image", required=True, help="Path to the image") 
args = vars(ap.parse_args()) 

# load the image, grab its dimensions, and show it 
image = cv2.imread(args["image"]) 
(h, w) = image.shape[:2] 
cv2.imshow("Original", image) 
cv2.waitKey(0) 

for i in range(0,1000): 
    image = cv2.imread(args["image"]) 
    cv2.imshow("The result",image); 
    cv2.waitKey(0) 

Run nel terminale:

  1. fonte attivare env_name
  2. pitone Filename.py --image imagename.png

Questo otterrà al vostro risultato in una finestra solo (aggiornando ogni volta) senza congelare e se si desidera un'immagine separata in ogni nuova finestra, quindi aggiungere .format (i) come indicato di seguito. Ma Ricordarsi di eseguire il terminale solo nei notebook jupyter.

È possibile controllare tramite i comandi del terminale in questo link il video https://www.youtube.com/watch?v=8O-FW4Wm10s

for i in range(0,1000): 
    image = cv2.imread(args["image"]) 
    cv2.imshow("The result{}".format(i),image); 
    cv2.waitKey(0) 

Questo può aiutare a farti 1000 immagini separatamente.

Problemi correlati