问题
I have managed to stream a webcam video inside a Wx-Python window using Open-CV but i want to record that video using control buttons. Let me know how to capture a webcam video while a click a button?
import wx
import vlc
import numpy as np
import time
import os
import user
import cv2.cv
class MainWindow(wx.Panel):
def __init__(self, parent,capture):
wx.Panel.__init__(self, parent)
mainSizer = wx.BoxSizer(wx.VERTICAL)
# video
videoWarper = wx.StaticBox(self,size=(640,480))
videoBoxSizer = wx.StaticBoxSizer(videoWarper, wx.VERTICAL)
videoFrame = wx.Panel(self, -1,size=(640,480))
capture = ShowCapture(videoFrame, capture)
videoBoxSizer.Add(videoFrame,0)
mainSizer.Add(videoBoxSizer,0)
parent.Centre()
self.Show()
self.SetSizerAndFit(mainSizer)
# Panels
# The first panel holds the video and it's all black
self.videopanel = wx.Panel(self, -1)
self.videopanel.SetBackgroundColour(wx.BLACK)
# The second panel holds controls
ctrlpanel = wx.Panel(self, -1 )
self.timeslider = wx.Slider(ctrlpanel, -1, 0, 0, 1000)
self.timeslider.SetRange(0, 1000)
pause = wx.Button(ctrlpanel, label="Pause")
play = wx.Button(ctrlpanel, label="Play")
stop = wx.Button(ctrlpanel, label="Stop")
record = wx.Button(ctrlpanel, label="Record")
cancel = wx.Button(ctrlpanel, label="Cancel")
volume = wx.Button(ctrlpanel, label="Vol")
self.volslider = wx.Slider(ctrlpanel, -1, 0, 0, 100, size=(100, -1))
# Bind controls to events
self.Bind(wx.EVT_BUTTON, self.OnPlay, play)
self.Bind(wx.EVT_BUTTON, self.OnPause, pause)
self.Bind(wx.EVT_BUTTON, self.OnStop, stop)
self.Bind(wx.EVT_BUTTON, self.OnRecord, record)
self.Bind(wx.EVT_BUTTON, self.OnCancel, cancel)
self.Bind(wx.EVT_BUTTON, self.OnToggleVolume, volume)
self.Bind(wx.EVT_SLIDER, self.OnSetVolume, self.volslider)
# Give a pretty layout to the controls
ctrlbox = wx.BoxSizer(wx.VERTICAL)
box = wx.BoxSizer(wx.HORIZONTAL)
# box contains some buttons and the volume controls
box.Add(play, flag=wx.RIGHT, border=5)
box.Add(pause)
box.Add(stop)
box.Add(record)
box.Add(cancel)
box.Add((-1, -1), 1)
box.Add(volume)
box.Add(self.volslider, flag=wx.TOP | wx.LEFT, border=5)
# Merge box1 and box2 to the ctrlsizer
ctrlbox.Add(box, flag=wx.EXPAND, border=10)
ctrlpanel.SetSizer(ctrlbox)
# Put everything togheter
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(ctrlpanel, flag=wx.EXPAND | wx.BOTTOM | wx.TOP, border=10)
self.SetSizer(sizer)
self.SetMinSize((350, 300))
# finally create the timer, which updates the timeslider
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
# VLC player controls
self.Instance = vlc.Instance()
self.player = self.Instance.media_player_new()
def OnClose(self, evt):
"""Closes the window.
"""
self.Close()
def OnOpen(self, evt):
"""Pop up a new dialow window to choose a file, then play the selected file.
"""
# if a file is already running, then stop it.
self.OnStop(None)
# Create a file dialog opened in the current home directory, where
# you can display all kind of files, having as title "Choose a file".
dlg = wx.FileDialog(self, "Choose a file", user.home, "",
"*.*", wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
dirname = dlg.GetDirectory()
filename = dlg.GetFilename()
# Creation
self.Media = self.Instance.media_new(unicode(os.path.join(dirname, filename)))
self.player.set_media(self.Media)
# Report the title of the file chosen
title = self.player.get_title()
# if an error was encountred while retriving the title, then use
# filename
if title == -1:
title = filename
self.SetTitle("%s - wxVLCplayer" % title)
# set the window id where to render VLC's video output
self.player.set_xwindow(self.videopanel.GetHandle())
# FIXME: this should be made cross-platform
self.OnPlay(None)
# set the volume slider to the current volume
self.volslider.SetValue(self.player.audio_get_volume() / 2)
# finally destroy the dialog
dlg.Destroy()
def OnPlay(self, evt):
"""Toggle the status to Play/Pause.
If no file is loaded, open the dialog window.
"""
# check if there is a file to play, otherwise open a
# wx.FileDialog to select a file
if not self.player.get_media():
self.OnOpen(None)
else:
# Try to launch the media, if this fails display an error message
if self.player.play() == -1:
self.errorDialog("Unable to play.")
else:
self.timer.Start()
def OnPause(self, evt):
"""Pause the player.
"""
self.player.pause()
def OnStop(self, evt):
"""Stop the player.
"""
self.player.stop()
# reset the time slider
self.timeslider.SetValue(0)
self.timer.Stop()
# -------begin capturing and saving video
def OnRecord(self, evt):
capture=cv2.VideoCapture(0)
if (not capture.isOpened()):
print "Error"
# video recorder
# Define the codec and create VideoWriter object
fourcc = cv2.cv.FOURCC('M','P','E','G')
out = cv2.VideoWriter('output.mp4',fourcc, 20.0, (640,480), isColor=True)
while(capture.isOpened()):
ret, frame = capture.read()
if ret==True:
# write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
def OnCancel(self, evt):
out = cv2.VideoWriter()
capture.release()
out.release()
cv2.destroyAllWindows()
def OnTimer(self, evt):
"""Update the time slider according to the current movie time.
"""
# since the self.player.get_length can change while playing,
# re-set the timeslider to the correct range.
length = self.player.get_length()
self.timeslider.SetRange(-1, length)
# update the time on the slider
time = self.player.get_time()
self.timeslider.SetValue(time)
def OnToggleVolume(self, evt):
"""Mute/Unmute according to the audio button.
"""
is_mute = self.player.audio_get_mute()
self.player.audio_set_mute(not is_mute)
# update the volume slider;
# since vlc volume range is in [0, 200],
# and our volume slider has range [0, 100], just divide by 2.
self.volslider.SetValue(self.player.audio_get_volume() / 2)
def OnSetVolume(self, evt):
"""Set the volume according to the volume sider.
"""
volume = self.volslider.GetValue() * 2
# vlc.MediaPlayer.audio_set_volume returns 0 if success, -1 otherwise
if self.player.audio_set_volume(volume) == -1:
self.errorDialog("Failed to set volume")
class ShowCapture(wx.Panel):
def __init__(self, parent, capture, fps=24):
wx.Panel.__init__(self, parent, wx.ID_ANY, (0,0), (640,480))
self.capture = capture
ret, frame = self.capture.read()
height, width = frame.shape[:2]
parent.SetSize((width, height))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.bmp = wx.BitmapFromBuffer(width, height, frame)
self.timer = wx.Timer(self)
self.timer.Start(1000./fps)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_TIMER, self.NextFrame)
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self)
dc.DrawBitmap(self.bmp, 0, 0)
def NextFrame(self, event):
ret, frame = self.capture.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.bmp.CopyFromBuffer(frame)
self.Refresh()
capture = cv2.VideoCapture(0)
app = wx.App(False)
frame = wx.Frame(None, title='CamGUI')
panel = MainWindow(frame,capture)
frame.Show()
app.MainLoop()
回答1:
I have modified your code so that control buttons come up, are visible and have functions. But you still have to work on the functions. You could also program the slider to jump to the points in the video:
import wx
import vlc
import numpy as np
import sys
import time
import os
import user
import cv2.cv
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent)
self.size = (640,480)
self.Bind(wx.EVT_CLOSE, self.OnClose)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.title = title
self.SetTitle(self.title)
self.panel = wx.Panel(self)
# video
self.Playing = False
self.capture = cv2.VideoCapture(0)
self.videoFrame = wx.Panel(self.panel, -1, size=self.size)
image = wx.EmptyImage(self.size[0], self.size[1])
imageBitmap = wx.BitmapFromImage(image)
self.videobmp = wx.StaticBitmap(self.videoFrame, wx.ID_ANY, imageBitmap)
self.ShowCapture()
videoSizer = wx.BoxSizer(wx.HORIZONTAL)
videoSizer.Add(self.videoFrame, 0)
mainSizer.Add(videoSizer, 0)
# The second panel holds controls
ctrlbox = wx.BoxSizer(wx.VERTICAL)
# ctrlpanel = wx.Panel(self, -1 )
self.timeslider = wx.Slider(self.panel, -1, 0, 0, 1000)
self.timeslider.SetRange(0, 1000)
ctrlbox.Add(self.timeslider, flag=wx.EXPAND, border=10)
box = wx.BoxSizer(wx.HORIZONTAL)
pause = wx.Button(self.panel, label="Pause")
play = wx.Button(self.panel, label="Play")
stop = wx.Button(self.panel, label="Stop")
record = wx.Button(self.panel, label="Record")
cancel = wx.Button(self.panel, label="Cancel")
volume = wx.Button(self.panel, label="Vol")
self.volslider = wx.Slider(self.panel, -1, 0, 0, 100, size=(100, -1))
self.volslider.SetValue(50)
# Bind controls to events
self.Bind(wx.EVT_BUTTON, self.OnPlay, play)
self.Bind(wx.EVT_BUTTON, self.OnPause, pause)
self.Bind(wx.EVT_BUTTON, self.OnStop, stop)
self.Bind(wx.EVT_BUTTON, self.OnRecord, record)
self.Bind(wx.EVT_BUTTON, self.OnCancel, cancel)
self.Bind(wx.EVT_BUTTON, self.OnToggleVolume, volume)
self.Bind(wx.EVT_SLIDER, self.OnSetVolume, self.volslider)
# box contains some buttons and the volume controls
box.Add(play, flag=wx.RIGHT, border=5)
box.Add(pause)
box.Add(stop)
box.Add(record)
box.Add(cancel)
box.Add((-1, -1), 1)
box.Add(volume)
box.Add(self.volslider, flag=wx.TOP | wx.LEFT, border=5)
# Merge box1 and box2 to the ctrlsizer
ctrlbox.Add(box, flag=wx.EXPAND, border=10)
# ctrlpanel.SetSizer(ctrlbox)
mainSizer.Add(ctrlbox, 0)
# finally create the timer, which updates the timeslider
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
# VLC player controls
self.Instance = vlc.Instance()
self.player = self.Instance.media_player_new()
self.panel.SetSizer(mainSizer)
mainSizer.Fit(self)
# self.SetSizerAndFit(mainSizer)
self.Centre()
self.Show()
def OnClose(self, evt):
"""Closes the window.
"""
# self.Close()
self.Destroy()
def OnOpen(self, evt):
"""Pop up a new dialow window to choose a file, then play the selected file.
"""
# if a file is already running, then stop it.
self.OnStop(None)
# Create a file dialog opened in the current home directory, where
# you can display all kind of files, having as title "Choose a file".
dlg = wx.FileDialog(self, "Choose a file", user.home, "",
"*.*", wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
self.Playing = True
dirname = dlg.GetDirectory()
filename = dlg.GetFilename()
# Creation
self.Media = self.Instance.media_new(unicode(os.path.join(dirname, filename)))
self.player.set_media(self.Media)
# Report the title of the file chosen
title = self.player.get_title()
# if an error was encountred while retriving the title, then use
# filename
if title == -1:
title = filename
self.SetTitle("%s - wxVLCplayer" % title)
# set the window id where to render VLC's video output
# set the window id where to render VLC's video output
# handle = self.videopanel.GetHandle()
handle = self.videoFrame.GetHandle()
if sys.platform.startswith('linux'): # for Linux using the X Server
self.player.set_xwindow(handle)
elif sys.platform == "win32": # for Windows
self.player.set_hwnd(handle)
elif sys.platform == "darwin": # for MacOS
self.player.set_nsobject(handle)
self.OnPlay(None)
# set the volume slider to the current volume
self.volslider.SetValue(self.player.audio_get_volume() / 2)
# finally destroy the dialog
dlg.Destroy()
def OnPlay(self, evt):
"""Toggle the status to Play/Pause.
If no file is loaded, open the dialog window.
"""
# check if there is a file to play, otherwise open a
# wx.FileDialog to select a file
if not self.player.get_media():
self.OnOpen(None)
else:
# Try to launch the media, if this fails display an error message
if self.player.play() == -1:
self.errorDialog("Unable to play.")
else:
self.timer.Start()
self.Playing = True
def OnPause(self, evt):
"""Pause the player.
"""
self.player.pause()
self.Playing = True
def OnStop(self, evt):
"""Stop the player.
"""
self.player.stop()
# reset the time slider
self.timeslider.SetValue(0)
self.timer.Stop()
self.Playing = False
# -------begin capturing and saving video
def OnRecord(self, evt):
# capture=cv2.VideoCapture(0)
if (not self.capture.isOpened()):
print "Error"
# video recorder
# Define the codec and create VideoWriter object
fourcc = cv2.cv.FOURCC('M','P','E','G')
out = cv2.VideoWriter('output.mp4',fourcc, 20.0, (640,480), isColor=True)
while(self.capture.isOpened()):
ret, frame = self.capture.read()
if ret==True:
# write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
def OnCancel(self, evt):
out = cv2.VideoWriter()
self.capture.release()
out.release()
cv2.destroyAllWindows()
def OnTimer(self, evt):
"""Update the time slider according to the current movie time.
"""
# since the self.player.get_length can change while playing,
# re-set the timeslider to the correct range.
length = self.player.get_length()
self.timeslider.SetRange(-1, length)
# update the time on the slider
time = self.player.get_time()
self.timeslider.SetValue(time)
def OnToggleVolume(self, evt):
"""Mute/Unmute according to the audio button.
"""
is_mute = self.player.audio_get_mute()
self.player.audio_set_mute(not is_mute)
# update the volume slider;
# since vlc volume range is in [0, 200],
# and our volume slider has range [0, 100], just divide by 2.
self.volslider.SetValue(self.player.audio_get_volume() / 2)
def OnSetVolume(self, evt):
"""Set the volume according to the volume sider.
"""
volume = self.volslider.GetValue() * 2
# vlc.MediaPlayer.audio_set_volume returns 0 if success, -1 otherwise
if self.player.audio_set_volume(volume) == -1:
self.errorDialog("Failed to set volume")
def ShowCapture(self, fps=24):
ret, self.frame = self.capture.read()
self.height, self.width = self.frame.shape[:2]
# self.SetSize((self.width, self.height))
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
self.bmp = wx.BitmapFromBuffer(self.width, self.height, self.frame)
self.timer2 = wx.Timer(self)
self.timer2.Start(1000./fps)
# self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_TIMER, self.NextFrame)
# def OnPaint(self, evt):
# dc = wx.BufferedPaintDC(self)
# dc.DrawBitmap(self.bmp, 0, 0)
def NextFrame(self, event):
if not self.Playing:
ret, self.frame = self.capture.read()
if ret:
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
self.bmp.CopyFromBuffer(self.frame)
self.videobmp.SetBitmap(self.bmp)
self.Refresh()
app = wx.App(False)
frame = MainWindow(None, title='CamGUI')
frame.Show()
app.MainLoop()
来源:https://stackoverflow.com/questions/37961949/record-webcam-video-with-wxpython-open-cv-using-control-buttons