任何快速的Python GUI用于显示来自摄像头的实时图像
我正在尝试从我的1394相机实时显示图像。目前我的代码可以在一个循环中从相机获取图像,我想找一个可以动态更新的简单图形界面(作为一个单独的线程)。我可以在PyQt中使用QThreads来实现这个功能,但有没有什么推荐的方法或者更快的方式呢?这是我的代码:
# 循环捕获相机的画面
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
谢谢。
5 个回答
3
我建议使用Tkinter,因为它已经是Python的一部分了。我自己没用过PIL,但快速查一下发现用PIL的图片在Tk的控件里显示很简单(可以通过pil.ImageTk.PhotoImage()这个方法来实现)。
如果你已经设置了一个Tkinter的控件来显示图片(比如Label控件就很好用),你只需要安排每隔一秒更新一次图片就可以了。你可以用tkinter的after
命令来做到这一点。
这里有个例子;我没有PIL,所以用的是一张静态图片,但这个例子说明了如何使用事件循环每秒获取一次图片:
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()
4
我想试试PyQt4的imageviewer.py示例,结果对我来说很好用。谢谢大家的帮助。以下是我修改过的代码:
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_())
6
这里有一段 wxPython 的代码,可以实现这个功能...
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()