Introduction To Computational Media (ICM) : Week 5
External Libraries
Processing offers us the ability to use external libraries (created in Java) that are crafted in a special manner.
A couple of interesting and useful ones are:
Video: http://www.processing.org/reference/libraries/video/index.html video capture and playback.
Serial: http://www.processing.org/reference/libraries/serial/index.html reading and writing data through the serial port.
Net: http://www.processing.org/reference/libraries/net/index.html reading and writing data over the network.
OpenGL: http://www.processing.org/reference/libraries/opengl/index.html highly optimized graphics API.
Sonia: http://sonia.pitaru.com/ advanced audio capabilities.
More at: http://www.processing.org/reference/libraries/index.html
To utilize an external library, you first need to install that library in Processing.
The library should be placed in the Processing Application's "libraries" folder.
To use the library in your Processing application, you need to create an "import" statement which specifies the library name including any "packages" that library is in. (The easy way to do this is through Processing's "Import Library" command under the "Sketch" menu.
The import statement for the video library:
import processing.video.*;
The * means import all of the Classes defined within that Library.
Gimme Eyes
Video Capture
Processing has an external library for capturing video from live cameras (firewire, composite or s-video and DV, basically anythiing that QuickTime supports).
(If you are working on a pc you may need this additional driver for your camera: http://www.vdig.com/WinVDIG/. You may also need to download QuickTime http://www.apple.com/quicktime/download/win.html and if you have a choice, do the "Custom" install and select "QuickTime for Java" support.)
Here is an example of displaying the video from a camera:
// Import the Library
import processing.video.*;
// Create an Object of type Capture
Capture myCapture;
void setup()
{
size(320, 240);
// List the available video capture devices
println(Capture.list());
// Initialize the capture object, give it "this", the width you would like, the height and the framerate.
myCapture = new Capture(this, width, height, 30);
// Another version of the capture object initialization, this time specifying the capture device
myCapture = new Capture(this, "IIDC FireWire Video", width, height, 30);
}
// A function that get's called when a new frame is available
void captureEvent(Capture myCapture)
{
// Read the captured frame
myCapture.read();
}
void draw()
{
// Draw the captured frame as an image
image(myCapture, 0, 0);
}
Pixels, Pixels and More Pixels
Processing offers the ability to get at the array of pixels that make up what is display on the screen, an image, or video frame.
Here is a quick example that changes an image from RGB to Black and White and back again when the mouse is clicked:
PImage img;
boolean showBandW = false;
void setup()
{
img = loadImage("example_image.jpg");
println("Our image is " + img.width + " pixels wide");
println("Our image is " + img.height + " pixels high");
size(img.width,img.height);
}
void draw()
{
if (!showBandW)
{
image(img,0,0); // Just to draw the image normally
}
else
{
loadPixels(); // Tell Processing that we are going to access the pixels of the screen
// Create a loop within a loop to get at all of the columns and rows of pixels
for (int x = 0; x < img.width; x++)
{
for (int y = 0; y < img.height; y++)
{
int currentPixel = y * img.width + x;
float currentPixelBrightness = brightness(img.pixels[currentPixel]); // Pull out the brightness of that pixel
color c = color(currentPixelBrightness); // Create a color using that, black and white because not three values
//img.pixels[currentPixel] = c; // Set the pixel of the image to that value
pixels[currentPixel] = c; // Set the pixel of the screen to that value
}
}
//image(img,0,0); // Display our image
updatePixels(); // Tell Processing we are done with the pixel manipulation and we want to display our work
}
}
void mousePressed()
{
showBandW = !showBandW;
}
Here is the Image
See it in action
The pixels array allows you to access and set what is displayed on the screen.
The pixles array of a PImage object allows you to access and set the pixels of the image.
The pixles array of a Capture object allows you to access and set the pixels of a video frame.
Video Tracking
One interesting thing that can be done with video capture is to use it as a means to track obects through space.
Here is an example (courtesy of DanO):
import processing.video.*;
Capture video;
float targetRed = 255.0; //set some numbers for the target you are chasing
float targetGreen = 0.0;
float targetBlue = 0.0;
void setup()
{
video = new Capture(this, 200, 200, 12); //initiate the video, resolution and frame rate
size(320, 240); //give you Processing window a size
}
void captureEvent(Capture camera)
{
camera.read();
}
void draw()
{
float worldRecord = 1000.0; //intialize the worldrecord
int xFound = 0; // initialize the location of the red tracking ball
int yFound = 0;
for(int j=0; j < video.height; j=j+1) { //for each row
for(int i=0; i < video.width; i=i+1) { //for each column
//get the color of this pixels
//find pixel in linear array using formula: pos = row*rowWidth+column
color pix = video.pixels[j*video.width+i];
//find the difference
float diff = abs(targetRed - red(pix)) + abs(targetGreen - green(pix)) + abs(targetBlue - blue(pix));
if (diff< worldRecord){ // if this is closest to our target color
worldRecord = diff;
yFound = j; //mark the spot for drawing it later
xFound = i;
}
}
}
image(video,0,0); //draw the video, this might be optional
//after all the pixels have been tested, draw the winner
fill(255,0,0);
ellipse(xFound, yFound, 10, 10);
}
void mousePressed(){
//allow the target color to be changed
color pix = video.pixels[mouseY*video.width+mouseX];
targetRed = red(pix); //get the color of the pixel they clicked on
targetGreen = green(pix);
targetBlue = blue(pix);
}
Breakfast Food
Serial Input and Output
By now, you should have learned a bit about Serial from the PIC to the PC in Physical Computing. If not, you will shortly ;-).
Tom Igoe has put together some great pages dedicated to Serial:
Serial to the Desktop: http://tigoe.net/pcomp/serial-processing.shtml
More on Serial Communication: http://tigoe.net/pcomp/serialdata.shtml
We will be using slightly different code than what Tom provides but many of the concepts are the same.
// Original Example by Dan O'Sullivan (with apologies to Tom Igoe)
// Heavy mods by Shawn V.
import processing.serial.*; // The import for the serial library
Serial myPort; // The serial port object
int slide; // A variable to hold our slider value
int light; // A variable to hold our photocell value
int button; // A variable to hold our button value
char DELIMITER = 44;
char ENDLINE = '\r';
String savedSerialData = "";
void setup()
{
// List all the available serial ports:
println(Serial.list());
size(600,600);
// I know that the first port in the serial list on my mac
// is always my Keyspan adaptor, so I open Serial.list()[0].
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[1], 9600);
//prime the pump in case your microcontroller is stuck in serin
myPort.write(65);
}
void draw()
{
background(0);
fill(255,light,255); // Use the photocell value to set our Blue fill
if (button == 1) // If our button is pressed
{
ellipse(slide,100,10,10); // Draw an elipse based on the slider value
}
else // If our button is not pressed
{
rect(slide,100,10,10); // Draw a rect based on the slider value
}
}
// Our callback function for serial, gets executed whenever serial data is available
void serialEvent(Serial p)
{
String serialData = myPort.readStringUntil(ENDLINE);
if (serialData != null)
{
//println(serialData);
String[] parsedSerialData = split(serialData, DELIMITER);
//println(parsedSerialData.length);
int[] serialDataInts = int(parsedSerialData);
if (serialDataInts.length >= 3)
{
light = serialDataInts[0];
slide = serialDataInts[1];
button = serialDataInts[2];
}
int servoRange = 250-65;
float percentageAcross = mouseX/float(width);
int servoOut = int(servoRange*percentageAcross) + 65;
myPort.write(servoOut);
}
}
The code on our PIC (see the PIC BASIC Text Style)
Serial on the Mac (MacOS X)
From:http://processing.org/faq/bugs.html#serial
We use rxtx (version 2.1_6) to handle serial I/O, which is included with the Processing release. If this is the first time you're using rxtx, you'll need to make your way to the "libraries" folder, find "serial", and inside, and run macosx_setup.command (double-click it and follow the instructions). This will make sure that things are properly set up (a few permissions need to be changed).