Archive for the ‘as3’ Category

Flashy Fisheye

Friday, April 20th, 2007

Today I figured I’d make some fisheye lens out of my webcam. So I did.

It worked out fine, even though it isn’t optimized in any way. Here you have a look at my garden:
Webcam fisheye with AS3

Of course, you can also try this for yourself if you like. To spice things up, I’ve got the source here for you:

import flash.display.*;

var my_cam:Camera = Camera.getCamera();
my_cam.setMode(320,240,10);

var my_video:Video = new Video();
my_video.width = my_cam.width;
my_video.height = my_cam.height;
my_video.attachCamera(my_cam);

var bmd_video:BitmapData = new BitmapData(my_cam.width,my_cam.height);
var bm_video:Bitmap = new Bitmap(bmd_video);
bm_video.x = 0;
bm_video.y = 0;
this.addChild(bm_video);

//size of the fish-eye BitmapData
var feSize:uint = Math.min(bmd_video.width, bmd_video.height);

var bmd_fisheye:BitmapData = new BitmapData(feSize,feSize,false,0xFF000000);
var bm_fisheye:Bitmap = new Bitmap(bmd_fisheye);
bm_fisheye.x = my_cam.width;
bm_fisheye.y = 0;
this.addChild(bm_fisheye);

var updateInterval:uint = setInterval(update,100);

function update() {
  bmd_video.draw(my_video);

  //hw,hh = centre of the video bitmap
  var hw:uint = bmd_video.width / 2;
  var hh:uint = bmd_video.height / 2;

  //radius of the 'lens'
  var radius:uint = feSize / 2;

  for (var x:uint = 0; x < feSize; x++) {
    for (var y:uint = 0; y < feSize; y++) {

      //calculate distance to the centre
      var dx:int = x - radius;
      var dy:int = y - radius;
      var dist:Number = Math.sqrt(dx * dx + dy * dy);

      //skip the rest if outside of the circle we want to draw
      if (dist > radius) continue;

      //This code calculates which pixel should be copied from
      //the original bitmap.

      //first, convert the current distance to a float 0..1,
      //indicating zero to maximum distance.
      var ndist:Number = dist / radius;
      //multiply by PI/2 - which is equivalent to an angle of 0-90°
      ndist *= (Math.PI / 2);
      //Do a cosine on that, which makes the 'fish-eye' effect come true
      ndist = Math.cos(ndist);
      //Since this is still a value between 0 and 1, multiply by the radius
      ndist *= radius;
      //It is still inverse (distance 0 -> cos(0) = 1; distance 1 -> cos(pi/2) =0)
      //substract ndist from radius
      ndist = radius - ndist

      //the angle at which the current pixel is located
      var angle = Math.atan2(dx,dy) + Math.PI / 2;

      //calculate x and y in original picture,
      //x is flipped and they are relative to the centre of the image
      var ox:int = Math.cos(angle) * ndist;
      var oy:int = Math.sin(angle) * ndist;

      //make them relative to the upperleft corner of the image
      ox = hw - ox;
      oy = hh + oy;

      //finally, copy the pixels
      bmd_fisheye.setPixel(x,y,bmd_video.getPixel(ox,oy));
    }
  }
}

Surely things can be done a lot faster with specialized filters, but I just wanted to see if I could work this out myself. Perhaps I’ll improve this later.

‘Hi-res’ webcam image analysis

Thursday, April 19th, 2007

As of late, I am working a lot with webcams in Flash. A real pain is that in Flash 8 it is impossible to wrench a high resolution image out of the Video-object attachted to the webcam for use as a BitmapData-object. No matter what you try, even if the feed is displayed razor sharp at 640×480, you won’t get more than 160×120 pixels to play with. I was able to blow this up to a whopping 320×240 pixels with AS3. Well… whopping? But it is a definite improvement.

In Flash8 / AS2 you have to create a Video-object in the library first, then put it onto the stage, name it, and then you can reference to it from within the code (it’s called my_video):

import flash.display.*;

var my_cam:Camera = Camera.get();
my_cam.setMode(320,240,10);
my_video._width = my_cam.width;
my_video._height = my_cam.height;
my_video.attachVideo(my_cam);

var bmd_video:BitmapData = new BitmapData(my_cam.width,my_cam.height);

var mc_video:MovieClip = createEmptyMovieClip("mc_video", getNextHighestDepth());
mc_video._x = my_cam.width;
mc_video.attachBitmap(bmd_video,1);

var updateInterval:Number = setInterval(update,100);

function update() {
  bmd_video.draw(my_video);
}

As you can make out from the code above, the webcam image in my_video is drawn 10 times per second onto the bmd_video BitmapData. However, the image is downsized to 160×120 pixels, as you can witness on the image below, which I took during some late-night Flash adventure:
Webcam result with Flash 8 / AS2

It is worth noting that, since bmd_video has an actual size of 320×240 pixels, the rest of the image retains it’s color, in this case the default white (the movie background actually was blue).

With Flash9 Alpha / AS3 I initially encountered the same problem, however, here it can partially be solved. In AS3 you can actually create a Video-object with scripting alone, and then it works for resolutions up to 320×240. It’s not the best you can hope for, but at least a bit better than the former 160×120. It does not work when you use a Video-object already on the stage, but it does work when you use code to build it from scratch. Here’s a little sample-code:

var my_cam:Camera = Camera.getCamera();
my_cam.setMode(320,240,10);

var my_video:Video = new Video();
my_video.attachCamera(my_cam);
my_video.width = my_cam.width;
my_video.height = my_cam.height;
addChild(my_video);

var bmd_video:BitmapData = new BitmapData(my_cam.width,my_cam.height);
var bm:Bitmap = new Bitmap(bmd_video);
bm.x = my_cam.width;
addChild(bm);

var updateInterval:uint = setInterval(update,100);

function update() {
  bmd_video.draw(my_video);
}

If you place that in a 640×240 Flash movie, you will be rewarded with something like the following picture (which, as you can guess, was taken that same night):
Webcam result (320) with Flash 9 / AS3

You see that the BitmapData on the right is now actually a 320×240 pixel image, so any analysis you might intent to do with it (motion detection on different parts of the image, for example) can now actually be done with a 4 times higher resolution! However… as I mentioned, it won’t get better than 320×240; here’s a picture of me (even later that night, as you can deduct from the way my hear gets all jumpy) having used my_cam.setMode(640,480,10);:
IMG Webcam result (640) with Flash 9 / AS3

So, actually it proofs to be rather simple to get a bit higher resolution image out of a webcam using AS3. Albeit an image of 320×240 pixels might be way too small for anything beyond the web, it is definetly an improvement over the 160×120 pixels we had before and can thus lead to a more accurate analysis of the image. I hope you find this useful in some way, please enjoy!

Update!

At the time I created this post I was still working with the Flash9 Alpha. Now, with CS3, it also works with 640×480 pixels! Finally! Since my webcam is limited to 640×480 pixels, I haven’t been able to try higher resolutions.