Animate static image

526 views Asked by At

I have a static image that I would like to animate to appear like this (except starting from a black image, not a white image):

enter image description here

(image is from this post: Create animated gif from static image)

Here is the code:

import random
import imageio
import numpy as np
from PIL import Image

img = Image.open('/Users/tom/Desktop/sink.jpeg')
pixels = img.load()
width, height = img.size
img2 = Image.new('RGB', img.size, color='black')
pixels2 = img2.load()

coord = []
for x in range(width):
    for y in range(height):
        coord.append((x, y))

images = []
while coord:
    x, y = random.choice(coord)
    pixels2[x, y] = pixels[x, y]
    coord.remove((x, y))
    if len(coord) % 500 == 0:
        images.append(np.array(img2))

imageio.mimsave('/Users/tom/Desktop/sink.gif', images)

When I run the code, the script never stops/outputs anything. Anyone know why?

1

There are 1 answers

0
FirefoxMetzger On

Your code works, it is just very slow. If you are okay with a transparent background you can do something like this:

import numpy as np
import imageio.v3 as iio

rng = np.random.default_rng()
px_per_iter = 1000

img = iio.imread("imageio:chelsea.png")
n_pixels = img.shape[0] * img.shape[1]
batches = int(np.ceil(n_pixels / px_per_iter))  # number of frames
pixels = rng.permutation(n_pixels)  # order in which pixels are revealed

frames = np.zeros((batches + 1, *img.shape[:2], 4), dtype=np.uint8)
for batch_idx in range(batches):
    idx_batch = pixels[px_per_iter*batch_idx:px_per_iter*(batch_idx+1)]
    y_idx, x_idx = np.unravel_index(idx_batch, img.shape[:2])

    frame = frames[batch_idx+1]
    frame[y_idx, x_idx, :3] = img[y_idx, x_idx]
    frame[y_idx, x_idx, 3] = 255  # make added pixels non-transparent

iio.imwrite("fancy.gif", frames, loop=True)

resulting GIF

(500kb GIF)

If you need the black background, you can use something like this; however, be aware that it will produce larger files:

import numpy as np
import imageio.v3 as iio

rng = np.random.default_rng()
px_per_iter = 1000

img = iio.imread("imageio:chelsea.png")
n_pixels = img.shape[0] * img.shape[1]
batches = int(np.ceil(n_pixels / px_per_iter))  # number of frames
pixels = rng.permutation(n_pixels)  # order in which pixels are revealed

frames = np.zeros((batches + 1, *img.shape), dtype=np.uint8)
for batch_idx in range(batches):
    idx_batch = pixels[px_per_iter*batch_idx:px_per_iter*(batch_idx+1)]
    y_idx, x_idx = np.unravel_index(idx_batch, img.shape[:2])

    frame = frames[batch_idx+1]
    frame[:] = frames[batch_idx]
    frame[y_idx, x_idx] = img[y_idx, x_idx]

iio.imwrite("fancy.gif", frames)

(result exceeds 2MB, which is SO's limit)