Ghoul Fool
Ghoul Fool

Reputation: 6949

Sort image as NP array

I'm trying to sort an image by luminosity using NumPy, which I'm new to. I've managed to create a random image and sort it.

def create_image(output, width, height, arr):

  array = np.zeros([height, width, 3], dtype=np.uint8)

  numOfSwatches = len(arr)
  swatchWidth = int(width/ numOfSwatches)

  for i in range (0, numOfSwatches):
    m = i * swatchWidth
    r = (i+1) * swatchWidth 
    array[:, m:r] = arr[i]

  img = Image.fromarray(array)
  img.save(output)

Which creates this image: random colour stripes

So far so good. Only now I want to switch from creating random images to loading them and then sorting them.

#!/usr/bin/python3

import numpy as np
from PIL import Image

# --------------------------------------------------------------
def load_image( infilename ) :
  img = Image.open( infilename )
  img.load()
  data = np.asarray( img, dtype = "int32" )
  return data

# --------------------------------------------------------------
def lum (r,g,b):
 return math.sqrt( .241 * r + .691 * g + .068 * b )


myImageFile = "random_colours.png"
imageNP = load_image(myImageFile)
imageNP.sort(key=lambda rgb: lum(*rgb) )

The image should look like this: stripe image sorted by luminosity

The error I get is TypeError: 'key' is an invalid keyword argument for this function I may have created the NP array incorrectly as it worked when it was a random NP array.

Upvotes: 1

Views: 453

Answers (1)

Lith
Lith

Reputation: 803

Have not ever used PIL, but the following approach hopefully works (I'm not sure as I can't reproduce your exact examples), and of course there might be more efficient ways to do so. I'm using your functions, having changed the math.sqrt function to np.sqrt in the lum function - as it is better for vector calculations. By the way, I believe this won't work with an int32 type array (as in your load_image function).

The key part is Numpy's argsort function (last line), which gives the indices that would sort the given array; this is applied to a row of the luminosity array (exploiting simmetry) and later used as indexer of img_array.

# Create random image
np.random.seed(4)
img = create_image('test.png', 75, 75, np.random.random((25,3))*255)
# Convert to Numpy array and calculate luminosity
img_array  = np.array(img, dtype = np.uint8)
luminosity = lum(img_array[...,0], img_array[...,1], img_array[...,2])
# Sort by luminosity and convert to image again
img_sorted = Image.fromarray(img_array[:,luminosity[0].argsort()])

The original picture:
The original picture

And the luminosity-sorted one:
And the luminosity-sorted one

Upvotes: 1

Related Questions