SECRET OF CSS

Python Pixelation | Better Programming


Sometimes we get lost in the pursuit of 8K, HDR, 120HZ imagery. Here’s a way to reverse all that makes images look pixelated for a change 🙂

1*tqwGyGisE0dLpteeaC3TPw
Left: A mandala. Right: The same mandala, but worse.

I know a lot of people (everyone) opt to use OpenCV when performing computer vision tasks in Python. I COULD have done it that way, but I discovered PIL pretty early on in my coding life — and I can’t be arsed learning a new package.

PIL (Python Image Library) is easy to read, easy to use, and extremely versatile. We’ll be using just a small bit of PIL to open images, perform downsampling/upsampling, and eventually save images too. Sick.

The 2nd and last package we’ll be using is good-old Numpy, and we’re ONLY using this to round floats into nice integers.

The Gist

  1. Open an image and get its dimensions (width and height).
  2. Get a set of new dimensions based on your input.
  3. Downsample the original image to those new dimensions (we’ll just use some fraction of the original dimensions).
  4. Upsample that new image to its original dimensions.

The trick is the resampling method used in step 4. If we were to just go with the default option (which I believe is “nearest neighbour”), you’ll end up blowing up a small image into a larger one. Which just creates a blurry mess.

Instead, we’ll opt for “bicubic” resampling, which gives the intended pixelated effect.

Code

#import those 2 modules I mentioned
from PIL import Image
import numpy as np
#open desired image
im = Image.open('path/to/image.jpg'
#find its width & height
w,h = im.size
#find NEW dimensions from user-defined number (50% for example)
new_w = w * 0.5
new_h = h * 0.5
#round to nearest whole number and convert from float to int
new_w = np.round(new_w)
new_w = int(new_w)
new_h = np.round(new_h)
new_h = int(new_h)
#downsample image to these new dimensions
down_sampled = im.resize((new_w, new_h))
#upsample back to original size (using "4" to signify bicubic)
up_sampled = down_sampled.resize((w, h), resample = 4)
#save the image
up_sampled.save('path/to/new_image.jpg')

That’s it. Although we should probably turn this into a function we can use easily. Also, we should be more “Pythonic” and try to convert some many-liners into one-liners:

#import those 2 modules I mentioned
from PIL import Image
import numpy as np
#define our sick pixelation function
def pixelate(image_path, pixelation_amount): #open image
im = Image.open(image_path)
#new dimensions via list comprehension
new_dims = [int(np.round(a*pixelation_amount)) for a in im.size]
#downsample, upsample, and return
return im.resize(new_dim).resize(im.size, resample = 4)

So there’s a function that does everything we’ve been talking about. Here it is in action:

1*RU6AB9qVHHcMfi 4r96LQQ
Some nail-clippers with 100%, 10% and 5% the amount of pixels.

Cheers.



News Credit

%d bloggers like this: