1

Assume we have a priorly known set of n colors C. We are given a list of colors l.

The goal is for every color l, match it to a color in C such that it minimizes a distance function D.

The most straightforward approach is to use the euclidean distance, however that's not a good idea because of the following example:

Assume the input color is (0.1, 0, 0) so very dark red. Assume that brown (0,5, 0.5, 0) and pure red (1,0,0) are both in C.

The euclidean distance gives:

  • distance to brown = (0.4^2 + 0.5^2) = 0.41

  • distance to red = (0.9^2) = 0.81

Thus dark red is mapped to brown instead of red, which visually doesn't really make sense.

We could try the chebychev distance:

  • distance to brown = max(0.4, 0.5, 0) = 0.5

  • distance to red = max(0.9, 0, 0) = 0.9

Or the manhattan distance:

distance to brown = max(0.4 + 0.5) = 0.9

distance to red = max(0.9 + 0 + 0) = 0.9

The first still chooses brown over red, where the second picks both as equally valid choices. Although an improvement, it's not the ideal.

I however am not sure how to measure "visual distance", i.e if a color would "look green" to a human, how to map said color to green for example.

I am using opencv, and I have searched the documentation but I don''t seem to find if this problem is already solved.

Makogan
  • 8,208
  • 7
  • 44
  • 112

1 Answers1

1

Welcome to the world of Colors! If you're using RGB, the mentioned distance metrics are unlikely to work because RGB is not a perceptually uniform color space (distances between vectors in the color space do not resemble the human perceived changes). CIELAB color space is supposedly a perceptually uniform one.

A popular color distance metric that was subjected to a few revisions over the time is CIELAB \deltaE*

These distance metrics are available in the colormath package.

from docs:

from colormath.color_objects import LabColor
from colormath.color_diff import delta_e_cie1976

# Reference color.
color1 = LabColor(lab_l=0.9, lab_a=16.3, lab_b=-2.22)
# Color to be compared to the reference.
color2 = LabColor(lab_l=0.7, lab_a=14.2, lab_b=-1.80)
# This is your delta E value as a float.
delta_e = delta_e_cie1976(color1, color2)

In your problem, if the size of your known set of colors (C) is small (say 10), even the delta_E might not work as expected. A more reliable way would be to collect a new set S that has a lot of shades of each color in C (You can use Color Dictionaries) and map each color in l to it's closet in S and then to C. You can speed up your search by using a data structure like kd-tree by pre-computing your distance metrics.

akilat90
  • 5,436
  • 7
  • 28
  • 42