当前位置: 代码迷 >> 图形/图像 >> Python图像处理(三):视频显示
  详细解决方案

Python图像处理(三):视频显示

热度:1128   发布时间:2016-05-13 02:27:10
Python图像处理(3):视频显示

快乐虾

http://blog.csdn.net/lights_joy/(QQ群:Visual EmbedLinux Tools 375515651)

欢迎转载,但请保留作者信息



1.    OpenCV进行视频显示


之前用OpenCV做了一个简单的视频显示:


# -*- coding: utf-8 -*- # 使用OpenCV播放视频import cv2wnd = 'OpenCV Video' #获得视频的格式videoCapture = cv2.VideoCapture('f:\\tmp\\cotton.mp4') #获得码率及尺寸fps = videoCapture.get(cv2.cv.CV_CAP_PROP_FPS)size = (int(videoCapture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)),         int(videoCapture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)))cv2.namedWindow(wnd, flags=0)cv2.resizeWindow(wnd, size[0]/2, size[1]/2)# 读帧success, frame = videoCapture.read() while success :    cv2.imshow(wnd, frame) #显示    cv2.waitKey(1000 / int(fps)) #延迟    success, frame = videoCapture.read() #获取下一帧

完全用cv2做视频读取和显示,这个程序有两个问题,一个是cv2窗口的缩放问题导致视频图像的变形,另一个是opencv提供的界面控制功能很弱,甚至于它都不提供在界面上显示按纽的能力,因此我们想办法替换界面显示的部分。


2.    wxFormBuilder构建界面


wxFormBuilder是一个使用wxWidgetsUI界面设计工具,可以很直观地进行UI设计,并生成C++/Python/Lua/Xrc相关的代码。我们用它构建视频播放器的界面:



在主窗口上留下一个Panel控件用以嵌入matplotlib的窗口。


wxFormBuilder自动生成了Python代码:


# -*- coding: utf-8 -*- ############################################################################# Python code generated with wxFormBuilder (version Jun  5 2014)## http://www.wxformbuilder.org/#### PLEASE DO "NOT" EDIT THIS FILE!###########################################################################import wximport wx.xrc############################################################################# Class MainFrame###########################################################################class MainFrame ( wx.Frame ):		def __init__( self, parent ):		wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Video Player", pos = wx.DefaultPosition, size = wx.Size( 757,562 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )				self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )				self.m_timer = wx.Timer()		self.m_timer.SetOwner( self, wx.ID_ANY )		self.m_timer.Start( 40 )				MainSizer = wx.BoxSizer( wx.VERTICAL )				ButtonSizer = wx.BoxSizer( wx.HORIZONTAL )				self.m_btnStart = wx.Button( self, wx.ID_ANY, u"开始", wx.DefaultPosition, wx.DefaultSize, 0 )		ButtonSizer.Add( self.m_btnStart, 0, wx.ALL, 5 )				self.m_btnStop = wx.Button( self, wx.ID_ANY, u"停止", wx.DefaultPosition, wx.DefaultSize, 0 )		ButtonSizer.Add( self.m_btnStop, 0, wx.ALL, 5 )						MainSizer.Add( ButtonSizer, 0, wx.EXPAND, 5 )				PanelSizer = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Matplotlib 控制区" ), wx.VERTICAL )				self.m_pnlMatplot = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.Size( -1,-1 ), 0 )		MatplotSizer = wx.BoxSizer( wx.VERTICAL )						self.m_pnlMatplot.SetSizer( MatplotSizer )		self.m_pnlMatplot.Layout()		MatplotSizer.Fit( self.m_pnlMatplot )		PanelSizer.Add( self.m_pnlMatplot, 1, wx.EXPAND |wx.ALL, 5 )						MainSizer.Add( PanelSizer, 1, wx.EXPAND, 5 )						self.SetSizer( MainSizer )		self.Layout()				self.Centre( wx.BOTH )				# Connect Events		self.Bind( wx.EVT_TIMER, self.OnTimer, id=wx.ID_ANY )		self.m_btnStart.Bind( wx.EVT_BUTTON, self.OnStart )		self.m_btnStop.Bind( wx.EVT_BUTTON, self.OnStop )		def __del__( self ):		pass			# Virtual event handlers, overide them in your derived class	def OnTimer( self, event ):		event.Skip()		def OnStart( self, event ):		event.Skip()		def OnStop( self, event ):		event.Skip()	

直接在此播放器工程中新建一个py文件,再将此代码复制到我们的播放器工程中,加上App和事件循环:

app = wx.App()frame = MainFrame(None)	frame.Show()app.MainLoop()

3.    编码问题


在上节中直接在python工程中建立了一个新的py文件并将wxFormBuilder生成的代码复制过来,结果很悲摧:



更改此文件的编码为UTF-8


再运行就好了:


4.    加上matplotlib显示


接下来加上matplotlib显示功能。


首先在Frame初始化的时候创建matplotlib所需要的canvas


        self.mpl_control = FigureCanvas(self.m_pnlMatplot, -1, plt.gcf())        MatplotSizer.Add(self.mpl_control, 1, wx.LEFT | wx.TOP | wx.GROW)

在按下开始的时候打开文件和定时器:

    def OnStart( self, event ):        self.videoCapture = cv2.VideoCapture('f:\\tmp\\cotton.mp4')        if(self.videoCapture == None):            wx.SafeShowMessage('start', 'Open Failed')            return        self.fps = self.videoCapture.get(cv2.cv.CV_CAP_PROP_FPS)        self.m_timer.Start(100)

在按下停止的时候停止定时器:

    def OnStop( self, event ):        self.m_timer.Stop()

在定时器事件中绘图:

    def OnTimer( self, event ):        success, self.frame = self.videoCapture.read()        if(success) :            plt.imshow(self.frame)            self.mpl_control.draw_idle()

运行的结果就是这样的:



5.    内存泄漏


在上述代码中,运行时存在严重的内存泄漏,在视频播放的时候内存使用率不断上升。


查一下imshow的代码:

    @docstring.dedent_interpd    def imshow(self, X, cmap=None, norm=None, aspect=None,               interpolation=None, alpha=None, vmin=None, vmax=None,               origin=None, extent=None, shape=None, filternorm=1,               filterrad=4.0, imlim=None, resample=None, url=None, **kwargs):        """        Display an image on the axes.......        """......        im = mimage.AxesImage(self, cmap, norm, interpolation, origin, extent,                       filternorm=filternorm,                       filterrad=filterrad, resample=resample, **kwargs)        im.set_data(X)        im.set_alpha(alpha)        if im.get_clip_path() is None:            # image does not already have clipping set, clip to axes patch            im.set_clip_path(self.patch)        #if norm is None and shape is None:        #    im.set_clim(vmin, vmax)        if vmin is not None or vmax is not None:            im.set_clim(vmin, vmax)        else:            im.autoscale_None()        im.set_url(url)        # update ax.dataLim, and, if autoscaling, set viewLim        # to tightly fit the image, regardless of dataLim.        im.set_extent(im.get_extent())        self.add_image(im)        return im

在这个函数的末尾使用


        self.add_image(im)


将创建出来的图像添加到了图像列表中,而不是替换已经有的图像,这就导致了内存不断上升!知道原因后就容易处理了,修改我们的代码,在显示图像前删除之前的图像:

    # Virtual event handlers, overide them in your derived class    def OnTimer( self, event ):        success, self.frame = self.videoCapture.read()        if(success) :            if(self.image != None) :                self.image.remove()            (b, g, r) = cv2.split(self.frame)            self.frame = cv2.merge([r,g,b])            self.image = plt.imshow(self.frame)            self.mpl_control.draw_idle()

搞定!

















??
本站暂不开放注册!
内测阶段只得通过邀请码进行注册!