我对Python还比较陌生,只是在过去一个月左右的时间里学会了它,并根据我在网上找到的示例和其他代码一起破解了它。
我得到了一个Tkinter图形用户界面,可以将来自网络摄像头的提要显示为画布上不断更新的图像的循环。退出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
当错误发生时,无法读取图像,videofeed也无法接收图像来更新画布。脚本运行正常,第一次和第二次都没有错误。从以前对cv2模块中的VideoCapture功能的测试中,我发现必须删除camera对象才能释放它,这样后续的运行就可以毫无问题地捕获camera流。通过在控制台中键入who
来检查命名空间不会显示cam
,因此我知道在关闭GUI后它会被正确删除。我不明白为什么cv2的read函数会出错。我认为这只是每秒钟发生一次,因为当错误发生时,一些垃圾收集或错误处理会删除或释放一些与相机有关的内容,但我不知道这是什么。。。
这是我的代码:
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,arguments,master)“修复了第二个错误(以及其他我没有发布的错误)。正如kobejohn指出的,添加了一个try:except块也修复了第二个错误。详情请看他的回答。
2-在cv2中是否有比.read()更快、更高效的函数?编辑:有没有办法重构我的代码以获得更高的帧率?read函数是文档中列出的唯一一个函数,我只是在某个地方读到,如果它不在文档中,那么它就不可用。这种方法只给我5帧每秒,其中10-20帧会更容易接受。
更新:从kobejohn的测试和我的不同相机之间的差异来看,低帧率是由于劣质网络摄像头造成的。更高质量的网络摄像头产生更高的帧率。
3-我读到应该尽可能避免update(),但是如何让画布重新绘制图像(或者用这段代码实现update_idletasks())?。我必须实现某种线程还是可以避免?
UPDATE:我在不使用UPDATE()方法的情况下让代码工作,但无论如何都必须考虑实现线程,因为当我从主GUI的按钮开始录制videofeed时,它会冻结/变得没有响应。
完成的程序将用于Ubuntu和windows(可能也用于macs)。我运行Windows7,IDE是Spyder2.1.11(Python2.7.3)。
提前感谢您,任何建议和/或解决方案将非常感谢!
谨致问候
S.Chia公司
解决了!python中的OpenCV 2.4.2/cv2
出于某种奇怪的原因,我在之前和其他论坛上都找不到'release'方法,页面特别提到了opencv的python绑定不包括release方法。也许这只适用于使用“导入简历”。我用后者做了我的初始原型,由于某种原因,我在寻找ReleaseCapture方法时错过了cv2中的“release”方法。
刚在文件里找到的:http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html
你能试试这个代码看看你能得到多少FPS吗?我包括了一个FPS的计算,所以我们可以比较笔记。(编辑:还有什么错误。我没有得到你在原始代码中得到的错误,下面的代码也没有错误)
我从头开始只是想看看我是否想出了不同的东西。有几个不同点:
cv2.COLOR_RGB2GRAY
-->;cv2.COLOR_BGR2GRAY
。你可以在VideoCapture example中看到他们做了类似的事情。使用此代码,我可以获得15 FPS,并且在windows 7上没有错误:
相关问题 更多 >
编程相关推荐