A Flash Developer Resource Site

Results 1 to 18 of 18

Thread: VR Headtracking

Threaded View

  1. #1
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770

    VR Headtracking

    I've been trying a few methods to do headtracking with a webcam, and I'm more and more convinced it's possible in flash with items you have at home.

    Attached is the begining of my experiments, using the same on-screen demo environment type as shown on the youtube videos for WiiFlash and PS3Eye. It doesn't have the same amount of freedom yet, no rotation around the y-axis and rotation around the x-axis is auto-focused on the horizon. A single light source develops z-depth issues when the detection area fluctuates, but that can be smoothed out with multi-sampling. Once I mount a couple of lights on a hat, I'm sure the increased width will be easier to work with.

    I think for full freedom (or close to it), I'll need a third light source either at the brim or top of the hat. This will allow for z-depth dertimination by height and y-axis rotation by width and the distance between the points. I don't know how to do rotation with two points without constraining right->left and left->right (ie you couldn't look left if you are standing on the left), which is fine for windowing but isn't full freedom.

    Any ideas on better methods?

    Here's some ugly code I'm working on:
    PHP Code:
    // import flash.display.BitmapData, flash.geom.Rectangle, flash.geom.Point, and flash.geom.Matrix

    // set up rendering variables
    var Ox Stage.width/2;
    var 
    Oy Stage.height/2;
    var 
    focalLength 100;
    var 
    cam = new Object();
    cam.0;
    cam.0;
    cam.100;

    // light source width multiplier
    // for a single point of light try values between 5 and 20
    // for two points of light, or a light bar, try values between 0.1 and 5
    var scaler 10;

    // attach the webcam video to a video object
    my_cam Camera.get();
    webcam_video.attachVideo(my_cam);

    // create a mirror image of the webcam video, scaled 2* for help with precision later
    createEmptyMovieClip('holder'getNextHighestDepth());
    now = new flashBitmapData(webcam_video._width 2webcam_video._height 2);
    holder.attachBitmap(nowholder.getNextHighestDepth());
    with(holder){
        
    _x webcam_video._width;
        
    _y webcam_video._height 10;
        
    _xscale = -50;
        
    _yscale 50;
    }

    // create a box to place around the isolated light source for debugging
    createEmptyMovieClip('box',getNextHighestDepth());
    with(box){
        
    lineStyle(10xFFFFFF); lineTo(1000); lineTo(100100); lineTo(0100); lineTo(00);
    }

    // create some target objects
    createEmptyMovieClip('targets'getNextHighestDepth());

    MovieClip.prototype.makeTargets=function(targetObj){
        for(
    06n++){
            
    this.createEmptyMovieClip(targetObj.names[n], 100+n);
            
    with(this[targetObj.names[n]]){
                
    lineStyle(100targetObj.colors[n]); lineTo(1,0);
                
    lineStyle(500xffffff); moveTo(00); lineTo(10);
                
    lineStyle(25targetObj.colors[n]); moveTo(00); lineTo(10);
                
    lineStyle(120xffffff); moveTo(00); lineTo(10);
            }
            
    this[targetObj.names[n]].targetObj.x[n];
            
    this[targetObj.names[n]].targetObj.y[n];
            
    this[targetObj.names[n]].targetObj.z[n];
        }
    };

    targetsObject = new Object();
    targetsObject.names = new Array('target1','target2','target3','target4','target5','target6');
    targetsObject.= new Array(0,200,-300,-100,-300,300);
    targetsObject.= new Array(0,200,-100,-100,-300,-300);
    targetsObject.= new Array(100,200,300,500,700,700);
    targetsObject.colors = new Array('0xff0000','0x0000ff','0x00b000','0xff00ff','0xffff00','0xff6666');

    targets.makeTargets(targetsObject);

    // work the magic
    this.onEnterFrame=function(){

        
    // draw the current webcam image to a bitmapdata object
        // scaling up will help with accuracy a bit
        
    matrix = new flashGeomMatrix();
        
    matrix.scale(2,2);
        
    now.draw(webcam_videomatrix);

        
    // eleminate all but the brightest colors
        
    now.threshold(nownow.rectangle, new flashGeomPoint(00), '<='0xFF6666660xFF0000000xFF0000FFfalse);

        
    // find the bounding box of the brightest color
        
    redBox=now.getColorBoundsRect(0x00FF0000,0x00FFFFFF,false);

        
    // TO-DO -- use multiple lights, subdivide the bounding box and repeat to isolate each light

        // if a light source is detected, track it
        
    if(redBox.width>0){

            
    // align and resize box indicator for debugging
            
    box._x redBox.x/2-redBox.width/4+webcam_video._x;
            
    box._y redBox.y/2-redBox.height/4+webcam_video._y;
            
    box._width redBox.width/2;
            
    box._height redBox.height/2;

            
    // set z based on bounding box width and scaler value
            
    cam.redBox.width*scaler;

            
    // determine the head position in 3d space (remember that holder has been scaled to 2*)
            
    var ratio focalLength / (focalLength cam.z);
            
    cam.= (holder._width redBox.x) * ratio 4;
            
    cam.= (redBox.holder._height 2) * ratio 4;
            
    cam.rotY 1-(redBox.y/holder._height); // keeps the camera pointed at horizon

            // TO-DO -- decide which freedoms are important, rotation vs position in x/y planes
            // perhaps 3 points of light can be used to triangulate all freedoms using x,y,width,height ratios

            // render targets and perspective lines        
            
    adjust3d(targets.target1cam);
            
    adjust3d(targets.target2cam);
            
    adjust3d(targets.target3cam);
            
    adjust3d(targets.target4cam);
            
    adjust3d(targets.target5cam);
            
    adjust3d(targets.target6cam);
            
    renderLines(cam);
        }
    };

    // 3d perspective rendering
    function adjust3d(objcam){
        var 
    TminusC = (obj.z-cam.== 0) ? obj.cam.z;
        if(
    focalLength TminusC == 0){
            var 
    ratio 0.00000001;
        }else{
            var 
    ratio focalLength / (focalLength TminusC);
        }
        
    obj._x Ox + (obj.cam.x) * ratio;
        
    obj._y Oy + (obj.cam.y) * ratio;
        
    obj._xscale obj._yscale ratio 100;
        if(
    obj.cam.focalLength){ obj._visible false; }else{ obj._visible true; }
        
    obj.swapDepths(Math.round(10000-obj.z-cam.z));
    }

    // render prespective lines
    function renderLines(cam){
        
    with(_root){
            
    clear();
            for(var 
    = -Stage.width<= Stage.widthx+=200){
                var 
    = -Stage.height;
                var 
    0;
                var 
    ratio focalLength / (focalLength 200-cam.z);
                var 
    sx Ox + (cam.x) * ratio;
                var 
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength + -cam.z+100000);
                var 
    ex Ox + (cam.x) * ratio;
                var 
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);

                
    Stage.height;
                
    0;
                
    ratio focalLength / (focalLength 200-cam.z);
                
    sx Ox + (cam.x) * ratio;
                
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength + -cam.z+100000);
                
    ex Ox + (cam.x) * ratio;
                
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);
            }
            for(var 
    = -Stage.height<= Stage.heightv+=200){
                var 
    = -Stage.width;
                var 
    v;
                var 
    0;
                var 
    ratio focalLength / (focalLength 200-cam.z);
                var 
    sx Ox + (cam.x) * ratio;
                var 
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength + -cam.z+100000);
                var 
    ex Ox + (cam.x) * ratio;
                var 
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);

                
    Stage.width;
                
    v;
                
    0;
                
    ratio focalLength / (focalLength 200-cam.z);
                
    sx Ox + (cam.x) * ratio;
                
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength + -cam.z+100000);
                
    ex Ox + (cam.x) * ratio;
                
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);
            }

            for(var 
    200<= 100000z*=1.5){
                var 
    Stage.width;
                var 
    Stage.height;
                var 
    ratio focalLength / (focalLength z-cam.z);
                var 
    sx Ox + (cam.x) * ratio;
                var 
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength z-cam.z);
                
    = -Stage.height;
                var 
    ex Ox + (cam.x) * ratio;
                var 
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);

                
    = -Stage.width;
                
    Stage.height;
                
    ratio focalLength / (focalLength z-cam.z);
                
    sx Ox + (cam.x) * ratio;
                
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength z-cam.z);
                
    = -Stage.height;
                
    ex Ox + (cam.x) * ratio;
                
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);

                
    Stage.width;
                
    Stage.height;
                
    ratio focalLength / (focalLength z-cam.z);
                
    sx Ox + (cam.x) * ratio;
                
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength z-cam.z);
                
    = -Stage.width;
                
    ex Ox + (cam.x) * ratio;
                
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);

                
    Stage.width;
                
    = -Stage.height;
                
    ratio focalLength / (focalLength z-cam.z);
                
    sx Ox + (cam.x) * ratio;
                
    sy Oy + (cam.y) * ratio;
                
    ratio focalLength / (focalLength z-cam.z);
                
    = -Stage.width;
                
    ex Ox + (cam.x) * ratio;
                
    ey Oy + (cam.y) * ratio;
                
    lineStyle(1,0xffffff);
                
    moveTo(sx,sy);
                
    lineTo(ex,ey);
            }
        }
    }

    stop(); 
    Note- For this to work, you need either a dark room, or a piece of film over the webcam lens to filter out all light other than your lightsource
    Attached Files Attached Files
    Last edited by JerryScript; 02-20-2008 at 07:19 PM. Reason: forgot to add attachment

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center