Python GStreamer网络摄像头查看器

时间:2010-06-29 10:20:21

标签: python pygtk gstreamer

我正在研究这个很好的例子,它在一个带有python和GStreamer的GTK小部件中显示了一个网络摄像头输出:

http://pygstdocs.berlios.de/pygst-tutorial/webcam-viewer.html 这是代码:

#!/usr/bin/env python

import sys, os
import pygtk, gtk, gobject
import pygst
pygst.require("0.10")
import gst

class GTK_Main:

def __init__(self):
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.set_title("Webcam-Viewer")
    window.set_default_size(500, 400)
    window.connect("destroy", gtk.main_quit, "WM destroy")
    vbox = gtk.VBox()
    window.add(vbox)
    self.movie_window = gtk.DrawingArea()
    vbox.add(self.movie_window)
    hbox = gtk.HBox()
    vbox.pack_start(hbox, False)
    hbox.set_border_width(10)
    hbox.pack_start(gtk.Label())
    self.button = gtk.Button("Start")
    self.button.connect("clicked", self.start_stop)
    hbox.pack_start(self.button, False)
    self.button2 = gtk.Button("Quit")
    self.button2.connect("clicked", self.exit)
    hbox.pack_start(self.button2, False)
    hbox.add(gtk.Label())
    window.show_all()

    # Set up the gstreamer pipeline
    self.player = gst.parse_launch ("v4l2src ! autovideosink")

    bus = self.player.get_bus()
    bus.add_signal_watch()
    bus.enable_sync_message_emission()
    bus.connect("message", self.on_message)
    bus.connect("sync-message::element", self.on_sync_message)

def start_stop(self, w):
    if self.button.get_label() == "Start":
        self.button.set_label("Stop")
        self.player.set_state(gst.STATE_PLAYING)
    else:
        self.player.set_state(gst.STATE_NULL)
        self.button.set_label("Start")

def exit(self, widget, data=None):
    gtk.main_quit()

def on_message(self, bus, message):
    t = message.type
    if t == gst.MESSAGE_EOS:
        self.player.set_state(gst.STATE_NULL)
        self.button.set_label("Start")
    elif t == gst.MESSAGE_ERROR:
        err, debug = message.parse_error()
        print "Error: %s" % err, debug
        self.player.set_state(gst.STATE_NULL)
        self.button.set_label("Start")

def on_sync_message(self, bus, message):
    if message.structure is None:
        return
    message_name = message.structure.get_name()
    if message_name == "prepare-xwindow-id":
        # Assign the viewport
        imagesink = message.src
        imagesink.set_property("force-aspect-ratio", True)
        imagesink.set_xwindow_id(self.movie_window.window.xid)

GTK_Main()
gtk.gdk.threads_init()
gtk.main()

我想要做的是获取当前帧的快照并保存到磁盘的方法。 我认为有两种方法可以做到: - 一些gstreamer方法(但我想我至少应该修改管道) - 用GTK本身以某种方式抓住图片

有什么暗示吗? 我没有使用gstreamer或gtk的经验,非常感谢任何帮助

非常感谢 莫罗

2 个答案:

答案 0 :(得分:4)

感谢OpenCV,我设法用wxPython重写了所有内容(我比pyGTK更了解)。这是一个完整的工作示例(蒙特快照!),如果有人感兴趣的话。 另请查看OpenCV wiki:http://opencv.willowgarage.com/wiki/wxpython

import wx
import opencv.cv as cv
import opencv.highgui as gui


class CvMovieFrame(wx.Frame):
    TIMER_PLAY_ID = 101
    def __init__(self, parent):        

        wx.Frame.__init__(self, parent, -1,)        

        sizer = wx.BoxSizer(wx.VERTICAL)         

        self.capture = gui.cvCreateCameraCapture(0)
        frame = gui.cvQueryFrame(self.capture)
        cv.cvCvtColor(frame, frame, cv.CV_BGR2RGB)

        self.SetSize((frame.width + 300, frame.height + 100))

        self.bmp = wx.BitmapFromBuffer(frame.width, frame.height, frame.imageData)
        self.displayPanel= wx.StaticBitmap(self, -1, bitmap=self.bmp)
        sizer.Add(self.displayPanel, 0, wx.ALL, 10)

        self.shotbutton = wx.Button(self,-1, "Shot")
        sizer.Add(self.shotbutton,-1, wx.GROW)

        self.retrybutton = wx.Button(self,-1, "Retry")
        sizer.Add(self.retrybutton,-1, wx.GROW)     
        self.retrybutton.Hide()   

        #events
        self.Bind(wx.EVT_BUTTON, self.onShot, self.shotbutton)
        self.Bind(wx.EVT_BUTTON, self.onRetry, self.retrybutton)
        self.Bind(wx.EVT_PAINT, self.onPaint)
        self.Bind(wx.EVT_CLOSE, self.onClose)

        self.playTimer = wx.Timer(self, self.TIMER_PLAY_ID)
        wx.EVT_TIMER(self, self.TIMER_PLAY_ID, self.onNextFrame)

        self.fps = 8;
        self.SetSizer(sizer)
        sizer.Layout()
        self.startTimer()        

    def startTimer(self):
        if self.fps!=0: self.playTimer.Start(1000/self.fps)#every X ms
        else: self.playTimer.Start(1000/15)#assuming 15 fps        

    def onRetry(self, event):
        frame = gui.cvQueryFrame(self.capture)
        cv.cvCvtColor(frame, frame, cv.CV_BGR2RGB)
        self.bmp = wx.BitmapFromBuffer(frame.width, frame.height, frame.imageData)
        self.startTimer()
        self.shotbutton.Show()
        self.retrybutton.Hide()
        self.hasPicture = False
        self.Layout()
        event.Skip()    

    def onShot(self, event):
        frame = gui.cvQueryFrame(self.capture)
        self.playTimer.Stop()
        gui.cvSaveImage("foo.png", frame)        

        self.hasPicture = True
        self.shotbutton.Hide()
        self.retrybutton.Show()
        self.Layout()
        event.Skip()

    def onClose(self, event):
        try:
            self.playTimer.Stop()
        except:
            pass

        self.Show(False)
        self.Destroy()      

    def onPaint(self, evt):
        if self.bmp:
            self.displayPanel.SetBitmap(self.bmp)
        evt.Skip()

    def onNextFrame(self, evt):

        frame = gui.cvQueryFrame(self.capture)
        if frame:
            cv.cvCvtColor(frame, frame, cv.CV_BGR2RGB)
            self.bmp = wx.BitmapFromBuffer(frame.width, frame.height, frame.imageData)
            self.Refresh()        
        evt.Skip()

if __name__=="__main__":
    app = wx.App()
    f = CvMovieFrame(None)
    f.Centre()
    f.Show(True)
    app.MainLoop()

答案 1 :(得分:2)

我很确定你能做到:

self.movie_window.window.get_image(0, 0, 500, 400)

使用网络摄像头的最后一帧获取GtkImage。 500和400是窗口的宽度和高度。