views:

83

answers:

4

Hi, I am trying to display live images from my 1394 camera. Currently my code is able to obtain images in a loop from the camera and I was looking for any quick GUI that will update dynamically (as a separate thread). I can do this in PyQt maybe using QThreads but is there any recommendation or faster way of doing this?? Here's my code

#Loop capturing frames from camera

for frame in range(1,500):

print 'frame:',frame

TIME.sleep(1) #capture frame every second

image_binary    = pycam.cam.RetrieveBuffer()

#convert to PIL Image

pilimg = PIL.Image.frombuffer("L",(cimg.GetCols(),cimg.GetRows()),image_binary,'raw', "RGBA", 0, 1)
    # At this point I want to send my image data to a GUI window and display it

Thank you.

A: 

Try to take a look at gstreamer. This is the first result google gave me searching for "gstreamer 1394" and this one is the first for "gstreamer pyqt".

mg
Hey mg, gstreamer looks like a whole package that does everything. Well, I nice library that gets me custom images from my 1394 camera so I dont want to use any lib for that. And i was looking for something small. I've edited my post and added code. Let me know if you have any suggestions.Best,
reddy
The [second result by google](http://pypi.python.org/pypi/Dc1394/0.1). For the UI integration, look the other answers or look at the [test script ](http://www.rzuser.uni-heidelberg.de/~ge6/Programing/download/FastDisplay.py) at the [dc1394 home page](http://www.rzuser.uni-heidelberg.de/~ge6/Programing/dc1394python.html).
mg
+2  A: 

Here's wxPython code that will do it...

import wx
from PIL import Image

SIZE = (640, 480)

def get_image():
    # Put your code here to return a PIL image from the camera.
    return Image.new('L', SIZE)

def pil_to_wx(image):
    width, height = image.size
    buffer = image.convert('RGB').tostring()
    bitmap = wx.BitmapFromBuffer(width, height, buffer)
    return bitmap

class Panel(wx.Panel):
    def __init__(self, parent):
        super(Panel, self).__init__(parent, -1)
        self.SetSize(SIZE)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.update()
    def update(self):
        self.Refresh()
        self.Update()
        wx.CallLater(15, self.update)
    def create_bitmap(self):
        image = get_image()
        bitmap = pil_to_wx(image)
        return bitmap
    def on_paint(self, event):
        bitmap = self.create_bitmap()
        dc = wx.AutoBufferedPaintDC(self)
        dc.DrawBitmap(bitmap, 0, 0)

class Frame(wx.Frame):
    def __init__(self):
        style = wx.DEFAULT_FRAME_STYLE & ~wx.RESIZE_BORDER & ~wx.MAXIMIZE_BOX
        super(Frame, self).__init__(None, -1, 'Camera Viewer', style=style)
        panel = Panel(self)
        self.Fit()

def main():
    app = wx.PySimpleApp()
    frame = Frame()
    frame.Center()
    frame.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()
FogleBird
Hi FogleBird,I get the following error:AttributeError: 'module' object has no attribute 'CallLater'. So I used wx.FutureCall, then I get the error AttributeError: 'module' object has no attribute 'BitmapFromBuffer'Any recommendations??
reddy
What version of wxPython are you using? What platform?
FogleBird
Ubuntu 10.04; wxPython 2.8; Python 2.6
reddy
wxPython 2.8.10? Or lower?
FogleBird
A: 

I recommend using Tkinter since it's already part of python. I've never used PIL but a quick google shows it's easy to use PIL images in Tk widgets (via the pil.ImageTk.PhotoImage() method).

If you already have a Tkinter widget set up to display images (a Label widget works fine) all you need to do is arrange for the image to be updated every second or so. You can do this by using the after command of tkinter.

Here's an example; I don't have PIL so it uses a static image but it illustrates how to use the event loop to fetch images every second:

import Tkinter

class App(Tkinter.Tk):
    def __init__(self):
        Tkinter.Tk.__init__(self)
        self.label = Tkinter.Label(text="your image here", compound="top")
        self.label.pack(side="top", padx=8, pady=8)
        self.iteration=0
        self.UpdateImage(1000)

    def UpdateImage(self, delay, event=None):
        # this is merely so the display changes even though the image doesn't
        self.iteration += 1

        self.image = self.get_image()
        self.label.configure(image=self.image, text="Iteration %s" % self.iteration)
        # reschedule to run again in 1 second
        self.after(delay, self.UpdateImage, 1000)

    def get_image(self):
        # this is where you get your image and convert it to 
        # a Tk PhotoImage. For demonstration purposes I'll
        # just return a static image
        data = '''
            R0lGODlhIAAgALMAAAAAAAAAgHCAkC6LV76+vvXeswD/ANzc3DLNMubm+v/6zS9PT6Ai8P8A////
            /////yH5BAEAAAkALAAAAAAgACAAAAS00MlJq7046803AF3ofAYYfh8GIEvpoUZcmtOKAO5rLMva
            0rYVKqX5IEq3XDAZo1GGiOhw5rtJc09cVGo7orYwYtYo3d4+DBxJWuSCAQ30+vNTGcxnOIARj3eT
            YhJDQ3woDGl7foNiKBV7aYeEkHEignKFkk4ciYaImJqbkZ+PjZUjaJOElKanqJyRrJyZgSKkokOs
            NYa2q7mcirC5I5FofsK6hcHHgsSgx4a9yzXK0rrV19gRADs=
        '''
        image = Tkinter.PhotoImage(data=data)
        return image

if __name__ == "__main__":
    app=App()
    app.mainloop()
Bryan Oakley
I tried using Tkinter but when inorder to display the GUI window I had to call mainloop() which stops everything at that point i.e. it is a blocking function. I want to get images and update the Tkinter GUI window. Is there a way to do that?
reddy
@chenna: you'll have this problem no matter what toolkit you use. All GUI toolkits need an event loop. They all also have a way to interject events (for lack of a better description). In the case of Tkinter, you can call `after` to have something called by the event loop at some point in the future. I've edited my answer to give you a working example.
Bryan Oakley
Thanks Bryan. I get the following error, any ideas what is causing it?? File "LiveCam.py", line 28, in __init__ self.UpdateImage(1000) File "LiveCam.py", line 36, in UpdateImage self.label.configure(image=self.image) File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1205, in configure return self._configure('configure', cnf, kw) File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1196, in _configure self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))TypeError: __str__ returned non-string (type instance)
reddy
@chenna: I don't know. My guess is your Get_image method is not returning a proper tk image.
Bryan Oakley
ya, i guessed the same. Anyways, I tried PyQt4 and it worked, i've posted my solution below. I am actually a little biased towards Qt since I've been using it for a long time :D. I'll still try fixing my tk code n keep u updated. Thanks for the help Bryan
reddy
A: 

Hey Guys, I thought I'd try PyQt4 imageviewer.py example and it worked for me. Thanks for all your help guys. Here's my modified code:

from PyQt4 import QtCore, QtGui
class CameraViewer(QtGui.QMainWindow):
    def __init__(self):
    super(CameraViewer, self).__init__()

    self.imageLabel = QtGui.QLabel()
    self.imageLabel.setBackgroundRole(QtGui.QPalette.Base)
    self.imageLabel.setScaledContents(True)

    self.scrollArea = QtGui.QScrollArea()
    self.scrollArea.setWidget(self.imageLabel)
    self.setCentralWidget(self.scrollArea)

    self.setWindowTitle("Image Viewer")
    self.resize(640, 480)

    timer = QtCore.QTimer(self)
    timer.timeout.connect(self.open)
    timer.start(33) #30 Hz

    def open(self):
    #get data and display
    pilimg = getMyPILImageDatFromCamera()
    image = PILQT.ImageQt.ImageQt(pilimg)
    if image.isNull():
        QtGui.QMessageBox.information(self, "Image Viewer","Cannot load %s." % fileName)
        return

    self.imageLabel.setPixmap(QtGui.QPixmap.fromImage(image))
    self.imageLabel.adjustSize()


if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)
    CameraViewer = CameraViewer()
    CameraViewer.show()
    sys.exit(app.exec_())
reddy