ゼロ交差法によるエッジ検出
『画像処理プログラミング』という本と、
http://d.hatena.ne.jp/matsu4512/20090711/1247321353
を参考にゼロ交差法というエッジ検出をやってみました。
が、ぜんぜん速くならなかった…
/**
* Copyright utabi ( http://wonderfl.net/user/utabi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fRJG
*/
// 『画像処理プログラミング』という本と、
// http://d.hatena.ne.jp/matsu4512/20090711/1247321353
// を参考にゼロ交差法というエッジ検出をやってみました。
// が、ぜんぜん速くならなかった…
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.ConvolutionFilter;
import flash.filters.ColorMatrixFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.Camera;
import flash.media.Video;
import flash.text.TextField;
import net.hires.debug.*;
[SWF(width = "465", height = "465", frameRate = "15",backgroundColor="0xffffff")]
public class ZeroCrossing extends Sprite
{
private var camera:Camera;
private var video:Video;
private var videoWidth:int = 465;
private var videoHeight:int = 232;
private var now:BitmapData;
private var bdGX:BitmapData, bdGY:BitmapData, bdGXY:BitmapData, bdGXX:BitmapData, bdGYY:BitmapData;
private var bmd:BitmapData;
private var rect:Rectangle;
private var pt:Point;
private var i:int;
private var xp:int, yp:int;
private var xx:int, yy:int;
private var xo:int, yo:int;
private var current:int, gray:uint;
private var Lx:Number, Ly:Number, Lxy:Number, Lxx:Number, Lyy:Number;
private var lap:Vector.<Number> = new Vector.<Number>();
private var edge:Vector.<Number> = new Vector.<Number>();
private var zeroCross:Vector.<uint> = new Vector.<uint>();
private var msize:int;
private var g:Object = new Object();
private var noiseReduction:ConvolutionFilter;
private var grayFilter:ColorMatrixFilter = new ColorMatrixFilter([
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0, 0, 0, 0, 255
]);
private var filterGX:ConvolutionFilter;
private var filterGY:ConvolutionFilter;
private var filterGXY:ConvolutionFilter;
private var filterGXX:ConvolutionFilter;
private var filterGYY:ConvolutionFilter;
private var filterSet:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(5);
public function ZeroCrossing(){
//super();
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
camera = Camera.getCamera();
//カメラあり
if(camera != null){
setUpCamera();
//カメラ無し
}else{
var txt:TextField = new TextField();
txt.text ='カメラ無し';
addChild(txt);
}
noiseReduction = new ConvolutionFilter(3, 3,[
1, 2, 1,
2, 4, 2,
1, 2, 1
],52);
bmd = new BitmapData(videoWidth,videoHeight,false);
addChild(new Bitmap(bmd));
now = new BitmapData(videoWidth,videoHeight,false);
bdGX = new BitmapData(videoWidth,videoHeight,false);
bdGY = new BitmapData(videoWidth,videoHeight,false);
bdGXY = new BitmapData(videoWidth,videoHeight,false);
bdGXX = new BitmapData(videoWidth,videoHeight,false);
bdGYY = new BitmapData(videoWidth,videoHeight,false);
rect = new Rectangle(0, 0, videoWidth, videoHeight);
pt = new Point(0,0);
msize = 5;
g = setupGaussianFilters(.6,msize);
filterGX = new ConvolutionFilter(msize,msize,g.gx,0,127);
filterGY = new ConvolutionFilter(msize,msize,g.gy,0,127);
filterGXY = new ConvolutionFilter(msize,msize,g.gxy,0,127);
filterGXX = new ConvolutionFilter(msize,msize,g.gxx,0,127);
filterGYY = new ConvolutionFilter(msize,msize,g.gyy,0,127);
lap = new Vector.<Number>(rect.width*rect.height);
edge = new Vector.<Number>(rect.width*rect.height);
zeroCross = new Vector.<uint>(rect.width*rect.height);
addChild(new Stats);
addEventListener(Event.ENTER_FRAME,loop);
}
private function setUpCamera():void {
camera.setMode(videoWidth, videoHeight, 15);
video = new Video(videoWidth, videoHeight);
video.attachCamera(camera);
addChild(video);
}
private function loop(e:Event=null):void {
now.draw(video);
//now.applyFilter(now, rect, pt, noiseReduction);
now.applyFilter(now, rect, pt, grayFilter);
bdGX.applyFilter(now, rect, pt, filterGX);
bdGY.applyFilter(now, rect, pt, filterGY);
bdGXY.applyFilter(now, rect, pt, filterGXY);
bdGXX.applyFilter(now, rect, pt, filterGXX);
bdGYY.applyFilter(now, rect, pt, filterGYY);
filterSet[0] = bdGX.getVector(rect);
filterSet[1] = bdGY.getVector(rect);
filterSet[2] = bdGXY.getVector(rect);
filterSet[3] = bdGXX.getVector(rect);
filterSet[4] = bdGYY.getVector(rect);
bmd.setVector(rect,zero_cross(rect.width, rect.height, 0.025, filterSet));
//bmd.draw(bdGXX);
}
private function zero_cross(w:Number, h:Number,th:Number,f:Vector.<Vector.<uint>>):Vector.<uint>{
for(yp = 1; yp < h-1; yp++){
for(xp = 1; xp < w-1; xp++){
current = yp * w + xp;
Lx = -0.5 + (( f[0][current] - 0xff000000) / 0x00ffffff);
Ly = -0.5 + (( f[1][current] - 0xff000000) / 0x00ffffff);
Lxy = -0.5 + (( f[2][current] - 0xff000000) / 0x00ffffff);
Lxx = -0.5 + (( f[3][current] - 0xff000000) / 0x00ffffff);
Lyy = -0.5 + (( f[4][current] - 0xff000000) / 0x00ffffff);
//この値で+-が反転している部分を見つける
lap[current] = ((Lx * Lx * Lxx) + (2.0 * Lxy * Lx * Ly) + (Ly * Ly * Lyy) );
//エッジの強度
edge[current] = Math.sqrt(Lx * Lx + Ly * Ly);
if(edge[current] >= th && (lap[current] * lap[current-1] < 0.0 || lap[current] * lap[current-w] < 0.0)){
zeroCross[current] = 0xff000000;
} else {
zeroCross[current] = 0xffffffff;
}
}
}
//trace(edge[current],lap[current] * lap[current-1], lap[current] * lap[current-w], 0xffffffff-0xff000000);
return zeroCross;
}
//ガウス関数を微分したマスクを求める。
private function setupGaussianFilters(scale:Number, matrix_size:int):Object{
var x0:int, y0:int;
var r0:Number, exponent:Number, id:int;
var Gx:Array = [], Gy:Array = [], Gxy:Array = [], Gxx:Array = [], Gyy:Array = [];
var ret:Object = new Object;
//フィルタの中心を求める
x0 = y0 = matrix_size/2;
for(var y:uint = 0; y < matrix_size; y++){
for(var x:uint = 0; x < matrix_size; x++){
id = y*matrix_size+x;
//中心からの距離を求める
r0 = Number((y-y0)*(y-y0)+(x-x0)*(x-x0));
//平滑化をするための2次元のガウス関数
exponent = 1.0/(2.0*Math.PI*scale) * Math.exp(-r0/(2.0*scale));
//中心からの距離に応じて重み付け
Gx[id] = (-Number((x-x0))/scale) * exponent;
Gy[id] = (-Number((y-y0))/scale) * exponent;
Gxy[id] = (Number((y-y0)*(x-x0))/(scale*scale)) * exponent;
Gxx[id] = (Number((x-x0)*(x-x0))/(scale*scale)-1.0/scale) * exponent;
Gyy[id] = (Number((y-y0)*(y-y0))/(scale*scale)-1.0/scale) * exponent;
}
}
ret = {gx:Gx, gy:Gy, gxy:Gxy, gxx:Gxx, gyy:Gyy};
//trace(ret.gx);
//trace(ret.gy);
return ret
}
}
}