Yesterday I gave a guest lecture at the Korea National University of the Arts in an Arduino class taught by my friend Uram Choe, an amazing mechanized sculpture artist. As seen above, if you like metal working, gears and motors, you will love his sculptures!
The topic of my lecture was using computer vision with the Arduino. Now I am not a computer vision expert or scientist, I have however, dabbled with OpenCV (the most popular computer vision library) enough over the years to know my way around the library fairly well, and get some pretty decent results. The emphasis here is how to use OpenCV with an Arduino to combine things like motors with video tracking. It’s surprisingly easy!
Usually I work with openframeworks when using OpenCv but for this lecture I used Processing for simplicity. After all this lecture was for an Arduino class not a computer graphics class. Processing also has a nice OpenCV library that implements most of the basic functions of OpenCV. It’s a great place to get started with computer vision.
Demonstrated here is one part of my lecture, which is a simple example of using the Haarfinder face detection algorithm from OpenCV in combination with the Arduino, the Firmata firmware and an RC servo motor. The first step is to setup your servo motor and Arduino board, this is quite painless but if you are new to RC servos here is a breadboard diagram I whipped up in Fritzing.

The next step is to go and install all the correct libraries for both Processing and Arduino. For Processing you will need:
1. The OpenCV library and the OpenCV Processing Library. Follow this link and instructions to download and install both. Download
2. The Firmata library for Processing (also called the Arduino Library for Processing). Download. Place this Library into your Processing libraries folder, which is located inside of your Processing sketchbook.
For the Arduino you will need:
1. The Firmata library firmware for Arduino. Download. Place this library inside your Arduino libraries folder which is located inside of your Arduino Sketchbook.
So now you have all the proper files and libraries installed, the next step is to put the Firmata firmware on to the Arduino. All you need to do here is in your Arduino IDE select the Menu: Files -> Examples -> Arduino -> firmware -> Standard_Firmata and open and program this sketch onto your Arduino. So now you have the Firmata firmware on your Arduino so you can now easily interface with Processing.
So go ahead and startup your Processing IDE and lets start some coding. The full example code is here: Download. The code is documented with lots of comments so most of it I won’t cover here. However, I will go over a few of the more important or difficult aspects of the code.
In your Processing setup function there is one line of code that sets the input resolution of your camera. In this example the input resolution is being set to width, height, which is the size of your window. In many applications you will want to have a window that is bigger then your camera input resolution. If your windows is larger then 320×240 go ahead and change the opencv.capture parameters to your actual camera resolution.
void setup() {
size( 320, 240 ); //set window size
opencv = new OpenCV( this ); //setup openCV
opencv.capture( width, height ); // open video stream
The next critical part of code in the setup function is to set the opencv cascade type.
opencv.cascade( OpenCV.CASCADE_FRONTALFACE_ALT );
In this line the cascade type is set to: CASCADE_FRONTALFACE_ALT which means the face detection algorithm will look for front facing faces. There are however, other types of cascades available to you. Here is a fairly self explainable list of alternatives from the OpenCV processing library docs:
- CASCADE_FRONTALFACE_DEFAULT
- CASCADE_PROFILEFACE
- CASCADE_FULLBODY
- CASCADE_LOWERBODY
- CASCADE_UPPERBODY
Now there is only one important part of the code left to explain and that is the code contained in the Processing draw() function. The first part of this code is a call to the openCV library to look at the current video frame, detect all the faces in that video and populate those face location and sizes as Rectangles into an array.
// detect faces and put them in an array Rectangle[] faces = opencv.detect( 1.2, 2, OpenCV.HAAR_DO_CANNY_PRUNING, 40, 40 );
The next few lines of code is what interfaces your Arduino with processing which is the core element of this whole tutorial. Thanks to the Firmata library its surprisingly simple. First we check if there are faces in the scene. We don’t want to try to send values if there are no faces present. The next important thing is to map the values of the face X location to a value between 0 and 255. Since 0-255 is the range of values the analogWrite command can send to the RC servo. So now when the face is at X coordinate 320, the RC servo will be sent the value 255. In the next line we actually call the Arduino analogWrite command and send the mapped value. The cool feature of Firmata is that you can make actual Arduino function calls from inside processing and the interfacing happens seamlessly. You don’t need to worry about sending serial data and parsing the results on the Arduino side. By calling the analogWrite command in Processing the Arduino calls that command and PWMs the correct value to the RC servo.
if(faces.length > 0)
{
int mappedValue = (int) map(faces[0].x,0,width, 0, 255);
arduino.analogWrite(3, mappedValue);
}
Now we have face tracking controlling a motor! Very nice! Obviously this could be taken much further with multiple faces, multiple motors, and multiple axises. This however, is a great start and its super easy to extend from here. Goodluck!
UPDATE
It has come to my attention that people are having some issues with this example using windows 7. Something to do with the Processing window showing a blank screen and no video image. I imagine it has something to do with the OpenCV lib having problems grabbing the video from the camera. So I found a work around for the issue. It involves using the normal processing video library to grab the video, then to copy each frame of video into openCV to perform the face detection. This avoids depending on OpenCV to grab the video from the camera. Here is the code:
import processing.video.*;
import hypermedia.video.*;
import java.awt.Rectangle;
Capture myCapture;
OpenCV opencv;
int contrast_value = 0;
int brightness_value = 0;
void setup()
{
size( 320,240 );
myCapture = myCapture = new Capture(this, width, height, 30);
opencv = new OpenCV( this );
opencv.allocate(width,height);
opencv.cascade( OpenCV.CASCADE_FRONTALFACE_ALT );
}
void draw()
{
//read the output image
myCapture.read();
opencv.copy(myCapture); //copy the video frame into openCV
//put the image on the frame
image( opencv.image(), 0, 0 );
opencv.convert( GRAY ); //convert frame to gray scale
opencv.contrast( contrast_value ); //apply contrast filter
opencv.brightness( brightness_value ); //apply brightness filter
// detect faces and put them in an array
Rectangle[] faces = opencv.detect( 1.2, 2, OpenCV.HAAR_DO_CANNY_PRUNING, 40, 40 );
//etc, etc, the same as before
}
Hi, awesome info!
Thanks for sharing.
But i’m a little confused about how do you connect the camera to arduino
Can you tell me the how to connect the USB camera pin out to the arduino UNO?
I really thank you a lot!
Hi Luis,
Actually the camera is not attached to the arduino at all. The camera is plugged into a PC and the PC is connected via the USB to the arduino. It can be a little confusing because in the code I am calling arduino functions, ex:
arduino.analogWrite(3, mappedValue);However, all the code is actually written in Processing using the Firmata Processing library (notice thearduino.functionName()). So when I callarduino.analogWrite(3, mappedValue);What is happening is the Firmata library is sending serial data from Processing to the arduino that tells the firmata firmware on to the arduino to toggle PWM on pin 3. To do anything with computer vision you will still need a PC, unfortunately the arduino doesn’t have the CPU power to do any computer vision…now if we were using some fancy ARM chip it might be a different story.. I hope that clears things up!Noah
Hi, thanks for answer.
So, if you plug the cam to a PC. Why do you process the data with arduino and not with the PC? Just for fun/research? or there is something i’m missing?
(Just Ask because i’m a beginner with Arduino)
Thanks again for your time
Well, actually the computer vision data is all done on the PC programmed in the Processing.org programming environment. The X location of the first detected face is being sent using the Firmata protocol via USB to the Arduino which has the Firmata firmware installed. Then the arduino is wired up to a RC servo. The reason to do things like this is because its not easy to attach (near impossible?) a RC servo directly to a PC. The Arduino acts as a interface between PC and RC servo. The PC can do computer vision, and the RC servo can move around, the arduino is just in the middle allowing them to communicate. You might want to read about the Processing programming environment as well as Firmata, and then you will probably be clear on how this works. Good luck!
Yes, i understand.
I did a similar project (to automate the office’s door lock) but the face detection process is at the PC. and only send to Arduino signal to move the servo/motor or whatever… The point is a don’t understand why you process the face detection at arduino and not on the computer.
Thanks
Ah, but I am doing the face detection on the computer and sending the X value to the arduino to move the servo motor. The automated office door lock you described is exactly what I am doing. I am just using the Firmata protocol to make the communication easier between the PC and the Arduino.
Hey, man. Thanks for sharing the information. Meanwhile, I’m having a problem… Could you tell me why is a blank image coming up on the screen instead of showing the image from the camera? The lights of the came is on, but there is no video streaming.
Code below:
import hypermedia.video.*;
import processing.video.*;
OpenCV opencv;
int width = 320;
int height = 240;
void setup() {
size( 320, 240 ); //set window size
opencv = new OpenCV( this ); //setup openCV
opencv.capture( width, height ); // open video stream
opencv.cascade( OpenCV.CASCADE_FRONTALFACE_ALT );
}
void draw(){
opencv.read();
image(opencv.image(), 0, 0);
}
Thanks in advance!
Hmmm, everything looks pretty good. The only two problems I can find are you don’t need
import processing.video.*;since the openCV does its own video capture. Also width and height are processing system variables, you might want to change the names to camWidth and camHeight or something. Other then that it looks ok to me. Maybe your camera doesn’t work at 320 by 240? Or perhaps the camera type/drivers are not working with OpenCVs camera capture? You could try using the Processings camera capture library then grabbing the pixels from the incoming video and copying them into OpenCV. Check out the openCV copy() function.That’s for a great clear article.
I’m just sitting down to get this working with hopes of getting smile detection going.
Is this approach a good choice to get started for that?
I mean “Thanks” for a clear article. Please update my comment and delete this comment.
Hi Sir
I’ve modified your program with the update you wrote above and
copied your if(faces.length > 0) code in the draw function
At first I got an error saying
It says cannot find anything named arduino.
So I included the
import processing.serial.*;
import cc.arduino.*;
Arduino arduino;
then I myCapture = myCapture = new Capture(this, width, height, 30);
line highlighted and got another error saying No capture could be found, or the VDIG is not installed correctly.
Please help me out
Hi, Yeah looking carefully at the post update, there are a few errors here. You might be better off using the download link for the full sketch code.
First off this line which says:
myCapture = myCapture = new Capture(this, width, height, 30);
should be:
myCapture = new Capture(this, width, height, 30);
Second the update code in the post doesn’t have any of the lines that refer to the servo/firmata control. It just has how to setup the video. Download the project files and start from there, then if you have issues with Windows 7 fix it with the code from the update. Goodluck!