// Based on Code from tinker.it
// https://code.google.com/p/tinkerit/wiki/SerialToDmx
class dmx {
Serial myPort;
dmx(Serial port) {
myPort = port;
}
void setChannel(int channel, int value) {
// Die Parameter werden in Text konvertiert: bei 132c45w ist 132 der Kanal und 45 der Wert
// dann wird der text an den Arduino geschikt
// Convert the parameters into a message of the form: 123c45w where 123 is the channel and 45 is the value
// then send to the Arduino
myPort.write( str(channel) + "c" + str(value) + "w" );
}
}
//
// Benedikt Frank, Arduino-Kurs SS10, Dozent: Jochen Koubek, Universität Bayreuth
//
// Set-Up:
//
// Whiteboard mit 4 farbigen Magneten (rot, grün, blau, gelb)
// gefilmt von einer Webcam
//
// Whiteboard with 4 colored Magnets (red, green, blue, yellow)
// filmed by a wabcam.
import codeanticode.gsvideo.*;
import processing.serial.*;
GSPipeline pipe;
Serial myPort;
//Bildschirmgröße
//Screensize
int w=640;
int h=480;
// Ränder, in denen die Punkte nicht gezählt werden
// Borders
int borderx=65;
int bordery=36;
// Faktoren, um die Bildschirmgröße auf DMX-Werte umzurechnen
// factors to convert screen size to dmx-value
float fx=0.5;
float fy=0.625;
// DMX-Kanäle für RGB
// DMX-Channels for RGB
int r=2;
int g=3;
int b=4;
// Werte für die DMX-Kanäle
// Values of DMX-Channels
int rv1;
int gv1;
int bv1;
int rv2;
int gv2;
int bv2;
// Werte für zusätzliche Steuerung
// Values for extra contoller
int cv1;
int cv2;
//Timer
int timer;
int timerlength = 1000;
boolean timerswitch;
//Strobotimer
int strobo;
int strobolength = 42;
int strobocount;
boolean stroboswitch;
tracker t;
dmx led;
void setup() {
size(w,h);
// Bild von der Webcam holen
// Get picture from Webcam
println(Serial.list()); // Zeigt die vorhandenen seriellen Anschlüsse / shows available serial ports on the system
myPort = new Serial(this, Serial.list()[0], 9600);
pipe = new GSPipeline(this, "v4l2src device=/dev/video1 ! ffmpegcolorspace ! video/x-raw-rgb, width=640, height=480, bpp=32, depth=24");
t = new tracker (pipe);
led =new dmx(myPort);
smooth();
rv1=0;
gv1=0;
bv1=0;
rv2=0;
gv2=0;
bv2=0;
cv1=0;
cv2=0;
timer = millis();
timerswitch = true;
stroboswitch = true;
}
void draw() {
//neues Bild holen
//grab new frame
if (pipe.available() == true) {
pipe.read();
//Bild anzeigen
//display image
image(pipe, 0, 0 );
}
pipe.loadPixels();
t.configure();
t.track();
// Farben finden
// track colors
// Farbe 1 - x-Wert
// color 1 - x-value
if (t.pos(0,"rot")>=borderx && t.pos(0,"rot")<=w-borderx) {
rv1 = int(t.pos(0,"rot")*fx);
}
if (t.pos(0,"gruen")>=borderx && t.pos(0,"gruen")<=w-borderx) {
gv1 = int(t.pos(0,"gruen")*fx);
}
if (t.pos(0,"blau")>=borderx && t.pos(0,"blau")<=w-borderx) {
bv1 = int(t.pos(0,"blau")*fx);
}
if (t.pos(0,"gelb")>=borderx && t.pos(0,"gelb")<=w-borderx) {
cv1 = int(t.pos(0,"gelb")*fx);
}
// Farbe 2 - y-Wert
// color 2 - y-value
if (t.pos(1,"rot")>=borderx && t.pos(1,"rot")<=w-borderx) {
rv2 = int(t.pos(1,"rot")*fx);
}
if (t.pos(1,"gruen")>=borderx && t.pos(1,"gruen")<=w-borderx) {
gv2 = int(t.pos(1,"gruen")*fx);
}
if (t.pos(1,"blau")>=borderx && t.pos(1,"blau")<=w-borderx) {
bv2 = int(t.pos(1,"blau")*fx);
}
if (t.pos(1,"gelb")>=borderx && t.pos(1,"gelb")<=w-borderx) {
cv2 = int(t.pos(1,"gelb")*fx);
}
// Timer
timerlength = cv1 * 20;
if (millis() - timer > timerlength) {
timer = millis();
if (timerswitch == true) {
timerswitch = false;
}
else {
timerswitch = true;
}
}
//Strobo
if (millis() - strobo > strobolength) {
strobo = millis();
strobocount ++;
if (stroboswitch == false && strobocount > cv2/12) {
stroboswitch = true;
strobocount = 0;
}
else {
stroboswitch = false;
}
}
// Strobo geht aus, wenn der Kontroll-Magnet ganz unten ist
// Strobo is off, when controll-magnet is at the bottom
if (stroboswitch == false && cv2 < 190) {
led.setChannel(r,0);
led.setChannel(g,0);
led.setChannel(b,0);
}
else {
// Farbwechsel
// change of colors
if (timerswitch == true) {
led.setChannel(r,rv1);
led.setChannel(g,gv1);
led.setChannel(b,bv1);
}
else {
led.setChannel(r,rv2);
led.setChannel(g,gv2);
led.setChannel(b,bv2);
}
}
}
// Basiert auf dem Farberkennungs-Algorythmus von Daniel Shiffman
// Based on a tracking algorithm by Daniel Shiffman
// http://www.learningprocessing.com/examples/chapter-16/example-16-11/
class tracker {
color trackRed;
color trackGreen;
color trackBlue;
color trackYellow;
color trackColor;
color[] colors;
public int[][] positions;
float worldRecord;
GSPipeline pipe;
tracker (GSPipeline pipel) {
pipe = pipel;
colors = new color[4];
positions = new int[2][4];
}
// Konfiguration der Farberkennung
// Configuration of color tracking
//
// Funktion: Taste für einzelne Farbe (r,g,b,y) gedrückt halten
// und mit der Maus auf den jeweiligen Farbpunkt im Bild klicken.
// Function: press key for the color (r,g,b,y) and click the point
// with the mouse on the screen
void configure() {
if (keyPressed) {
if (key == 'r' || key == 'R') {
if (mousePressed == true) {
// Farbe, die die Maus anklickt, in der Variable trackColor speichern
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*pipe.width;
trackRed = color(pipe.pixels[loc]);
}
}
if (key == 'g' || key == 'G') {
if (mousePressed == true) {
// Farbe, die die Maus anklickt, in der Variable trackColor speichern
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*pipe.width;
trackGreen = color(pipe.pixels[loc]);
}
}
if (key == 'b' || key == 'B') {
if (mousePressed == true) {
// Farbe, die die Maus anklickt, in der Variable trackColor speichern
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*pipe.width;
trackBlue = color(pipe.pixels[loc]);
}
}
if (key == 'y' || key == 'Y') {
if (mousePressed == true) {
// Farbe, die die Maus anklickt, in der Variable trackColor speichern
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*pipe.width;
trackYellow = color(pipe.pixels[loc]);
}
}
}
colors[0]=trackRed;
colors[1]=trackGreen;
colors[2]=trackBlue;
colors[3]=trackYellow;
}
// Funktion zur Farberkennung
// Function for color tracking
void track() {
worldRecord = 500;
for (int c=0; c < colors.length; c++) {
trackColor = colors[c];
// Loop, der durch jedes Pixel läuft
// Begin loop to walk through every pixel
for (int x = 0; x < pipe.width; x ++ ) {
for (int y = 0; y < pipe.height; y ++ ) {
int loc = x + y*pipe.width;
// Aktuelle Farbe abfragen
// What is current color
color currentColor = pipe.pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
// Mit dem euklidischem Abstand Farben vergleichen (dist()-Funktion)
// Using euclidean distance to compare colors (dist()-function)
float d = dist(r1,g1,b1,r2,g2,b2);
// Wenn die aktuelle Farbe der gesuchten Farbe mehr ähnelt als
// die näheste Farbe, dann wird die Position und die Differenz
// gespeichert
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
positions[0][c] = x;
positions[1][c] = y;
}
}
}
// Wir betrachten die Farbe als gefunden, wenn die Distanz weniger als 50 beträgt.
// Die Grenze von 50 ist frei wählbar und kann verändert werden, je nachdem wie
// genau die Suche sein soll.
// We only consider the color found if its color distance is less than 50.
// This threshold of 50 is arbitrary and you can adjust this number depending
// on how accurate you require the tracking to be.
if (worldRecord < 50) {
// Malt einen Kreis um das erkannte Pixel
// Draw a circle at the tracked pixel
fill(trackColor);
strokeWeight(4.0);
stroke(0);
ellipse(positions[0][c],positions[1][c],16,16);
}
}
}
// Funktion zur Ausgabe der Position
// Function to return positions
int pos(int axis, String tcolor) {
int a=axis;
String c= tcolor;
int b=0;
// Fehlermeldung bei falscher Eingabe
// Error if entry is wrong
if (a!=0 && a!=1) {
println("Flasche Postionsangabe. Nur '0' für 'x' und '1' für 'y' sind gültige Werte.");
}
if (c.equals("rot")||c.equals("red")) {
b=0;
}
if (c.equals("gruen")||c.equals("green")) {
b=1;
}
if (c.equals("blau")||c.equals("blue")) {
b=2;
}
if (c.equals("gelb")||c.equals("yellow")) {
b=3;
}
return positions[a][b];
}
}
Prototype for the course "digital media: arduino" at the University of Bayreuth in summer 2010. Arduino sends the DMX-signal to a LED-PAR-Headlight. Color-tracking and the change of light is controlled by processing.
Prototyp für das Seminar "Digitale Medien: Arduino" an der Uni Bayreuth, Sommersemester 2010. Der Arduino sendet das DMX-Signal an den LED-Scheinwerfer. Bilderkennung und Farbwechsel werden von Processing gesteuert.
Needs the SerialToDmx-Code running on the Arduino!
Der SerialToDmx-Code muss auf dem Arduino laufen!
(http://goo.gl/rWUCY)
Demo video: http://goo.gl/9jIbj