Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python GStreamer webcam viewer

I'working on this nice example that shows a webcam output in a GTK widget with python and GStreamer:

http://pygstdocs.berlios.de/pygst-tutorial/webcam-viewer.html here is the code:

#!/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()

What I'd like to do is have a method to take a snapshot of the current frame and save to disk. I think there are 2 ways to do it: - some gstreamer method (but i think I should at least modify the pipeline) - grab the picture somehow with GTK itself

Any hint on this? I have no experience with gstreamer or gtk, any help is really appreciated

Thanks a lot Mauro

like image 509
Mauro Bianchi Avatar asked Jun 29 '10 10:06

Mauro Bianchi


2 Answers

Thanks to OpenCV I managed to rewrite everything with wxPython (which i know better than pyGTK). Here is a full working example (whith snapshot!), if anyone interested. Also checkout the OpenCV wiki here: 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()
like image 80
Mauro Bianchi Avatar answered Nov 16 '22 14:11

Mauro Bianchi


I'm pretty sure that you could do:

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

To get a GtkImage with the last frame from the webcam. The 500 and 400 is the width and the height of the window.

like image 42
Linus Unnebäck Avatar answered Nov 16 '22 13:11

Linus Unnebäck