4

I am trying to create an API which takes an image URL as input and returns back a color palette in JSON format as output.

It should work something like this: http://lokeshdhakar.com/projects/color-thief/

But should be in Python. I have looked into PIL (Python Image Library) but didn't get what I want. Can someone point me in the right direction?

Input: Image URL Output: List of Colors as a palette 
2
  • I have looked into PIL (Python Image Library) but didn't get what I want - care to elaborate? Commented Sep 14, 2013 at 11:28
  • Since I am a newbie at PIL, I could not find tools I needed to accomplish this. Commented Sep 14, 2013 at 11:41

2 Answers 2

13
import numpy as np import Image def palette(img): """ Return palette in descending order of frequency """ arr = np.asarray(img) palette, index = np.unique(asvoid(arr).ravel(), return_inverse=True) palette = palette.view(arr.dtype).reshape(-1, arr.shape[-1]) count = np.bincount(index) order = np.argsort(count) return palette[order[::-1]] def asvoid(arr): """View the array as dtype np.void (bytes) This collapses ND-arrays to 1D-arrays, so you can perform 1D operations on them. http://stackoverflow.com/a/16216866/190597 (Jaime) http://stackoverflow.com/a/16840350/190597 (Jaime) Warning: >>> asvoid([-0.]) == asvoid([0.]) array([False], dtype=bool) """ arr = np.ascontiguousarray(arr) return arr.view(np.dtype((np.void, arr.dtype.itemsize * arr.shape[-1]))) img = Image.open(FILENAME, 'r').convert('RGB') print(palette(img)) 

palette(img) returns a numpy array. Each row can be interpreted as a color:

[[255 255 255] [ 0 0 0] [254 254 254] ..., [213 213 167] [213 213 169] [199 131 43]] 

To get the top ten colors:

palette(img)[:10] 
Sign up to request clarification or add additional context in comments.

5 Comments

Well, I want to get to get top 10 dominating colors. How do I retrieve that from the output?
@ManishPatel: Take a look at stackoverflow.com/questions/9448029/…. If that does not answer your question, please post a new question with a sample of your input (is it an array, a list, a int?) and the expected output.
This is excelent and suepr fast. Can you suggest a way to convert it into an RGBa image? You now have a palette of shape (nbcolors,4) how do I make so that is (nbcolors,1,4) to have an image of size nbcolors x 1 pixels and 4 channels?
@ZloySmiertniy: Given p = palette(img) with shape (nbcolors, 4), you could use p[:,None,:] or p[:,np.newaxis,:], or p.reshape(-1, 1, 4) to obtain an array of shape (nbcolors, 1, 4). (reshape will automatically replace the minus 1 with the only reasonable choice for you).
@unutbu thank you, I was using np.expand_dims(p, axis=0) It is good to see many possible approaches
3

The color-thief library is also available in python: https://github.com/fengsp/color-thief-py

Example implementation :

pip install colorthief 
# -*- coding: utf-8 -*- import sys if sys.version_info < (3, 0): from urllib2 import urlopen else: from urllib.request import urlopen import io from colorthief import ColorThief fd = urlopen('http://lokeshdhakar.com/projects/color-thief/img/photo1.jpg') f = io.BytesIO(fd.read()) color_thief = ColorThief(f) print(color_thief.get_color(quality=1)) print(color_thief.get_palette(quality=1)) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.