Hi all,
I’ve been building some code from scratch to compare the pixels of a reference image to the pixels of each new frame of video being captured by the webcam.
I was able to get it to work the way that I wanted (I still ned to tweak it a bit, but it’s coming along):
CODE A
void compareFrames_WORKS() {
for (int h = 0; h < height; h++) { // a loop for the height of the image
for (int w = 0; w < width; w++) { // a loop for the width of the image
color A = reference.get(w, h); // Get color from reference image
color B = get(w, h); // get color from current frame
float diffR = abs(red(A) - red(B)); //abs() makes the number in the parameter positive
float diffG = abs(green(A) - green(B));
float diffB = abs(blue(A) - blue(B));
if (diffR > thresh || diffG > thresh || diffB > thresh) {
stroke(255); // fill white if above threshold
} else {
stroke(0); // fill black if below threshold
}
point(w, h); // draw a new pixel
}
}
}
The problem is, it’s clearly not efficient because my computer’s fan kicks in within a few seconds of running the sketch. I looked around and found the FrameDifferencing example that comes with the Processing IDE.
The FrameDifferencing code does close to what I want, but it looks at the previous frame and compares it to the current frame, and I want to compare a reference frame (that is always the same) with the current frame.
My problem here is that I don’t fully understand how to use the pixel[] array properly, and I haven’t been able to figure it out with other forum posts and reference page examples. I’m confused about what’s being referenced, and when I need to use things like loadPixels(), and how dot syntax comes into play.
Using the FrameDifferencing file as reference, I have converted the CODE A to this:
CODE B
void compareFrames() {
loadPixels();
for (int i = 0; i < numPix; i++) {
color A = reference.pixels[1]; // Get color from reference image
color B = videoCam.pixels[i]; // get color from current frame
float diffR = abs(red(A) - red(B)); //abs() makes the number in the parameter positive
float diffG = abs(green(A) - green(B));
float diffB = abs(blue(A) - blue(B));
if (diffR > thresh || diffG > thresh || diffB > thresh) {
pixels[i] = color(255); // fill white if above threshold
} else {
pixels[i] = color(0); // fill black if below threshold
}
}
updatePixels();
}
But I’m missing something, because it’s not functioning as CODE A does.
Full (in progress) sketch below:
import processing.video.*;
Capture videoCam;
//-------------------------------//
// CAPTURE //
//-------------------------------//
void captureEvent(Capture videoCam) {
videoCam.read();
}
//-----------------------------//
// SETUP //
//-----------------------------//
void setup() {
size(427, 240);
videoCam = new Capture(this, 427, 240);
videoCam.start();
rectMode(CORNERS);
stroke(255, 0, 0);
noFill();
instructionsSetup();
numPix = width * height;
}
//----------------------------//
// DRAW //
//----------------------------//
void draw() {
if (state == instructions) {
instructionsDraw();
} else if (state == calibrate) {
calibratePhase();
} else if (state == run) {
drawCamFrame();
//background(255, 0, 0);
compareFrames();
}
}
//---------------------------------//
// CALIBRATE //
//---------------------------------//
PImage reference;
PImage now;
int instructions = 0;
int calibrate = 1;
int run = 2;
int state = instructions;
int calibrateStep = 0;
int maskStep = 0;
// first and second points for the rectancgle that outlines the "playing field" that the artist wants to work with.
// The program will ignore any visual information outside of this rectangle.
float point0x;
float point0y;
float point1x;
float point1y;
PShape mask;
//-----------------------------------------//
// INSTRUCTIONS PHASE //
//-----------------------------------------//
// Instructions found in the draw loop.
void instructionsDraw() {
textAlign(CENTER);
textSize(16);
text("See console for instructions.", width/2, height/2);
}
//-----------------------------------------//
// INSTRUCTIONS PHASE //
//-----------------------------------------//
// Instructions found in the draw loop.
void instructionsSetup() {
println("----------------------");
println("1) Click canvas to start.");
println("2) Press 'C' to capture desired reference frame (e.g. the room with no one in it).");
println("3) Indicate which portion of the image you would like to monitor for activity. Do so as follows:");
println(" Click and drag to create a rectangle over the reference frame.");
println(" Make sure to drag from upper left to lower right, or the mask won't work.");
println(" If satisfied, click 'S'. If you want to draw it again, click 'C'.");
println("4) Once you click 'S' The program will automatically start monitoring the area specified.");
println("----------------------");
}
//-----------------------------------------------//
// CAPTURE REFERENCE FRAME //
//-----------------------------------------------//
// Capture's reference image when C is pressed on the keyboard.
void saveTheFrame() {
image(videoCam, 0, 0);
if (keyPressed) {
if (key == 'c' || key == 'C') {
saveFrame("ref.jpg");
reference = loadImage("ref.jpg");
calibrateStep = 1;
}
}
}
//---------------------------------------//
// REFERENCE AREA //
//---------------------------------------//
// Creates a rectantle to outline the area of the video that you want to look for activity within.
void referenceArea() {
if (maskStep == 1) {
image(reference, 0, 0);
rect(point0x, point0y, mouseX, mouseY);
}
if (maskStep == 2) {
image(reference, 0, 0);
rect(point0x, point0y, point1x, point1y);
println("Point 0: " + point0x +", " + point0y);
println("Point 1: " + point1x +", " + point1y);
maskStep = 3;
}
if (maskStep == 3) {
if (keyPressed) {
if (key == 'c' || key == 'C') {
image(reference, 0, 0);
maskStep = 0;
}
}
if (key == 's' || key == 'S') {
image(reference, 0, 0); // Draw the reference image.
generateMask();
shape(mask); // Draw the mask on top of it.
saveFrame("ref.jpg"); // Save the reference image with the mask superimposed.
state = run;
}
}
}
//-----------------------------------//
// RECT POINTS //
//-----------------------------------//
// Saves the rectangle's coordinate points.
void rectPoints() {
if (maskStep == 1) {
point1x = mouseX;
point1y = mouseY;
maskStep = 2;
} else if (maskStep == 0) {
point0x = mouseX;
point0y = mouseY;
maskStep = 1;
}
}
//-------------------------------------//
// MOUSE PRESSED //
//-------------------------------------//
void mousePressed() {
if (state == instructions) {
state = calibrate;
}
if (calibrateStep == 1) {
rectPoints(); // Saves the rectangle's coordinate points.
}
}
//-------------------------------------------//
// GENERATE BLACK MASK //
//-------------------------------------------//
// Generate (but not yet draw (that's shape(mask)) a black mask to cover the unmonitoried area of the screen.
void generateMask() {
// Make a shape
mask = createShape();
mask.beginShape();
mask.noStroke();
mask.fill(0);
// Exterior part of shape
mask.vertex(0, 0); // A
mask.vertex(width, 0); // B
mask.vertex(width, height); // C
mask.vertex(0, height); // D
mask.vertex(0, 0); // A
// Interior part of shape
mask.beginContour();
mask.vertex(point0x, point1y); // D
mask.vertex(point1x, point1y); // C
mask.vertex(point1x, point0y); // B
mask.vertex(point0x, point0y); // A
mask.vertex(point0x, point1y); // D
mask.endContour();
// Finish off shape
mask.endShape(CLOSE);
}
//---------------------------------------//
// CALIBRATE PHASE //
//---------------------------------------//
// Runs the Calibrate phase
void calibratePhase() {
if (calibrateStep == 0) {
saveTheFrame();
} else if (calibrateStep == 1) {
//perform calibrateStep 1 inside mousePressed() function (save the the mouseX and Y coordinates when mouse is clicked)
referenceArea();
}
}
//-----------------------------------//
// MONITOR //
//-----------------------------------//
int thresh = 40;
int numPix;
int[ ] pix = new int[ numPix ] ;
void drawCamFrame() {
image(videoCam, 0, 0);
shape(mask);
}
//---------------------------------------------------------------//
// WANT TO WORK LIKE compareFrames_WORKS() //
//---------------------------------------------------------------//
void compareFrames() {
loadPixels();
for (int i = 0; i < numPix; i++) {
color A = reference.pixels[1]; // Get color from reference image
color B = videoCam.pixels[i]; // get color from current frame
float diffR = abs(red(A) - red(B)); //abs() makes the number in the parameter positive
float diffG = abs(green(A) - green(B));
float diffB = abs(blue(A) - blue(B));
if (diffR > thresh || diffG > thresh || diffB > thresh) {
pixels[i] = color(255); // fill white if above threshold
} else {
pixels[i] = color(0); // fill black if below threshold
}
}
updatePixels();
}
//-----------------------------------------------------------------//
// WORKS CLOSE TO THE WAY I WANT BUT IS SLOW //
//-----------------------------------------------------------------//
void compareFrames_WORKS() {
for (int h = 0; h < height; h++) { // a loop for the height of the image
for (int w = 0; w < width; w++) { // a loop for the width of the image
color A = reference.get(w, h); // Get color from reference image
color B = get(w, h); // get color from current frame
float diffR = abs(red(A) - red(B)); //abs() makes the number in the parameter positive
float diffG = abs(green(A) - green(B));
float diffB = abs(blue(A) - blue(B));
if (diffR > thresh || diffG > thresh || diffB > thresh) {
stroke(255); // fill white if above threshold
} else {
stroke(0); // fill black if below threshold
}
point(w, h); // draw a new pixel
}
}
}
Thanks for your help!