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 Shizzleimport processing.opengl.*; // Import OpenGL, just incase ya'knowimport hypermedia.video.*; // Import OpenCVOpenCV opencv; // New OpenCV Object// Particles Setup + ArrayPImage particleImg; // Add the particle imageParticle[] particles; // Add the particle arrayfinal int MAX_PARTICLES = 50; // Maximum particles to be added to array// Create ImagesPImage trailsImg; // Create image for trailsPImage maskImg; // Create mask imagePImage nikeMagic; // Create logo imagevoid setup(){// Setup Stagesize(640, 480, OPENGL); // Set stage size, OPENGL for performanceframeRate(30); // Set framerate, make sure it's 30background(0); // Set backgrund to black for masknoStroke(); // Just incase I need itsmooth(); // Also just incaseimageMode(CORNER); // Makes sure images drawn from corner// Load Particlesparticles=new Particle[0];particleImg=loadImage("sparkle.png");// Setup OpenCVopencv=new OpenCV(this); // Initialise OpenCV objectopencv.capture(320, 240); // Open video capture streamtrailsImg=new PImage(640, 480); // Initialise trailsImg// Load custom imagesmaskImg=loadImage("mask.png"); // Initialise mask imagenikeMagic=loadImage("nikemagic.png"); // Initialise logo image}void draw(){// Draw Camera, Scale itpushMatrix(); // Startscale(2); // Scale the camera upmotionTracking(); // Load Cam and FilterspopMatrix(); // Stop// Draw Maskimage(maskImg, 0, 0); // Place mask image at top left corner// Draw ParticlesparticleSpawn(); // Call particle varialbes// Draw Logoimage(nikeMagic, (width-301), 0); // Place logo flush right, flush top}
void motionTracking(){// OpenCV Shizzleopencv.read(); // Grab a framePImage camImage; // Make ImagecamImage=opencv.image(); // Store Unprocessed Frame// Filter Shizzleopencv.absDiff(); // Difference Modeopencv.flip(OpenCV.FLIP_HORIZONTAL); // Flip Imageopencv.convert(OpenCV.GRAY); // Difference Image to Grayscaleopencv.blur(OpenCV.BLUR,40); // Difference Bluropencv.threshold(20); // Threshold Filter// Blend movement image with trails imagetrailsImg.blend(opencv.image(), 0, 0, 640, 480, 0, 0, 640, 480, SCREEN);// Colour ShizzlecolorMode(HSB); // HSB so I can change Huetint(color(145, 255, 255)); // Tint with HSB - Hue(Blue), Saturation(Full), Brightness(Full)image(trailsImg, 0, 0); // Display the blended difference imagenoTint(); // Otherwise tints the mask, makes me sad when that happens// Trails Shizzleopencv.copy(trailsImg); // Copies trailsImg into OpenCV buffer for effectsopencv.blur( OpenCV.BLUR, 10); // Blur trailsopencv.brightness(-5); // Fade Speed for trailstrailsImg=opencv.image(); // Puts the modified image from the buffer back into trailsImgopencv.remember(); // Remember current frame}
void particleSpawn(){// Particle Shizzlefor(int i =0; i {Particle p = particles[i];p.update(); // Update particles commandp.render(); // Draw Particles command}Particle p = new Particle((width/100)*85, (height/100)*15); //Calculates screen percentage and places particlesp.render();particles = (Particle[]) append(particles, p);if(particles.length>MAX_PARTICLES)particles = (Particle[]) subset(particles, particles.length-MAX_PARTICLES); // Setup max particle controller}// Particle Variablesclass Particle{float xPos;float yPos;float xVel;float yVel;float currentAlpha=255;float currentScale=0;float drag=0.95; // Drag speedfloat fadeSpeed=6; // How quickly they fade outfloat shrink=0.97; // How fast they shrinkfloat gravity=0.5; // Particle gravity// Setup physics, scale etcParticle(float xpos, float ypos){this.xPos=xpos;this.yPos=ypos;this.xVel=random(-12,9); // How far left or right the particle gothis.yVel=random(2, 2); // Downward velocitythis.currentScale=random(0.3, 0.5); // Particle scaling variable}// Update each particle's variables every framevoid update(){xVel*=drag; // Calculate X axis dragyVel*=drag; // Calculate Y axis dragyVel+=gravity; // Calculate gravity (Y axis only, duh)xPos+=xVel; // Add the X axis velocity to the X positionyPos+=yVel; // Add the Y axis delocity to the Y positioncurrentAlpha-=fadeSpeed; // Reduces to alpha each frame according to fadeSpeedcurrentScale*=shrink; // Reduces scale each frame according to shrink variable}// Draw the particlevoid render(){tint(255,currentAlpha); // Draws the particle at the currentAlphaimage(particleImg,xPos, yPos, particleImg.width*currentScale, particleImg.height*currentScale);}}