Matplotlib - анимированные изображения PIL в Jupyter - PullRequest
0 голосов
/ 13 февраля 2019

Как я могу создать анимацию в Jupyter, используя изображения PIL?

Я создаю рисунки с помощью PIL.Вот код для одного кадра (другие кадры генерируются только путем увеличения тета)

import matplotlib.pyplot as plt
import math
from PIL import Image, ImageDraw

width, height = 800,800
theta = math.pi / 3
image = Image.new('RGBA', (width, height))
draw = ImageDraw.Draw(image)

# draw sun
sun_radius = 80
center_x = width/2
center_y = width/2
draw.ellipse(
    (
        center_x - sun_radius/2, 
        center_y - sun_radius/2, 
        center_x + sun_radius/2, 
        center_y + sun_radius/2
    ), 
    fill = 'yellow', outline ='orange'
)

# draw planet
planet_radius = 20
orbit_radius = 300
planet_offset_x = center_x + math.cos(theta) * orbit_radius
planet_offset_y = center_y + math.sin(theta) * orbit_radius
draw.ellipse(
    (
        planet_offset_x - planet_radius/2, 
        planet_offset_y - planet_radius/2, 
        planet_offset_x + planet_radius/2, 
        planet_offset_y + planet_radius/2
    ), 
    fill = 'blue', outline ='blue'
)

plt.imshow(image)

Этот кадр, который генерирует вышеуказанный код enter image description here


У меня уже есть решение, я публикую его, потому что мне потребовалось некоторое время, чтобы начать работать, и я думаю, что оно будет полезно для других

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Я бы посоветовал сделать всю анимацию в matplotlib напрямую, так как это более эффективно использует память (нет необходимости создавать хранилище на 100 изображений) и дает лучшее качество графики (поскольку пиксели не нужно пересчитывать).

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.patches import Circle
from IPython.display import HTML


fig, ax = plt.subplots()

width, height = 800,800
planet_radius = 20
orbit_radius = 300
sun_radius = 80
center_x = width/2
center_y = width/2


ax.axis([0,width,0,height])
ax.set_aspect("equal")

sun = Circle((center_x,center_y), radius=sun_radius,
             facecolor="yellow", edgecolor="orange")
ax.add_patch(sun)


def get_planet_offset(theta):
    x = center_x + np.cos(theta) * orbit_radius
    y = center_y + np.sin(theta) * orbit_radius
    return x,y

planet = Circle(get_planet_offset(0), radius=planet_radius,
                 color="blue")
ax.add_patch(planet)

def update(theta):
    planet.center = get_planet_offset(theta)

ani = animation.FuncAnimation(fig, update, frames=np.linspace(0, 2 * np.pi, 100), 
                              interval=50, repeat_delay=1000)
HTML(ani.to_html5_video())

enter image description here

0 голосов
/ 13 февраля 2019

Используйте ArtistAnimation matplotlib и to_html5_video ().Соответствующие источники

enter image description here

Это решение требует установки ffmpeg (и imagemagick при сохранении GIF).Простой способ установить оба - просто установить imagemagick с опциями «legacy» и «ffmpeg» (кроссплатформенный, простая exe установка для windows)

import numpy as np
import math

from matplotlib import animation, rc
from IPython.display import HTML
from PIL import Image, ImageDraw

fig = plt.figure()

width, height = 800,800
images = []
for theta in np.linspace(0, 2 * math.pi, 100):
    image = Image.new('RGBA', (width, height))
    draw = ImageDraw.Draw(image)

    # draw sun
    sun_radius = 80
    center_x = width/2
    center_y = width/2
    draw.ellipse(
        (
            center_x - sun_radius/2, 
            center_y - sun_radius/2, 
            center_x + sun_radius/2, 
            center_y + sun_radius/2
        ), 
        fill = 'yellow', outline ='orange'
    )

    # draw planet
    planet_radius = 20
    orbit_radius = 300
    planet_offset_x = center_x + math.cos(theta) * orbit_radius
    planet_offset_y = center_y + math.sin(theta) * orbit_radius
    draw.ellipse(
        (
            planet_offset_x - planet_radius/2, 
            planet_offset_y - planet_radius/2, 
            planet_offset_x + planet_radius/2, 
            planet_offset_y + planet_radius/2
        ), 
        fill = 'blue', outline ='blue'
    )
    im = plt.imshow(image, animated=True)
    images.append([im])

ani = animation.ArtistAnimation(fig, images, interval=50, blit=True, repeat_delay=1000)
HTML(ani.to_html5_video())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...