Edward Atkin - Coding Heaven

Making an Image Crappifier

You may read that title and wonder, why would anyone want to make an image crappifier?

Well for my game Ert Wurm, I wanted to capture feelings of resentment and being trapped in a situation. I wanted the graphics to represent some sort of frustration, so in order to do so I heavily edited images to give them a crunchy, ugly feel.

For this I decided I would put my Data Science skills to good use once again and create a utility to deliberately crappify images.

So how does one “crappify” an image? Well we use every Data Scientist’s favourite tool, Numpy.

Using Pillow to load the image, we can then represent the image as a Numpy array. For this example, I use the famous Ball Dude (stored in my images directory):

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
ball_dude = Image.open('images/ef8c99de-61d1-431f-b84a-e784f9e997ee.png')
ball_dude_array = np.array(ball_dude)

Ball Dude is quite a small image, 16×16, so I upscale it to a more appropriate size of 200×200. The crappification process will become increasingly slow for larger images.

# Upsize image to about 200x200
scale = 200 / ball_dude.width
ball_dude_upsized = ball_dude.resize((round(ball_dude.width * scale), round(ball_dude.height * scale)))

Taking advantage of the fact I now have a smaller version of the image, I randomly paste multiple copies of the original 16×16 image over the top of the new 200×200 image.

If your original image is quite large, it will be worth resizing it to a more modest 16×16 for this process to work effectively.

# Now we can randomly add repeated ball dudes
for i in range(0, ball_dude_upsized.width, ball_dude.width):
    xx = np.random.randint(0, ball_dude_upsized.width)
    yy = np.random.randint(0, ball_dude_upsized.height)
    ball_dude_upsized.paste(ball_dude, (xx, yy))

Now take random bits of the image and replace them with randomly coloured pixels:

# Now replace random bits because it'll be funny
for i in range(0, ball_dude_upsized.width):
    for j in range(0, ball_dude_upsized.height):
        if np.random.randint(0, 100) < 10:
            ball_dude_upsized.putpixel((i, j), (np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255)))

And the final touch, swap random pixel locations:

 # Now randomly shuffle the pixels
for i in range(ball_dude_upsized.width * ball_dude_upsized.height):
   if np.random.randint(0, 100) < 50:
        # Pick two random pixels to swap
        x1 = np.random.randint(0, ball_dude_upsized.width)
        y1 = np.random.randint(0, ball_dude_upsized.height)
        x2 = np.random.randint(0, ball_dude_upsized.width)
        y2 = np.random.randint(0, ball_dude_upsized.height)
        # Swap them
        temp = ball_dude_upsized.getpixel((x1, y1))
        ball_dude_upsized.putpixel((x1, y1), ball_dude_upsized.getpixel((x2, y2)))
        ball_dude_upsized.putpixel((x2, y2), temp)

Loop through this process an arbitrary number of times, and we can display our masterpiece:

plt.imshow(ball_dude_upsized)

Nobody will ever know that half the backgrounds in Ert Worm are pictures of shit.

Full code:

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
ball_dude = Image.open('images/ef8c99de-61d1-431f-b84a-e784f9e997ee.png')
ball_dude_array = np.array(ball_dude)

# Upsize image to about 200x200
scale = 200 / ball_dude.width
ball_dude_upsized = ball_dude.resize((round(ball_dude.width * scale), round(ball_dude.height * scale)))

for q in range(20):
    # Now we can randomly add repeated ball dudes
    for i in range(0, ball_dude_upsized.width, ball_dude.width):
        xx = np.random.randint(0, ball_dude_upsized.width)
        yy = np.random.randint(0, ball_dude_upsized.height)
        ball_dude_upsized.paste(ball_dude, (xx, yy))

    # Now replace random bits because it'll be funny
    for i in range(0, ball_dude_upsized.width):
        for j in range(0, ball_dude_upsized.height):
            if np.random.randint(0, 100) < 10:
                ball_dude_upsized.putpixel((i, j), (np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255)))

    # Now randomly shuffle the pixels
    for i in range(ball_dude_upsized.width * ball_dude_upsized.height):
        if np.random.randint(0, 100) < 50:
            # Pick two random pixels to swap
            x1 = np.random.randint(0, ball_dude_upsized.width)
            y1 = np.random.randint(0, ball_dude_upsized.height)
            x2 = np.random.randint(0, ball_dude_upsized.width)
            y2 = np.random.randint(0, ball_dude_upsized.height)
            # Swap them
            temp = ball_dude_upsized.getpixel((x1, y1))
            ball_dude_upsized.putpixel((x1, y1), ball_dude_upsized.getpixel((x2, y2)))
            ball_dude_upsized.putpixel((x2, y2), temp)

plt.imshow(ball_dude_upsized)
built with btw btw logo