
Про самодельный датчик цвета мы уже писали, так что идея использовать RGB-светодиода (или нескольких цветных светодиодов) для поочерёдного освещения объекта и считывания на фоторезисторе напряжения с последующим выбором наилучшего отклика — не нова.
Однако, попытка сделать реальную «фотошоповскую пипетку» (Eyedropper) продолжает ждать своего воплощения 🙂
real world eyedropper: color sensing for the arduino
код для Arduino:
// Define colour sensor LED pins
int ledArray[] = {2,3,4};
// boolean to know if the balance has been set
boolean balanceSet = false;
//place holders for colour detected
int red = 0;
int green = 0;
int blue = 0;
//floats to hold colour arrays
float colourArray[] = {0,0,0};
float whiteArray[] = {0,0,0};
float blackArray[] = {0,0,0};
//place holder for average
int avgRead;
void setup(){
//setup the outputs for the colour sensor
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
//begin serial communication
Serial.begin(9600);
}
void loop(){
checkBalance();
checkColour();
printColour();
}
void checkBalance(){
//check if the balance has been set, if not, set it
if(balanceSet == false){
setBalance();
}
}
void setBalance(){
//set white balance
delay(5000); //delay for five seconds, this gives us time to get a white sample in front of our sensor
//scan the white sample.
//go through each light, get a reading, set the base reading for each colour red, green, and blue to the white array
for(int i = 0;i<=2;i++){
digitalWrite(ledArray[i],HIGH);
delay(100);
getReading(5); //number is the number of scans to take for average, this whole function is redundant, one reading works just as well.
whiteArray[i] = avgRead;
digitalWrite(ledArray[i],LOW);
delay(100);
}
//done scanning white, now it will pulse blue to tell you that it is time for the black (or grey) sample.
//set black balance
delay(5000); //wait for five seconds so we can position our black sample
//go ahead and scan, sets the colour values for red, green, and blue when exposed to black
for(int i = 0;i<=2;i++){
digitalWrite(ledArray[i],HIGH);
delay(100);
getReading(5);
blackArray[i] = avgRead;
//blackArray[i] = analogRead(2);
digitalWrite(ledArray[i],LOW);
delay(100);
}
//set boolean value so we know that balance is set
balanceSet = true;
//delay another 5 seconds to allow the human to catch up to what is going on
delay(5000);
}
void checkColour(){
for(int i = 0;i<=2;i++){
digitalWrite(ledArray[i],HIGH); //turn or the LED, red, green or blue depending which iteration
delay(100); //delay to allow CdS to stabalize, they are slow
getReading(5); //take a reading however many times
colourArray[i] = avgRead; //set the current colour in the array to the average reading
float greyDiff = whiteArray[i] - blackArray[i]; //the highest possible return minus the lowest returns the area for values in between
colourArray[i] = (colourArray[i] - blackArray[i])/(greyDiff)*255; //the reading returned minus the lowest value divided by the possible range multiplied by 255 will give us a value roughly between 0-255 representing the value for the current reflectivity(for the colour it is exposed to) of what is being scanned
digitalWrite(ledArray[i],LOW); //turn off the current LED
delay(100);
}
}
void getReading(int times){
int reading;
int tally=0;
//take the reading however many times was requested and add them up
for(int i = 0;i < times;i++){
reading = analogRead(0);
tally = reading + tally;
delay(10);
}
//calculate the average and set it
avgRead = (tally)/times;
}
//prints the colour in the colour array, in the next step, we will send this to processing to see how good the sensor works.
void printColour(){
Serial.print("R = ");
Serial.println(int(colourArray[0]));
Serial.print("G = ");
Serial.println(int(colourArray[1]));
Serial.print("B = ");
Serial.println(int(colourArray[2]));
//delay(2000);
}
код Processing-а для визуализации:
import processing.serial.*;
import java.awt.datatransfer.*;
import java.awt.Toolkit;
String buff = "";
int val = 0;
int wRed, wGreen, wBlue;
String col = "ffffff";
ClipHelper cp = new ClipHelper();
Serial port;
void setup(){
size(200,200);
port = new Serial(this, "COM3", 9600); //remember to replace COM20 with the appropriate serial port on your computer
}
void draw(){
background(wRed,wGreen,wBlue);
// check for serial, and process
while (port.available() > 0) {
serialEvent(port.read());
}
}
void keyPressed() { cp.copyString(""+col); }
void serialEvent(int serial) {
if(serial != '\n') {
buff += char(serial);
}
else {
int cRed = buff.indexOf("R");
int cGreen = buff.indexOf("G");
int cBlue = buff.indexOf("B");
if(cRed >=0){
String val = buff.substring(cRed+3);
wRed = Integer.parseInt(val.trim());
}
if(cGreen >=0){
String val = buff.substring(cGreen+3);
wGreen = Integer.parseInt(val.trim());
}
if(cBlue >=0){
String val = buff.substring(cBlue+3);
wBlue = Integer.parseInt(val.trim());
}
col = hex(color(wRed, wGreen, wBlue), 6);
buff = "";
}
}
// CLIPHELPER OBJECT CLASS:
class ClipHelper {
Clipboard clipboard;
ClipHelper() {
getClipboard();
}
void getClipboard () {
// this is our simple thread that grabs the clipboard
Thread clipThread = new Thread() {
public void run() {
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
}
};
// start the thread as a daemon thread and wait for it to die
if (clipboard == null) {
try {
clipThread.setDaemon(true);
clipThread.start();
clipThread.join();
}
catch (Exception e) {}
}
}
void copyString (String data) {
copyTransferableObject(new StringSelection(data));
}
void copyTransferableObject (Transferable contents) {
getClipboard();
clipboard.setContents(contents, null);
}
String pasteString () {
String data = null;
try {
data = (String)pasteObject(DataFlavor.stringFlavor);
}
catch (Exception e) {
System.err.println("Error getting String from clipboard: " + e);
}
return data;
}
Object pasteObject (DataFlavor flavor)
throws UnsupportedFlavorException, IOException
{
Object obj = null;
getClipboard();
Transferable content = clipboard.getContents(null);
if (content != null)
obj = content.getTransferData(flavor);
return obj;
}
}
остаётся реализовать это в виде плагина для фотошопа или GIMP-а 😉
Ссылки
Using an RGB LED to Detect Colours
Beginner project: Color Sensing with RGB LEDs and a photocell

0 комментариев на «“Датчик цвета из RGB-светодиода и фотоэлемента — реальная фотошоповская пипетка”»
Интересна точность получаемого цвета. И можно ли использовать его в качестве фотоспектрометра для подбора краски, к примеру, в автопокрасочных?
думаю, для этого лучше использовать web-камеру 🙂
Ни в коем случае. Обычные светодиоды не дают нормальных RGB-цветов — можно собрать несложное устройство и сравнить получаемый цвет с его изображением на экране.
Если уж так хочется сделать спектрофотометр своими руками, необходимо использовать датчик из любого недорогого калибратора цвета — цена примерно 3500-5000р (дорогие начинаются от 12-15) и эталонный источник освещения. А описанный девайс сможет только различать принципиально разные цвета, без мельчайших оттенков.
Может быть датчик можно сделать точнее, если использовать белый светодиод (или лучше какой-либо другой источник с более белым светом) и 3 фоторезистора\транзистора\диода с R,G и B фильтрами соответственно?