OpenCV (cv2 en Python) VideoCapture de ne pas déclencher l'appareil photo après la suppression

Je suis relativement nouveau à Python, juste après avoir appris au cours du dernier mois ou deux et ont piraté cet ensemble basée sur des exemples et des autres code que j'ai trouvé en ligne.

J'ai obtenu une interface graphique Tkinter pour afficher le flux à partir d'une webcam comme une boucle continue de la mise à jour des images sur une toile. La fermeture de l'interface graphique et de ré-exécuter le script à chaque fois que les résultats de cette erreur:

Exception in Tkinter callback
Traceback (most recent call last):
    File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
        return self.func(*args)
    File "C:\Python27\lib\lib-tk\Tkinter.py", line 495, in callit
        func(*args)
   File "C:\...\cv2_cam_v8.py", line 20, in update_video
        (self.readsuccessful,self.f) = self.cam.read()
SystemError: NULL object passed to Py_BuildValue

Lorsque l'erreur se produit pas d'images à le lire et le videofeed reçoit pas d'images à mettre à jour le canevas. Le script s'exécute normalement sans erreur la première fois et à chaque fois deuxième. À partir de tests précédents avec la VideoCapture fonction dans le cv2 module, j'ai trouvé que j'ai dû supprimer l'objet caméra pour la libérer de sorte que les passages suivants sont capables de capturer des flux de caméra sans problème. Les contrôles sur l'espace de noms en tapant who dans la console ne montrent pas cam donc je sais qu'il est en train d'être supprimés correctement après que l'interface graphique est fermé. Je ne comprends pas pourquoi cv2 la fonction de lecture donne une erreur. Je pense que c'est seulement une fois sur deux, parce que lorsque l'erreur se produit, certains de collecte des ordures ou d'erreur de manipulation supprime ou libère quelque chose à faire avec la caméra, mais je ne sais pas ce que c'est...

Voici mon code:

import cv2
import Tkinter as tk
from PIL import Image, ImageTk
class vid():      
def __init__(self,cam,root,canvas):
self.cam = cam
self.root = root
self.canvas = canvas
def update_video(self):
(self.readsuccessful,self.f) = self.cam.read()
self.gray_im = cv2.cvtColor(self.f, cv2.COLOR_RGB2GRAY)
self.a = Image.fromarray(self.gray_im)
self.b = ImageTk.PhotoImage(image=self.a)
self.canvas.create_image(0,0,image=self.b,anchor=tk.NW)
self.root.update()
self.root.after(33,self.update_video)
if __name__ == '__main__':
root = tk.Tk()
videoframe = tk.LabelFrame(root,text='Captured video')
videoframe.grid(column=0,row=0,columnspan=1,rowspan=1,padx=5, pady=5, ipadx=5, ipady=5)
canvas = tk.Canvas(videoframe, width=640,height=480)
canvas.grid(column=0,row=0)
cam = cv2.VideoCapture(2)
x = vid(cam,root,canvas)
root.after(0,x.update_video)
button = tk.Button(text='Quit',master=videoframe,command=root.destroy)
button.grid(column=0,row=1)
root.mainloop()
del cam

Refactoriser le code comme ceci:

def update_video(cam,root,canvas):
(readsuccessful,f) = cam.read()
gray_im = cv2.cvtColor(f, cv2.COLOR_RGB2GRAY)
a = Image.fromarray(gray_im)
b = ImageTk.PhotoImage(image=a)
canvas.create_image(0,0,image=b,anchor=tk.NW)
root.update()
root.after(33,update_video(cam,root,canvas))
if __name__ == '__main__':
root = tk.Tk()
videoframe = tk.LabelFrame(root,text='Captured video')
videoframe.grid(column=0,row=0,columnspan=1,rowspan=1,padx=5, pady=5, ipadx=5, ipady=5)
canvas = tk.Canvas(videoframe, width=640,height=480)
canvas.grid(column=0,row=0)
cam = cv2.VideoCapture(2)
root.after(0,update_video(cam,root,canvas))
button = tk.Button(text='Quit',master=videoframe,command=root.destroy)
button.grid(column=0,row=1)
root.mainloop()
del cam

ne pas afficher le bouton dans l'interface graphique et donne cette erreur après la fermeture de la fenêtre:

RuntimeError: Too early to create image

J'ai 3 questions

1 - Comment puis-je empêcher d'exception?
Mise à JOUR: la modification "de la racine.après l'(0,update_video(cam,de racine,de la toile))", "root".après l'(0,lambda: update_video(cam,de racine,de la toile))" et "update_video(cam,de racine,de la toile)", "update_video(cam,de racine,de la toile,event=None)" OU de passer les arguments à la fonction de rappel à l'aide de ce format: "la racine.après(time_to_wait, de rappel, d'arguments, de master)" résout la deuxième erreur (et d'autres je n'ai pas de poste). Aussi comme kobejohn souligné, en ajoutant un essai: à l'exception du bloc fixe également la deuxième erreur. Veuillez voir sa réponse pour plus de détails.

2 - Est-il plus rapide, plus efficace de sa fonction .read() dans cv2? Edit: Est-il un moyen de revoir mon code pour obtenir un framerate plus élevé? La fonction de lecture est le seul à paraître dans les docs et je viens de lire quelque part que si elle n'est pas dans les docs, alors il n'est pas disponible. Cette méthode ne donne que moi au sujet de 5fps, où 10-20fps serait beaucoup plus acceptable.
Mise à JOUR: à Partir de la divergence entre kobejohn de tests et les miens avec des appareils différents, le framerate est le résultat d'une mauvaise qualité des webcams. Meilleure qualité des webcams de rendement élevé flux d'images.

3 - j'ai lu que la mise à jour() doit être évitée autant que possible, mais comment puis-je obtenir le canevas de dessin de l'image dans le cas contraire (ou de mettre en œuvre update_idletasks() avec ce code)?. Dois-je mettre en œuvre une sorte de filetage ou puis-je éviter cela?
Mise à JOUR: j'ai obtenu le code fonctionne sans l'aide de la méthode update (), mais faut regarder la mise en œuvre de filetage de toute façon parce que quand j'ai démarrer l'enregistrement de la videofeed à partir d'un bouton de l'interface graphique principale, il se fige/ne répond pas.

Le programme sera utilisé dans Ubuntu et windows (sur mac). Je suis sous Windows 7, l'IDE est Spyder 2.1.11 (Python 2.7.3).

Je vous remercie à l'avance de tous les conseils et/ou des solutions seront appréciés!

Ce qui concerne,

S. Chia

J'ai exécuter votre code d'origine de nombreuses fois et il arrêts/redémarrages sans erreur pour moi. Pouvez-vous essayer un autre appareil photo peut-être (c'est à dire peut-être que c'est une caméra problème de pilote?)
Pourquoi ne pas nous concentrer sur le premier code? Je crois que le deuxième code a au moins une erreur: root.after(0,update_video(cam,root,canvas)) est l'enregistrement de la valeur de retour de update_video(...) plutôt que de la fonction update_video lui-même.
Pour info je suis aussi d'obtenir des taux de trame élevé (probablement autour de 20 à 30?).
J'ai essayé le premier, trop, et de ne pas démarrer à nouveau, après j'ai arrêté.
Toutes mes excuses pour avoir pris tant de temps pour mettre à jour, les gars. J'avais eu du mal à obtenir un troisième webcam sans avoir à en acheter un. J'ai d'abord testé sur ma webcam et une webcam bon marché et ils ont donné le même problème. J'ai testé sur la troisième webcam, j'ai obtenu et le problème a persisté. Peut-être que c'est juste ma machine et/ou mon windows d'installation de python agir. Je vais trouver une autre machine pour tester le code sur et mettre à jour à nouveau.

OriginalL'auteur S. Chia | 2013-03-17