Python PIL - Finding Nearest Color (Rounding Colors)
Asked Answered
D

2

7

There is a game called Roblox, in which the player makes the game, usually of lego-looking bricks.

In Roblox, for the Brick colors, you can use typical RGB values, but that'd require an additional element that is not very efficient when it comes to file size. Instead of using RGB values, BrickColor is much more economic in file size. It uses an integer to be interpreted as a certain color. Here is what I mean: Color Codes

Here is a snippet of my code:

import Image
f = raw_input('Image:\n')
im = Image.open(f)
rgb_im = im.convert('RGB')
r, g, b = rgb_im.getpixel((x, y))

In my program, I need to find the color code closest to an RGB value.

How might this be accomplished?

Datura answered 19/12, 2015 at 3:32 Comment(1)
Have you looked up the Lego color guide? There should be one somewhere that includes RGB and Pantone as both would want to match the colors.Sememe
L
10

Create a list of colors in your table (I call it colors). Sort the list by the distance to the r, g, b point you are questioning The first element in the list is the closest color

def distance(c1, c2):
    (r1,g1,b1) = c1
    (r2,g2,b2) = c2
    return math.sqrt((r1 - r2)**2 + (g1 - g2) ** 2 + (b1 - b2) **2)

colors = list(rgb_code_dictionary.keys())
closest_colors = sorted(colors, key=lambda color: distance(color, point))
closest_color = closest_colors[0]
code = rgb_code_dictionary[closest_color]
Loris answered 19/12, 2015 at 5:5 Comment(4)
I got it so it finds the nearest RGB value in a table of RGB values, but how would I translate that into finding the color integer (as in the color codes I linked in my question)?Datura
Each RGB value should be mapped to an integer as their color code. You can create a dictionary where the key is the RGB value and the value is the integer. I'll note that the RGB value must be a tuple, not a list in order for it to be a key in the dictionary. See #1939114Loris
Thanks, I got it to work by formatting the colors table like so: {(27,42,53):26, (242,243,243):1, (163,162,165):194, etc.}Datura
This is not a very good function for color similarity, see also stackoverflow.com/questions/5392061Dempsey
B
10

Expanding on mattsap's answer:

We don't need to sort all the colours, since we're only looking for the closest. i.e. We can avoid the computationally expensive sort and use min instead.

We also don't need to calculate the absolute distance between the colours, since we're only interested in relative distance. i.e. We can also avoid the "square root" part of Pythagoras.

This gives:

colours = ( (255, 255, 255, "white"),
            (255, 0, 0, "red"),
            (128, 0, 0, "dark red"),
            (0, 255, 0, "green") )


def nearest_colour( subjects, query ):
    return min( subjects, key = lambda subject: sum( (s - q) ** 2 for s, q in zip( subject, query ) ) )


print( nearest_colour( colours, (64, 0, 0) ) ) # dark red
print( nearest_colour( colours, (0, 192, 0) ) ) # green
print( nearest_colour( colours, (255, 255, 64) ) ) # white

Of course, once you consider different colour spaces and the contributions of each colour component to its perception of the human eye, there's a whole rabbit hole to go down, as per this question, but that's probably overly overkill for most cases.

Burlingame answered 1/11, 2019 at 9:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.