//ODYSSEY: a curious but cautiously shy desk lamp. //Talk to Arduino to control 2 motors (horiz and vert) //to move lamp based on location of detected face. //Tracks face when user is far using openCV. //Ray LC 10-15-2017. import processing.serial.*; import cc.arduino.*; import gab.opencv.*; import org.opencv.imgproc.Imgproc; import processing.video.*; import java.awt.Rectangle; Serial myPort; //Create Serial object Capture video; OpenCV opencv; int cols, rows; //in video coordinates (i.e. smaller scale) int vwidth, vheight; int VSCALE = 3; //how many times to make display bigger char TILTCH =0; char PANCH = 1; int CENTERP = 80, CENTERT = 110; int xdiff = 0, ydiff = 0; void setup() { size(960, 720); myPort = new Serial(this, Serial.list()[0], 57600); //opens COM1 on windows myPort.write(PANCH); myPort.write(80); myPort.write(TILTCH); myPort.write(110); cols = width/VSCALE; rows = height/VSCALE; vwidth = cols*2; vheight = rows*2; video = new Capture(this, cols, rows); opencv = new OpenCV(this, cols, rows); opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE); video.start(); } void draw() { background(100); fill(255); opencv.loadImage(video); Rectangle[] faces = opencv.detect(); scale(VSCALE); if (faces.length>0) { faces[0].x += faces[0].width/2; //middle of face faces[0].y += faces[0].height/2; //ellipse(faces[0].x, faces[0].y, faces[0].width, faces[0].height); xdiff = video.width/2 - faces[0].x; //flipped because of mirroring. ydiff = video.height/2 - faces[0].y; //flipped y in processing. println(xdiff + ", " + ydiff); if (xdiff != 0) { //Not centered horizontally, so move it towards face. myPort.write(PANCH); myPort.write(CENTERP+xdiff/4); } if (ydiff != 0) { //Not centered vertically, so move it towards face. myPort.write(TILTCH); myPort.write(CENTERT+ydiff/6); } video.loadPixels(); //To highlight the face. for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { // Calculate the 1D location from a 2D grid int loc = i + j*video.width; // Get the red, green, blue values from a pixel float r = red (video.pixels[loc]); float g = green(video.pixels[loc]); float b = blue (video.pixels[loc]); if (dist(i, j, faces[0].x, faces[0].y) < faces[0].width/2) { r *= 1.5; g *= 1.5; b *= 1.5; //Highlight face location. } // Constrain RGB to make sure they are within 0-255 color range r = constrain(r, 0, 255); g = constrain(g, 0, 255); b = constrain(b, 0, 255); // Make a new color and set pixel in the window color c = color(r, g, b); video.pixels[loc] = c; } } updatePixels(); image(video, 0, 0); //no face is found (not looking) } else { image(video, 0, 0); } } // An event for when a new frame is available void captureEvent(Capture video) { video.read(); }