/* * PROJECT: FLARToolKit * -------------------------------------------------------------------------------- * This work is based on the NyARToolKit developed by * R.Iizuka (nyatla) * http://nyatla.jp/nyatoolkit/ * * The FLARToolKit is ActionScript 3.0 version ARToolkit class library. * Copyright (C)2008 Saqoosha * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * For further information please contact. * http://www.libspark.org/wiki/saqoosha/FLARToolKit * <saq(at)saqoosha.net> * */ package org.libspark.flartoolkit.processor { import jp.nyatla.nyartoolkit.as3.core.match.*; import jp.nyatla.nyartoolkit.as3.core.pickup.*; import jp.nyatla.nyartoolkit.as3.core.squaredetect.*; import jp.nyatla.nyartoolkit.as3.core.transmat.*; import jp.nyatla.nyartoolkit.as3.core.raster.*; import jp.nyatla.nyartoolkit.as3.core.raster.rgb.*; import jp.nyatla.nyartoolkit.as3.core.*; import jp.nyatla.nyartoolkit.as3.core.rasterfilter.rgb2bin.*; import jp.nyatla.nyartoolkit.as3.core.types.*; import jp.nyatla.nyartoolkit.as3.*; import jp.nyatla.nyartoolkit.as3.core.analyzer.raster.*; import jp.nyatla.nyartoolkit.as3.core.analyzer.raster.threshold.*; import jp.nyatla.as3utils.*; import org.libspark.flartoolkit.core.raster.*; import org.libspark.flartoolkit.core.rasterfilter.rgb2bin.*; import org.libspark.flartoolkit.core.squaredetect.*; import org.libspark.flartoolkit.core.*; import org.libspark.flartoolkit.*; import org.libspark.flartoolkit.core.param.*; import org.libspark.flartoolkit.core.raster.rgb.*; import org.libspark.flartoolkit.core.transmat.*; import org.libspark.flartoolkit.core.analyzer.raster.threshold.*; import org.libspark.flartoolkit.core.analyzer.raster.*; /** * ã“ã®ã‚¯ãƒ©ã‚¹ã¯ã€åŒæ™‚ã«ï¼‘個ã®ãƒžãƒ¼ã‚«ã‚’処ç†ã™ã‚‹ã“ã¨ã®ã§ãã‚‹ã€ã‚¢ãƒ—リケーションプãƒã‚»ãƒƒã‚µã§ã™ã€‚ * マーカã®å‡ºç¾ãƒ»ç§»å‹•ãƒ»æ¶ˆæ»…ã‚’ã€ã‚¤ãƒ™ãƒ³ãƒˆã§é€šçŸ¥ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ * クラスã«ã¯è¤‡æ•°ã®ãƒžãƒ¼ã‚«ã‚’登録ã§ãã¾ã™ã€‚一ã¤ã®ãƒžãƒ¼ã‚«ãŒè¦‹ã¤ã‹ã‚‹ã¨ã€ãƒ—ãƒã‚»ãƒƒã‚µã¯ç¶™ç¶šã—ã¦åŒã˜ãƒžãƒ¼ã‚«ã‚’ * 1ã¤ã ã‘èªè˜ã—続ã‘ã€è¦‹å¤±ã†ã¾ã§ã®é–“ã¯ä»–ã®ãƒžãƒ¼ã‚«ã‚’èªè˜ã—ã¾ã›ã‚“。 * * イベントã¯ã€ OnEnter→OnUpdate[n]→OnLeaveã®é †ã§ç™ºç”Ÿã—ã¾ã™ã€‚ * マーカãŒè¦‹ã¤ã‹ã‚‹ã¨ã¾ãšOnEnterãŒï¼‘度発生ã—ã¦ã€ä½•ç•ªã®ãƒžãƒ¼ã‚«ãŒç™ºè¦‹ã•ã‚ŒãŸã‹ãŒã‚ã‹ã‚Šã¾ã™ã€‚ * 次ã«OnUpdateã«ã‚ˆã‚Šã€ç¾åœ¨ã®å¤‰æ›è¡Œåˆ—ãŒé€£ç¶šã—ã¦æ¸¡ã•ã‚Œã¾ã™ã€‚最後ã«ãƒžãƒ¼ã‚«ã‚’見失ã†ã¨ã€OnLeave * イベントãŒç™ºç”Ÿã—ã¾ã™ã€‚ * */ public class FLSingleARMarkerProcesser { /**オーナーãŒè‡ªç”±ã«ä½¿ãˆã‚‹ã‚¿ã‚°å¤‰æ•°ã§ã™ã€‚ */ public var tag:Object; private var _lost_delay_count:int = 0; private var _lost_delay:int = 5; private var _square_detect:NyARSquareContourDetector; protected var _transmat:INyARTransMat; private var _offset:NyARRectOffset; private var _threshold:int = 110; // [AR]検出çµæžœã®ä¿å˜ç”¨ private var _bin_raster:FLARBinRaster; private var _tobin_filter:FLARRasterFilter_Threshold; protected var _current_arcode_index:int = -1; private var _threshold_detect:NyARRasterThresholdAnalyzer_SlidePTile; public function FLSingleARMarkerProcesser() { return; } private var _initialized:Boolean=false; protected function initInstance(i_param:FLARParam):void { //åˆæœŸåŒ–済? NyAS3Utils.assert(this._initialized==false); var scr_size:NyARIntSize = i_param.getScreenSize(); // 解æžã‚ªãƒ–ジェクトを作る this._square_detect = new FLARSquareContourDetector(scr_size); this._transmat = new NyARTransMat(i_param); this._tobin_filter=new FLARRasterFilter_Threshold(110); // 2値画åƒãƒãƒƒãƒ•ã‚¡ã‚’作る this._bin_raster = new FLARBinRaster(scr_size.w, scr_size.h); this._threshold_detect=new FLARRasterThresholdAnalyzer_SlidePTile(15,4); this._initialized=true; //コールãƒãƒƒã‚¯ãƒãƒ³ãƒ‰ãƒ© this._detectmarker_cb=new DetectSquareCB(i_param); this._offset=new NyARRectOffset(); return; } /*自動・手動ã®è¨å®šãŒå‡ºæ¥ãªã„ã®ã§ã€ã‚³ãƒ¡ãƒ³ãƒˆã‚¢ã‚¦ãƒˆ public void setThreshold(int i_threshold) { this._threshold = i_threshold; return; }*/ /**検出ã™ã‚‹ãƒžãƒ¼ã‚«ã‚³ãƒ¼ãƒ‰ã®é…列を指定ã—ã¾ã™ã€‚ 検出状態ã§ã“ã®é–¢æ•°ã‚’実行ã™ã‚‹ã¨ã€ * オブジェクト状態ã«å¼·åˆ¶ãƒªã‚»ãƒƒãƒˆãŒã‹ã‹ã‚Šã¾ã™ã€‚ */ public function setARCodeTable(i_ref_code_table:Vector.<FLARCode>,i_code_resolution:int,i_marker_width:Number):void { if (this._current_arcode_index != -1) { // 強制リセット reset(true); } //検出ã™ã‚‹ãƒžãƒ¼ã‚«ã‚»ãƒƒãƒˆã€æƒ…å ±ã€æ¤œå‡ºå™¨ã‚’作り直ã™ã€‚(1ピクセル4ãƒã‚¤ãƒ³ãƒˆã‚µãƒ³ãƒ—リング,マーカã®ãƒ‘ã‚¿ãƒ¼ãƒ³é ˜åŸŸã¯50%) this._detectmarker_cb.setNyARCodeTable(i_ref_code_table,i_code_resolution); this._offset.setSquare(i_marker_width); return; } public function reset(i_is_force:Boolean):void { if (this._current_arcode_index != -1 && i_is_force == false) { // 強制書ãæ›ãˆã§ãªã‘ã‚Œã°ã‚¤ãƒ™ãƒ³ãƒˆã‚³ãƒ¼ãƒ« this.onLeaveHandler(); } // カレントマーカをリセット this._current_arcode_index = -1; return; } private var _detectmarker_cb:DetectSquareCB; public function detectMarker(i_raster:INyARRgbRaster):void { // サイズãƒã‚§ãƒƒã‚¯ NyAS3Utils.assert(this._bin_raster.getSize().isEqualSize_int(i_raster.getSize().w, i_raster.getSize().h)); //BINイメージã¸ã®å¤‰æ› this._tobin_filter.setThreshold(this._threshold); this._tobin_filter.doFilter(i_raster, this._bin_raster); // スクエアコードを探㙠this._detectmarker_cb.init(i_raster,this._current_arcode_index); this._square_detect.detectMarkerCB(this._bin_raster,this._detectmarker_cb); // èªè˜çŠ¶æ…‹ã‚’æ›´æ–° var is_id_found:Boolean=updateStatus(this._detectmarker_cb.square,this._detectmarker_cb.code_index); //閾値フィードãƒãƒƒã‚¯(detectExistMarkerã«ã‚‚ã‚るよ) if(!is_id_found){ //マーカãŒãªã‘ã‚Œã°ã€æŽ¢ç´¢+DualPTailã§åŸºæº–è¼åº¦æ¤œç´¢ var th:int=this._threshold_detect.analyzeRaster(i_raster); this._threshold=(this._threshold+th)/2; } return; } /** * * @param i_new_detect_cf * @param i_exist_detect_cf */ public function setConfidenceThreshold(i_new_cf:Number,i_exist_cf:Number):void { this._detectmarker_cb.cf_threshold_exist=i_exist_cf; this._detectmarker_cb.cf_threshold_new=i_new_cf; } private var __NyARSquare_result:FLARTransMatResult = new FLARTransMatResult(); /** オブジェクトã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚’æ›´æ–°ã—ã€å¿…è¦ã«å¿œã˜ã¦ãƒãƒ³ãƒ‰ãƒ«é–¢æ•°ã‚’駆動ã—ã¾ã™ã€‚ * 戻り値ã¯ã€ã€Œå®Ÿéš›ã«ãƒžãƒ¼ã‚«ã‚’発見ã™ã‚‹äº‹ãŒã§ããŸã‹ã€ã§ã™ã€‚クラスã®çŠ¶æ…‹ã¨ã¯ç•°ãªã‚Šã¾ã™ã€‚ */ private function updateStatus(i_square:FLARSquare,i_code_index:int):Boolean { var result:FLARTransMatResult = this.__NyARSquare_result; if (this._current_arcode_index < 0) {// 未èªè˜ä¸ if (i_code_index < 0) {// 未èªè˜ã‹ã‚‰æœªèªè˜ã®é·ç§» // ãªã«ã‚‚ã—ãªã„よーん。 return false; } else {// 未èªè˜ã‹ã‚‰èªè˜ã®é·ç§» this._current_arcode_index = i_code_index; // ã‚¤ãƒ™ãƒ³ãƒˆç”Ÿæˆ // OnEnter this.onEnterHandler(i_code_index); // 変æ›è¡Œåˆ—ã‚’ä½œæˆ this._transmat.transMat(i_square, this._offset, result); // OnUpdate this.onUpdateHandler(i_square, result); this._lost_delay_count = 0; return true; } } else {// èªè˜ä¸ if (i_code_index < 0) {// èªè˜ã‹ã‚‰æœªèªè˜ã®é·ç§» this._lost_delay_count++; if (this._lost_delay < this._lost_delay_count) { // OnLeave this._current_arcode_index = -1; this.onLeaveHandler(); } return false; } else if (i_code_index == this._current_arcode_index) {// åŒã˜ARCodeã®å†èªè˜ // ã‚¤ãƒ™ãƒ³ãƒˆç”Ÿæˆ // 変æ›è¡Œåˆ—ã‚’ä½œæˆ this._transmat.transMat(i_square, this._offset, result); // OnUpdate this.onUpdateHandler(i_square, result); this._lost_delay_count = 0; return true; } else {// ç•°ãªã‚‹ã‚³ãƒ¼ãƒ‰ã®èªè˜â†’今ã¯ã‚µãƒãƒ¼ãƒˆã—ãªã„。 throw new NyARException(); } } } protected function onEnterHandler(i_code:int):void { throw new NyARException("onEnterHandler not implemented."); } protected function onLeaveHandler():void { throw new NyARException("onLeaveHandler not implemented."); } protected function onUpdateHandler(i_square:FLARSquare, result:FLARTransMatResult):void { throw new NyARException("onUpdateHandler not implemented."); } } } import jp.nyatla.nyartoolkit.as3.core.param.*; import jp.nyatla.nyartoolkit.as3.core.match.*; import jp.nyatla.nyartoolkit.as3.core.pickup.*; import jp.nyatla.nyartoolkit.as3.core.squaredetect.*; import jp.nyatla.nyartoolkit.as3.core.transmat.*; import jp.nyatla.nyartoolkit.as3.core.raster.*; import jp.nyatla.nyartoolkit.as3.core.raster.rgb.*; import jp.nyatla.nyartoolkit.as3.core.*; import jp.nyatla.nyartoolkit.as3.core.rasterfilter.rgb2bin.*; import jp.nyatla.nyartoolkit.as3.core.types.*; import jp.nyatla.nyartoolkit.as3.*; import org.libspark.flartoolkit.core.*; import org.libspark.flartoolkit.core.squaredetect.*; /** * detectMarkerã®ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯é–¢æ•° */ class DetectSquareCB implements NyARSquareContourDetector_IDetectMarkerCallback { //公開プãƒãƒ‘ティ public var square:FLARSquare=new FLARSquare(); public var confidence:Number=0.0; public var code_index:int=-1; public var cf_threshold_new:Number = 0.50; public var cf_threshold_exist:Number = 0.30; //å‚ç…§ private var _ref_raster:INyARRgbRaster; //所有インスタンス private var _inst_patt:INyARColorPatt; private var _deviation_data:NyARMatchPattDeviationColorData; private var _match_patt:Vector.<NyARMatchPatt_Color_WITHOUT_PCA>; private var __detectMarkerLite_mr:NyARMatchPattResult=new NyARMatchPattResult(); private var _coordline:NyARCoord2Linear; public function DetectSquareCB(i_param:NyARParam) { this._match_patt=null; this._coordline=new NyARCoord2Linear(i_param.getScreenSize(),i_param.getDistortionFactor()); return; } public function setNyARCodeTable(i_ref_code:Vector.<FLARCode>,i_code_resolution:int):void { /*unmanagedã§å®Ÿè£…ã™ã‚‹ã¨ãã¯ã€ã“ã“ã§ãƒªã‚½ãƒ¼ã‚¹è§£æ”¾ã‚’ã™ã‚‹ã“ã¨ã€‚*/ this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution,i_code_resolution); this._inst_patt=new NyARColorPatt_Perspective_O2(i_code_resolution,i_code_resolution,4,25); this._match_patt = new Vector.<NyARMatchPatt_Color_WITHOUT_PCA>(i_ref_code.length); for(var i:int=0;i<i_ref_code.length;i++){ this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code[i]); } } private var __tmp_vertex:Vector.<NyARIntPoint2d>=NyARIntPoint2d.createArray(4); private var _target_id:int; /** * Initialize call back handler. */ public function init(i_raster:INyARRgbRaster,i_target_id:int):void { this._ref_raster=i_raster; this._target_id=i_target_id; this.code_index=-1; this.confidence = Number.MIN_VALUE; } /** * 矩形ãŒè¦‹ä»˜ã‹ã‚‹ãŸã³ã«å‘¼ã³å‡ºã•ã‚Œã¾ã™ã€‚ * 発見ã—ãŸçŸ©å½¢ã®ãƒ‘ターンを検査ã—ã¦ã€æ–¹ä½ã‚’考慮ã—ãŸé ‚点データを確ä¿ã—ã¾ã™ã€‚ */ public function onSquareDetect(i_sender:NyARSquareContourDetector,i_coordx:Vector.<int>,i_coordy:Vector.<int>,i_coor_num:int,i_vertex_index:Vector.<int>):void { if (this._match_patt==null) { return; } //輪éƒåº§æ¨™ã‹ã‚‰é ‚点リストã«å¤‰æ› var vertex:Vector.<NyARIntPoint2d>=this.__tmp_vertex; vertex[0].x=i_coordx[i_vertex_index[0]]; vertex[0].y=i_coordy[i_vertex_index[0]]; vertex[1].x=i_coordx[i_vertex_index[1]]; vertex[1].y=i_coordy[i_vertex_index[1]]; vertex[2].x=i_coordx[i_vertex_index[2]]; vertex[2].y=i_coordy[i_vertex_index[2]]; vertex[3].x=i_coordx[i_vertex_index[3]]; vertex[3].y=i_coordy[i_vertex_index[3]]; //ç”»åƒã‚’å–å¾— if (!this._inst_patt.pickFromRaster(this._ref_raster,vertex)){ return;//å–得失敗 } //å–得パターンをカラー差分データã«å¤‰æ›ã—ã¦è©•ä¾¡ã™ã‚‹ã€‚ this._deviation_data.setRaster(this._inst_patt); //code_index,dir,c1ã«ãƒ‡ãƒ¼ã‚¿ã‚’得る。 var mr:NyARMatchPattResult=this.__detectMarkerLite_mr; var lcode_index:int = 0; var dir:int = 0; var c1:Number = 0; var i:int; for (i = 0; i < this._match_patt.length; i++) { this._match_patt[i].evaluate(this._deviation_data,mr); var c2:Number = mr.confidence; if (c1 < c2) { lcode_index = i; c1 = c2; dir = mr.direction; } } //èªè˜å‡¦ç† if (this._target_id == -1) { // マーカ未èªè˜ //ç¾åœ¨ã¯æœªèªè˜ if (c1 < this.cf_threshold_new) { return; } if (this.confidence > c1) { // 一致度ãŒä½Žã„。 return; } //èªè˜ã—ã¦ã„るマーカIDã‚’ä¿å˜ this.code_index=lcode_index; }else{ //ç¾åœ¨ã¯ãƒžãƒ¼ã‚«èªè˜ä¸ // ç¾åœ¨ã®ãƒžãƒ¼ã‚«ã‚’èªè˜ã—ãŸã‹ï¼Ÿ if (lcode_index != this._target_id) { // èªè˜ä¸ã®ãƒžãƒ¼ã‚«ã§ã¯ãªã„ã®ã§ç„¡è¦– return; } //èªè˜ä¸ã®é–¾å€¤ã‚ˆã‚Šå¤§ãã„ã‹ï¼Ÿ if (c1 < this.cf_threshold_exist) { return; } //ç¾åœ¨ã®å€™è£œã‚ˆã‚Šã‚‚一致度ã¯å¤§ãã„ã‹ï¼Ÿ if (this.confidence>c1) { return; } this.code_index=this._target_id; } //æ–°ã—ãèªè˜ã€ã¾ãŸã¯ç¶™ç¶šèªè˜ä¸ã«æ›´æ–°ãŒã‚ã£ãŸã¨ãã ã‘ã€Squareæƒ…å ±ã‚’æ›´æ–°ã™ã‚‹ã€‚ //ココã‹ã‚‰å…ˆã¯ã“ã®æ¡ä»¶ã§ã—ã‹å®Ÿè¡Œã•ã‚Œãªã„。 //一致率ã®é«˜ã„矩形ãŒã‚ã‚Œã°ã€æ–¹ä½ã‚’考慮ã—ã¦é ‚ç‚¹æƒ…å ±ã‚’ä½œæˆ this.confidence=c1; var sq:NyARSquare=this.square; //directionを考慮ã—ã¦ã€squareã‚’æ›´æ–°ã™ã‚‹ã€‚ for(i=0;i<4;i++){ var idx:int=(i+4 - dir) % 4; this._coordline.coord2Line(i_vertex_index[idx],i_vertex_index[(idx+1)%4],i_coordx,i_coordy,i_coor_num,sq.line[i]); } for (i = 0; i < 4; i++) { //ç›´ç·šåŒå£«ã®äº¤ç‚¹è¨ˆç®— if(!NyARLinear.crossPos(sq.line[i],sq.line[(i + 3) % 4],sq.sqvertex[i])){ throw new NyARException();//ã“ã“ã®ã‚¨ãƒ©ãƒ¼å¾©å¸°ã™ã‚‹ãªã‚‰ãƒ€ãƒ–ルãƒãƒƒãƒ•ã‚¡ã«ã™ã‚Œã°OK } } } }