Using RGB Sensor (TCS3472) - Attempting to Find Best Match Color From A Table
Mahonroy
Posts: 175
in Propeller 1
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.
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.
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!
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
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?
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
My readings are pretty stable. With nothing really moving much the values pretty much stay put, and are somewhat repeatable.
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?
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
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
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...
-Phil