マルチマーカー対応FLARToolKit
from flartoolkit SimpleCube example
print this marker: http://saqoosha.net/lab/FLARToolKit/flarlogo-marker.pdf
flash.geom.* でFLAR使うテスト。あってるかな、、
座標系まちごうとったから変えた
/**
* Copyright umhr ( http://wonderfl.net/user/umhr )
* GNU General Public License, v3 ( http://www.gnu.org/licenses/quick-guide-gplv3.html )
* Downloaded from: http://wonderfl.net/c/xTXe
*/
// forked from nutsu's FLARToolKit use flash.geom package test
// forked from mash's FLARToolKit SimpleCube sample
// from flartoolkit SimpleCube example
// print this marker: http://saqoosha.net/lab/FLARToolKit/flarlogo-marker.pdf
//flash.geom.* でFLAR使うテスト。あってるかな、、
//座標系まちごうとったから変えた
package
{
import flash.display.Sprite;
[SWF( width=465, height=465, frameRate=30, backgroundColor=0x000000 )]
public class Main extends Sprite
{
private var _mulitiMarker:MulitiMarker;
public function Main()
{
Wonderfl.capture_delay( 5 );
_mulitiMarker = new MulitiMarker();
this.addChild(_mulitiMarker);
}
}
}
//マルチマーカー用のAppBaseが無いので、作ってみた。
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.PixelSnapping;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.media.Camera;
import flash.media.Video;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import org.libspark.flartoolkit.core.FLARCode;
import org.libspark.flartoolkit.core.param.FLARParam;
import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector;
import org.libspark.flartoolkit.detector.FLARMultiMarkerDetector;
[Event(name="init",type="flash.events.Event")]
[Event(name="init",type="flash.events.Event")]
[Event(name="ioError",type="flash.events.IOErrorEvent")]
[Event(name = "securityError", type = "flash.events.SecurityErrorEvent")]
class ARMulitiAppBase extends Sprite {
private var _loader:URLLoader;
private var _cameraFile:String;
private var _codeFile:String;
private var _codeFiles:Array;
private var _width:int;
private var _height:int;
private var _codeWidth:int;
private var _codeWidthes:Array;
protected var _param:FLARParam;
protected var _raster:FLARRgbRaster_BitmapData;
protected var _mulitiDetector:FLARMultiMarkerDetector;
protected var _webcam:Camera;
protected var _video:Video;
protected var _capture:Bitmap;
private var _multiLoader:MultiLoader;
public var codeNum:int;
public function ARMulitiAppBase() {
}
protected function init(cameraFile:String, codeFiles:Array, canvasWidth:int = 320, canvasHeight:int = 240, codeWidthes:Array = null):void {
_cameraFile = cameraFile;
_width = canvasWidth;
_height = canvasHeight;
_codeFiles = codeFiles.concat();
codeNum = codeFiles.length;
if (!codeWidthes) {
codeWidthes = [];
var n:int = codeFiles.length;
for (var i:int = 0; i < n; i++) {
codeWidthes[i] = 80;
}
}
_codeWidthes = codeWidthes.concat();
_loader = new URLLoader();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
_loader.addEventListener(Event.COMPLETE, _onLoadParam);
_loader.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_loader.load(new URLRequest(_cameraFile));
}
private function _onLoadParam(e:Event):void {
_loader.removeEventListener(Event.COMPLETE, _onLoadParam);
_loader.removeEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_param = new FLARParam();
_param.loadARParam(_loader.data);
_param.changeScreenSize(_width, _height);
_loader = null;
_multiLoader = new MultiLoader("ARMulitiAppBase");
var n:int = _codeFiles.length;
for (var i:int = 0; i < n; i++) {
_multiLoader.add(_codeFiles[i], { id:String(i) } );
}
_multiLoader.addEventListener(MultiLoader.COMPLETE, _onLoadCode);
_multiLoader.start();
}
private function _onLoadCode(e:Event):void {
var codes:Array = [];
var n:int = codeNum;
for (var i:int = 0; i < n; i++) {
codes[i] = new FLARCode(16, 16);
codes[i].loadARPatt(_multiLoader.getText(String(i)));
}
_webcam = Camera.getCamera();
if (!_webcam) {
throw new Error('No webcam!!!!');
}
_webcam.setMode(_width, _height, 30);
_video = new Video(_width, _height);
_video.attachCamera(_webcam);
_capture = new Bitmap(new BitmapData(_width, _height, false, 0), PixelSnapping.AUTO, true);
// setup ARToolkit
_raster = new FLARRgbRaster_BitmapData(_capture.bitmapData);
_mulitiDetector = new FLARMultiMarkerDetector(_param, codes, _codeWidthes, n);
_mulitiDetector.setContinueMode(true);
dispatchEvent(new Event(Event.INIT));
}
protected function onInit():void {
}
}
//class fileがひとつだと、ドキュメントクラスに継承できないので、別クラス化
//MulitiMarker
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Point;
import flash.geom.Utils3D;
import org.libspark.flartoolkit.core.FLARMat;
import org.libspark.flartoolkit.core.param.FLARParam;
import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
import org.libspark.flartoolkit.core.types.FLARIntSize;
import org.libspark.flartoolkit.example.ARAppBase;
import org.libspark.flartoolkit.detector.FLARMultiMarkerDetector;
class MulitiMarker extends ARMulitiAppBase {
private var _base:Sprite;
private var _fr_mat:Matrix3D;
private var _projmat:Matrix3D;
private var _projectMatrixes:Vector.<Matrix3D>;
private var _view:View;
public function MulitiMarker()
{
addEventListener(Event.INIT, _onInit);
init('http://assets.wonderfl.net/static/flar/camera_para.dat', ['http://assets.wonderfl.net/static/flar/flarlogo.pat','http://mztm.heteml.jp/umhr/wonderfl/gap.pat','http://mztm.heteml.jp/umhr/wonderfl/uniqlo.pat']);
}
private function _onInit(e:Event):void
{
addChild( _base = new Sprite() );
//
_capture.width = 640;
_capture.height = 480;
_base.addChild(_capture);
//
_view = new View();
_view.x = 320;
_view.y = 240;
_view.scaleX = _view.scaleY = 2;
this.addChild(_view);
//
_fr_mat = new Matrix3D();
initCamera( this._param );
_projectMatrixes = new Vector.<Matrix3D>();
var n:int = this.codeNum;
for ( var i:int = 0; i < n; i++ ) {
_projectMatrixes[i] = new Matrix3D();
}
//
_projmat = new Matrix3D();
//
stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
}
private function _onEnterFrame(e:Event):void
{
_capture.bitmapData.draw(_video);
var i_indexFromIndex:Array = [];
var n:int = this.codeNum;
var detectedes:Array = [];
for (var i:int = 0; i < n; i++) {
detectedes[i] = -1;
i_indexFromIndex[i] = -1;
}
var detected:Boolean = false;
try {
var m:int = _mulitiDetector.detectMarkerLite(_raster, 80);
if (m > 0) {
for (i = 0; i < m; i++) {
var j:int = _mulitiDetector.getARCodeIndex(i);
var conf:Number = _mulitiDetector.getConfidence(i);
if (conf > detectedes[j]) {
if (conf > 0.5) {
i_indexFromIndex[i] = j;
detectedes[j] = conf;
detected = true;
}
}
}
}
} catch (e:Error) {}
if (detected) {
for (i = 0; i < n; i++) {
j = i_indexFromIndex[i];
if (j == -1) { continue };
var rmatrixes:FLARTransMatResult = new FLARTransMatResult();
_mulitiDetector.getTransmationMatrix(i, rmatrixes);
var de_mat:Matrix3D = new Matrix3D();
de_mat.rawData = Vector.<Number>(
[ rmatrixes.m00, rmatrixes.m10, rmatrixes.m20, 0,
rmatrixes.m01, rmatrixes.m11, rmatrixes.m21, 0,
rmatrixes.m02, rmatrixes.m12, rmatrixes.m22, 0,
rmatrixes.m03, rmatrixes.m13, rmatrixes.m23, 1 ]
);
_projectMatrixes[j].rawData = Vector.<Number>([0,1,0,0, 1,0,0,0, 0,0,1,0, 0,0,0,1]);
_projectMatrixes[j].append( de_mat );
_projectMatrixes[j].append( _fr_mat );
}
_view.drawObjects(detectedes, _projectMatrixes);
_view.visible = true;
} else {
_view.visible = false;
}
}
//無駄あったから整理した
private function initCamera( param:FLARParam ):void
{
var size:FLARIntSize = param.getScreenSize();
var width:int = size.w;
var height:int = size.h;
var tMat:FLARMat = new FLARMat (3, 4);
var iMat:FLARMat = new FLARMat (3, 4);
param.getPerspectiveProjectionMatrix().decompMat(iMat, tMat);
var icpara:Array = iMat.getArray();
for (var i:int = 0; i < 4; i++) {
icpara[1][i] = (height - 1) * (icpara[2][i]) - icpara[1][i];
}
var w:Number = icpara[0][0] / icpara[2][2];
var h:Number = -icpara[1][1] / icpara[2][2];
_fr_mat.rawData = Vector.<Number>(
[ w, 0, 0, 0,
0, h, 0, 0,
0, 0, 1, 1,
0, 0, 0, 0 ]
);
}
}
//立方体を描画
import flash.display.Sprite;
class View extends Sprite {
private var _view:Shape;
private var g:Graphics;
private var vert1:Vector.<Number>;
private var uvt1:Vector.<Number>;
private var vert2:Vector.<Number>;
private var uvt2:Vector.<Number>;
private var vout:Vector.<Number>;
public function View():void {
_view = new Shape();
this.addChild(_view);
g = _view.graphics;
initARObjects();
}
private function initARObjects():void
{
// Create Plane with same size of the marker.
vert1 = new Vector.<Number>();
uvt1 = new Vector.<Number>();
var w:Number = 40;
vert1.push( 0, 0, 0,
-w, -w, 0, w, -w, 0, w, w, 0, -w, w, 0,
w, 0, 0, 0, w, 0, 0, 0, w );
for ( var i:int = 0; i < vert1.length; i++ ) {
uvt1.push( 0 );
}
//cube
vert2 = new Vector.<Number>();
uvt2 = new Vector.<Number>();
w /= 2;
vert2.push( -w, -w, -w, w, -w, -w, w, w, -w, -w, w, -w,
-w, -w, w, w, -w, w, w, w, w, -w, w, w );
for ( i = 0; i < vert1.length; i++ ) {
uvt1.push( 0 );
}
vout = new Vector.<Number>();
}
public function drawObjects(detectedes:Array, projectMatrixes:Vector.<Matrix3D>):void
{
g.clear();
var colors:Array = [0x00FF00, 0x0000FF, 0xFF0000];
var n:int = detectedes.length;
for (var i:int = 0; i < n; i++) {
if (detectedes[i] == -1) { continue };
vout.length = 0;
Utils3D.projectVectors( projectMatrixes[i], vert1, vout, uvt1 );
g.lineStyle( 2, 0xffffff );
g.beginFill( colors[i], 0.2 );
quad( vout[2], vout[3], vout[4], vout[5], vout[6], vout[7], vout[8], vout[9] );
g.endFill();
//x axis
g.lineStyle( 2, 0xff0000 );
line( vout[0], vout[1], vout[10], vout[11] );
//y axis
g.lineStyle( 2, 0x0000ff );
line( vout[0], vout[1], vout[12], vout[13] );
//z axis
g.lineStyle( 2, 0x00ff00 );
line( vout[0], vout[1], vout[14], vout[15] );
//cube
var mat:Matrix3D = new Matrix3D();
mat.appendTranslation( 0, 0, 20 );
var vert2t:Vector.<Number> = new Vector.<Number>();
mat.transformVectors( vert2, vert2t );
vout.length = 0;
Utils3D.projectVectors( projectMatrixes[i], vert2t, vout, uvt2 );
g.lineStyle( 1, colors[i] );
quad( vout[0], vout[1], vout[2], vout[3], vout[4], vout[5], vout[6], vout[7] );
quad( vout[8], vout[9], vout[10], vout[11], vout[12], vout[13], vout[14], vout[15] );
line( vout[0], vout[1], vout[8], vout[9] );
line( vout[2], vout[3], vout[10], vout[11] );
line( vout[4], vout[5], vout[12], vout[13] );
line( vout[6], vout[7], vout[14], vout[15] );
}
}
private function line( x0:Number, y0:Number, x1:Number, y1:Number ):void
{
g.moveTo( x0, y0 );
g.lineTo( x1, y1 );
}
private function quad( x0:Number, y0:Number, x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number ):void
{
g.moveTo( x0, y0 );
g.lineTo( x1, y1 );
g.lineTo( x2, y2 );
g.lineTo( x3, y3 );
g.lineTo( x0, y0 );
}
}
/*
* Fileローダー
* */
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.utils.Dictionary;
class MultiLoader{
public static var IMAGE_EXTENSIONS:Array = ["swf", "jpg", "jpeg", "gif", "png"];
public static var TEXT_EXTENSIONS:Array = ["txt", "js", "xml", "php", "asp", "pat"];
public static const COMPLETE:String = "complete";
private var _listener:Function = function(event:Event):void{};
private var _loads:Dictionary;
private var _keyFromId:Dictionary;
private var _loadCount:int;
private var _itemsLoaded:int;
public var items:Array;
public function MultiLoader(name:String){
_loads = new Dictionary();
_keyFromId = new Dictionary();
_itemsLoaded = 0;
items = [];
}
public function add(url:String, props:Object = null):void {
var loadingItem:LoadingItem = new LoadingItem();
loadingItem.url = new URLRequest(url);
loadingItem.type = getType(url);
if(props){
if(props.context){
loadingItem.context = props.context;
}
if (props.id) {
_keyFromId[props.id] = url;
}
}
items.push(loadingItem);
}
private function getType(url:String):String{
var i:int;
var extension:String;
var n:int = IMAGE_EXTENSIONS.length;
var result:String = "";
for (i = 0; i < n; i++) {
extension = IMAGE_EXTENSIONS[i];
if(extension == url.substr(-extension.length).toLowerCase()){
result = "image";
break;
}
}
if(result == ""){
n = TEXT_EXTENSIONS.length;
for (i = 0; i < n; i++) {
extension = TEXT_EXTENSIONS[i];
if(extension == url.substr(-extension.length).toLowerCase()){
result = "text";
break;
}
}
}
return result;
}
public function start():void{
var n:int = items.length;
for (var i:int = 0; i < n; i++) {
var type:String = items[i].type;
if(type == "image"){
_loads[items[i].url.url] = loadImage(items[i].url,items[i].context);
}if(type == "text"){
_loads[items[i].url.url] = loadText(items[i].url);
}
}
}
public function addEventListener(type:String,listener:Function):void{
_listener = listener;
}
public function getBitmap(key:String):Bitmap{
key = keyMatching(key);
var bitmap:Bitmap = _loads[key].content;
return bitmap;
}
public function getBitmapData(key:String):BitmapData{
key = keyMatching(key);
var bitmap:Bitmap = getBitmap(key);
var bitmapData:BitmapData = new BitmapData(bitmap.width,bitmap.height);
bitmapData.draw(bitmap);
return bitmapData;
}
private function loadImage(url:URLRequest, context:LoaderContext = null):Loader {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComp);
loader.load(url,context);
return loader;
}
public function getText(key:String):String {
key = keyMatching(key);
return _loads[key].data;
}
private function keyMatching(key:String):String {
return _loads[key]?key:_keyFromId[key];
}
private function loadText(url:URLRequest):URLLoader{
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE,onComp);
loader.load(url);
return loader;
}
private function onComp(event:Event):void{
_itemsLoaded ++;
if(_itemsLoaded == items.length){
_listener(event);
}
}
public function get itemsTotal():int{
return items.length;
}
public function get itemsLoaded():int{
return _itemsLoaded;
}
public function get loadedRatio():Number {
return _itemsLoaded/items.length;
}
}
class LoadingItem{
public var url:URLRequest;
public var type:String;
public var status:String;
public var context:LoaderContext;
public function LoadingItem(){};
}