Датчик цвета из RGB-светодиода и фотоэлемента — реальная фотошоповская пипетка


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

По теме
Самодельный датчик цвета
Processing и Arduino


0 комментариев на «“Датчик цвета из RGB-светодиода и фотоэлемента — реальная фотошоповская пипетка”»

  1. Интересна точность получаемого цвета. И можно ли использовать его в качестве фотоспектрометра для подбора краски, к примеру, в автопокрасочных?

    • думаю, для этого лучше использовать web-камеру 🙂

    • Ни в коем случае. Обычные светодиоды не дают нормальных RGB-цветов — можно собрать несложное устройство и сравнить получаемый цвет с его изображением на экране.

      Если уж так хочется сделать спектрофотометр своими руками, необходимо использовать датчик из любого недорогого калибратора цвета — цена примерно 3500-5000р (дорогие начинаются от 12-15) и эталонный источник освещения. А описанный девайс сможет только различать принципиально разные цвета, без мельчайших оттенков.

  2. Может быть датчик можно сделать точнее, если использовать белый светодиод (или лучше какой-либо другой источник с более белым светом) и 3 фоторезистора\транзистора\диода с R,G и B фильтрами соответственно?

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение