OpenCV(Python中的cv2)VideoCapture删除后未释放摄像机

问题描述 投票:6回答:3

我对Python还是比较陌生,在过去一个月左右的时间里就已经学会了它,并根据我在网上找到的示例和其他代码将它们一起破解。

我已经有了一个Tkinter GUI,可以将来自网络摄像头的提要显示为在画布上不断更新的图像循环。每隔两次退出GUI并重新运行脚本会导致此错误:

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

发生错误时,没有图像被读取,并且视频订阅源也没有图像来更新画布。脚本第一次和第二次正常运行且没有错误。从先前在cv2模块中使用VideoCapture功能进行的测试中,我发现必须删除camera对象才能释放它,以便后续运行能够捕获相机流而没有问题。通过在控制台中键入who来检查名称空间不会显示cam,因此我知道在关闭GUI后已将其正确删除。我不明白为什么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

不显示在GUI中的按钮,并且在关闭窗口后给出此错误:

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,回调,参数,主对象)”修复了第二个错误(我做了其他错误)不发布)。同样正如kobejohn指出的那样,添加try:except块也可以解决第二个错误。请参阅他的答案以获取更多详细信息。

2-cv2中是否有比.read()更快,更有效的功能?编辑:有没有一种方法可以重构我的代码以获得更高的帧率? read函数是文档中列出的唯一函数,而我只是在某处读到,如果不在文档中,则该函数不可用。这种方法只能给我大约5fps,而10-20fps则可以接受。更新:从科比约翰测试和使用不同相机的地雷之间的差异来看,帧率低是由于网络摄像头质量差所致。网络摄像头质量更好,帧率更高。

3-我一直在阅读应尽可能避免使用update(),但如何获取画布以其他方式重绘图像(或使用此代码实现update_idletasks())?我必须实现某种线程还是可以避免这种情况?更新:我已经获得了无需使用update()方法即可工作的代码,但无论如何都必须考虑实现线程,因为当我开始从按钮录制视频时,主GUI会冻结/变得无响应。

完成的程序将在Ubuntu和Windows中使用(可能在Mac上也是如此)。我正在运行Windows 7,IDE是Spyder 2.1.11(Python 2.7.3)。

谢谢您,任何建议和/或解决方案将不胜感激!

问候,

S。嘉

python opencv tkinter video-capture
3个回答
7
投票

已解决! python中的OpenCV 2.4.2 / cv2

[出于某种奇怪的原因,在之前的论坛和其他论坛上,我找不到'release'方法,页面专门提到与opencv的python绑定不包含release方法。也许这仅在使用“ import cv”时适用。我使用后者进行了初始原型制作,由于某种原因,我在寻找ReleaseCapture方法时错过了cv2中的“ release”方法。]

刚刚在文档中找到它:http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html

import cv2

cam=cv2.VideoCapture(0)
cam.release

0
投票

您可以尝试使用此代码并查看获得的FPS吗?我包括了FPS计算,以便我们可以比较注释。 (编辑:还有什么错误。我没有得到您在原始代码中得到的错误,而我在下面的代码中得到了零错误)


0
投票

在opencv中初始化相机对象之前,请设置环境变量。

© www.soinside.com 2019 - 2024. All rights reserved.