The k-NN (k-nearest neighbors) algorithm is among the simplest of all machine learning algorithms. We will use this algorithm to classify the color of a new object. As our training set of learned colors will only contain one sampe per color, k = 1, and the object is simply assigned to the class of that single nearest neighbor.
We will work in a 3-dimensional Euclidean space
. The x-axis represents the ratio of the clear channel frequency to the red channel frequency, the y-axis the ratio of the clear channel frequency to the green channel frequency and the z-axis the ratio of the clear channel frequency to the blue channel frequency (see TCS3200 data sheet for more details).
The image below illustrates the 3-dimensional Euclidean space, the trained colors (white, orange, yellow, red, green and blue point) and a new sample (black point), which color needs to be classified. The black lines are the so called Euclidean distances from the new sample point to every trained color point. All we need to do is to find the smallest distance.
In general, for an n-dimensional Euclidean space
, the Euclidean distance between two points
and
is given by
Beside many other applications this color machine learning algorithm could be used for automated test strip reading:
Image credit http://www.terumo.com
Hardware Required:
- Arduino board or other micro controller
- TCS3200 breakout board
- Hook-up wire
Circuit:
Not as shown I have used a TCS3200 breakout board with a collimator lens.
Example:
byte LED = 2, S0 = 3, S1 = 4, S2 = 5, S3 = 6, OUT = 7; char* color[] = {"white", "orange", "yellow", "red", "green", "blue", "out of range"}; char point[] = "Point color sensor to "; char object[] = " object"; char submit[] = "Submit 'ok' if it's done"; int learned_colors[3][6]; int PercentageRed, PercentageGreen, PercentageBlue; float OutOfRange;https://www.youtube.com/watch?v=cDvhVbhBprcvoid setup() {
Serial.begin(9600);
TCS3200_Setup();
}void loop() {
learning_mode();
while(1) {
new_sample();
classify();
}
}void TCS3200_Setup() {
pinMode(S0,OUTPUT);
pinMode(S1,OUTPUT);
pinMode(S2,OUTPUT);
pinMode(S3,OUTPUT);
pinMode(LED,OUTPUT);
pinMode(OUT,INPUT);
}void TCS3200_On() {
digitalWrite(LED,HIGH); // switch LED on
digitalWrite(S0,HIGH); // output frequency scaling (100%)
digitalWrite(S1,HIGH);
delay(5);
}void TCS3200_Off() {
digitalWrite(LED,LOW); // switch LED off
digitalWrite(S0,LOW); // power off sensor
digitalWrite(S1,LOW);
}void NoFilter() {
digitalWrite(S2,HIGH); // select no filter
digitalWrite(S3,LOW);
delay(5);
}void RedFilter() {
digitalWrite(S2,LOW); // select red filter
digitalWrite(S3,LOW);
delay(5);
}void GreenFilter() {
digitalWrite(S2,HIGH); // select green filter
digitalWrite(S3,HIGH);
delay(5);
}void BlueFilter() {
digitalWrite(S2,LOW); // select blue filter
digitalWrite(S3,HIGH);
delay(5);
}void input() {
String inputBuffer = “”;
while (inputBuffer != “ok”) {
inputBuffer = “”;
while (Serial.available() > 0) {
char ch = Serial.read();
inputBuffer += ch;
delay (10);
}
}
}void getColor() {
float FrequencyClear, FrequencyRed, FrequencyGreen, FrequencyBlue;
TCS3200_On();
NoFilter();
FrequencyClear = float(pulseIn(OUT,LOW,10000));
RedFilter();
FrequencyRed = float(pulseIn(OUT,LOW,10000));
GreenFilter();
FrequencyGreen = float(pulseIn(OUT,LOW,10000));
BlueFilter();
FrequencyBlue = float(pulseIn(OUT,LOW,10000));
TCS3200_Off();
PercentageRed = int((FrequencyClear / FrequencyRed) * 100.0);
PercentageGreen = int((FrequencyClear / FrequencyGreen) * 100.0);
PercentageBlue = int((FrequencyClear / FrequencyBlue) * 100.0);
OutOfRange = 500.0 / FrequencyClear;
}void learning_mode() {
for(byte i = 0; i < 6; i ++) {
Serial.print(point);
if(i == 1) Serial.print("an ");
else Serial.print(“a “);
Serial.print(color[i]);
Serial.println(object);
Serial.println(submit);
Serial.println(””);
input();
getColor();
learned_colors[0][i] = PercentageRed;
learned_colors[1][i] = PercentageGreen;
learned_colors[2][i] = PercentageBlue;
}
}void new_sample() {
Serial.print(point);
Serial.print(“a new”);
Serial.println(object);
Serial.println(submit);
Serial.println("");
input();
getColor();
}void classify() {
int i_color;
int ClosestColor;
float MaxDiff;
float MinDiff = 100.0;
if(OutOfRange < 1.5) ClosestColor = 6; // object out of range
else {
// find nearest neighbor, k = 1
for (i_color = 0; i_color < 6; i_color ++) {
// compute Euclidean distances
float ED = sqrt(pow((learned_colors[0][i_color] - PercentageRed),2.0) +
pow((learned_colors[1][i_color] - PercentageGreen),2.0) + pow((learned_colors[2][i_color] - PercentageBlue),2.0));
MaxDiff = ED;
// find minimum distance
if (MaxDiff < MinDiff) {
MinDiff = MaxDiff;
ClosestColor = i_color;
}
}
}
Serial.print(“Object is “); // print result
Serial.println(color[ClosestColor]);
Serial.println(””);
}