--- /dev/null
+/* \r
+ * Capture Test NyARToolkitCSサンプルプログラム\r
+ * --------------------------------------------------------------------------------\r
+ * Copyright (C)2008 R.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
+ * \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
+ * 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
+ * \r
+ * For further information please contact.\r
+ * http://nyatla.jp/nyatoolkit/\r
+ * <airmail(at)ebony.plala.or.jp>\r
+ * \r
+ */\r
+package jp.nyatla.nyartoolkit.sandbox.x2;\r
+\r
+import jp.nyatla.nyartoolkit.NyARException;\r
+import jp.nyatla.nyartoolkit.core.*;\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.types.*;\r
+import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
+import jp.nyatla.nyartoolkit.core2.rasteranalyzer.threshold.NyARRasterThresholdAnalyzer_SlidePTile;\r
+\r
+/**\r
+ * このクラスは、同時に1個のマーカを処理することのできる、アプリケーションプロセッサです。\r
+ * マーカの出現・移動・消滅を、イベントで通知することができます。\r
+ * クラスには複数のマーカを登録できます。一つのマーカが見つかると、プロセッサは継続して同じマーカを\r
+ * 1つだけ認識し続け、見失うまでの間は他のマーカを認識しません。\r
+ * \r
+ * イベントは、 OnEnter→OnUpdate[n]→OnLeaveの順で発生します。\r
+ * マーカが見つかるとまずOnEnterが1度発生して、何番のマーカが発見されたかがわかります。\r
+ * 次にOnUpdateにより、現在の変換行列が連続して渡されます。最後にマーカを見失うと、OnLeave\r
+ * イベントが発生します。\r
+ * \r
+ */\r
+public abstract class SingleARMarkerProcesser_X2\r
+{\r
+ /**selectARCodeIndexFromListが値を返す時に使う変数型です。\r
+ */\r
+\r
+ private class TResult_selectARCodeIndex\r
+ {\r
+ public int direction;\r
+\r
+ public double confidence;\r
+\r
+ public int code_index;\r
+ }\r
+ /**オーナーが自由に使えるタグ変数です。\r
+ */\r
+ public Object tag;\r
+\r
+ private int _lost_delay_count = 0;\r
+\r
+ private int _lost_delay = 5;\r
+\r
+ private INyARSquareDetector _square_detect;\r
+\r
+ //<X2 patch>\r
+ protected NyARTransMat_X2 _transmat;\r
+ //</X2 patch>\r
+ private double _marker_width;\r
+\r
+ private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
+\r
+ private NyARSquareStack _square_list = new NyARSquareStack(100);\r
+\r
+ private INyARColorPatt _patt = null;\r
+\r
+ private double _cf_threshold_new = 0.30;\r
+ private double _cf_threshold_exist = 0.15;\r
+ \r
+ private int _threshold = 110;\r
+ // [AR]検出結果の保存用\r
+ private NyARBinRaster _bin_raster;\r
+\r
+ private NyARRasterFilter_ARToolkitThreshold _tobin_filter;\r
+\r
+ protected int _current_arcode_index = -1;\r
+\r
+ private NyARMatchPattDeviationColorData _deviation_data;\r
+ private NyARRasterThresholdAnalyzer_SlidePTile _threshold_detect;\r
+ \r
+ protected SingleARMarkerProcesser_X2()\r
+ {\r
+ return;\r
+ }\r
+\r
+\r
+ protected void initInstance(NyARParam i_param,int i_raster_type) throws NyARException\r
+ {\r
+ NyARIntSize scr_size = i_param.getScreenSize();\r
+ // 解析オブジェクトを作る\r
+//<X2 patch>\r
+ this._square_detect = new NyARSquareDetector_X2(i_param.getDistortionFactor(), scr_size);\r
+ this._transmat = new NyARTransMat_X2(i_param);\r
+//</X2 patch>\r
+\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
+ return;\r
+ }\r
+\r
+ /**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
+ * オブジェクト状態に強制リセットがかかります。\r
+ */\r
+ public void setARCodeTable(NyARCode[] i_ref_code_table, int i_code_resolution, double i_marker_width)\r
+ {\r
+ if (this._current_arcode_index != -1) {\r
+ // 強制リセット\r
+ reset(true);\r
+ }\r
+ //検出するマーカセット、情報、検出器を作り直す。(1ピクセル4ポイントサンプリング,マーカのパターン領域は50%)\r
+ this._patt = new NyARColorPatt_Perspective_O2(i_code_resolution, i_code_resolution,4,25);\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
+ return;\r
+ }\r
+\r
+ public void reset(boolean i_is_force)\r
+ {\r
+ if (this._current_arcode_index != -1 && i_is_force == false) {\r
+ // 強制書き換えでなければイベントコール\r
+ this.onLeaveHandler();\r
+ }\r
+ // カレントマーカをリセット\r
+ this._current_arcode_index = -1;\r
+ return;\r
+ }\r
+\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
+ 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
+ }\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
+ final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ //閾値フィードバック(detectExistMarkerにもあるよ)\r
+ if(!is_id_found){\r
+ //マーカがなければ、探索+DualPTailで基準輝度検索\r
+ this._threshold_detect.analyzeRaster(i_raster);\r
+ this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
+ }\r
+ }\r
+\r
+ /**マーカの継続認識 現在認識中のマーカを優先して認識します。 \r
+ * (注)この機能はたぶん今後いろいろ発展するからNewと混ぜないこと。\r
+ */\r
+ private void detectExistMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack, int i_current_id) 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
+ // 現在のマーカを認識したか?\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
+ final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ //閾値フィードバック(detectExistMarkerにもあるよ)\r
+ if(!is_id_found){\r
+ //マーカがなければ、探索+DualPTailで基準輝度検索\r
+ this._threshold_detect.analyzeRaster(i_raster);\r
+ this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
+ }\r
+ \r
+ }\r
+\r
+ private NyARTransMatResult __NyARSquare_result = new NyARTransMatResult();\r
+\r
+ /** オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
+ * 戻り値は、「実際にマーカを発見する事ができたか」です。クラスの状態とは異なります。\r
+ */\r
+ private boolean updateStatus(NyARSquare i_square, int i_code_index, double i_cf, int i_dir) 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
+ // 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._lost_delay_count++;\r
+ if (this._lost_delay < this._lost_delay_count) {\r
+ // OnLeave\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
+ // 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
+ }\r
+\r
+ protected abstract void onEnterHandler(int i_code);\r
+\r
+ protected abstract void onLeaveHandler();\r
+\r
+ protected abstract void onUpdateHandler(NyARSquare i_square, NyARTransMatResult result);\r
+}\r
}\r
} \r
/**\r
- * BYTE1D_B8G8R8X8_32のヒストグラム計算クラス\r
+ * BYTE1D_X8R8G8B8_32のヒストグラム計算クラス\r
*\r
*/ \r
final class CreateHistgramImpl_BYTE1D_X8R8G8B8_32 implements ICreateHistgramImpl\r
}\r
return sum;\r
}\r
- } \r
+ }\r
+ \r
+ /**\r
+ * WORD1D_R5G6B5_16LEのヒストグラム計算クラス\r
+ *\r
+ */ \r
+ final class CreateHistgramImpl_WORD1D_R5G6B5_16LE implements ICreateHistgramImpl\r
+ {\r
+ private int _v_interval;\r
+ public CreateHistgramImpl_WORD1D_R5G6B5_16LE(int i_v_interval)\r
+ {\r
+ this._v_interval = i_v_interval;\r
+ return;\r
+ }\r
+ public int createHistgramImpl(INyARBufferReader i_reader, NyARIntSize i_size, int[] o_histgram)\r
+ {\r
+ assert(i_reader.isEqualBufferType(INyARBufferReader.BUFFERFORMAT_WORD1D_R5G6B5_16LE));\r
+ short[] input = (short[])i_reader.getBuffer();\r
+ int pix_count = i_size.w;\r
+ int pix_mod_part = pix_count - (pix_count % 8);\r
+ int sum = 0;\r
+ for (int y = i_size.h - 1; y >= 0; y -= this._v_interval)\r
+ {\r
+ sum += i_size.w;\r
+ int pt = y * i_size.w;\r
+ int x, v;\r
+ for (x = pix_count - 1; x >= pix_mod_part; x--)\r
+ {\r
+ v =(int)input[pt];\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ pt++;\r
+ }\r
+ //タイリング\r
+ for (; x >= 0; x -= 8)\r
+ {\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ v =(int)input[pt];pt++;\r
+ v = (((v & 0xf800) >> 8) + ((v & 0x07e0) >> 3) + ((v & 0x001f) << 3))/3;\r
+ o_histgram[v]++;\r
+ }\r
+ }\r
+ return sum;\r
+ }\r
+ }\r
+\r
+ \r
+ \r
+ \r
\r
private int _persentage;\r
private int _threshold;\r
case INyARBufferReader.BUFFERFORMAT_BYTE1D_X8R8G8B8_32:\r
this._histgram = new CreateHistgramImpl_BYTE1D_X8R8G8B8_32(i_vertical_interval);\r
break;\r
+ case INyARBufferReader.BUFFERFORMAT_WORD1D_R5G6B5_16LE:\r
+ this._histgram=new CreateHistgramImpl_WORD1D_R5G6B5_16LE(i_vertical_interval);\r
+ break;\r
default:\r
throw new NyARException();\r
}\r
import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.*;\r
import jp.nyatla.nyartoolkit.core.types.*;\r
import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
+import jp.nyatla.nyartoolkit.core2.rasteranalyzer.threshold.NyARRasterThresholdAnalyzer_SlidePTile;\r
\r
/**\r
* このクラスは、同時に1個のマーカを処理することのできる、アプリケーションプロセッサです。\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
\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
return;\r
}\r
\r
- \r
+ /*自動・手動の設定が出来ないので、コメントアウト\r
public void setThreshold(int i_threshold)\r
{\r
this._threshold = i_threshold;\r
return;\r
- }\r
+ }*/\r
\r
/**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
* オブジェクト状態に強制リセットがかかります。\r
dir = detect_result.direction;\r
}\r
// 認識状態を更新\r
- updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ //閾値フィードバック(detectExistMarkerにもあるよ)\r
+ if(!is_id_found){\r
+ //マーカがなければ、探索+DualPTailで基準輝度検索\r
+ this._threshold_detect.analyzeRaster(i_raster);\r
+ this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
+ }\r
}\r
\r
/**マーカの継続認識 現在認識中のマーカを優先して認識します。 \r
square_index = i;\r
}\r
// 認識状態を更新\r
- updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+ //閾値フィードバック(detectExistMarkerにもあるよ)\r
+ if(!is_id_found){\r
+ //マーカがなければ、探索+DualPTailで基準輝度検索\r
+ this._threshold_detect.analyzeRaster(i_raster);\r
+ this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
+ }\r
+ \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, double i_cf, int i_dir) 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
// 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
// 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