WebCam Test For Various Filters - Motion and Edge Detection
includes j2e's EdgeTransform Function for color-coded edges with orientation data
japanese2english@gmail.com
カメラ画像を取得してRGBに分解します。
画面をクリックすると分割した画像を1点に重ねます。
背景が黒、ブレンドモードがADDなら元画像と同じになるはずです。
ブレンドモードをいじったりしてみてください。
/**
* Copyright j2e ( http://wonderfl.net/user/j2e )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/cYFe
*/
// forked from j2e's forked from: カメラ映像を分解したり戻したり
// includes j2e's EdgeTransform Function for color-coded edges with orientation data
// japanese2english@gmail.com
//
// forked from undo's カメラ映像を分解したり戻したり
/*
* カメラ画像を取得してRGBに分解します。
* 画面をクリックすると分割した画像を1点に重ねます。
* 背景が黒、ブレンドモードがADDなら元画像と同じになるはずです。
* ブレンドモードをいじったりしてみてください。
*/
package
{
import flash.events.ActivityEvent;
import caurina.transitions.Tweener;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.media.Camera;
import flash.media.Video;
import flash.system.Security;
import flash.system.SecurityPanel;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.filters.ConvolutionFilter;
import flash.filters.BitmapFilter;
[SWF(backgroundColor = 0x0)]
public class CameraTests extends Sprite
{
public function CameraTests()
{
Wonderfl.capture_delay(1);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
this.camWidth = this.stage.stageWidth/2;
this.camHeight = this.stage.stageHeight/2;
init();
}
private var myBmd:BitmapData;
private const SMOOTHING:uint = 1;
// SMOOTHING defines how far away sampled pixels will be for comparison,
//higher numbers may help to eliminate graininess
private var _cam:Camera;
private var _vid:Video;
private var _bmd:BitmapData;
private var _redBmd:BitmapData;
private var _greenBmd:BitmapData;
private var _blueBmd:BitmapData;
private var _rbm:Bitmap;
private var _gbm:Bitmap;
private var _bbm:Bitmap;
private var camWidth:Number;
private var camHeight:Number;
private var camFPS:Number = 15;
private var bMode:String = BlendMode.DIFFERENCE;
private var conved:Boolean = false;
private function init():void
{
Security.allowDomain('*');
_cam = Camera.getCamera();
if(!_cam) return;
_vid = new Video(camWidth, camHeight);
_cam.setMode(camWidth, camHeight, camFPS);
_vid.attachCamera(_cam);
_bmd = new BitmapData(camWidth, camHeight, false);
_redBmd = new BitmapData(camWidth, camHeight, false,0);
_greenBmd = new BitmapData(camWidth, camHeight, false,0);
_blueBmd = new BitmapData(camWidth, camHeight, false,0);
// BitmapData to save nonmoving object data for reuse
//_backgroundBmd = new BitmapData(camWidth, camHeight, false,0);
_rbm = new Bitmap(_redBmd);
_gbm = new Bitmap(_greenBmd);
_bbm = new Bitmap(_blueBmd);
_rbm.y = _gbm.y = camHeight;
_bbm.x = _gbm.x = camWidth;
var rsp:Sprite = new Sprite();
var gsp:Sprite = new Sprite();
var bsp:Sprite = new Sprite();
rsp.cacheAsBitmap = true;
gsp.cacheAsBitmap = true;
bsp.cacheAsBitmap = true;
this.addChild(new Bitmap(_bmd));
this.addChild(_rbm);
this.addChild(_gbm);
this.addChild(_bbm);
_rbm.blendMode = bMode;
_gbm.blendMode = bMode;
_bbm.blendMode = bMode;
addEventListener(Event.ENTER_FRAME, onEnter);
_cam.setMotionLevel(5, 1000);
//_cam.addEventListener(ActivityEvent.ACTIVITY, onMotion);
stage.addEventListener(MouseEvent.CLICK, onClick);
}
private function onEnter(evt:Event):void
{
var matrix:Matrix = new Matrix();
matrix.scale(-1, 1);
matrix.translate(camWidth, 0);
//_redBmd.draw(_vid, matrix);
//Set redBmd to motion outline, then find the old position and new position
//outlines, so that the old position pixels can be transferred to the new positions.
// Also, the moving parts could be filtered out of the background, and the background
// image could be saved as its own separate image with moving object "NORMAL" blended images.
_redBmd.draw(_vid, matrix);
_redBmd.draw(_bmd, null, null, BlendMode.DIFFERENCE);
//RightEdges(_redBmd);
//_redBmd.floodFill(0, 0, 0x0000FF);
_blueBmd.draw(_vid, matrix);
_greenBmd.draw(_vid, matrix);
EdgeTransform(_blueBmd);
//_blueBmd.draw(_redBmd, null, null, BlendMode.SCREEN);
//EdgeTransform(_greenBmd);
_bmd.draw(_vid, matrix);
//_bmd.draw(_blueBmd, null, null, BlendMode.ADD);
//_redBmd.draw(_vid, matrix);
//_rbm.draw(_vid);
//feed.copyPixels(buffer, rect, pnt);
//buffer.draw(prev, null, null, BlendMode.DIFFERENCE);
//prev.draw(video);
//canvas.copyPixels(buffer, rect, pnt);
//_redBmd.copyChannel(_bmd, _bmd.rect, new Point(), 1, 1);
//_greenBmd.copyChannel(_bmd, _bmd.rect, new Point(), 2, 2);
//_blueBmd.copyChannel(_bmd, _bmd.rect, new Point(), 4, 4);
}
private function SectionBitmap(bmd:BitmapData):void {
}
private function RightEdges(bmd:BitmapData):void {
var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
var pt:Point = new Point(0, 0);
var solidifyFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [1, 0, 0, 1, 0, 0, 1, 0, 0])
var rightEdgeFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 0, -5, 5, 0, 0, 0, 0]);
bmd.applyFilter(bmd, rect, pt, rightEdgeFilter);
}
private function onMotion(evt:ActivityEvent):void {
var matrix:Matrix = new Matrix();
}
private function onClick(evt:MouseEvent):void
{
trace(conved);
Tweener.removeAllTweens();
if(conved)
{
Tweener.addTween(_rbm, {x:0, time:1, transition:"easeInOutCubic"});
Tweener.addTween(_bbm, {y:0, time:1, transition:"easeInOutCubic"});
conved = false;
}
else
{
Tweener.addTween(_rbm, {x: camWidth, time: 1, transition: "easeInOutCubic"});
Tweener.addTween(_bbm, {y: camHeight, time: 1, transition: "easeInOutCubic"});
conved = true;
}
}
/*
* functions
*/
private function selectCamera():void
{
//ダイアログを表示して、ユーザにカメラを選択してもらう
Security.showSettings(SecurityPanel.CAMERA);
}
private function setCamToVideo(c:Camera, v:Video = null):Video
{
//Videoへカメラを設定する
if (!v)
v = new Video();
v.attachCamera(c);
return v;
}
///I tried this 'QuickEdges' version which is more elegant to write but is waaayy slower
///than the 'EdgeTransform' version I wrote below.
/// I thought convolution filters would be faster, but they turned out to take about 3 times as long
private function QuickEdges(bmd:BitmapData):void {
var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
var pt:Point = new Point(0, 0);
var verthorvertEdges:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, 0, 0, -1, 4, -1, 0, 0, -1]);
var horhorvertEdges:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, -1, 0, 0, 4, 0, 0, -1, -1]);
var horverthorEdges:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, -1, -1, 0, 4, 0, -1, -1, 0]);
// Create bitmaps for writing edge info to
var nRedBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var nGreenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var nBlueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
nRedBmd.applyFilter(bmd, rect, pt, verthorvertEdges);
nGreenBmd.applyFilter(bmd, rect, pt, horhorvertEdges);
nBlueBmd.applyFilter(bmd, rect, pt, horverthorEdges);
bmd.copyChannel(nRedBmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
bmd.copyChannel(nGreenBmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
bmd.copyChannel(nBlueBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
}
/// EdgeTransform takes bitmapData and overwrites it with its edge info
private function EdgeTransform(bmd:BitmapData):void {
var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
var pt:Point = new Point(0, 0);
/// Split input bitmap into different color channels to preserve color contrast effect
var redBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var greenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var blueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
redBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
greenBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
blueBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
// Create bitmaps for writing edge info to
var nRedBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var nGreenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var nBlueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
var rgbR:uint;
var rgbG:uint;
var rgbB:uint;
var oldRgbR:uint;
var oldRgbG:uint;
var oldRgbB:uint;
var vertOrientation:uint;
var horOrientation:uint;
var verthorOrientation:uint;
var horvertOrientation:uint;
var ul:uint;
var ll:uint;
var dl:uint;
var uu:uint;
var ur:uint;
var rr:uint;
var dr:uint;
var c:uint;
var dd:uint;
var y:uint;
var x:uint;
//// Go through each channel bitmap separately to preserve color contrast effect
//// First red channel
for (y = SMOOTHING; y < bmd.height; y++)
{
// Get pixel colors from a 2x3 box of bitmap
c = redBmd.getPixel(SMOOTHING, y);
ul = redBmd.getPixel(0, y-SMOOTHING);
ll = redBmd.getPixel(0, y);
dl = redBmd.getPixel(0, y+SMOOTHING);
uu = redBmd.getPixel(SMOOTHING, y-SMOOTHING);
dd = redBmd.getPixel(SMOOTHING, y+SMOOTHING);
for (x = SMOOTHING; x < bmd.width; x++)
{
// Get pixel colors from right-hand column of 3x3 box
ur = redBmd.getPixel(x+SMOOTHING, y-SMOOTHING);
rr = redBmd.getPixel(x+SMOOTHING, y);
dr = redBmd.getPixel(x+SMOOTHING, y+SMOOTHING);
//calculate the angle of the edge for the center point c
// depending upon surrounding edge pattern in 3x3 box
vertOrientation = uint((Math.abs(ll - c) + Math.abs(rr - c)) / 2);
horOrientation = uint((Math.abs(uu - c) + Math.abs(dd - c)) / 2);
verthorOrientation = uint((Math.abs(ur - c) + Math.abs(dl - c)) / 2);
horvertOrientation = uint((Math.abs(dr - c) + Math.abs(ul - c)) / 2);
// Give each instantaneous edge orientation angle a color code
rgbR = uint((vertOrientation + horvertOrientation)/0x010101);
rgbG = uint((horOrientation + horvertOrientation)/0x010101);
rgbB = uint((horOrientation + verthorOrientation)/0x010101);
rgbR *= 0x010000;
rgbG *= 0x000100;
rgbB *= 0x000001;
oldRgbR = nRedBmd.getPixel(x, y);
oldRgbG = nGreenBmd.getPixel(x, y);
oldRgbB = nBlueBmd.getPixel(x, y);
nRedBmd.setPixel(x, y, rgbR + oldRgbR);
nGreenBmd.setPixel(x, y, rgbG + oldRgbG);
nBlueBmd.setPixel(x, y, rgbB + oldRgbB);
//shift values for next pass when checking next 3x3 box
ll = c;
c = rr;
ul = uu;
uu = ur;
dl = dd;
dd = dr;
}
}
// Next blue channel
for (y = SMOOTHING; y < bmd.height; y++)
{
// Get pixel colors from a 2x3 box of bitmap
c = blueBmd.getPixel(SMOOTHING, y);
ul = blueBmd.getPixel(0, y-SMOOTHING);
ll = blueBmd.getPixel(0, y);
dl = blueBmd.getPixel(0, y+SMOOTHING);
uu = blueBmd.getPixel(SMOOTHING, y-SMOOTHING);
dd = blueBmd.getPixel(SMOOTHING, y+SMOOTHING);
for (x = SMOOTHING; x < bmd.width; x++)
{
// Get pixel colors from right-hand column of 3x3 box
ur = blueBmd.getPixel(x+SMOOTHING, y-SMOOTHING);
rr = blueBmd.getPixel(x+SMOOTHING, y);
dr = blueBmd.getPixel(x+SMOOTHING, y+SMOOTHING);
//calculate the angle of the edge for the center point c
// depending upon surrounding edge pattern in 3x3 box
vertOrientation = uint((Math.abs(ll - c) + Math.abs(rr - c)) / 2);
horOrientation = uint((Math.abs(uu - c) + Math.abs(dd - c)) / 2);
verthorOrientation = uint((Math.abs(ur - c) + Math.abs(dl - c)) / 2);
horvertOrientation = uint((Math.abs(dr - c) + Math.abs(ul - c)) / 2);
// Give each instantaneous edge orientation angle a color code
rgbR = uint((vertOrientation + horvertOrientation)/0x010101);
rgbG = uint((horOrientation + horvertOrientation)/0x010101);
rgbB = uint((horOrientation + verthorOrientation)/0x010101);
rgbR *= 0x010000;
rgbG *= 0x000100;
rgbB *= 0x000001;
oldRgbR = nRedBmd.getPixel(x, y);
oldRgbG = nGreenBmd.getPixel(x, y);
oldRgbB = nBlueBmd.getPixel(x, y);
nRedBmd.setPixel(x, y, rgbR + oldRgbR);
nGreenBmd.setPixel(x, y, rgbG + oldRgbG);
nBlueBmd.setPixel(x, y, rgbB + oldRgbB);
//shift values for next pass when checking next 3x3 box
ll = c;
c = rr;
ul = uu;
uu = ur;
dl = dd;
dd = dr;
}
}
/// Next green channel
for (y = SMOOTHING; y < bmd.height; y++)
{
// Get pixel colors from a 2x3 box of bitmap
c = greenBmd.getPixel(SMOOTHING, y);
ul = greenBmd.getPixel(0, y-SMOOTHING);
ll = greenBmd.getPixel(0, y);
dl = greenBmd.getPixel(0, y+SMOOTHING);
uu = greenBmd.getPixel(SMOOTHING, y-SMOOTHING);
dd = greenBmd.getPixel(SMOOTHING, y+SMOOTHING);
for (x = SMOOTHING; x < bmd.width; x++)
{
// Get pixel colors from right-hand column of 3x3 box
ur = greenBmd.getPixel(x+SMOOTHING, y-SMOOTHING);
rr = greenBmd.getPixel(x+SMOOTHING, y);
dr = greenBmd.getPixel(x+SMOOTHING, y+SMOOTHING);
//calculate the angle of the edge for the center point c
// depending upon surrounding edge pattern in 3x3 box
vertOrientation = uint((Math.abs(ll - c) + Math.abs(rr - c)) / 2);
horOrientation = uint((Math.abs(uu - c) + Math.abs(dd - c)) / 2);
verthorOrientation = uint((Math.abs(ur - c) + Math.abs(dl - c)) / 2);
horvertOrientation = uint((Math.abs(dr - c) + Math.abs(ul - c)) / 2);
// Give each instantaneous edge orientation angle a color code
rgbR = uint((vertOrientation + horvertOrientation)/0x010101);
rgbG = uint((horOrientation + horvertOrientation)/0x010101);
rgbB = uint((horOrientation + verthorOrientation)/0x010101);
rgbR *= 0x010000;
rgbG *= 0x000100;
rgbB *= 0x000001;
oldRgbR = nRedBmd.getPixel(x, y);
oldRgbG = nGreenBmd.getPixel(x, y);
oldRgbB = nBlueBmd.getPixel(x, y);
nRedBmd.setPixel(x, y, rgbR + oldRgbR);
nGreenBmd.setPixel(x, y, rgbG + oldRgbG);
nBlueBmd.setPixel(x, y, rgbB + oldRgbB);
//shift values for next pass when checking next 3x3 box
ll = c;
c = rr;
ul = uu;
uu = ur;
dl = dd;
dd = dr;
}
}
// Copy edge information from each respective channel over to original bitmap
bmd.copyChannel(nRedBmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
bmd.copyChannel(nGreenBmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
bmd.copyChannel(nBlueBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
}
}
}