19

I need to detect the color of an online image and save it in the name of the detected color.

imageurl='http://www.example.com/'
opener1 = urllib2.build_opener()
page1=opener1.open(imageurl)
my_picture=page1.read()
fout = open('images/tony'+image[s], "wb")
fout.write(my_picture)
fout.close()
Smart Manoj
  • 5,230
  • 4
  • 34
  • 59
user244470
  • 7,469
  • 4
  • 17
  • 10

7 Answers7

12

Use a PIL (Python Image Library) histogram. Loop over the histogram and take the average of pixel color weighed by the pixel count.

Jonathan Root
  • 535
  • 2
  • 14
  • 31
olooney
  • 2,467
  • 1
  • 16
  • 25
  • 6
    In response to a follow up question, here is a working example demonstrating this approach: https://gist.github.com/1246268 – olooney Sep 27 '11 at 21:15
11

As mentionned by others, PIL is the right library. Here is a function that open an image and look for the main color.

def get_main_color(file):
    img = Image.open(file)
    colors = img.getcolors(256) #put a higher value if there are many colors in your image
    max_occurence, most_present = 0, 0
    try:
        for c in colors:
            if c[0] > max_occurence:
                (max_occurence, most_present) = c
        return most_present
    except TypeError:
        raise Exception("Too many colors in the image")

I hope it helps

Update : passing 256 to getcolors is ok for very small images but may not work in most cases. This value must be increased for bigger images. for example, 1024*1024 is ok for 400 pixels * 300 pixel image.

luc
  • 41,928
  • 25
  • 127
  • 172
6

You should use PIL's Parser from the ImageFile class to read the file in from the url. Then life is pretty easy because you said that the whole image is the same color. Here is some code that builds on your code:

import urllib2
import ImageFile

image_url = "http://plainview.files.wordpress.com/2009/06/black.jpg"
opener1 = urllib2.build_opener()
page1=opener1.open(image_url)

p = ImageFile.Parser()

while 1:
    s = page1.read(1024)
    if not s:
        break
    p.feed(s)

im = p.close()
r,g,b = im.getpixel((0,0))

fout = open('images/tony'+image[s]+"%d%_d%_d"%(r,g,b), "wb")
fout.write(my_picture)
fout.close()

This should append the red green and blue values of the color of the first pixel of the image to the end of the image name. I tested everything up until the fout lines.

Jonathan Root
  • 535
  • 2
  • 14
  • 31
Justin Peel
  • 46,722
  • 6
  • 58
  • 80
  • Thanks Justin for ur reply it really helped a lot.Actually i got the filename with red green and blue values of the color of the given pixel of the image.Is it possible to get actual color name of that image for the given pixel....or can we convert the obtained pixels to corresponding color name regards Arun – user244470 Feb 16 '10 at 10:10
  • 1
    you would need to make a dictionary with RGB values as the keys and the names as the values. You could use the color list at this site, http://en.wikipedia.org/wiki/List_of_colors, maybe. You would use urllib2 to retrieve the names and the corresponding RGB values. – Justin Peel Feb 16 '10 at 16:23
2

You could use K-means algorithm to get the K main colours of the image. Here is an example of how to do it: K-means using OpenCV (Python)

karl71
  • 1,082
  • 2
  • 18
  • 29
2

All the answers discuss the methods to find a single color in an image but knowing how to find multiple colors in the image is always beneficial. Especially when you deal with segmentation task's images.

Let's take an image for our explanation

Segmentation Task

Clearly, every class of objects in this picture has a different color.

Let's write a function to download an image from a URL and convert it into a numpy array. It becomes very easy to deal with images in this way.

import numpy as np
import cv2
import urllib
from urllib.request import urlopen
import webcolors
import time

def getImageArray(mask):
    req = requestObject(mask) 
    arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
    im = cv2.imdecode(arr, -1) 
    im = im[:, :, :3] 
    return im

def requestObject(mask):
    temp_req = {'status': 403}
    retry_counter = 1
    while((temp_req['status'] != 200) and (retry_counter <= 10)):
        try:
            req = urlopen(mask)
            temp_req = {"status": 200}
        except:
            print("Retrying for: ", retry_counter)
            temp_req = {"status": 403}
            time.sleep(4)
        retry_counter = retry_counter + 1

    return req

Now, Let's get the image:

url = 'https://i.stack.imgur.com/Bi16j.jpg'
image = getImageArray(url)

Let's write a function to find all the colors:

def bgr_to_hex(bgr):
   rgb =list(bgr)
   rgb.reverse()
   return webcolors.rgb_to_hex(tuple(rgb))

def FindColors(image):
    color_hex = []
    for i in image:
        for  j in i:
            j = list(j)
            color_hex.append(bgr_to_hex(tuple(j)))
    return set(color_hex)

color_list = FindColors(image)

Try running the above script in your terminal and you'll get the list of hexadecimal codes for all colors in the variable color_list.

Let me know if the code works/doesn't for you :)

Lavish Saluja
  • 221
  • 5
  • 10
  • Thank you, it works perfectly. I have one more, how could I get several main colors in an image, for example top 10 colors? – ah bon Aug 18 '19 at 16:49
  • 2
    @ahbon Happy to know it helped you. Good question, what I can think of is doing one of these approaches: <1> using "image.getcolors()" function in PIL which returns a {color,count}. <2> trying to loop over the image and use 'color_list' to maintain a dictionary for every color in 'color_list' as key with value as count. <3> I've read about Instagram using Color Palette for stories, I'm not sure how they do it but I'm sure their way must be very efficient, probably making an image histogram and picking up the top 10? You should read about it in detail. <>Let me know if any works for you :) – Lavish Saluja Aug 19 '19 at 21:00
  • This can be easily achieved by using one-liner in PIL, as was suggested above – Lenka Pitonakova Jul 05 '23 at 20:22
0

You could use the PIL library's Image module to do this. See: http://effbot.org/imagingbook/image.htm.

Jonathan Root
  • 535
  • 2
  • 14
  • 31
Kyle Lutz
  • 7,966
  • 2
  • 20
  • 23
0

Trying using pillow for optimal way or quickest way.

Image(yourimagehere).convert('RGB').getcolors()

I tried answer by @Lavish but it was way to resource consuming and has worst case for speed.

REASON: It took way to long on iterating over few images having black dots. and i used pillow which result in few seconds for all images.

:)

dotsinspace
  • 661
  • 7
  • 21