WEBCAM REQUIRED.
I’ve been playing around with the webcam on AS3 and finally i got into something i liked.
Basically what I’m doing here is to generate a grid of shapes keeping references between objects using a linked list. I am working with a small video size to optimize performance, so I keep two positions in each properties at Particle class: origin and staticPosition.
origin is a Point keeping the coordinates of the pixel on the Video object which corresponds to the particle.
staticPosition is a Point keeping the coordinate that corresponds at stage.
Here there is a sample of the generate grid method, it has comments and the complete source is ready to download at the end of this post.
[as]
private function setupGrid() : void{
// iniatialize the linked list with initLink Particle
var p : Particle = initLink;
// set the x / y coordinates to zero
var _x : uint = 0;
var _y : uint = 0;
// this bucle creates the particles
for (var i : int = 0; i < quantity; i++) {
// if the x coordinate exceeds the defined width limit
if(i % nw == 0 && i!= 0){
// set the ‘x’ coordinate to zero
_x = 0;
// ad the height of the particle to the ‘y’ coordinate
_y += particleHeight;
}
// storing the next particle at current
p.next = new Particle();
// define the coordinate that corresponds this iteration at the source video
var origin : Point = new Point(_x / particleWidth, _y / particleHeight);
// send it to the origin propertie at the particle
p.origin = origin;
// define the current position at stage
var point : Point = new Point(_x, _y);
// place it to two properties at the particle
// at ‘staticPosition’ , this value will not change
p.staticPosition = new Point(point.x, point.y);
// and at ‘position’, this value will change to animate flight
p.position = point;
// place the particle at stage coords
p.x = point.x;
p.y = point.y;
// add the displayObject to the container
particles.addChild(p);
// refresh the ‘p’ variable to store the next particle at next iteration of this bucle
p = p.next;
// add a particle width to the ‘_x’ var for the next iteration
_x += particleWidth;
}
}
[/as]
We can color each particle based on each pixel rgb value that points to the origin coords, doing so we can win a nice semitone effect for the video capture.
On the other side, the class MotionTracker has a very simple motion detection implementation, it draws each frame of the Video Object over the last frame using BlendMode.DIFFERENCE and then thresholding filtering the pixels with a color higher than 0x111111
Here the code of the detection
[as]
private function tictac(event:TimerEvent) : void{
// locking bitmapdatas for better performance
current.lock();
output.lock();
input.lock();
// a current copy from the source
current.draw(source);
// making a temporary copy of currentFrame to work with both input and current
var temp : BitmapData = current.clone();
// here we are drawing the previous frame on top of the current and the difference blendMode will make the rest
temp.draw(input, null, null, BlendMode.DIFFERENCE);
// filter the pixels tha are greater than darkgrey #111111 and thresholding them into blue #0000FF overwriting the previous bmp
temp.threshold(temp, temp.rect, temp.rect.topLeft, “>”, 0xFF111111, 0xFF0000FF, 0x00FFFFFF, true);
// resets output’s color information
output.fillRect(output.rect, 0xFF000000);
// stores the current frame wich will be the previous on the next tictac
input = current.clone();
// thresholding the temp bitmapdata into the output bitmapdata with ‘equal’ colors
output.threshold(temp, output.rect, output.rect.topLeft, “==”, 0xFF0000FF, 0xFF0000FF, 0x00FFFFFF, false);
// unlocking bitmapdatas
current.unlock();
output.unlock();
input.unlock();
// cleaning memory
temp.dispose();
}
[/as]
I think it would be interesting if the particles would move randomly at the same point where the movement was detected by the motionTracker, and here we go.
The Particle class has two methods to move scale and position, it implements a wonderful bouncing easing equation seen at Erik Natzke’s blog and one method to modify the internal position Point to a random value.
[as]
public function moveScale(scale : Number) : void{
scaleX -= ax = (ax + (scaleX – (scale * 3)) * div) * .9;
scaleY -= ay = (ay + (scaleY – (scale * 3)) * div) * .9;
}
public function movePosition(p : Point) : void{
x -= bx = (bx + (x – (p.x)) * div) * .5;
y -= by = (by + (y – (p.y)) * div) * .5;
}
public function flight() : void{
position.x = staticPosition.x – (Math.random() * 200 * sign());
position.y = staticPosition.y – (Math.random() * 200 * sign());
}
public function unFlight() : void{
position.x = staticPosition.x;
position.y = staticPosition.y;
}
[/as]
These methods are called from the Main class at the enterframe handler
[as]
while(p.next != null){
var color : uint = bmd.getPixel(p.origin.x, p.origin.y);
var scale : Number = color / 0xFFFFFF;
if(motion.output.getPixel(p.origin.x, p.origin.y) != 0){
p.flight();
} else{
p.unFlight();
}
p.moveScale(scale);
p.movePosition(p.position);
p.color = color;
// p.color = colors[Math.floor( scale * colors.length )];
p = p.next;
}
[/as]