数字認識 forked from: Mouse Gesture
マウスジェスチャを利用して数字認識
マウスジェスチャのストローク特徴から数字のパターン認識を行います.
数字をマウスで書いた後マウスカーソルをFlash外に出すと,認識結果が表示されます.
桁数に制限はありませんが,数字が小さくなるとうまく認識されません.
0 と 6 以外はジェスチャ情報しか使ってないので,位置が乙でも
ストロークがマッチすれば何らかの数字に認識されてしまいます.
また,逆に形がきれいでも書き順が小学校で習ったやつじゃないと認識されません.
// forked from a24's Mouse Gesture
//マウスジェスチャを利用して数字認識
/*
マウスジェスチャのストローク特徴から数字のパターン認識を行います.
数字をマウスで書いた後マウスカーソルをFlash外に出すと,認識結果が表示されます.
桁数に制限はありませんが,数字が小さくなるとうまく認識されません.
0 と 6 以外はジェスチャ情報しか使ってないので,位置が乙でも
ストロークがマッチすれば何らかの数字に認識されてしまいます.
また,逆に形がきれいでも書き順が小学校で習ったやつじゃないと認識されません.
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;
[ SWF( width = "465" , height = "465" , backgroundColor = "0xFFFFFF" , frameRate = "60" ) ]
public class MouseGesture extends Sprite
{
private var _startPoint : Point;
private var _nextPoint : Point;
private var _strokeBeginPoints : Array;
private var _strokeEndPoints : Array;
private var _baseDistance : Number;
private var _tempDirection : String;
private var _direction : String;
private var _sp : Sprite;
private var _detected : TextField;
private var _strokes : String;
//各数字のストロークデータ
private var _ZEROorSIX : RegExp = /L?DRUL_/;
private var _ONE : RegExp = /((U|R)D_)|(_D_)|(^D_)/g;
private var _TWO : RegExp = /URDL?D?R_/g;
private var _THREE : RegExp = /RDLD?RD?L_/g;
private var _FOUR : RegExp = /L?D?R_D_/g;
private var _FIVE : RegExp = /L?DRDLU?_R_/g;
private var _SEVEN : RegExp = /D_R((D?L?)+|(L?D?)+)_/g;
private var _EIGHT : RegExp = /ULDR?D?L(UR)+_/g;
private var _NINE : RegExp = /ULDRU?D_/g;
/*======================================================================*//**
* コンストラクタ
*/
public function MouseGesture()
{
_tempDirection = _direction = "";
_baseDistance = 20;
_strokeBeginPoints = new Array();
_strokeEndPoints = new Array();
_sp = new Sprite;
addChild( _sp );
_detected = new TextField();
_detected.selectable = false;
_detected.width = _detected.height = 445;
_detected.defaultTextFormat = new TextFormat("MS Gothic", 40, 0xFF3333, null, null, null, null, null, "center");
_detected.text = "大きく丁寧に!\n" + "数字を書いたあと\nマウスカーソルを外へ";
_detected.defaultTextFormat = new TextFormat("MS Gothic", 500, 0xFF3333, null, null, null, null, null, "center");
addChild( _detected )
newPage( null );
}
private function newPage( e: MouseEvent ):void
{
_strokes = "";
stage.addEventListener( MouseEvent.MOUSE_DOWN , mouseDownHandler );
stage.removeEventListener( MouseEvent.CLICK, newPage );
}
/*======================================================================*//**
* マウスダウン
*/
private function mouseDownHandler( e:MouseEvent ):void
{
var _color : Number = 0x0000FF;
_startPoint = new Point( stage.mouseX , stage.mouseY );
_sp.graphics.lineStyle( 8 , _color , 1.0 );
_sp.graphics.moveTo( _startPoint.x , _startPoint.y );
_strokeBeginPoints.push( _startPoint );
stage.addEventListener( MouseEvent.MOUSE_MOVE , mouseMoveHandler );
stage.addEventListener( MouseEvent.MOUSE_UP , mouseUpHandler );
}
/*======================================================================*//**
* マウスムーヴ
*/
private function mouseMoveHandler( e:MouseEvent ):void
{
_nextPoint = new Point( stage.mouseX , stage.mouseY );
var _distance : Number = Point.distance( _startPoint , _nextPoint );
// 一定の距離で線を描画、方向判定
if ( Math.abs( _distance ) > _baseDistance )
{
_sp.graphics.lineTo( _nextPoint.x , _nextPoint.y );
putDirection();
_startPoint = new Point( stage.mouseX , stage.mouseY );
}
}
/*======================================================================*//**
* マウスアップ
*/
private function mouseUpHandler( e:MouseEvent ):void
{
_strokeEndPoints.push( new Point( stage.mouseX, stage.mouseY ) );
if( _direction != "" )
{
_strokes += _direction + "_";
_direction = "";
}
stage.removeEventListener( MouseEvent.MOUSE_MOVE , mouseMoveHandler );
stage.removeEventListener( MouseEvent.MOUSE_UP , mouseUpHandler );
if( Point.distance( _strokeBeginPoints[_strokeBeginPoints.length-1], _strokeEndPoints[_strokeEndPoints.length-1] ) > 2 )
{
stage.addEventListener( Event.MOUSE_LEAVE, mouseLeaveHandler );
}
else
{
_strokeBeginPoints.pop();
_strokeEndPoints.pop();
}
}
//serachの返すindexから,何ストローク目かを求める
private function getStrokeIndex( stringIndex:int ):int
{
var strokeIndex:int = 0;
if( stringIndex == -1 )
{
return -1;
}
else if( stringIndex == 0 )
{
return 0;
}
else
{
for( var j:int = 0; j < stringIndex; j++ )
{
if( _strokes.charAt( j ) == "_" ) strokeIndex++;
}
return strokeIndex;
}
return -1;
}
private function mouseLeaveHandler( e:Event ):void
{
_direction = "";
_sp.graphics.clear();
//正規表現を使ってストローク解析
for( var i:int = 0; i < _strokeBeginPoints.length; i++ )
{
if( _strokes.search( /[LDUR]/ ) == -1 ) break;
// 0 と 6 だけはストロークが完全に一緒なのでストロークの開始点と終了点から識別
var strokeIndex:int = getStrokeIndex( _strokes.search( _ZEROorSIX ) );
if( strokeIndex != -1 )
{
if( _strokeEndPoints[strokeIndex].y - _strokeBeginPoints[strokeIndex].y < 50 )
{
_strokes = _strokes.replace( _ZEROorSIX, "0_" );
}
else
{
_strokes = _strokes.replace( _ZEROorSIX, "6_" );
}
}
_strokes = _strokes.replace( _EIGHT, "8_" );
_strokes = _strokes.replace( _NINE, "9_" );
_strokes = _strokes.replace( _THREE, "3_" );
_strokes = _strokes.replace( _TWO, "2_");
_strokes = _strokes.replace( _FIVE, "5_" );
_strokes = _strokes.replace( _SEVEN , "7_" );
_strokes = _strokes.replace( _FOUR, "4_" );
_strokes = _strokes.replace( _ONE, "1_" );
}
_strokes = _strokes.replace( /[LURD_]/g, "" );
if( _strokes == "" )
{
_strokes = "unknown";
}
_detected.text = _strokes;
_direction = _strokes = "";
_strokeBeginPoints.length = _strokeEndPoints.length = 0;
stage.removeEventListener( Event.MOUSE_LEAVE, mouseLeaveHandler );
}
/*======================================================================*//**
* 角度から方向を割りだす
*/
private function putDirection():void
{
var _vector:Point = _nextPoint.subtract( _startPoint );
var _angle : Number = Math.atan2( _vector.y , _vector.x ) * 180 / Math.PI;
if ( _angle >= 45 && _angle < 125 ) _tempDirection = "D";
else if ( _angle >= 125 || _angle < -125 ) _tempDirection = "L";
else if ( _angle >= -45 && _angle < 45 ) _tempDirection = "R";
else if ( _angle >= -125 && _angle < -45 ) _tempDirection = "U";
if ( _direction.substr( _direction.length - 1 , 1 ) != _tempDirection ) _direction += _tempDirection;
//_detected.text = _direction;
}
}
}