import processing.video.*; Capture cam; PFont font; // Variables to determine the size of the box used to acquire a target int colorDist = 50; //Controls how close the current pixel color must match to the target color color targetColor = color(255,255,255); //Color of the target boolean acquireMode = true; int targetX = 10; int targetY = 25; int targetSide = 10; //Used to find the geometric center of the target based on an average float wandX = 0; float wandY = 0; boolean wandFound = false; ArrayList targets; //an ArrayList is a dynamic way to manage arrays int N = 5; //Number of targets to keep on the screen at any given time void setup() { size (720, 540); //set to 4x3 aspect ratio for screencasting cam = new Capture(this, width, height); frameRate(60); font = loadFont("Baskerville-Bold-48.vlw"); //Be sure to create the font using "Tools -> Create Font" targets = new ArrayList(); // Create a new list for (int i=0; i < N; i++) { targets.add(new Target("Hat", "Rabbit")); } } void draw() { if (cam.available()) { cam.read(); image(cam,0,0); } if(acquireMode) { //Display the current target color strokeWeight(1); fill(targetColor); rect(targetX,targetY - 2 * targetSide,targetSide, targetSide); //Display the acquisition box fill(color(255,255,255)); rect(targetX,targetY,targetSide, targetSide); textSize(10); text("Place target in square and press any key when done.", targetX + 1.5 * targetSide,targetY + targetSide); // Set a new random color gradient targetColor = acquireTargetColor(); } else { searchForTargetColor(); //Process the list of targets fill(255,0,0); ellipse(wandX,wandY,10,10); for (int i=0; i < targets.size(); i++) { Target t = (Target)targets.get(i); //Fetch the i'th target from the Array t.paint(); // Paint it //Check for collisions if (t.detectCollision(wandX, wandY)) { if (! t.inTarget) { t.toggle(); t.inTarget = true; } } else { t.inTarget = false; } t.step(); // Advance it on the screen //If the current target has moved off the stage, delete it from the list and create a new target if (!t.onStage()) { targets.remove(i); targets.add(new Target("Hat", "Rabbit")); } } } } // Finds the average target color that has been placed in the target box // Loops through each pixel in the target acquisition area and determines // the "average" color color acquireTargetColor() { int r = 0; int g = 0; int b = 0; int cnt = 0; cam.loadPixels(); for (int i = 0; i < targetSide; i++) { for (int j=0; j < targetSide; j++) { cnt += 1; int x = targetX + i; //x point inside the target box int y = targetY + j; //y point inside the target box // Pull out the current pixel color color c = cam.pixels[y*width + x]; r += red(c); g += green(c); b += blue(c); } } targetColor = color(r/cnt, g/cnt, b/cnt); return targetColor; } //Searches for the target color. Searches each pixel in the entire image // and compares it to the target color. If the distance is less than the // threshold colorDist, it's assummed to be a match void searchForTargetColor() { // Reset wand wandX = 0; wandY = 0; wandFound = false; cam.updatePixels(); //Now search for pixels that match the target color int numPoints = 0; //Number of points found int sx = 0; //Sum of all x coordinates found int sy = 0; //Sum of all the y coordinates found for (int i=0; i < width; i++) { for (int j=0; j < height; j++) { color pix = cam.pixels[j*width + i]; //Grab pixel at i,j float dr = red(targetColor) - red(pix); float dg = green(targetColor) - green(pix); float db = blue(targetColor) - blue(pix); float d = sqrt ( pow(dr,2) + pow(dg,2) + pow(db,2)); // If it's a match, then keep a running total if (d < colorDist) { numPoints += 1; sx += i; sy += j; } } } // If we found the target color, set the wand coordinates if (numPoints > 0) { wandX = sx / numPoints; wandY = sy / numPoints; wandFound = true; } } //Toggle the acquire mode void keyPressed() { acquireMode = !acquireMode; }