53

我正在研究一些计算机视觉算法,我想展示一个 numpy 数组在每个步骤中是如何变化的。

现在有效的是,如果我imshow( array )的代码末尾有一个简单的,窗口就会显示并显示最终图像。

但是,我想做的是在每次迭代中图像更改时更新和显示 imshow 窗口。

所以例如我想做:

import numpy as np
import matplotlib.pyplot as plt
import time

array = np.zeros( (100, 100), np.uint8 )

for i in xrange( 0, 100 ):
    for j in xrange( 0, 50 ):
        array[j, i] = 1

        #_show_updated_window_briefly_
        plt.imshow( array )
        time.sleep(0.1)

问题是这样,Matplotlib 窗口不会被激活,只有在整个计算完成后才会被激活。

我已经尝试过原生 matplotlib 和 pyplot,但结果是一样的。对于绘图命令,我找到了一个.ion()开关,但在这里它似乎不起作用。

Q1。连续显示对 numpy 数组(实际上是 uint8 灰度图像)的更新的最佳方法是什么?

Q2。是否可以使用动画功能来做到这一点,就像在动态图像示例中一样?我想在循环中调用一个函数,因此我不知道如何使用动画函数来实现这一点。

4

6 回答 6

52

你不需要一直打电话imshow。使用对象的方法要快得多set_data

myobj = imshow(first_image)
for pixel in pixels:
    addpixel(pixel)
    myobj.set_data(segmentedimg)
    draw()

draw()应该确保后端更新图像。

更新:您的问题已被显着修改。在这种情况下,最好问另一个问题。这是处理第二个问题的一种方法:

Matplotlib 的动画只处理一个增加的维度(时间),所以你的双循环不会做。您需要将索引转换为单个索引。这是一个例子:

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation

nx = 150
ny = 50

fig = plt.figure()
data = np.zeros((nx, ny))
im = plt.imshow(data, cmap='gist_gray_r', vmin=0, vmax=1)

def init():
    im.set_data(np.zeros((nx, ny)))

def animate(i):
    xi = i // ny
    yi = i % ny
    data[xi, yi] = 1
    im.set_data(data)
    return im

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=nx * ny,
                               interval=50)
于 2013-07-24T14:53:34.590 回答
12

我努力使它工作,因为许多帖子都在谈论这个问题,但似乎没有人关心提供一个工作示例。然而,在这种情况下,原因是不同的:

  • 我不能使用 Tiago 或 Bily 的答案,因为它们与问题的范式不同。在问题中,刷新是由算法本身安排的,而对于 funcanimation 或 videofig,我们处于事件驱动的范例中。事件驱动编程对于现代用户界面编程来说是不可避免的,但是当你从一个复杂的算法开始时,可​​能很难将它转换为事件驱动方案——我也希望能够在经典的过程范式中做到这一点。
  • Bub Espinja 的回复遇到了另一个问题:我没有在 jupyter 笔记本的上下文中尝试过,但是重复 imshow 是错误的,因为它每次都会重新创建新的数据结构,这会导致重要的内存泄漏并减慢整个显示过程。

Tiago 还提到了调用draw(),但没有指定从哪里获取它 - 顺便说一下,你不需要它。你真正需要调用的函数是flush_event(). 有时它可以在没有的情况下工作,但这是因为它是从其他地方触发的。你不能指望它。真正棘手的一点是,如果你调用imshow()一个空表,你需要指定 vmin 和 vmax 否则它将无法初始化它的颜色映射并且 set_data 也会失败。

这是一个有效的解决方案:

IMAGE_SIZE = 500
import numpy as np
import matplotlib.pyplot as plt


plt.ion()

fig1, ax1 = plt.subplots()
fig2, ax2 = plt.subplots()
fig3, ax3 = plt.subplots()

# this example doesn't work because array only contains zeroes
array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
axim1 = ax1.imshow(array)

# In order to solve this, one needs to set the color scale with vmin/vman
# I found this, thanks to @jettero's comment.
array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
axim2 = ax2.imshow(array, vmin=0, vmax=99)

# alternatively this process can be automated from the data
array[0, 0] = 99 # this value allow imshow to initialise it's color scale
axim3 = ax3.imshow(array)

del array

for _ in range(50):
    print(".", end="")
    matrix = np.random.randint(0, 100, size=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
    
    axim1.set_data(matrix)
    fig1.canvas.flush_events()
    
    axim2.set_data(matrix)
    fig1.canvas.flush_events()
    
    axim3.set_data(matrix)
    fig1.canvas.flush_events()
print()

更新:我根据@Jettero 的评论添加了 vmin/vmax 解决方案(一开始我错过了)。

于 2020-07-13T16:29:26.843 回答
7

如果您使用的是 Jupyter,也许这个答案会让您感兴趣。我在这个网站上读到,嵌入功能clear_output可以解决问题:

%matplotlib inline
from matplotlib import pyplot as plt
from IPython.display import clear_output

plt.figure()
for i in range(len(list_of_frames)):
    plt.imshow(list_of_frames[i])
    plt.title('Frame %d' % i)
    plt.show()
    clear_output(wait=True)

确实,这种方法很慢,但它可以用于测试目的。

于 2020-01-14T15:18:53.867 回答
3

我实现了一个方便的脚本,正好适合您的需求。在这里试试

在自定义目录中显示图像的示例如下所示:

  import os
  import glob
  from scipy.misc import imread

  img_dir = 'YOUR-IMAGE-DIRECTORY'
  img_files = glob.glob(os.path.join(video_dir, '*.jpg'))

  def redraw_fn(f, axes):
    img_file = img_files[f]
    img = imread(img_file)
    if not redraw_fn.initialized:
      redraw_fn.im = axes.imshow(img, animated=True)
      redraw_fn.initialized = True
    else:
      redraw_fn.im.set_array(img)
  redraw_fn.initialized = False

  videofig(len(img_files), redraw_fn, play_fps=30)
于 2017-05-10T06:44:51.170 回答
1

我有一个类似的问题 - 想要更新图像,不想重复替换轴,但是plt.imshow()(也不ax.imshow()是)没有更新显示的图形。

我终于发现需要某种形式的draw()。但是fig.canvas.draw()ax.draw()......一切都没有奏效。我终于在这里找到了解决方案:

%matplotlib notebook  #If using Jupyter Notebook
import matplotlib.pyplot as plt
import numpy as np

imData    = np.array([[1,3],[3,1]])

  # Setup and plot image
fig = plt.figure()
ax  = plt.subplot(111)
im  = ax.imshow(imData)

  # Change image contents
newImData = np.array([[2,2],[2,2]])
im.set_data( newImData )
im.draw()
于 2022-02-11T02:05:10.333 回答
0
import numpy as np
import matplotlib.pyplot as plt
k = 10
plt.ion()
array = np.zeros((k, k))
for i in range(k):
    for j in range(k):
        array[i, j] = 1
        plt.imshow(array)
        plt.show()
        plt.pause(0.001)
        plt.clf()
于 2022-01-23T10:47:50.567 回答