Code Evaluation

Now that I have completed the coding portion of the project and filmed a demonstration it is time to see what I have done as well as the process that lead me here.

The Process
(Get it? ...nevermind)
I started out just reading the processing book I bought to learn the basics, tutorials on the website and the lectures with Seb. After I became a bit more confident I began playing with some of the examples that Seb created to teach us the principles of Processing. I have posted some on this blog, and while most of the time it was nothing more than changing values on the variables it really helped with the learning process to see a real visible change from a piece of code.

Up until we started messing with the webcam image in Processing I only had very abstract ideas about how to apply what I was learning to the camera and how I could use it. The majority of our lecture time was dedicated to the construction of a sketch at first and then a focus on how to create particles. In the end the lectures about particles ended up being useful as I found a way to use them in my sketch.

The real construction began near the end of our series of lectures from Seb. How my piece is ocnstructed is directly influenced by one of the examples he showed us for making particles respond to the webcam (one was brightness, this one was motion) where you could draw an image on the screen using the difference filter and threshold. Any area in the image that was different from the previous frame was filled in with white. Using this threshold filter an outline of the motion was outlined and had fading trails of the previous frames of motion.

Using this idea I looked in to how I could make this outline less like an outline and more like blobs of paint or light, as I was set on something more like a light painting instead of just showing the outline of people's bodies moving about.

My starting point was to go through Seb's example code breaking it down line by line and commenting it so that I could understand what was going on. Processing has a function where you can highlight a piece of code and look it up on the Processing website, Processing.org which is a very useful feature when trying to understand what the code is doing. By commenting each line, breaking it apart, taking parts out and adding parts in I was able to get an understanding of what his example did and what I wanted to do.

Production
Once I was done understanding the code I began writing out my sketch. I am very methodical and like t write as clean and clear as possible (a habit I picked up from writing out HTML and CSS). I also commented every line as I went along to make sure I got everything correct.

Initially it was fairly easy. Outlining the sketch was pretty simple and just involved importing the correct libraries (OpenCV for code and OpenGL for rendering), setting up the stage and drawing the webcam image. I used Seb's particle examples and his trails examples as the framework for my particle system and use of OpenCV for the webcam image.

I used the examples for reference, but thy are largely the same because I needed to recreate the same functionality. I just re-wrote it slightly differently in formatting and some of the names of objects so that I would understand them better and I could format it for my comments.

In line with my demand for clean coding I used Processing's tab feature to store pieces of code separate from the main sketch and then 'call' the functions in the main sketch using one short line making it much easier to read and a better sense of organisation.

I feel like I have written, structured and commented the code in such a way that pretty much anyone even with no code experience (like me at the start of the project) could understand what is going on and see what I am doing. i did this for myself but it is also useful for anyone examining/marking my code.


Conclusion and Code
As a conclusion I will post my code here so it is in a readily available and easily accessible format for anyone who wants to look at it. Of course, I would prefer the code to be viewed correctly formatted in Processing but you can't have everything in life.

/*
Draw Order:
- Cam with Trails Image, pre-applied filters from motiontracking
- Mask image, to mask out trails
- Particles, over the top of the mask
- Logo image, to sit over particle spawn location
*/


// Import Library Shizzle
import processing.opengl.*; // Import OpenGL, just incase ya'know
import hypermedia.video.*; // Import OpenCV
OpenCV opencv; // New OpenCV Object

// Particles Setup + Array
PImage particleImg; // Add the particle image
Particle[] particles; // Add the particle array
final int MAX_PARTICLES = 50; // Maximum particles to be added to array

// Create Images
PImage trailsImg; // Create image for trails
PImage maskImg; // Create mask image
PImage nikeMagic; // Create logo image


void setup()
{
// Setup Stage
size(640, 480, OPENGL); // Set stage size, OPENGL for performance
frameRate(30); // Set framerate, make sure it's 30
background(0); // Set backgrund to black for mask
noStroke(); // Just incase I need it
smooth(); // Also just incase
imageMode(CORNER); // Makes sure images drawn from corner

// Load Particles
particles=new Particle[0];
particleImg=loadImage("sparkle.png");

// Setup OpenCV
opencv=new OpenCV(this); // Initialise OpenCV object
opencv.capture(320, 240); // Open video capture stream
trailsImg=new PImage(640, 480); // Initialise trailsImg
// Load custom images
maskImg=loadImage("mask.png"); // Initialise mask image
nikeMagic=loadImage("nikemagic.png"); // Initialise logo image
}


void draw()
{
// Draw Camera, Scale it
pushMatrix(); // Start
scale(2); // Scale the camera up
motionTracking(); // Load Cam and Filters
popMatrix(); // Stop

// Draw Mask
image(maskImg, 0, 0); // Place mask image at top left corner

// Draw Particles
particleSpawn(); // Call particle varialbes
// Draw Logo
image(nikeMagic, (width-301), 0); // Place logo flush right, flush top
}

void motionTracking()
{
// OpenCV Shizzle
opencv.read(); // Grab a frame
PImage camImage; // Make Image
camImage=opencv.image(); // Store Unprocessed Frame

// Filter Shizzle
opencv.absDiff(); // Difference Mode
opencv.flip(OpenCV.FLIP_HORIZONTAL); // Flip Image
opencv.convert(OpenCV.GRAY); // Difference Image to Grayscale
opencv.blur(OpenCV.BLUR,40); // Difference Blur
opencv.threshold(20); // Threshold Filter

// Blend movement image with trails image
trailsImg.blend(opencv.image(), 0, 0, 640, 480, 0, 0, 640, 480, SCREEN);

// Colour Shizzle
colorMode(HSB); // HSB so I can change Hue
tint(color(145, 255, 255)); // Tint with HSB - Hue(Blue), Saturation(Full), Brightness(Full)
image(trailsImg, 0, 0); // Display the blended difference image
noTint(); // Otherwise tints the mask, makes me sad when that happens

// Trails Shizzle
opencv.copy(trailsImg); // Copies trailsImg into OpenCV buffer for effects
opencv.blur( OpenCV.BLUR, 10); // Blur trails
opencv.brightness(-5); // Fade Speed for trails
trailsImg=opencv.image(); // Puts the modified image from the buffer back into trailsImg
opencv.remember(); // Remember current frame
}

void particleSpawn()
{
// Particle Shizzle
for(int i =0; i
{
Particle p = particles[i];
p.update(); // Update particles command
p.render(); // Draw Particles command
}

Particle p = new Particle((width/100)*85, (height/100)*15); //Calculates screen percentage and places particles
p.render();
particles = (Particle[]) append(particles, p);

if(particles.length>MAX_PARTICLES)
particles = (Particle[]) subset(particles, particles.length-MAX_PARTICLES); // Setup max particle controller
}


// Particle Variables
class Particle
{
float xPos;
float yPos;
float xVel;
float yVel;
float currentAlpha=255;
float currentScale=0;

float drag=0.95; // Drag speed
float fadeSpeed=6; // How quickly they fade out
float shrink=0.97; // How fast they shrink
float gravity=0.5; // Particle gravity

// Setup physics, scale etc
Particle(float xpos, float ypos)
{
this.xPos=xpos;
this.yPos=ypos;
this.xVel=random(-12,9); // How far left or right the particle go
this.yVel=random(2, 2); // Downward velocity
this.currentScale=random(0.3, 0.5); // Particle scaling variable
}

// Update each particle's variables every frame
void update()
{
xVel*=drag; // Calculate X axis drag
yVel*=drag; // Calculate Y axis drag
yVel+=gravity; // Calculate gravity (Y axis only, duh)
xPos+=xVel; // Add the X axis velocity to the X position
yPos+=yVel; // Add the Y axis delocity to the Y position

currentAlpha-=fadeSpeed; // Reduces to alpha each frame according to fadeSpeed
currentScale*=shrink; // Reduces scale each frame according to shrink variable
}

// Draw the particle
void render()
{
tint(255,currentAlpha); // Draws the particle at the currentAlpha
image(particleImg,xPos, yPos, particleImg.width*currentScale, particleImg.height*currentScale);
}
}