Using RGB Sensor (TCS3472) - Attempting to Find Best Match Color From A Table

Hey guys, I have a TCS3472 from Adafruit wired up and working on a Propeller:
https://www.adafruit.com/product/1334

I created a table of roughly 50 colors (RGB), and I am trying to take the sensor readings and match it up with the most similar color.

Here is what I tried so far:
I first looped through the table of colors, and calculated a new table that is based off percentages of RGB.
repeat i from 0 to 49
    Data_Red_Percent[i] := (Data_Red[i] * 100) / (Data_Red[i] + Data_Green[i] + Data_Blue[i])
    Data_Green_Percent[i] := (Data_Green[i] * 100) / (Data_Red[i] + Data_Green[i] + Data_Blue[i])
    Data_Blue_Percent[i] := (Data_Blue[i] * 100) / (Data_Red[i] + Data_Green[i] + Data_Blue[i])

So for example, RGB(255,255,255) would now be 33%, 33%, 33%. A RGB(255,127,127) would be 50%, 25%, 25%. I figured this would be a way for normalizing the colors.... if a color came out a little darker or a little lighter, its ratios might still be the same.

I then do the same thing with the RGB sensor readings. Next I create a table of differences.
repeat i from 0 to 50
    Compare_Red_Variance[i] := ||(Red_Percentage - Data_Red_Percent[i])
    Compare_Green_Variance[i] := ||(Green_Percentage - Data_Green_Percent[i])
    Compare_Blue_Variance[i] := ||(Blue_Percentage - Data_Blue_Percent[i])

The color that has the less amount of variance should be the color that is the closest match right?

So this sort of works, but it doesn't seem to be all that accurate. I am having a hard time telling if this is even a good method/algorithm or not, or if the external lighting near the sensor might be the problem? The sensor is equipped with a white LED directly to the side of the sensor. The intention is to light up the material you are measuring, so the sensor can get a good reading. I understand there are a lot of different wavelengths for "white" LED, which could shift the sensor readings slightly.

Are you aware of a better algorithm for finding colors, or is this the correct method?

Thanks and any help or advice is greatly appreciated!

Comments

  • 7 Comments sorted by Date Added Votes
  • JohnCJohnC Posts: 43
    edited March 13 Vote Up0Vote Down
    I'm starting project with this same sensor and will have 30-50 color bins as well. I'm not terribly deep in the programming yet, but the Euclidian math here looks interesting:

    https://en.wikipedia.org/wiki/Color_difference

    If you sense the same object ten times in a row, with neither the object nor the sensor moving, how stable are your readings?
  • Color distances are, on some level, completely arbitrary. Ideally, you want a formula that approximates the human response as to which colors are most similar. If you don't care about lightness or darkness, for example, you might consider converting your RGB values to the HSB (hue, saturation, and brightness) color space, then measure the distance along the H and S dimensions. But, by this method, white and black would be the same color. Maybe not what you want.

    The metric I usually favor for color distances is what I call the minimax distance. It can be applied in any color space and consists of minimizing the maximum distance among the two, three, or four color coordinates. For example, if the observed color in RGB space is (100, 30, 200) and you have two target colors, (255, 20, 150) and (125, 50, 90), compute the absolute values of the differences between the observed and target values:

    (155, 10, 50) and (25, 20, 110)

    The observed color is closer to the second target because its maximum difference (110) is less than that of the first target (155). One huge advantage of this method is that it requires no multiplications or square roots to compute. And it gives results that align rather well with human perception.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • JohnC wrote: »
    I'm starting project with this same sensor and will have 30-50 color bins as well. I'm not terribly deep in the programming yet, but the Euclidian math here looks interesting:

    https://en.wikipedia.org/wiki/Color_difference

    If you sense the same object ten times in a row, with neither the object nor the sensor moving, how stable are your readings?
    Thanks for the link, I'll look into this.
    My readings are pretty stable. With nothing really moving much the values pretty much stay put, and are somewhat repeatable.
    Color distances are, on some level, completely arbitrary. Ideally, you want a formula that approximates the human response as to which colors are most similar. If you don't care about lightness or darkness, for example, you might consider converting your RGB values to the HSB (hue, saturation, and brightness) color space, then measure the distance along the H and S dimensions. But, by this method, white and black would be the same color. Maybe not what you want.

    The metric I usually favor for color distances is what I call the minimax distance. It can be applied in any color space and consists of minimizing the maximum distance among the two, three, or four color coordinates. For example, if the observed color in RGB space is (100, 30, 200) and you have two target colors, (255, 20, 150) and (125, 50, 90), compute the absolute values of the differences between the observed and target values:

    (155, 10, 50) and (25, 20, 110)

    The observed color is closer to the second target because its maximum difference (110) is less than that of the first target (155). One huge advantage of this method is that it requires no multiplications or square roots to compute. And it gives results that align rather well with human perception.

    -Phil
    Hey Phil, thanks for the info! This would basically be what I am doing now correct? Instead of subtracting the actual RGB values, I'm subtracting the difference between the ratios of RGB values. Would one be preferred over the other?
  • Mahonroy wrote:
    This would basically be what I am doing now correct?
    I'm not sure. In your first post you said, "The color that has the less amount of variance should be the color that is the closest match right?"

    It depends upon how you compute "the less amount of variance." If you compare the maximum variances among the RGB ratios and pick the target with the lowest maximum, then, yes. But if you're adding the variances or their squares and comparing sums, then no. Also, your method does not account for brightness differences, and mine does. But that may be what you want.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 22,106
    edited March 13 Vote Up0Vote Down
    Here's an image that demonstrates minimax color differences. The center square's RGB colors are (255, 128, 64). The colors in the inner ring all have the same minimax distance from the center, i.e. 32. The squares in the outer ring differ by 64.

    minimax_difs.png

    You also mentioned what to do about white. Actually you need to define what white is before you proceed to match other colors. You do this by showing the sensor a white card. Suppose that the sensor responds with (200, 223, 240). Using these values, you have to balance any subsequent readings against your defined white, as follows:

    Red (balanced) = Red (read) * 255 / 200
    Grn (balanced) = Grn (read) * 255 / 223
    Blu (balanced) = Blu (read) * 255 / 240

    You can then use this "white-balanced" reading to compare with the colors in your target list.

    Finally, how well your matching works will depend a lot upon your selection of target colors. If all colors are treated equally, your target colors should be equally distributed based upon minimax or whatever other distance metric you're using. But you might be fussier about some colors than others. For example, you might want to ensure that flesh tones are extremely well-matched, since you don't want a greenish hue to be identified as flesh. In that case, you will want to include a tighter cluster of target colors around acceptable flesh tones than the other colors in your target palette. (As an aside, later analog color TVs included circuitry to "pull" colors toward a standard flesh tone. This made it easier for users to balance the TV's RGB sensitivities without people on the screen looking like martians or the Flying Purple People Eater.)

    -Phil
    285 x 285 - 6K
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • RaymanRayman Posts: 8,907
    edited March 13 Vote Up0Vote Down
    I think I'd try a "least squares" approach...

    Subtract reading from table value and square it for R, then G, then B. Add the three together and pick whichever table value gives the smallest sum of squares...

    Green does count more than red or blue though... So, maybe I'd double the green square before adding it to red and blue...
    Prop Info and Apps: http://www.rayslogic.com/
  • The least squares approach is the same as the Euclidean distance, except that you don't take a square root (which is unnecessary anyway for comparison purposes).

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
Sign In or Register to comment.