Я получил графический интерфейс Tkinter для отображения канала с веб-камеры в виде цикла постоянно обновляемых изображений на холсте. Выход из графического интерфейса и повторный запуск сценария каждый раз приводит к этой ошибке:
Код: Выделить всё
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
Вот мой код:
Код: Выделить всё
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
Код: Выделить всё
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
Код: Выделить всё
RuntimeError: Too early to create image
1 – Как я могу предотвратить любое исключение?
ОБНОВЛЕНИЕ: изменение «root.after(0,update_video(cam,root,canvas))» на «root.after(0,lambda: update_video(cam,root,canvas))» и «update_video(cam, root,canvas)» на «update_video(cam,root,canvas,event=None)» ИЛИ передача аргументов обратному вызову в следующем формате: «root.after(time_to_wait, callback, аргументы, мастер)» исправляет вторую ошибку ( и другие, которые я не публиковал). Также, как отметил Кобежон, добавление блока try: кроме также исправляет вторую ошибку. Подробнее см. в его ответе.
2 - Есть ли в cv2 более быстрая и эффективная функция, чем .read()? Изменить: есть ли способ реорганизовать мой код, чтобы получить более высокую частоту кадров? Функция чтения — единственная, указанная в документации, и я просто где-то прочитал, что если ее нет в документации, то она недоступна. Этот метод дает мне только около 5 кадров в секунду, тогда как 10-20 кадров в секунду были бы гораздо более приемлемыми.
ОБНОВЛЕНИЕ: Судя по расхождениям между тестами Кобежона и моими с разными камерами, низкая частота кадров является результатом низкого качества веб-камер. . Веб-камеры более высокого качества дают более высокую частоту кадров.
3 - Я читал, что следует избегать использования update(), насколько это возможно, но как мне заставить холст в противном случае перерисовать изображение (или реализовать update_idletasks() с помощью этого кода)?. Нужно ли мне реализовывать какую-то многопоточность или можно этого избежать?
ОБНОВЛЕНИЕ: мне удалось заставить код работать без использования метода update(), но мне все равно придется рассмотреть возможность реализации многопоточности, потому что, когда я начните запись видео с кнопки в главном графическом интерфейсе, он зависнет/перестанет отвечать на запросы.
Готовая программа будет использоваться в Ubuntu и Windows (возможно, также и на Mac). Я использую Windows 7, IDE — Spyder 2.1.11 (Python 2.7.3).
Заранее спасибо, любые советы и/или решения будут высоко оценены!
С уважением,
С. Чиа
Подробнее здесь: https://stackoverflow.com/questions/154 ... r-deletion