Про самодельный датчик цвета мы уже писали, так что идея использовать 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 фильтрами соответственно?