如何使用Pillow显示并更新图像?

6

我想展示一个从img-vector重新创建的图像,一切都很顺利。 现在我正在编辑矢量图,并希望每秒钟显示新图像多次。 我的实际代码打开了大量窗口,其中包含新图片。

loop
{
    rearr0 = generateNewImageVector()
    reimg0 = Image.fromarray(rearr0, 'RGB')
    reimg0.show()
}

我要怎样才能创建一个窗口,并始终显示最新的图像?

你正在使用什么软件来构建你的应用程序? - Bill Bell
3个回答

11

另一种方法是利用 OpenCVimshow() 函数,在窗口中显示一个 numpy 图像,并在更新数据时重新绘制它。

请注意,OpenCV 的安装相当复杂,但也许您已经在使用它了。所以,这段代码比基于pygame的答案简单得多,但是安装OpenCV可能需要很多小时/天......

#!/usr/local/bin/python3
import numpy as np
import cv2

def sin2d(x,y):
    """2-d sine function to plot"""
    return np.sin(x) + np.cos(y)

def getFrame():
    """Generate next frame of simulation as numpy array"""

    # Create data on first call only
    if getFrame.z is None:
        xx, yy = np.meshgrid(np.linspace(0,2*np.pi,w), np.linspace(0,2*np.pi,h))
        getFrame.z = sin2d(xx, yy)
        getFrame.z = cv2.normalize(getFrame.z,None,alpha=0,beta=1,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

    # Just roll data for subsequent calls
    getFrame.z = np.roll(getFrame.z,(1,2),(0,1))
    return getFrame.z

# Frame size
w, h = 640, 480

getFrame.z = None

while True:
       
    # Get a numpy array to display from the simulation
    npimage=getFrame()

    cv2.imshow('image',npimage)
    cv2.waitKey(1)

看起来是这样的:

输入图像描述


在现实生活中,它非常流畅,没有"条纹"效应,但在StackOverflow上有 2MB 的限制,所以我不得不降低质量和帧率以保持尺寸。


我尝试使用这个解决方案,但变量w未定义。我稍微更改了一下,所以我的代码是Image.open('image.png')。 - Давид Шико
你的代码没有定义w和h,但如果我添加它们,它可以很好地工作。 - N. Virgo
1
此外,安装opencv并不需要太多时间,只需快速运行pip3 install --user opencv-python即可。如果您的操作系统比较旧,可以尝试运行pip3 install --user opencv-python==3.3.0.10 - N. Virgo
+1 对于 OpenCV 安装所需的时间几乎不需要任何时间 - 我最初被你的警告吓到了,但是 opencv-python 只有 40 MB。 - Alex Wulff
请更新代码以包括w和h。由于它们是局部变量,这有点奇怪并不明显。我添加了我的w和h以获得所需的窗口大小,然后就可以正常工作了。只需添加:# 窗口大小 w, h = (800, 640) - Ismael Harun

3
你可以使用pygame相当简单快速地完成这项任务。
编写一个名为getFrame()的函数,该函数返回一个numpy数组,其中包含由模拟计算得出的图像。
例如,在第一次通过时,我创建了一个二维正弦波,然后在随后的调用中将其向下滚动1个像素并向右滚动2个像素以模拟运动。
#!/usr/local/bin/python3
import numpy as np
import pygame

h,w=480,640
border=50
N=0
getFrame.z = None


def sin2d(x,y):
    """2-d sine function to plot"""

    return np.sin(x) + np.cos(y)

def getFrame():
    """Generate next frame of simulation as numpy array"""

    # Create data on first call only
    if getFrame.z is None:
        xx, yy = np.meshgrid(np.linspace(0,2*np.pi,h), np.linspace(0,2*np.pi,w))
        getFrame.z = sin2d(xx, yy)
        getFrame.z = 255*getFrame.z/getFrame.z.max()

    # Just roll data for subsequent calls
    getFrame.z = np.roll(getFrame.z,(1,2),(0,1))
    return getFrame.z



pygame.init()
screen = pygame.display.set_mode((w+(2*border), h+(2*border)))
pygame.display.set_caption("Serious Work - not games")
done = False
clock = pygame.time.Clock()

# Get a font for rendering the frame number
basicfont = pygame.font.SysFont(None, 32)

while not done:
        for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True

        # Clear screen to white before drawing 
        screen.fill((255, 255, 255))
       
        # Get a numpy array to display from the simulation
        npimage=getFrame()

        # Convert to a surface and splat onto screen offset by border width and height
        surface = pygame.surfarray.make_surface(npimage)
        screen.blit(surface, (border, border))

        # Display and update frame counter
        text = basicfont.render('Frame: ' + str(N), True, (255, 0, 0), (255, 255, 255))
        screen.blit(text, (border,h+border))
        N = N + 1

        pygame.display.flip()
        clock.tick(60)

这看起来像这样。在现实生活中,它非常快速和流畅,但是StackOverflow上的视频大小限制为2MB,因此我生成了一个帧率较低且尺寸较小的GIF,只是为了将其保持在2MB以下。

enter image description here

显然,您可以添加检测向上和向下箭头以加快或减慢动画速度,您还可以检测左/右箭头和空格键来向后/向前或暂停动画。

0
根据Pillow文档,方法Image.show()主要用于调试目的。在Windows上,它将图像保存到临时BMP文件中,并使用标准BMP显示实用程序来显示它。
你应该看一下matplotlib图像库
你可以尝试:
import matplotlib.pyplot as plt
imgplot = plt.imshow(rearr0) # "plot" the image.

对于每次迭代,您可以调用imgplot.clf()函数,它将清除绘图但保留轴。我尚未尝试过,但应该可以使用。


谢谢你的帮助,但是没有窗口弹出。我看了“文档”,但它没用。 - user7035883
你有任何错误吗?我认为你可以使用动画工具。看看这个例子:http://matplotlib.org/examples/animation/dynamic_image.html - Rafael
好的,但是现在我该如何添加新图片呢? - user7035883
问题在于图像是在循环期间生成的。 - user7035883
你需要循环使用 "imshow" 函数。你可能还需要使用 imgplot.show()。如果你使用 ipython,可能会有不同的行为,请查看文档。 - hyamanieu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接