I need to find an way to reduce a square image to 256 big pixels with python, preferably with the matplotlib and pillow libraries.
Got any ideas ?
I need to find an way to reduce a square image to 256 big pixels with python, preferably with the matplotlib and pillow libraries.
Got any ideas ?
Nine months pass and I can now cobble together some Python - per your original request on how to pixellate an image with Python and PIL/Pillow.
#!/usr/local/bin/python3
from PIL import Image
# Open image
img = Image.open("artistic-swirl.jpg")
# Resize smoothly down to 16x16 pixels
imgSmall = img.resize((16,16), resample=Image.Resampling.BILINEAR)
# Scale back up using NEAREST to original size
result = imgSmall.resize(img.size, Image.Resampling.NEAREST)
# Save
result.save('result.png')
Original Image
Result
If you take it down to 32x32 pixels (instead of 16x16) and then resize back up, you get:
Another option is to use PyPXL
Python script to pixelate images and video using K-Means clustering in the Lab colorspace. Video pixelating support multi-processing to achieve better performance.
Using the Paddington image as a source you can run:
python pypxl_image.py -s 16 16 paddington.png paddington_pixelated.png
Which gives this result
Of course if you wanted it to have 256 x 256 pixels rather than just 256 big pixels you could run
python pypxl_image.py -s 256 256 paddington.png paddington_pixelated.png
Which gives this result
Both results have a more retro 8-bit look to them compared to the other solutions, which might suit your needs.
Here is my solution using sliding window
import numpy as np
import matplotlib.pyplot as plt
def pixelate_rgb(img, window):
n, m, _ = img.shape
n, m = n - n % window, m - m % window
img1 = np.zeros((n, m, 3))
for x in range(0, n, window):
for y in range(0, m, window):
img1[x:x+window,y:y+window] = img[x:x+window,y:y+window].mean(axis=(0,1))
return img1
img = plt.imread('test.png')
fig, ax = plt.subplots(1, 4, figsize=(20,10))
ax[0].imshow(pixelate_rgb(img, 5))
ax[1].imshow(pixelate_rgb(img, 10))
ax[2].imshow(pixelate_rgb(img, 20))
ax[3].imshow(pixelate_rgb(img, 30))
# remove frames
[a.set_axis_off() for a in ax.flatten()]
plt.subplots_adjust(wspace=0.03, hspace=0)
The main idea is to slide a window of a certain size through the image and calculate the mean color for that area. Then replace the original pixels in that area with this color.
Another idea is to process grayscale images. Here we calculate the mean color of a grayscale image for a region, but now we replace the original pixels with white or black color depending on whether the mean exceeds a threshold:
def pixelate_bin(img, window, threshold):
n, m = img.shape
n, m = n - n % window, m - m % window
img1 = np.zeros((n,m))
for x in range(0, n, window):
for y in range(0, m, window):
if img[x:x+window,y:y+window].mean() > threshold:
img1[x:x+window,y:y+window] = 1
return img1
# convert image to grayscale
img = np.dot(plt.imread('test.png'), [0.299 , 0.587, 0.114])
fig, ax = plt.subplots(1, 3, figsize=(15,10))
plt.tight_layout()
ax[0].imshow(pixelate_bin(img, 5, .2), cmap='gray')
ax[1].imshow(pixelate_bin(img, 5, .3), cmap='gray')
ax[2].imshow(pixelate_bin(img, 5, .45), cmap='gray')
# remove frames
[a.set_axis_off() for a in ax.flatten()]
plt.subplots_adjust(wspace=0.03, hspace=0)
Keep in mind: png
has values between 0 and 1, whereas jpg
between 0 and 255
Sorry, I can't give you a Python solution, but I can show you the technique and the result, just using ImageMagick at the command-line:
Starting with this:
First, resize the image down to 16x16 pixels using normal cubic, or bilinear interpolation, then scale the image back up to its original size using "nearest neighbour" interpolation:
magick artistic-swirl.jpg -resize 16x16 -scale 500x500 result.png
Keywords:
Pixelate, pixellate, pixelated, pixellated, ImageMagick, command-line, commandline, image, image processing, nearest neighbour interpolation.
© 2022 - 2024 — McMap. All rights reserved.