/* \r
* Capture Test NyARToolkitCSサンプルプログラム\r
* --------------------------------------------------------------------------------\r
- * Copyright (C)2008 R.Iizuka\r
+ * The NyARToolkit is Java edition ARToolKit class library.\r
+ * Copyright (C)2008-2009 Ryo Iizuka\r
*\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
* \r
* This program is distributed in the hope that it will be useful,\r
* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
* GNU General Public License for more details.\r
- * \r
+ *\r
* You should have received a copy of the GNU General Public License\r
- * along with this framework; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
* \r
* For further information please contact.\r
* http://nyatla.jp/nyatoolkit/\r
- * <airmail(at)ebony.plala.or.jp>\r
+ * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
* \r
*/\r
package jp.nyatla.nyartoolkit.processor;\r
\r
import jp.nyatla.nyartoolkit.NyARException;\r
import jp.nyatla.nyartoolkit.core.*;\r
+import jp.nyatla.nyartoolkit.core.analyzer.raster.threshold.*;\r
import jp.nyatla.nyartoolkit.core.match.*;\r
import jp.nyatla.nyartoolkit.core.param.*;\r
import jp.nyatla.nyartoolkit.core.pickup.*;\r
import jp.nyatla.nyartoolkit.core.raster.*;\r
import jp.nyatla.nyartoolkit.core.raster.rgb.*;\r
import jp.nyatla.nyartoolkit.core.transmat.*;\r
-import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.*;\r
+import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.NyARRasterFilter_ARToolkitThreshold;\r
import jp.nyatla.nyartoolkit.core.types.*;\r
+import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
\r
/**\r
* このクラスは、同時に1個のマーカを処理することのできる、アプリケーションプロセッサです。\r
*/\r
public abstract class SingleARMarkerProcesser\r
{\r
- /**selectARCodeIndexFromListが値を返す時に使う変数型です。\r
+ /**\r
+ * detectMarkerのコールバック関数\r
*/\r
-\r
- private class TResult_selectARCodeIndex\r
+ private class DetectSquareCB implements NyARSquareContourDetector.IDetectMarkerCallback\r
{\r
- public int direction;\r
-\r
- public double confidence;\r
+ //公開プロパティ\r
+ public final NyARSquare square=new NyARSquare();\r
+ public double confidence=0.0;\r
+ public int code_index=-1; \r
+ public double cf_threshold_new = 0.50;\r
+ public double cf_threshold_exist = 0.30;\r
+ \r
+ //参照\r
+ private INyARRgbRaster _ref_raster;\r
+ //所有インスタンス\r
+ private INyARColorPatt _inst_patt;\r
+ private NyARMatchPattDeviationColorData _deviation_data;\r
+ private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
+ private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
+ private NyARCoord2Linear _coordline;\r
+ \r
+ public DetectSquareCB(NyARParam i_param)\r
+ {\r
+ this._match_patt=null;\r
+ this._coordline=new NyARCoord2Linear(i_param.getScreenSize(),i_param.getDistortionFactor());\r
+ return;\r
+ }\r
+ public void setNyARCodeTable(NyARCode[] i_ref_code,int i_code_resolution)\r
+ {\r
+ /*unmanagedで実装するときは、ここでリソース解放をすること。*/\r
+ this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution,i_code_resolution);\r
+ this._inst_patt=new NyARColorPatt_Perspective_O2(i_code_resolution,i_code_resolution,4,25);\r
+ this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code.length];\r
+ for(int i=0;i<i_ref_code.length;i++){\r
+ this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code[i]);\r
+ }\r
+ }\r
+ private NyARIntPoint2d[] __tmp_vertex=NyARIntPoint2d.createArray(4);\r
+ /**\r
+ * Initialize call back handler.\r
+ */\r
+ public void init(INyARRgbRaster i_raster)\r
+ {\r
+ this._ref_raster=i_raster;\r
+ this.code_index=-1;\r
+ this.confidence=Double.MIN_NORMAL;\r
+ }\r
\r
- public int code_index;\r
- }\r
+ /**\r
+ * 矩形が見付かるたびに呼び出されます。\r
+ * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。\r
+ */\r
+ public void onSquareDetect(NyARSquareContourDetector i_sender,int[] i_coordx,int[] i_coordy,int i_coor_num,int[] i_vertex_index) throws NyARException\r
+ {\r
+ if (this._match_patt==null) {\r
+ return;\r
+ }\r
+ //輪郭座標から頂点リストに変換\r
+ NyARIntPoint2d[] vertex=this.__tmp_vertex;\r
+ vertex[0].x=i_coordx[i_vertex_index[0]];\r
+ vertex[0].y=i_coordy[i_vertex_index[0]];\r
+ vertex[1].x=i_coordx[i_vertex_index[1]];\r
+ vertex[1].y=i_coordy[i_vertex_index[1]];\r
+ vertex[2].x=i_coordx[i_vertex_index[2]];\r
+ vertex[2].y=i_coordy[i_vertex_index[2]];\r
+ vertex[3].x=i_coordx[i_vertex_index[3]];\r
+ vertex[3].y=i_coordy[i_vertex_index[3]];\r
+ \r
+ //画像を取得\r
+ if (!this._inst_patt.pickFromRaster(this._ref_raster,vertex)){\r
+ return;//取得失敗\r
+ }\r
+ //取得パターンをカラー差分データに変換して評価する。\r
+ this._deviation_data.setRaster(this._inst_patt);\r
+\r
+ \r
+ //code_index,dir,c1にデータを得る。\r
+ final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
+ int lcode_index = 0;\r
+ int dir = 0;\r
+ double c1 = 0;\r
+ for (int i = 0; i < this._match_patt.length; i++) {\r
+ this._match_patt[i].evaluate(this._deviation_data,mr);\r
+ double c2 = mr.confidence;\r
+ if (c1 < c2) {\r
+ lcode_index = i;\r
+ c1 = c2;\r
+ dir = mr.direction;\r
+ }\r
+ }\r
+ \r
+ //認識処理\r
+ if (this.code_index == -1) { // マーカ未認識\r
+ //現在は未認識\r
+ if (c1 < this.cf_threshold_new) {\r
+ return;\r
+ }\r
+ if (this.confidence > c1) {\r
+ // 一致度が低い。\r
+ return;\r
+ }\r
+ //認識しているマーカIDを保存\r
+ this.code_index=lcode_index;\r
+ }else{\r
+ //現在はマーカ認識中 \r
+ // 現在のマーカを認識したか?\r
+ if (lcode_index != this.code_index) {\r
+ // 認識中のマーカではないので無視\r
+ return;\r
+ }\r
+ //認識中の閾値より大きいか?\r
+ if (c1 < this.cf_threshold_exist) {\r
+ return;\r
+ }\r
+ //現在の候補よりも一致度は大きいか?\r
+ if (this.confidence>c1) {\r
+ return;\r
+ }\r
+ }\r
+ //新しく認識、または継続認識中に更新があったときだけ、Square情報を更新する。\r
+ //ココから先はこの条件でしか実行されない。\r
+ \r
+ //一致率の高い矩形があれば、方位を考慮して頂点情報を作成\r
+ this.confidence=c1;\r
+ NyARSquare sq=this.square;\r
+ //directionを考慮して、squareを更新する。\r
+ for(int i=0;i<4;i++){\r
+ int idx=(i+4 - dir) % 4;\r
+ this._coordline.coord2Line(i_vertex_index[idx],i_vertex_index[(idx+1)%4],i_coordx,i_coordy,i_coor_num,sq.line[i]);\r
+ }\r
+ for (int i = 0; i < 4; i++) {\r
+ //直線同士の交点計算\r
+ if(!NyARLinear.crossPos(sq.line[i],sq.line[(i + 3) % 4],sq.sqvertex[i])){\r
+ throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK\r
+ }\r
+ }\r
+ }\r
+ } \r
/**オーナーが自由に使えるタグ変数です。\r
*/\r
public Object tag;\r
\r
private int _lost_delay = 5;\r
\r
- private NyARSquareDetector _square_detect;\r
-\r
- protected NyARTransMat _transmat;\r
-\r
- private double _marker_width;\r
-\r
- private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
+ private NyARSquareContourDetector _square_detect;\r
\r
- private NyARSquareStack _square_list = new NyARSquareStack(100);\r
+ protected INyARTransMat _transmat;\r
\r
- private NyARColorPatt_O3 _patt = null;\r
-\r
- private double _cf_threshold_new = 0.30;\r
-\r
- private double _cf_threshold_exist = 0.15;\r
- \r
+ private NyARRectOffset _offset; \r
private int _threshold = 110;\r
// [AR]検出結果の保存用\r
private NyARBinRaster _bin_raster;\r
\r
protected int _current_arcode_index = -1;\r
\r
- private NyARMatchPattDeviationColorData _deviation_data;\r
+ private NyARRasterThresholdAnalyzer_SlidePTile _threshold_detect;\r
+ \r
+ protected SingleARMarkerProcesser()\r
+ {\r
+ return;\r
+ }\r
\r
+ private boolean _initialized=false;\r
\r
- public SingleARMarkerProcesser(NyARParam i_param,int i_raster_type) throws NyARException\r
+ protected void initInstance(NyARParam i_param,int i_raster_type) throws NyARException\r
{\r
+ //初期化済?\r
+ assert(this._initialized==false);\r
+ \r
NyARIntSize scr_size = i_param.getScreenSize();\r
// 解析オブジェクトを作る\r
- this._square_detect = new NyARSquareDetector(i_param.getDistortionFactor(), scr_size);\r
+ this._square_detect = new NyARSquareContourDetector_Rle(i_param.getDistortionFactor(), scr_size);\r
this._transmat = new NyARTransMat(i_param);\r
this._tobin_filter=new NyARRasterFilter_ARToolkitThreshold(110,i_raster_type);\r
\r
// 2値画像バッファを作る\r
this._bin_raster = new NyARBinRaster(scr_size.w, scr_size.h);\r
+ this._threshold_detect=new NyARRasterThresholdAnalyzer_SlidePTile(15,i_raster_type,4);\r
+ this._initialized=true;\r
+ //コールバックハンドラ\r
+ this._detectmarker_cb=new DetectSquareCB(i_param);\r
+ this._offset=new NyARRectOffset();\r
return;\r
}\r
\r
+ /*自動・手動の設定が出来ないので、コメントアウト\r
public void setThreshold(int i_threshold)\r
{\r
this._threshold = i_threshold;\r
return;\r
- }\r
+ }*/\r
\r
/**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
* オブジェクト状態に強制リセットがかかります。\r
// 強制リセット\r
reset(true);\r
}\r
- // 検出するマーカセット、情報、検出器を作り直す。\r
- this._patt = new NyARColorPatt_O3(i_code_resolution, i_code_resolution);\r
- this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution, i_code_resolution);\r
- this._marker_width = i_marker_width;\r
-\r
- this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code_table.length];\r
- for(int i=0;i<i_ref_code_table.length;i++){\r
- this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code_table[i]);\r
- }\r
+ //検出するマーカセット、情報、検出器を作り直す。(1ピクセル4ポイントサンプリング,マーカのパターン領域は50%)\r
+ this._detectmarker_cb.setNyARCodeTable(i_ref_code_table,i_code_resolution);\r
+ this._offset.setSquare(i_marker_width);\r
return;\r
}\r
\r
this._current_arcode_index = -1;\r
return;\r
}\r
-\r
+ private DetectSquareCB _detectmarker_cb;\r
public void detectMarker(INyARRgbRaster i_raster) throws NyARException\r
{\r
// サイズチェック\r
assert(this._bin_raster.getSize().isEqualSize(i_raster.getSize().w, i_raster.getSize().h));\r
\r
- // コードテーブルが無ければここで終わり\r
- if (this._match_patt== null) {\r
- return;\r
- }\r
-\r
- // ラスタを(1/4の画像の)2値イメージに変換する.\r
+ //BINイメージへの変換\r
this._tobin_filter.setThreshold(this._threshold);\r
this._tobin_filter.doFilter(i_raster, this._bin_raster);\r
\r
- NyARSquareStack square_stack = this._square_list;\r
// スクエアコードを探す\r
- this._square_detect.detectMarker(this._bin_raster, square_stack);\r
- // 認識処理\r
- if (this._current_arcode_index == -1) { // マーカ未認識\r
- detectNewMarker(i_raster, square_stack);\r
- } else { // マーカ認識中\r
- detectExistMarker(i_raster, square_stack, this._current_arcode_index);\r
+ this._detectmarker_cb.init(i_raster);\r
+ this._square_detect.detectMarkerCB(this._bin_raster,this._detectmarker_cb);\r
+ \r
+ // 認識状態を更新\r
+ final boolean is_id_found=updateStatus(this._detectmarker_cb.square,this._detectmarker_cb.code_index);\r
+ //閾値フィードバック(detectExistMarkerにもあるよ)\r
+ if(!is_id_found){\r
+ //マーカがなければ、探索+DualPTailで基準輝度検索\r
+ int th=this._threshold_detect.analyzeRaster(i_raster);\r
+ this._threshold=(this._threshold+th)/2;\r
}\r
+ \r
+ \r
return;\r
}\r
-\r
- \r
- private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
- \r
- /**ARCodeのリストから、最も一致するコード番号を検索します。\r
- */\r
- private boolean selectARCodeIndexFromList(INyARRgbRaster i_raster, NyARSquare i_square, TResult_selectARCodeIndex o_result) throws NyARException\r
- {\r
- // 現在コードテーブルはアクティブ?\r
- if (this._match_patt==null) {\r
- return false;\r
- }\r
- // 評価基準になるパターンをイメージから切り出す\r
- if (!this._patt.pickFromRaster(i_raster, i_square)) {\r
- return false;\r
- }\r
- //評価データを作成して、評価器にセット\r
- this._deviation_data.setRaster(this._patt); \r
- final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
- int code_index = 0;\r
- int dir = 0;\r
- double c1 = 0;\r
- // コードと比較する\r
- for (int i = 0; i < this._match_patt.length; i++) {\r
- this._match_patt[i].evaluate(this._deviation_data,mr);\r
- double c2 = mr.confidence;\r
- if (c1 < c2) {\r
- code_index = i;\r
- c1 = c2;\r
- dir = mr.direction;\r
- }\r
- }\r
- o_result.code_index = code_index;\r
- o_result.direction = dir;\r
- o_result.confidence = c1;\r
- return true;\r
- }\r
-\r
- private TResult_selectARCodeIndex __detect_X_Marker_detect_result = new TResult_selectARCodeIndex();\r
-\r
- /**新規マーカ検索 現在認識中のマーカがないものとして、最も認識しやすいマーカを1個認識します。\r
- */\r
- private void detectNewMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack) throws NyARException\r
- {\r
- int number_of_square = i_stack.getLength();\r
- double cf = 0;\r
- int dir = 0;\r
- int code_index = -1;\r
- int square_index = 0;\r
- TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
- for (int i = 0; i < number_of_square; i++) {\r
- if (!selectARCodeIndexFromList(i_raster, (i_stack.getItem(i)), detect_result)) {\r
- // 見つからない。\r
- return;\r
- }\r
- if (detect_result.confidence < this._cf_threshold_new) {\r
- continue;\r
- }\r
- if (detect_result.confidence < cf) {\r
- // 一致度が低い。\r
- continue;\r
- }\r
- cf = detect_result.confidence;\r
- code_index = detect_result.code_index;\r
- square_index = i;\r
- dir = detect_result.direction;\r
- }\r
- // 認識状態を更新\r
- updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
- }\r
-\r
- /**マーカの継続認識 現在認識中のマーカを優先して認識します。 \r
- * (注)この機能はたぶん今後いろいろ発展するからNewと混ぜないこと。\r
+ /**\r
+ * \r
+ * @param i_new_detect_cf\r
+ * @param i_exist_detect_cf\r
*/\r
- private void detectExistMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack, int i_current_id) throws NyARException\r
+ public void setConfidenceThreshold(double i_new_cf,double i_exist_cf)\r
{\r
- int number_of_square = i_stack.getLength();\r
- double cf = 0;\r
- int dir = 0;\r
- int code_index = -1;\r
- int square_index = 0;\r
- TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
- for (int i = 0; i < number_of_square; i++) {\r
- if (!selectARCodeIndexFromList(i_raster,i_stack.getItem(i), detect_result)) {\r
- // 見つからない。\r
- return;\r
- }\r
- // 現在のマーカを認識したか?\r
- if (detect_result.code_index != i_current_id) {\r
- // 認識中のマーカではないので無視\r
- continue;\r
- }\r
- if (detect_result.confidence < this._cf_threshold_exist) {\r
- continue;\r
- }\r
- if (detect_result.confidence < cf) {\r
- // 一致度が高い方を選ぶ\r
- continue;\r
- }\r
- cf = detect_result.confidence;\r
- code_index = detect_result.code_index;\r
- dir = detect_result.direction;\r
- square_index = i;\r
- }\r
- // 認識状態を更新\r
- updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ this._detectmarker_cb.cf_threshold_exist=i_exist_cf;\r
+ this._detectmarker_cb.cf_threshold_new=i_new_cf;\r
}\r
\r
private NyARTransMatResult __NyARSquare_result = new NyARTransMatResult();\r
\r
- /**オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
+ /** オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
+ * 戻り値は、「実際にマーカを発見する事ができたか」です。クラスの状態とは異なります。\r
*/\r
- private void updateStatus(NyARSquare i_square, int i_code_index, double i_cf, int i_dir) throws NyARException\r
+ private boolean updateStatus(NyARSquare i_square, int i_code_index) throws NyARException\r
{\r
NyARTransMatResult result = this.__NyARSquare_result;\r
if (this._current_arcode_index < 0) {// 未認識中\r
if (i_code_index < 0) {// 未認識から未認識の遷移\r
// なにもしないよーん。\r
+ return false;\r
} else {// 未認識から認識の遷移\r
this._current_arcode_index = i_code_index;\r
// イベント生成\r
// OnEnter\r
this.onEnterHandler(i_code_index);\r
// 変換行列を作成\r
- this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
+ this._transmat.transMat(i_square, this._offset, result);\r
// OnUpdate\r
this.onUpdateHandler(i_square, result);\r
this._lost_delay_count = 0;\r
+ return true;\r
}\r
} else {// 認識中\r
if (i_code_index < 0) {// 認識から未認識の遷移\r
this._current_arcode_index = -1;\r
this.onLeaveHandler();\r
}\r
+ return false;\r
} else if (i_code_index == this._current_arcode_index) {// 同じARCodeの再認識\r
// イベント生成\r
// 変換行列を作成\r
- this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
+ this._transmat.transMatContinue(i_square, this._offset, result);\r
// OnUpdate\r
this.onUpdateHandler(i_square, result);\r
this._lost_delay_count = 0;\r
+ return true;\r
} else {// 異なるコードの認識→今はサポートしない。\r
throw new NyARException();\r
}\r
}\r
- return;\r
}\r
\r
protected abstract void onEnterHandler(int i_code);\r