1 | initial version |
This is part of a bigger project, so I had to peel the source code out of it - its dirty but it makes my point. The goal is an application which records a video and sends time stamps to various other machines and a PowerLab. WxPython is in the game because theres a lot of GUI and other processes. In the source code I left the video in its original size - because the effect comes earlier. (I know it would be a solution to make the video as small as possible but then the effect would simply occur later).
The capturing and writing out the frames is done by a wxpython timer. And theres no change if I remove the wxpython stuff. Thats the source code:
import wx import time import cv, cv2 import sys from pylab import *
class MyFrame(wx.Frame): def __init__(self, args, *kwds):
############################################################################ initialize camera and capturing
self.capture = cv2.VideoCapture(0)
ret, self.frame = self.capture.read()
self.cwidth=int(self.capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH))
self.cheight=int(self.capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))
self.capSize=(self.cwidth,self.cheight)
self.fps=12.5
self.frames=0
self.iterations=2000 ###################### number of frames to capture
self.frame_rate_data=[]
self.frame_data=[]
print 'Camera loaded',self.cwidth,self.cheight,self.capSize
######################################################################## wxpython
wx.Frame.__init__(self, *args, **kwds)
mainSizer = wx.BoxSizer(wx.VERTICAL)
videoWarper = wx.StaticBox(self, label="Video",size=(self.cwidth,self.cheight))
videoBoxSizer = wx.StaticBoxSizer(videoWarper, wx.VERTICAL)
self.videoPanel = wx.Panel(self, -1,size=(self.cwidth,self.cheight))
videoBoxSizer.Add(self.videoPanel,0)
mainSizer.Add(videoBoxSizer,0)
self.Show()
self.SetSizerAndFit(mainSizer)
######################################################################## convert frame to bmp for wx python
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
self.bmp = wx.BitmapFromBuffer(self.cwidth, self.cheight, self.frame)
######################################################################## initialize videowriter
self.fourcc = cv2.cv.CV_FOURCC('m', 'p', '4', 'v')
self.vout = cv2.VideoWriter() ################################################### open videowriter
self.outmovie='test'+'.mov'
success = self.vout.open(self.outmovie,self.fourcc,self.fps,self.capSize,True)
####################################################################### initialize timer
self.timer = wx.Timer(self.videoPanel)
self.videoPanel.Bind(wx.EVT_PAINT, self.OnPaint)
self.videoPanel.Bind(wx.EVT_TIMER, self.NextFrame)
self.t0 =time.time()
self.timer.Start(int(1000.0/self.fps))
def OnPaint(self, event):
dc = wx.BufferedPaintDC(self.videoPanel)
dc.DrawBitmap(self.bmp, 0, 0)
def NextFrame(self, event):
ret, self.frame = self.capture.read()
if ret:
self.xtime= time.time() - self.t0
self.frames=self.frames+1
self.vout.write(self.frame) ######################### this is the offending line !!! videowriter on - off
xtime= time.time() - self.t0
fpa= self.frames/xtime
#print self.frames, self.xtime, fpa
self.frame_rate_data.append (fpa)
self.frame_data.append (self.frames)
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
self.bmp.CopyFromBuffer(self.frame)
self.Refresh()
if self.frames ==self.iterations: ################### plot and quit
plot(self.frame_data,self.frame_rate_data)
grid(True)
savefig("test.png")
show()
self.Destroy()
sys.exit()
if __name__ == "__main__":
app=wx.App(False)
frame_1 = MyFrame(None, wx.ID_ANY, "")
app.SetTopWindow(frame_1)
frame_1.Show()
app.MainLoop()
Ok - thats the performance with commenting simply the line videowriter out:
Now lets write frames and the performance looks like this:
As you see the cumulative frames per second just drop away. The error can't be in the rest of the program, because its only by one line commented or uncommented.
Sorry for the dirty hack.