Pixel sorting

Reorganize image pixels by sorting them by brightness and hue.

In [1]:
from PIL import Image
import matplotlib.pyplot as plt
import cv2
import numpy as np
import math

Resize image to 500 px in width and height calculated from original aspect ratio.

In [2]:
basewidth = 500
img = Image.open('input1080.jpg')
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
img.save('smaller.jpg')

Read images.

In [3]:
big = cv2.imread('input1080.jpg')
small = cv2.imread('smaller.jpg')

Convert them to RGB colorspace, since OpenCV uses BGR by default.

In [4]:
big = cv2.cvtColor(big, cv2.COLOR_BGR2RGB)
small = cv2.cvtColor(small, cv2.COLOR_BGR2RGB)

Comparison of original and scaled images.

In [5]:
%matplotlib notebook
plt.figure(1, figsize=(9,3))

plt.subplot(1,2,1)
plt.imshow(big)
plt.title('Original image')

plt.subplot(1,2,2)
plt.imshow(small)
plt.title('Scaled image')
plt.show()

Read both images' sizes and save size of scaled image.

In [6]:
[w, h, c] = big.shape
print("Big image size: {}x{}".format(w, h))
[w, h, c] = small.shape
print("Small image size: {}x{}".format(w, h))
Big image size: 1080x1920
Small image size: 281x500

Convert image into 1D list for sorting.

In [7]:
pixel_list = list()

for i in range(h):
    for j in range(w):
        pixel_list.append(small[j, i])

Below is a veeery slow sorting algorithm. Don't use it.

In [ ]:
# Super slow!
# selection sorting
for i in range(len(pixel_list)):
    
    max_idx = i
    max_val = brightness(pixel_list[i])
    
    for j in range(i, len(pixel_list)):
        if brightness(pixel_list[j]) > max_val:
            max_idx = j
            max_val = brightness(pixel_list[j])
    
    # swap
    if max_idx != i:
        pixel_list[i], pixel_list[max_idx] = pixel_list[max_idx], pixel_list[i]

This function is used to convert 1D image list into 2D image array.

In [8]:
def list_to_image(pixels, width, height):
    image = np.zeros((width, height, 3), np.uint8)
    print("Number of pixels:", len(pixels))
    
    for i in range(len(pixels)):
        y = i % height
        x = int((i - y) / height)
        image[x, y] = pixels[i]
        
    return image

Functions used as keys in sorting. They return brightness and hue of a pixel.

In [9]:
def brightness(pixel):
    return sum(pixel)/3

def hue(pixel):
    R, G, B = pixel
    return math.atan2(math.sqrt(R) * (G - B), 2 * R - G - B)

Sort by brightness.

In [10]:
sorted_pixels_bright = sorted(pixel_list, key = brightness, reverse = True)
sorted_bright = list_to_image(sorted_pixels_bright, w, h)
Number of pixels: 140500

Sort by hue.

In [11]:
sorted_pixels_hue = sorted(pixel_list, key = hue, reverse = True)
sorted_hue = list_to_image(sorted_pixels_hue, w, h)
/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:6: RuntimeWarning: overflow encountered in ubyte_scalars
  
Number of pixels: 140500

Compare unsorted and sorted images.

Also show their histograms in order to prove, that none of the pixels are changed.

In [13]:
plt.figure(2, figsize=(11,6))
plt.subplot(2,3,1)
plt.title('Original image')
plt.imshow(small)

plt.subplot(2,3,2)
plt.imshow(sorted_bright)
plt.title('Sorted by brightness')
# plt.show()

plt.subplot(2,3,3)
plt.imshow(sorted_hue)
plt.title('Sorted by hue')
# plt.show()

color = ('r', 'g', 'b')
for channel, col in enumerate(color):
    hist = cv2.calcHist([small], [channel], None, [256], [0,256])
    plt.subplot(2,3,4)
    plt.plot(hist, color = col)
    plt.xlim([0,256])
plt.title('Histogram for original image')
# plt.show()

for channel, col in enumerate(color):
    hist = cv2.calcHist([sorted_bright], [channel], None, [256], [0,256])
    plt.subplot(2,3,5)
    plt.plot(hist, color = col)
    plt.xlim([0,256])
plt.title('Histogram brightness')
# plt.show()

for channel, col in enumerate(color):
    hist = cv2.calcHist([sorted_hue], [channel], None, [256], [0,256])
    plt.subplot(2,3,6)
    plt.plot(hist, color = col)
    plt.xlim([0,256])
plt.title('Histogram hue')
plt.show()

by Wojciech Wiertarka

http://wiertareczka.ddns.net/