Search code examples
opencvarduinoprocessingservo

Arduino servo with facetracking using arduino, processing and opencv


I'm working on a project to keep your face in the center of the screen, by using a camera on top of a servo. I've used the simple servo control tutorial, on the arduino playground website, to use the mouse to control the servo and tried to rewrite it to use your face's x coordinates to make the servo move in the desired direction.

simple servo control arduino playground

So far i got it working with the built-in camera. The servo moves nicely in the right direction with my face. But as soon as I use the external USB camera on top of the servo instead of the built-in camera I don't get the desired result. The camera doesn't wanna look at me. as soon as it detects your face it turns straight in the opposite direction. So if the camera detects your face on the left side of the screen, the servo will turn to the right until your face is out of the screen.

I hope that someone can answer or help me explain why it works with the built-in camera but not when I use the USB camera that i attached on the servo.

I'm using the Arduino, Processing and the OpenCV library in Processing.

This is the code that i have so far:

Arduino code:

#include <Servo.h>

Servo servo1; Servo servo2; 

void setup() {
 servo1.attach(4);  
 servo2.attach(10);

 Serial.begin(19200);
 Serial.println("Ready");
}

void loop() {

 static int v = 0;

 if ( Serial.available()) {
   char ch = Serial.read();

   switch(ch) {
     case '0'...'9':
       v = v * 10 + ch - '0';
        /*
           so if the chars sent are 45x (turn x servo to 45 degs)..
           v is the value we want to send to the servo and it is currently 0
           The first char (ch) is 4 so
           0*10 = 0 + 4 - 0 = 4;
           Second char is 4;
           4*10 = 40 + 5 = 45 - 0 = 45;
           Third char is not a number(0-9) so we  drop through...
        */
       break;
     case 's':
       servo1.write(v);
       v = 0;
       break;
     case 'w':
       servo2.write(v);
       v = 0;
       break;
     case 'd':
       servo2.detach();
       break;
     case 'a':
       servo2.attach(10);
       break;
   }
 }
}

My processing code:

import gab.opencv.*;
import processing.video.*;
import java.awt.*;

//----------------
import processing.serial.*;  

int gx = 15;
int gy = 35;
//int spos=90;
float midden=90;


float leftColor = 0.0;
float rightColor = 0.0;
Serial port; 
//----------------

Capture video;
OpenCV opencv;

void setup() {
  size(640, 480);


  String[] cameras = Capture.list();
  if (cameras.length == 0) {
    println("There are no cameras available for capture.");
    exit();
  } else {
    println("Available cameras:");
    for (int i = 0; i < cameras.length; i++) {
      println(cameras[i]);
    }
  }

  //----------------
  colorMode(RGB, 1.0);
  noStroke();

  frameRate(100);

  //println(Serial.list()); // List COM-ports

  //select second com-port from the list
  port = new Serial(this, Serial.list()[5], 19200); //arduino aangesloten aan linker USB
  //----------------

  video = new Capture(this, 640/2, 480/2, "USB2.0 Camera"); //external camera rechter USB
  //video = new Capture(this, 640/2, 480/2); //built-in camera
  opencv = new OpenCV(this, 640/2, 480/2);
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);  

  video.start();
  //-_-_-_-_-_-_-_-_-  weergave kleur camera
  opencv.useColor();
}

void draw() {
  //---------------- Mouse Control
  background(0.0);
  update(mouseX); 
  fill(mouseX/4); 
  rect(150, 320, gx*2, gx*2); 
  fill(180 - (mouseX/4)); 
  rect(450, 320, gy*2, gy*2);
  //----------------


  scale(2);
  opencv.loadImage(video);
  //-_-_-_-_-_-_-_-_-  Flip camera image
  opencv.flip(OpenCV.HORIZONTAL); 

  image(video, 0, 0 );


  //-_-_-_-_-_-_-_-_-
  image(opencv.getOutput(), 0, 0 );

  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);
  Rectangle[] faces = opencv.detect();
  //println(faces.length);

  for (int i = 0; i < faces.length; i++) {
    println(faces[i].x + "," + faces[i].y);
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height); //groene vierkant om het gezicht
    ellipse( faces[i].x + 0.5*faces[i].width, faces[i].y + 0.5*faces[i].height, 5, 5 ); //middenpunt v.h. gezicht
    midden= (faces[i].x + 0.5*faces[i].width);
    //midden= (faces[i].x);
  }
}

void captureEvent(Capture c) {
  c.read();
}

  //---------------- servo controls voor muislocatie en draaiing servo
void update(int x) 
{
  //Calculate servo postion from mouseX
  //spos= x/4;
  //Output the servo position ( from 0 to 180)
  port.write("s"+midden); 
  println(midden);
//    if( midden>80 && midden<150){
//     port.write("s"+90); 
//    } else if(midden<80){
//     port.write("s"+45);
//    }else{
//     port.write("s"+135); 
//    }
}
  //----------------

Solution

  • It sounds like the two images are flipped. To test this, try drawing a circle on the left side of both images (and then display using imshow) to see if they end up at the same location.