使用Glumpy实时显示NumPy数组为图像

8 投票
2 回答
4908 浏览
提问于 2025-04-16 05:32

我在用Python做一个模拟模型,使用了NumPy和SciPy,每次运行都会输出一个二维的NumPy数组。我现在是用matplotlib的imshow函数把这个输出显示成图片。不过,我最近发现了Glumpy,看到它的文档上说:

得益于IPython环境,Glumpy可以在交互模式下运行,这样你可以实时看到数组内容变化时的更新。

但是,我不知道怎么用他们给的例子来实现这个功能。简单来说,我的模型是一个函数,里面有一个很大的for循环,用来控制运行的次数。在每次循环结束时,我想显示这个数组。目前我用matplotlib把图片保存成png文件,因为通过matplotlib在屏幕上显示图片时,Python的进程会卡住。

我相信用Glumpy可以做到这一点,只是我不太清楚怎么做,也找不到有用的教程。

2 个回答

1

使用 pyformulas 0.2.8,你可以用 pf.screen 来创建一个不阻塞的屏幕:

import pyformulas as pf
import numpy as np

canvas = np.floor(np.random.normal(scale=50, size=(480,640,3)) % 256).astype(np.uint8)
screen = pf.screen(canvas)

while screen.exists():
    canvas = np.floor(np.random.normal(scale=50, size=(480,640,3)) % 256).astype(np.uint8)
    screen.update(canvas)

#screen.close()

免责声明:我是 pyformulas 的维护者

11

Glumpy 的文档几乎没有!这里有一个简单的模拟示例,比较了使用 glumpymatplotlib 的数组可视化效果:

import numpy as np
import glumpy
from OpenGL import GLUT as glut
from time import time
from matplotlib.pyplot import subplots,close
from matplotlib import cm

def randomwalk(dims=(256,256),n=3,sigma=10,alpha=0.95,seed=1):
    """ A simple random walk with memory """
    M = np.zeros(dims,dtype=np.float32)
    r,c = dims
    gen = np.random.RandomState(seed)
    pos = gen.rand(2,n)*((r,),(c,))
    old_delta = gen.randn(2,n)*sigma
    while 1:
        delta = (1.-alpha)*gen.randn(2,n)*sigma + alpha*old_delta
        pos += delta
        for ri,ci in pos.T:
            if not (0. <= ri < r) : ri = abs(ri % r)
            if not (0. <= ci < c) : ci = abs(ci % c)
            M[ri,ci] += 1
        old_delta = delta
        yield M

def mplrun(niter=1000):
    """ Visualise the simulation using matplotlib, using blit for 
    improved speed"""
    fig,ax = subplots(1,1)
    rw = randomwalk()
    im = ax.imshow(rw.next(),interpolation='nearest',cmap=cm.hot,animated=True)
    fig.canvas.draw()
    background = fig.canvas.copy_from_bbox(ax.bbox) # cache the background

    tic = time()
    for ii in xrange(niter):
        im.set_data(rw.next())          # update the image data
        fig.canvas.restore_region(background)   # restore background
        ax.draw_artist(im)          # redraw the image
        fig.canvas.blit(ax.bbox)        # redraw the axes rectangle

    close(fig)
    print "Matplotlib average FPS: %.2f" %(niter/(time()-tic))

def gprun(niter=1000):
    """ Visualise the same simulation using Glumpy """
    rw = randomwalk()
    M = rw.next()

    # create a glumpy figure
    fig = glumpy.figure((512,512))

    # the Image.data attribute is a referenced copy of M - when M
    # changes, the image data also gets updated
    im = glumpy.image.Image(M,colormap=glumpy.colormap.Hot)

    @fig.event
    def on_draw():
        """ called in the simulation loop, and also when the
        figure is resized """
        fig.clear()
        im.update()
        im.draw( x=0, y=0, z=0, width=fig.width, height=fig.height )

    tic = time()
    for ii in xrange(niter):
        M = rw.next()           # update the array          
        glut.glutMainLoopEvent()    # dispatch queued window events
        on_draw()           # update the image in the back buffer
        glut.glutSwapBuffers()      # swap the buffers so image is displayed

    fig.window.hide()
    print "Glumpy average FPS: %.2f" %(niter/(time()-tic))

if __name__ == "__main__":
    mplrun()
    gprun()

我使用 matplotlibGTKAgg 作为后端,并且用 blit 来避免每次都画背景,这样我能达到大约 95 帧每秒(FPS)。而使用 Glumpy 的话,我能达到大约 250-300 帧每秒,尽管我现在的笔记本电脑显卡配置比较差。话虽如此,Glumpy 的设置稍微复杂一些,除非你在处理非常大的矩阵,或者因为某种原因需要非常高的帧率,否则我建议还是用 matplotlib 搭配 blit

撰写回答