Как обновить окно matplotlib imshow() в интерактивном режиме?

Я работаю над некоторым алгоритмом компьютерного зрения, и я хотел бы показать, как изменяется массив 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. Возможно ли это сделать с помощью функции анимации, например, в примере динамического изображения? Я бы хотел вызвать функцию внутри цикла, поэтому я не знаю, как это сделать с помощью функции анимации.

Ответ 1

Вам не нужно вызывать 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)

Ответ 2

Я реализовал удобный script, который вам подходит. Попробуйте здесь

Пример, который рисует динамическую синусоидальную волну:

import numpy as np

def redraw_fn(f, axes):
  amp = float(f) / 3000
  f0 = 3
  t = np.arange(0.0, 1.0, 0.001)
  s = amp * np.sin(2 * np.pi * f0 * t)
  if not redraw_fn.initialized:
    redraw_fn.l, = axes.plot(t, s, lw=2, color='red')
    redraw_fn.initialized = True
  else:
    redraw_fn.l.set_ydata(s)

redraw_fn.initialized = False

videofig(100, redraw_fn)