The special effects in this video are created by a program my boyfriend, (in video) wrote. A white spot on his palm is tracked using a blob detection algorithm.
This program is written in Processing, a handy Java framework.
The effects can be rendered in real-time onto the video captured from web cam.
Input is captured using a port of the open source library OpenCV.
http://www.v3ga.net/processing/BlobDetection/
http://processing.org/
http://ubaa.net/shared/processing/opencv/index.html
Source:
import hypermedia.video.*;
import blobDetection.*;
import processing.video.*;
MovieMaker mov;
BlobDetection detector;
OpenCV cam;
PImage img;
String mode;
int[] camPixels;
int numFrames;
void setup()
{
frameRate(24);
size(640, 480);
ellipseMode(CENTER);
smooth();
cam = new OpenCV();
goIdle();
detector = new BlobDetection(width, height);
detector.setPosDiscrimination(true);
detector.setThreshold(0.68);
img = loadImage("Chidori.jpg"); // Download it here: http://i41.tinypic.com/2uro1zc.jpg
img.mask(img);
mode = "IDLE";
background(0);
}
void draw()
{
cam.read();
cam.flip(OpenCV.FLIP_HORIZONTAL);
if(mode == "RECORD") noTint(); else tint(255, 100);
image(cam.image(), 0, 0, width, height);
if(mode != "RECORD") { camPixels = cam.pixels(); apply(); }
if(mode != "IDLE") mov.addFrame();
if(mode == "RECORD") numFrames++;
if(mode == "PROCESS" && --numFrames == 0) goIdle();
}
void apply()
{
// find white pointer
detector.computeBlobs(camPixels);
int offset = 10;
float high = 0;
int xPos = 0;
int yPos = 0;
for(int i = 0; i < detector.getBlobNb(); i++)
{ blobDetection.Blob blob = detector.getBlob(i); int x = int(blob.x * width); int y = int(blob.y * height); float avg = avgBrightness(x - offset, y - offset, x + offset, y + offset, 0); if(avg > high) { xPos = x; yPos = y; high = avg; }
}
if(high == 0) return;
// draw a red dot in preview mode
if(mode == "IDLE" && mousePressed)
{ noStroke(); fill(255, 0, 0); ellipse(xPos, yPos, offset, offset); return;
}
// draw chidori when rendering
for(int i = 0; i < 6; i++)
{ float x = xPos; float y = yPos; float r = random(30, 10); while((r -= 0.4) > 0) { x += r * 1.5 * (0.46 - noise(r - frameCount * 6 + i * 1000)); y += r * 1.5 * (0.46 - noise(r + frameCount * 6 - i * 1000)); blend(img, 0, 0, img.width, img.height, (int)x, (int)y, (int)r, (int)r, ADD); }
}
int t = 15;
blend(img, 0, 0, img.width, img.height, xPos - 7 * t, yPos - 7 * t, 14 * t, 14 * t, ADD);
blend(img, 0, 0, img.width, img.height, xPos - 20 * t, yPos - 1 * t, 40 * t, 2 * t, ADD);
blend(img, 0, 0, img.width, img.height, xPos - 1 * t, yPos - 20 * t, 2 * t, 40 * t, ADD);
}
private float avgBrightness(int left, int top, int right, int bottom, int def)
{
if(left < 0) left = 0;
if(right > width) right = width;
if(top < 0) top = 0;
if(bottom > height) bottom = height;
if(top >= bottom || left >= right) return def;
float b = 0;
for(int i = top; i < bottom; i++)
{ int offset = i * width; for(int j = left; j < right; j++) b+= brightness(camPixels[offset + j]);
}
return b / ((bottom - top) * (right - left));
}
public void stop()
{
if(mov != null) mov.finish();
cam.stop();
super.stop();
}
void keyPressed()
{
if(key != ' ') return;
if(mode == "IDLE")
{ println("Recording to file: before.mov"); numFrames = 0; mov = new MovieMaker(this, width, height, "before.mov", 24, MovieMaker.ANIMATION, MovieMaker.LOSSLESS); mode = "RECORD"; return;
}
if(mode == "RECORD")
{ println("Rendering to file: after.mov"); mov.finish(); mov = new MovieMaker(this, width, height, "after.mov", 24, MovieMaker.ANIMATION, MovieMaker.HIGH); cam.stop(); cam.movie(sketchPath + "/before.mov", width, height); mode = "PROCESS"; background(0); return;
}
if(mode == "PROCESS")
{ goIdle(); return;
}
}
void goIdle()
{
if(mode == "PROCESS")
{ background(0); mov.finish(); mov = null; println("Done.");
}
mode = "IDLE";
cam.capture(width, height);
}
just to clarify I did not upload this..my boyfriend (in the video) did.
mystic132 2 years ago