OpenCV (cv2 в Python) VideoCapture не освобождает камеру после удаленияPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 OpenCV (cv2 в Python) VideoCapture не освобождает камеру после удаления

Сообщение Anonymous »

Я относительно новичок в Python, изучил его примерно за последний месяц и собрал все вместе на основе примеров и чужого кода, который нашел в Интернете.

Я получил графический интерфейс 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
При возникновении ошибки изображения не считываются, и видеопоток не получает изображений для обновления холста. Скрипт работает нормально, без ошибок в первый раз и каждый второй раз. Из предыдущих тестов с функцией VideoCapture в модуле cv2 я обнаружил, что мне пришлось удалить объект камеры, чтобы освободить его, чтобы последующие запуски могли без проблем захватывать поток камеры. Проверяет пространство имен, набирая в консоли who не показывать камеру, поэтому я знаю, что оно правильно удаляется после закрытия графического интерфейса. Я не понимаю, почему функция чтения cv2 выдает ошибку. Я думаю, что это происходит только каждый второй раз, потому что, когда возникает ошибка, какая-то сборка мусора или обработка ошибок удаляют или освобождают что-то, связанное с камерой, но я не знаю, что это такое...

Вот мой код:

Код: Выделить всё

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
У меня 3 вопроса

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
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»