0

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?

gnpunpun
  • 21
  • 2
  • The very first thing you should have done, before posting here, is step through your code line-by-line in a debugger so you can actually see what's going on. That's always going to be the most important first step when understanding an issue; relying on random internet strangers to do it for you won't always work. – Random Davis Apr 27 '22 at 16:30
  • it seems to be getting stuck on this line: Traceback (most recent call last): File "/Users/tom/pythonProject/main.py", line 21, in coord.remove((x, y)) KeyboardInterrupt – gnpunpun Apr 27 '22 at 16:36
  • Well that was just where code happened to be executing when you did a KeyboardInterrupt; we know it's stuck in the `while coords` loop, then, but not why, yet. Stepping through the code in a debugger will show exactly why, I'd imagine. – Random Davis Apr 27 '22 at 16:40
  • Also, have you verified that nothing is actually happening, or is it actually just happening slower than you'd expect? If you put a `print` within the `if len(coord) % 500 == 0:` statement, how often does it print? If you have an image with 164x164 pixels, that's 26896 total pixels that have to be removed, meaning you should expect that message to print 53 times. – Random Davis Apr 27 '22 at 16:48
  • good call, it may just be taking a very long time. if that's the case I will delete the post, thanks for the help – gnpunpun Apr 27 '22 at 17:04
  • No need to delete, you can actually self-answer your post with the solution; no harm in that at all. – Random Davis Apr 27 '22 at 17:19

1 Answers1

1

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)

FirefoxMetzger
  • 2,880
  • 1
  • 18
  • 32