public bool getContour(NyARBinRaster i_raster, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
        {
            Debug.Assert(i_raster.isEqualBufferType(NyARBufferType.INT1D_BIN_8));
            NyARIntSize s = i_raster.getSize();

            return(impl_getContour(i_raster, 0, 0, s.w - 1, s.h - 1, 0, i_entry_x, i_entry_y, o_coord));
        }
 /**
  * コンストラクタです。
  * 入力画像のサイズを指定して、インスタンスを生成します。
  * @param i_size
  * 入力画像のサイズ
  */
 public NyARSquareContourDetector_Rle(NyARIntSize i_size)
 {
     this.setupImageDriver(i_size);
     //ラベリングのサイズを指定したいときはsetAreaRangeを使ってね。
     this._coord = new NyARIntCoordinates((i_size.w + i_size.h) * 2);
     return;
 }
 /**
  * コンストラクタです。
  * 入力画像のサイズを指定して、インスタンスを生成します。
  * @param i_size
  * 入力画像のサイズ
  */
 public NyARSquareContourDetector_Rle(NyARIntSize i_size)
 {
     this.setupImageDriver(i_size);
     //ラベリングのサイズを指定したいときはsetAreaRangeを使ってね。
     this._coord = new NyARIntCoordinates((i_size.w + i_size.h) * 2);
     return;
 }
        /**
         * @override
         */
        public override void detectMarker(NyARBinRaster i_raster)
        {
            NyARRleLabelFragmentInfoPtrStack flagment = this._labeling.label_stack;
            NyARLabelOverlapChecker <NyARRleLabelFragmentInfo> overlap = this._overlap_checker;

            // ラベル数が0ならここまで
            flagment.clear();
            this._labeling.labeling(i_raster);
            int label_num = flagment.getLength();

            if (label_num < 1)
            {
                return;
            }
            //ラベルをソートしておく
            flagment.sortByArea();
            //ラベルリストを取得
            NyARRleLabelFragmentInfo[] labels = flagment.getArray();

            NyARIntCoordinates coord = this._coord;

            int[] mkvertex = this.__detectMarker_mkvertex;


            //重なりチェッカの最大数を設定
            overlap.setMaxLabels(label_num);

            for (int i = 0; i < label_num; i++)
            {
                NyARRleLabelFragmentInfo label_pt = labels[i];
                int label_area = label_pt.area;

                // 既に検出された矩形との重なりを確認
                if (!overlap.check(label_pt))
                {
                    // 重なっているようだ。
                    continue;
                }

                //輪郭を取得
                if (!this._cpickup.getContour(i_raster, label_pt.entry_x, label_pt.clip_t, coord))
                {
                    continue;
                }
                //輪郭線をチェックして、矩形かどうかを判定。矩形ならばmkvertexに取得
                if (!this._coord2vertex.getVertexIndexes(coord, label_area, mkvertex))
                {
                    // 頂点の取得が出来なかった
                    continue;
                }
                //矩形を発見したことをコールバック関数で通知
                this.onSquareDetect(coord, mkvertex);

                // 検出済の矩形の属したラベルを重なりチェックに追加する。
                overlap.push(label_pt);
            }
            return;
        }
        /**
         * 最大i_squre_max個のマーカーを検出するクラスを作成する。
         *
         * @param i_param
         */
        public NyARSquareContourDetector_ARToolKit(NyARIntSize i_size)
        {
            this._width    = i_size.w;
            this._height   = i_size.h;
            this._labeling = new NyARLabeling_ARToolKit();
            this._limage   = new NyARLabelingImage(this._width, this._height);

            // 輪郭の最大長は画面に映りうる最大の長方形サイズ。
            int number_of_coord = (this._width + this._height) * 2;

            // 輪郭バッファは頂点変換をするので、輪郭バッファの2倍取る。
            this._coord = new NyARIntCoordinates(number_of_coord);
            return;
        }
        /**
         * コンストラクタ
         * @param i_size
         * 入力画像のサイズ
         */
        public NyARSquareContourDetector_Rle(NyARIntSize i_size)
        {
            //特性確認
            Debug.Assert(NyARLabeling_Rle._sf_label_array_safe_reference);
            this._width  = i_size.w;
            this._height = i_size.h;
            //ラベリングのサイズを指定したいときはsetAreaRangeを使ってね。
            this._labeling = new Labeling(this._width, this._height);

            // 輪郭の最大長は画面に映りうる最大の長方形サイズ。
            int number_of_coord = (this._width + this._height) * 2;

            // 輪郭バッファ
            this._coord = new NyARIntCoordinates(number_of_coord);
            return;
        }
            /**
             * 矩形が見付かるたびに呼び出されます。
             * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。
             */
            public void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index)
            {
                if (this._match_patt == null)
                {
                    return;
                }
                //輪郭座標から頂点リストに変換
                NyARIntPoint2d[] vertex = this.__ref_vertex;
                vertex[0] = i_coord.items[i_vertex_index[0]];
                vertex[1] = i_coord.items[i_vertex_index[1]];
                vertex[2] = i_coord.items[i_vertex_index[2]];
                vertex[3] = i_coord.items[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にデータを得る。
                NyARMatchPattResult mr = this.__detectMarkerLite_mr;
                int lcode_index = 0;
                int dir = 0;
                double c1 = 0;
                for (int i = 0; i < this._match_patt.Length; i++)
                {
                    this._match_patt[i].evaluate(this._deviation_data, mr);
                    double c2 = 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;
                NyARSquare sq = this.square;
                //directionを考慮して、squareを更新する。
                for (int i = 0; i < 4; i++)
                {
                    int idx = (i + 4 - dir) % 4;
                    this._coordline.coord2Line(i_vertex_index[idx], i_vertex_index[(idx + 1) % 4], i_coord, sq.line[i]);
                }
                for (int i = 0; i < 4; i++)
                {
                    //直線同士の交点計算
                    if (!sq.line[i].crossPos(sq.line[(i + 3) % 4], sq.sqvertex[i]))
                    {
                        throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK
                    }
                }
            }
        /**
         * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。
         * 開始点は、輪郭の一部である必要があります。
         * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。
         * @param i_raster
         * 輪郭線を抽出するラスタを指定します。
         * @param i_th
         * 輪郭とみなす暗点の敷居値を指定します。
         * @param i_entry_x
         * 輪郭抽出の開始点です。
         * @param i_entry_y
         * 輪郭抽出の開始点です。
         * @param o_coord
         * 輪郭点を格納する配列を指定します。i_array_sizeよりも大きなサイズの配列が必要です。
         * @return
         * 輪郭の抽出に成功するとtrueを返します。輪郭抽出に十分なバッファが無いと、falseになります。
         * @
         */
        public bool getContour(INyARGrayscaleRaster i_raster, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
        {
            NyARIntSize s = i_raster.getSize();

            //ラスタドライバの切り替え
            if (i_raster != this._ref_last_input_raster)
            {
                this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver));
                this._ref_last_input_raster = i_raster;
            }
            return(this._imdriver.getContour(0, 0, s.w - 1, s.h - 1, i_entry_x, i_entry_y, i_th, o_coord));
        }
            /**
             * 矩形が見付かるたびに呼び出されます。
             * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。
             */
		    public void detectMarkerCallback(NyARIntCoordinates i_coord,int[] i_vertex_index)
            {
                //既に発見済なら終了
                if (this.marker_data != null)
                {
                    return;
                }
                //輪郭座標から頂点リストに変換
                NyARIntPoint2d[] vertex = this.__ref_vertex;
                vertex[0] = i_coord.items[i_vertex_index[0]];
                vertex[1] = i_coord.items[i_vertex_index[1]];
                vertex[2] = i_coord.items[i_vertex_index[2]];
                vertex[3] = i_coord.items[i_vertex_index[3]];

                NyIdMarkerParam param = this._marker_param;
                NyIdMarkerPattern patt_data = this._marker_data;
                // 評価基準になるパターンをイメージから切り出す
                if (!this._id_pickup.pickFromRaster(this._ref_raster.getGsPixelDriver(), vertex, patt_data, param))
                {
                    return;
                }
                //エンコード
                if (!this._encoder.encode(patt_data, this._data_temp))
                {
                    return;
                }

                //継続認識要求されている?
                if (this._prev_data == null)
                {
                    //継続認識要求なし
                    this._current_data.copyFrom(this._data_temp);
                }
                else
                {
                    //継続認識要求あり
                    if (!this._prev_data.isEqual((this._data_temp)))
                    {
                        return;//認識請求のあったIDと違う。
                    }
                }
                //新しく認識、または継続認識中に更新があったときだけ、Square情報を更新する。
                //ココから先はこの条件でしか実行されない。
                NyARSquare sq = this.square;
                //directionを考慮して、squareを更新する。
                for (int i = 0; i < 4; i++)
                {
                    int idx = (i + 4 - param.direction) % 4;
                    this._coordline.coord2Line(i_vertex_index[idx], i_vertex_index[(idx + 1) % 4], i_coord, sq.line[i]);
                }
                for (int i = 0; i < 4; i++)
                {
                    //直線同士の交点計算
                    if (!sq.line[i].crossPos(sq.line[(i + 3) % 4], sq.sqvertex[i]))
                    {
                        throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK
                    }
                }
                this.threshold = param.threshold;
                this.marker_data = this._current_data;//みつかった。
            }
        public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord)
        {
            Debug.Assert(i_t <= i_entry_x);
            int[] buf   = (int[])this._ref_raster.getBuffer();
            int[] xdir  = _getContour_xdir;   // static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
            int[] ydir  = _getContour_ydir;   // static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};
            int   width = this._ref_raster.getWidth();

            //クリップ領域の上端に接しているポイントを得る。
            NyARIntPoint2d[] coord = o_coord.items;
            int max_coord          = o_coord.items.Length;

            coord[0].x = i_entry_x;
            coord[0].y = i_entry_y;
            int coord_num = 1;
            int dir       = 5;

            int c = i_entry_x;
            int r = i_entry_y;

            for (;;)
            {
                dir = (dir + 5) % 8;        //dirの正規化
                //ここは頑張ればもっと最適化できると思うよ。
                //4隅以外の境界接地の場合に、境界チェックを省略するとかね。
                if (c > i_l && c < i_r && r > i_t && r < i_b)
                {
                    for (;;)            //gotoのエミュレート用のfor文
                                        //境界に接していないとき(暗点判定)
                    {
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        dir++;
                        if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th)
                        {
                            break;
                        }
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARRuntimeException();
                    }
                }
                else
                {
                    //境界に接しているとき
                    int i;
                    for (i = 0; i < 8; i++)
                    {
                        int x = c + xdir[dir];
                        int y = r + ydir[dir];
                        //境界チェック
                        if (x >= i_l && x <= i_r && y >= i_t && y <= i_b)
                        {
                            if (buf[(y) * width + (x)] <= i_th)
                            {
                                break;
                            }
                        }
                        dir++;                //倍長テーブルを参照するので問題なし
                    }
                    if (i == 8)
                    {
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARRuntimeException();// return(-1);
                    }
                }
                // xcoordとycoordをc,rにも保存
                c = c + xdir[dir];
                r = r + ydir[dir];
                coord[coord_num].x = c;
                coord[coord_num].y = r;
                //終了条件判定
                if (c == i_entry_x && r == i_entry_y)
                {
                    //開始点と同じピクセルに到達したら、終点の可能性がある。
                    coord_num++;
                    //末端のチェック
                    if (coord_num == max_coord)
                    {
                        //輪郭bufが末端に達した
                        return(false);
                    }
                    //末端候補の次のピクセルを調べる
                    dir = (dir + 5) % 8;            //dirの正規化
                    int i;
                    for (i = 0; i < 8; i++)
                    {
                        int x = c + xdir[dir];
                        int y = r + ydir[dir];
                        //境界チェック
                        if (x >= i_l && x <= i_r && y >= i_t && y <= i_b)
                        {
                            if (buf[(y) * width + (x)] <= i_th)
                            {
                                break;
                            }
                        }
                        dir++;                //倍長テーブルを参照するので問題なし
                    }
                    if (i == 8)
                    {
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARRuntimeException();
                    }
                    //得たピクセルが、[1]と同じならば、末端である。
                    c = c + xdir[dir];
                    r = r + ydir[dir];
                    if (coord[1].x == c && coord[1].y == r)
                    {
                        //終点に達している。
                        o_coord.length = coord_num;
                        break;
                    }
                    else
                    {
                        //終点ではない。
                        coord[coord_num].x = c;
                        coord[coord_num].y = r;
                    }
                }
                coord_num++;
                //末端のチェック
                if (coord_num == max_coord)
                {
                    //輪郭が末端に達した
                    return(false);
                }
            }
            return(true);
        }
        public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord)
        {
            Debug.Assert(i_t <= i_entry_x);
            INyARGrayscaleRaster raster = this._ref_raster;

            int[] xdir = _getContour_xdir; // static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
            int[] ydir = _getContour_ydir; // static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};
            //クリップ領域の上端に接しているポイントを得る。
            NyARIntPoint2d[] coord = o_coord.items;
            int max_coord          = o_coord.items.Length;

            coord[0].x = i_entry_x;
            coord[0].y = i_entry_y;
            int coord_num = 1;
            int dir       = 5;

            int c = i_entry_x;
            int r = i_entry_y;

            for (; ;)
            {
                dir = (dir + 5) % 8;//dirの正規化
                //境界に接しているとき
                int i;
                for (i = 0; i < 8; i++)
                {
                    int x = c + xdir[dir];
                    int y = r + ydir[dir];
                    //境界チェック
                    if (x >= i_l && x <= i_r && y >= i_t && y <= i_b)
                    {
                        if (raster.getPixel(x, y) <= i_th)
                        {
                            break;
                        }
                    }
                    dir++;//倍長テーブルを参照するので問題なし
                }
                if (i == 8)
                {
                    //8方向全て調べたけどラベルが無いよ?
                    throw new NyARRuntimeException();// return(-1);
                }
                // xcoordとycoordをc,rにも保存
                c = c + xdir[dir];
                r = r + ydir[dir];
                coord[coord_num].x = c;
                coord[coord_num].y = r;
                //終了条件判定
                if (c == i_entry_x && r == i_entry_y)
                {
                    //開始点と同じピクセルに到達したら、終点の可能性がある。
                    coord_num++;
                    //末端のチェック
                    if (coord_num == max_coord)
                    {
                        //輪郭bufが末端に達した
                        return(false);
                    }
                    //末端候補の次のピクセルを調べる
                    dir = (dir + 5) % 8;//dirの正規化
                    for (i = 0; i < 8; i++)
                    {
                        int x = c + xdir[dir];
                        int y = r + ydir[dir];
                        //境界チェック
                        if (x >= i_l && x <= i_r && y >= i_t && y <= i_b)
                        {
                            if (raster.getPixel(x, y) <= i_th)
                            {
                                break;
                            }
                        }
                        dir++;//倍長テーブルを参照するので問題なし
                    }
                    if (i == 8)
                    {
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARRuntimeException();
                    }
                    //得たピクセルが、[1]と同じならば、末端である。
                    c = c + xdir[dir];
                    r = r + ydir[dir];
                    if (coord[1].x == c && coord[1].y == r)
                    {
                        //終点に達している。
                        o_coord.length = coord_num;
                        break;
                    }
                    else
                    {
                        //終点ではない。
                        coord[coord_num].x = c;
                        coord[coord_num].y = r;
                    }
                }
                coord_num++;
                //末端のチェック
                if (coord_num == max_coord)
                {
                    //輪郭が末端に達した
                    return(false);
                }
            }
            return(true);
        }
 public abstract bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord);
Exemple #13
0
 /**
  * 通知ハンドラです。
  * この関数は、detectMarker関数のコールバック関数として機能します。
  * 継承先のクラスで、矩形の発見時の処理をここに記述してください。
  * @param i_coord
  * @param i_coor_num
  * @param i_vertex_index
  * @throws NyARException
  */
 protected abstract void onSquareDetect(NyARIntCoordinates i_coord, int[] i_vertex_index);
        public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord)
        {
            Debug.Assert(i_t <= i_entry_x);
            INyARGsPixelDriver reader = this._ref_raster.getGsPixelDriver();
            int[] xdir = _getContour_xdir;// static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
            int[] ydir = _getContour_ydir;// static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};
            //クリップ領域の上端に接しているポイントを得る。
            NyARIntPoint2d[] coord = o_coord.items;
            int max_coord = o_coord.items.Length;
            coord[0].x = i_entry_x;
            coord[0].y = i_entry_y;
            int coord_num = 1;
            int dir = 5;

            int c = i_entry_x;
            int r = i_entry_y;
            for (; ; )
            {
                dir = (dir + 5) % 8;//dirの正規化
                //境界に接しているとき
                int i;
                for (i = 0; i < 8; i++)
                {
                    int x = c + xdir[dir];
                    int y = r + ydir[dir];
                    //境界チェック
                    if (x >= i_l && x <= i_r && y >= i_t && y <= i_b)
                    {
                        if (reader.getPixel(x, y) <= i_th)
                        {
                            break;
                        }
                    }
                    dir++;//倍長テーブルを参照するので問題なし
                }
                if (i == 8)
                {
                    //8方向全て調べたけどラベルが無いよ?
                    throw new NyARException();// return(-1);
                }
                // xcoordとycoordをc,rにも保存
                c = c + xdir[dir];
                r = r + ydir[dir];
                coord[coord_num].x = c;
                coord[coord_num].y = r;
                //終了条件判定
                if (c == i_entry_x && r == i_entry_y)
                {
                    //開始点と同じピクセルに到達したら、終点の可能性がある。
                    coord_num++;
                    //末端のチェック
                    if (coord_num == max_coord)
                    {
                        //輪郭bufが末端に達した
                        return false;
                    }
                    //末端候補の次のピクセルを調べる
                    dir = (dir + 5) % 8;//dirの正規化
                    for (i = 0; i < 8; i++)
                    {
                        int x = c + xdir[dir];
                        int y = r + ydir[dir];
                        //境界チェック
                        if (x >= i_l && x <= i_r && y >= i_t && y <= i_b)
                        {
                            if (reader.getPixel(x, y) <= i_th)
                            {
                                break;
                            }
                        }
                        dir++;//倍長テーブルを参照するので問題なし
                    }
                    if (i == 8)
                    {
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARException();
                    }
                    //得たピクセルが、[1]と同じならば、末端である。
                    c = c + xdir[dir];
                    r = r + ydir[dir];
                    if (coord[1].x == c && coord[1].y == r)
                    {
                        //終点に達している。
                        o_coord.length = coord_num;
                        break;
                    }
                    else
                    {
                        //終点ではない。
                        coord[coord_num].x = c;
                        coord[coord_num].y = r;
                    }
                }
                coord_num++;
                //末端のチェック
                if (coord_num == max_coord)
                {
                    //輪郭が末端に達した
                    return false;
                }
            }
            return true;
        }
        /**
         * 輪郭点集合からay+bx+c=0の直線式を計算します。
         * @param i_st
         * @param i_ed
         * @param i_coord
         * @param o_line
         * @return
         * @throws NyARException
         */
        public bool coord2Line(int i_st, int i_ed, NyARIntCoordinates i_coord, NyARLinear o_line)
        {
            //頂点を取得
            int    n, st, ed;
            double w1;
            int    cood_num = i_coord.length;

            //探索区間の決定
            if (i_ed >= i_st)
            {
                //頂点[i]から頂点[i+1]までの輪郭が、1区間にあるとき
                w1 = (double)(i_ed - i_st + 1) * 0.05 + 0.5;
                //探索区間の決定
                st = (int)(i_st + w1);
                ed = (int)(i_ed - w1);
            }
            else
            {
                //頂点[i]から頂点[i+1]までの輪郭が、2区間に分かれているとき
                w1 = (double)((i_ed + cood_num - i_st + 1) % cood_num) * 0.05 + 0.5;
                //探索区間の決定
                st = ((int)(i_st + w1)) % cood_num;
                ed = ((int)(i_ed + cood_num - w1)) % cood_num;
            }
            //探索区間数を確認
            if (st <= ed)
            {
                //探索区間は1区間
                n = ed - st + 1;
                if (this._dist_factor != null)
                {
                    this._dist_factor.observ2IdealBatch(i_coord.items, st, n, this._xpos, this._ypos, 0);
                }
            }
            else
            {
                //探索区間は2区間
                n = ed + 1 + cood_num - st;
                if (this._dist_factor != null)
                {
                    this._dist_factor.observ2IdealBatch(i_coord.items, st, cood_num - st, this._xpos, this._ypos, 0);
                    this._dist_factor.observ2IdealBatch(i_coord.items, 0, ed + 1, this._xpos, this._ypos, cood_num - st);
                }
            }
            //要素数の確認
            if (n < 2)
            {
                // nが2以下でmatrix.PCAを計算することはできないので、エラー
                return(false);
            }
            //主成分分析する。
            NyARDoubleMatrix22 evec = this.__getSquareLine_evec;

            double[] mean = this.__getSquareLine_mean;


            this._pca.pca(this._xpos, this._ypos, n, evec, this.__getSquareLine_ev, mean);
            o_line.a = evec.m01;                                   // line[i][0] = evec->m[1];
            o_line.b = -evec.m00;                                  // line[i][1] = -evec->m[0];
            o_line.c = -(o_line.a * mean[0] + o_line.b * mean[1]); // line[i][2] = -(line[i][0]*mean->v[0] + line[i][1]*mean->v[1]);

            return(true);
        }
        /**
         * 内部関数です。
         * この関数は、thisの二次元矩形情報プロパティを更新します。
         * @param i_coord
         * @param i_vertex_index
         * @
         */
        protected internal void updateSquareInfo(NyARIntCoordinates i_coord, int[] i_vertex_index)
        {
            NyARMatchPattResult mr = this.__detectMarkerLite_mr;
            //輪郭座標から頂点リストに変換
            NyARIntPoint2d[] vertex = this.__ref_vertex;	//C言語ならポインタ扱いで実装
            vertex[0] = i_coord.items[i_vertex_index[0]];
            vertex[1] = i_coord.items[i_vertex_index[1]];
            vertex[2] = i_coord.items[i_vertex_index[2]];
            vertex[3] = i_coord.items[i_vertex_index[3]];

            //画像を取得
            if (!this._inst_patt.pickFromRaster(this._last_input_raster, vertex))
            {
                return;
            }
            //取得パターンをカラー差分データに変換して評価する。
            this._deviation_data.setRaster(this._inst_patt);
            if (!this._match_patt.evaluate(this._deviation_data, mr))
            {
                return;
            }
            //現在の一致率より低ければ終了
            if (this._confidence > mr.confidence)
            {
                return;
            }
            //一致率の高い矩形があれば、方位を考慮して頂点情報を作成
            NyARSquare sq = this._square;
            this._confidence = mr.confidence;
            //directionを考慮して、squareを更新する。
            for (int i = 0; i < 4; i++)
            {
                int idx = (i + 4 - mr.direction) % 4;
                this._coordline.coord2Line(i_vertex_index[idx], i_vertex_index[(idx + 1) % 4], i_coord, sq.line[i]);
            }
            //ちょっと、ひっくり返してみようか。
            for (int i = 0; i < 4; i++)
            {
                //直線同士の交点計算
                if (!sq.line[i].crossPos(sq.line[(i + 3) % 4], sq.sqvertex[i]))
                {
                    throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK
                }
            }
        }
 public void detectMarkerCallback(NyARIntCoordinates i_coord,int[] i_vertex_index)
 {
     this._parent.updateSquareInfo(i_coord, i_vertex_index);
 }
	public void detectMarkerCallback(NyARIntCoordinates i_coord,int[] i_vertex_index)
	{
		//とりあえずSquareスタックを予約
		SquareStack.Item sq_tmp=this._sq_stack.prePush();
		//確保できない(1つのdetectorが複数の候補を得る場合(同じARマーカが多くある場合など)に発生することがある。)
		if(sq_tmp==null){
			return;
		}

		//観測座標点の記録
		for(int i2=0;i2<4;i2++){
			sq_tmp.ob_vertex[i2].setValue(i_coord.items[i_vertex_index[i2]]);
		}
		//頂点分布を計算
		sq_tmp.vertex_area.setAreaRect(sq_tmp.ob_vertex,4);
		//頂点座標の中心を計算
		sq_tmp.center2d.setCenterPos(sq_tmp.ob_vertex,4);
		//矩形面積
		sq_tmp.rect_area=sq_tmp.vertex_area.w*sq_tmp.vertex_area.h;

		bool is_target_marker=false;
		for(;;){
			//トラッキング対象か確認する。
			if(this._ref_tracking_list.update(sq_tmp)){
				//トラッキング対象ならブレーク
				is_target_marker=true;
				break;
			}
			//@todo 複数マーカ時に、トラッキング済のarmarkerを探索対象外に出来ない?
			
			//nyIdマーカの特定(IDマーカの特定はここで完結する。)
            if (this._ref_idmk_list.Count > 0)
            {
				if(this._ref_idmk_list.update(this._ref_input_gs,sq_tmp)){
					is_target_marker=true;
					break;//idマーカを特定
				}
			}
			//PSARマーカの特定(IDマーカの特定はここで完結する。)
			if(this._ref_psmk_list.Count>0){
				if(this._ref_psmk_list.update(this._ref_input_gs,sq_tmp)){
					is_target_marker=true;
					break;//idマーカを特定
				}
			}
			//ARマーカの特定
			if(this._ref_armk_list.Count>0){
				//敷居値により1個のマーカに対して複数の候補が見つかることもある。
				if(this._ref_armk_list.update(this._ref_input_rfb,sq_tmp)){
					is_target_marker=true;
					break;
				}
			}
			break;
		}
		//この矩形が検出対象なら、矩形情報を精密に再計算
		if(is_target_marker){
			//矩形は検出対象にマークされている。
			for(int i2=0;i2<4;i2++){
				this._coordline.coord2Line(i_vertex_index[i2],i_vertex_index[(i2+1)%4],i_coord,sq_tmp.line[i2]);
			}
			for (int i2 = 0; i2 < 4; i2++) {
				//直線同士の交点計算
				if(!sq_tmp.line[i2].crossPos(sq_tmp.line[(i2 + 3) % 4],sq_tmp.sqvertex[i2])){
					throw new NyARException();//まずない。ありえない。
				}
			}
		}else{
			//この矩形は検出対象にマークされなかったので、解除
			this._sq_stack.pop();
		}
	}
Exemple #19
0
        /**
         * 座標集合から、頂点候補になりそうな場所を4箇所探して、そのインデクス番号を返します。
         * @param i_coord
         * 輪郭を格納した配列です。
         * @param i_area
         * @param o_vertex
         * @return
         */
        public bool getVertexIndexes(NyARIntCoordinates i_coord, int i_area, int[] o_vertex)
        {
            NyARVertexCounter wv1    = this.__getSquareVertex_wv1;
            NyARVertexCounter wv2    = this.__getSquareVertex_wv2;
            int    i_coord_num       = i_coord.length;
            int    vertex1_index     = getFarPoint(i_coord.items, i_coord_num, 0);
            int    prev_vertex_index = (vertex1_index + i_coord_num) % i_coord_num;
            int    v1     = getFarPoint(i_coord.items, i_coord_num, vertex1_index);
            double thresh = (i_area / 0.75) * 0.01 * VERTEX_FACTOR;

            o_vertex[0] = vertex1_index;

            if (!wv1.getVertex(i_coord.items, i_coord_num, vertex1_index, v1, thresh))
            {
                return(false);
            }
            if (!wv2.getVertex(i_coord.items, i_coord_num, v1, prev_vertex_index, thresh))
            {
                return(false);
            }

            int v2;

            if (wv1.number_of_vertex == 1 && wv2.number_of_vertex == 1)
            {
                o_vertex[1] = wv1.vertex[0];
                o_vertex[2] = v1;
                o_vertex[3] = wv2.vertex[0];
            }
            else if (wv1.number_of_vertex > 1 && wv2.number_of_vertex == 0)
            {
                //頂点位置を、起点から対角点の間の1/2にあると予想して、検索する。
                if (v1 >= vertex1_index)
                {
                    v2 = (v1 - vertex1_index) / 2 + vertex1_index;
                }
                else
                {
                    v2 = ((v1 + i_coord_num - vertex1_index) / 2 + vertex1_index) % i_coord_num;
                }
                if (!wv1.getVertex(i_coord.items, i_coord_num, vertex1_index, v2, thresh))
                {
                    return(false);
                }
                if (!wv2.getVertex(i_coord.items, i_coord_num, v2, v1, thresh))
                {
                    return(false);
                }
                if (wv1.number_of_vertex == 1 && wv2.number_of_vertex == 1)
                {
                    o_vertex[1] = wv1.vertex[0];
                    o_vertex[2] = wv2.vertex[0];
                    o_vertex[3] = v1;
                }
                else
                {
                    return(false);
                }
            }
            else if (wv1.number_of_vertex == 0 && wv2.number_of_vertex > 1)
            {
                //v2 = (v1+ end_of_coord)/2;
                if (v1 <= prev_vertex_index)
                {
                    v2 = (v1 + prev_vertex_index) / 2;
                }
                else
                {
                    v2 = ((v1 + i_coord_num + prev_vertex_index) / 2) % i_coord_num;
                }
                if (!wv1.getVertex(i_coord.items, i_coord_num, v1, v2, thresh))
                {
                    return(false);
                }
                if (!wv2.getVertex(i_coord.items, i_coord_num, v2, prev_vertex_index, thresh))
                {
                    return(false);
                }
                if (wv1.number_of_vertex == 1 && wv2.number_of_vertex == 1)
                {
                    o_vertex[1] = v1;
                    o_vertex[2] = wv1.vertex[0];
                    o_vertex[3] = wv2.vertex[0];
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }
            return(true);
        }
 public bool getContour(NyARGrayscaleRaster i_raster, NyARIntRect i_area, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
 {
     Debug.Assert(i_raster.isEqualBufferType(NyARBufferType.INT1D_GRAY_8));
     return(impl_getContour(i_raster, i_area.x, i_area.y, i_area.x + i_area.w - 1, i_area.h + i_area.y - 1, i_th, i_entry_x, i_entry_y, o_coord));
 }
	    /**
	     * 輪郭線を取得します。
	     * 取得アルゴリズムは、以下の通りです。
	     * 1.輪郭座標(n)の画素周辺の画素ベクトルを取得。
	     * 2.輪郭座標(n+1)周辺の画素ベクトルと比較。
	     * 3.差分が一定以下なら、座標と強度を保存
	     * 4.3点以上の集合になったら、最小二乗法で直線を計算。
	     * 5.直線の加重値を個々の画素ベクトルの和として返却。
	     */
        public bool traceConture(NyARIntCoordinates i_coord, int i_pos_mag, int i_cell_size, VecLinearCoordinates o_coord)
	    {
            VecLinearCoordinates.VecLinearCoordinatePoint[] pos = this._tmp_coord_pos;
		    // ベクトル化
            int MAX_COORD = o_coord.items.Length;
		    int i_coordlen = i_coord.length;
		    NyARIntPoint2d[] coord = i_coord.items;
            VecLinearCoordinates.VecLinearCoordinatePoint pos_ptr;

		    //0個目のライン探索
		    int number_of_data = 0;
		    int sq;
		    long sq_sum=0;
		    //0番目のピクセル
		    pos[0].scalar=sq=this.getAreaVector33(coord[0].x * i_pos_mag, coord[0].y * i_pos_mag,i_cell_size, i_cell_size,pos[0]);
		    sq_sum+=(int)sq;
		    //[2]に0を保管

		    //1点目だけは前方と後方、両方に探索をかける。
		    //前方探索の終点
		    int coord_last_edge=i_coordlen;
		    //後方探索
		    int sum=1;
		    double ave_dx=pos[0].dx;
		    double ave_dy=pos[0].dy;
		    for (int i = i_coordlen-1; i >0; i--)
		    {
			    // ベクトル取得
			    pos_ptr=pos[sum];
			    pos_ptr.scalar=sq=this.getAreaVector33(coord[i].x * i_pos_mag,coord[i].y * i_pos_mag, i_cell_size, i_cell_size,pos_ptr);
                sq_sum += (int)sq;
			    // 類似度判定
			    if(checkVecCos(pos[sum],pos[sum-1],ave_dx,ave_dy))
			    {
				    //相関なし->前方探索へ。
				    ave_dx=pos_ptr.dx;
				    ave_dy=pos_ptr.dy;
				    coord_last_edge=i;
				    break;
			    } else {
				    //相関あり- 点の蓄積
				    ave_dx+=pos_ptr.dx;
				    ave_dy+=pos_ptr.dy;
				    sum++;
			    }
		    }
		    //前方探索
		    for (int i = 1; i<coord_last_edge; i++)
		    {
			    // ベクトル取得
			    pos_ptr=pos[sum];
			    pos_ptr.scalar=sq=this.getAreaVector33(coord[i].x * i_pos_mag,coord[i].y * i_pos_mag, i_cell_size, i_cell_size,pos_ptr);
                sq_sum += (int)sq;			
			    if(sq==0){
				    continue;
			    }
			    //if (pos_ptr.getAbsVecCos(pos[sum-1]) < NyARMath.COS_DEG_5 && pos_ptr.getAbsVecCos(ave_dx,ave_dy)<NyARMath.COS_DEG_20) {
			    if (checkVecCos(pos[sum],pos[sum-1],ave_dx,ave_dy)) {
				    //相関なし->新しい要素を作る。
				    if(this.leastSquaresWithNormalize(pos,sum,o_coord.items[number_of_data],sq_sum/(sum*5))){
					    number_of_data++;
				    }
				    ave_dx=pos_ptr.dx;
				    ave_dy=pos_ptr.dy;
				    //獲得した値を0へ移動
				    pos[0].setValue(pos[sum]);
				    sq_sum=0;
				    sum=1;
			    } else {
				    //相関あり- 点の蓄積
				    ave_dx+=pos_ptr.dx;
				    ave_dy+=pos_ptr.dy;				
				    sum++;
			    }
			    // 輪郭中心を出すための計算
			    if (number_of_data == MAX_COORD) {
				    // 輪郭ベクトルバッファの最大を超えたら失敗
				    return false;
			    }
		    }
		    if(this.leastSquaresWithNormalize(pos,sum,o_coord.items[number_of_data],sq_sum/(sum*5))){
			    number_of_data++;
		    }
		    // ベクトル化2:最後尾と先頭の要素が似ていれば連結する。
		    // sq_distの合計を計算
		    o_coord.length = number_of_data;

		    return true;
	    }
 /**
  * 継承クラスのコンストラクタから呼び出す。
  * @param i_ref_raster
  * 基本画像
  * @param i_ref_raster_distortion
  * 歪み解除オブジェクト(nullの場合歪み解除を省略)
  * @param i_ref_rob_raster
  * エッジ探索用のROB画像
  * @param i_contour_pickup
  * 輪郭線取得クラス
  * @param
  */
 public void initInstance(NyARGrayscaleRaster i_ref_raster,NyARCameraDistortionFactor i_ref_raster_distortion,NyARGrayscaleRaster i_ref_rob_raster,NyARContourPickup i_contour_pickup)
 {
     this._rob_resolution=i_ref_raster.getWidth()/i_ref_rob_raster.getWidth();
     this._ref_rob_raster=i_ref_rob_raster;
     this._ref_base_raster=i_ref_raster;
     this._coord_buf = new NyARIntCoordinates((i_ref_raster.getWidth() + i_ref_raster.getHeight()) * 4);
     this._factor=i_ref_raster_distortion;
     this._tmp_coord_pos = VecLinearCoordinates.VecLinearCoordinatePoint.createArray(this._coord_buf.items.Length);
     this._cpickup = i_contour_pickup;
     return;
 }
 /**
  * この関数は、ラスタの指定点を基点に、画像の特定の範囲内から輪郭線を抽出します。
  * 開始点は、輪郭の一部である必要があります。
  * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。
  * @param i_raster
  * 輪郭線を抽出するラスタを指定します。
  * @param i_area
  * 輪郭線の抽出範囲を指定する矩形。i_rasterのサイズ内である必要があります。
  * @param i_th
  * 輪郭とみなす暗点の敷居値を指定します。
  * @param i_entry_x
  * 輪郭抽出の開始点です。
  * @param i_entry_y
  * 輪郭抽出の開始点です。
  * @param o_coord
  * 輪郭点を格納するオブジェクトを指定します。
  * @return
  * 輪郭線がo_coordの長さを超えた場合、falseを返します。
  * @
  */
 public bool getContour(INyARGrayscaleRaster i_raster, NyARIntRect i_area, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
 {
     //ラスタドライバの切り替え
     if (i_raster != this._ref_last_input_raster)
     {
         this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver));
         this._ref_last_input_raster = i_raster;
     }
     return this._imdriver.getContour(i_area.x, i_area.y, i_area.x + i_area.w - 1, i_area.h + i_area.y - 1, i_entry_x, i_entry_y, i_th, o_coord);
 }
 public abstract bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord);
        public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord)
        {
            Debug.Assert(i_t<=i_entry_x);
            int[] buf=(int[])this._ref_raster.getBuffer();
            int[] xdir = _getContour_xdir;// static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
            int[] ydir = _getContour_ydir;// static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};
            int width=this._ref_raster.getWidth();
            //クリップ領域の上端に接しているポイントを得る。
            NyARIntPoint2d[] coord=o_coord.items;
            int max_coord=o_coord.items.Length;
            coord[0].x = i_entry_x;
            coord[0].y = i_entry_y;
            int coord_num = 1;
            int dir = 5;

            int c = i_entry_x;
            int r = i_entry_y;
            for (;;) {
            dir = (dir + 5) % 8;//dirの正規化
            //ここは頑張ればもっと最適化できると思うよ。
            //4隅以外の境界接地の場合に、境界チェックを省略するとかね。
            if(c>i_l && c<i_r && r>i_t && r<i_b){
                for(;;){//gotoのエミュレート用のfor文
                    //境界に接していないとき(暗点判定)
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    dir++;
                    if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {
                        break;
                    }
                    //8方向全て調べたけどラベルが無いよ?
                    throw new NyARException();
                }
            }else{
                //境界に接しているとき
                int i;
                for (i = 0; i < 8; i++){
                    int x=c + xdir[dir];
                    int y=r + ydir[dir];
                    //境界チェック
                    if(x>=i_l && x<=i_r && y>=i_t && y<=i_b){
                        if (buf[(y)*width+(x)] <= i_th) {
                            break;
                        }
                    }
                    dir++;//倍長テーブルを参照するので問題なし
                }
                if (i == 8) {
                    //8方向全て調べたけどラベルが無いよ?
                    throw new NyARException();// return(-1);
                }
            }
            // xcoordとycoordをc,rにも保存
            c = c + xdir[dir];
            r = r + ydir[dir];
            coord[coord_num].x = c;
            coord[coord_num].y = r;
            //終了条件判定
            if (c == i_entry_x && r == i_entry_y){
                //開始点と同じピクセルに到達したら、終点の可能性がある。
                coord_num++;
                //末端のチェック
                if (coord_num == max_coord) {
                    //輪郭bufが末端に達した
                    return false;
                }
                //末端候補の次のピクセルを調べる
                dir = (dir + 5) % 8;//dirの正規化
                int i;
                for (i = 0; i < 8; i++){
                    int x=c + xdir[dir];
                    int y=r + ydir[dir];
                    //境界チェック
                    if(x>=i_l && x<=i_r && y>=i_t && y<=i_b){
                        if (buf[(y)*width+(x)] <= i_th) {
                            break;
                        }
                    }
                    dir++;//倍長テーブルを参照するので問題なし
                }
                if (i == 8) {
                    //8方向全て調べたけどラベルが無いよ?
                    throw new NyARException();
                }
                //得たピクセルが、[1]と同じならば、末端である。
                c = c + xdir[dir];
                r = r + ydir[dir];
                if(coord[1].x ==c && coord[1].y ==r){
                    //終点に達している。
                    o_coord.length=coord_num;
                    break;
                }else{
                    //終点ではない。
                    coord[coord_num].x = c;
                    coord[coord_num].y = r;
                }
            }
            coord_num++;
            //末端のチェック
            if (coord_num == max_coord) {
                //輪郭が末端に達した
                return false;
            }
            }
            return true;
        }
        /**
         * arDetectMarker2を基にした関数
         * この関数はNyARSquare要素のうち、directionを除くパラメータを取得して返します。
         * directionの確定は行いません。
         * @param i_raster
         * 解析する2値ラスタイメージを指定します。
         * @throws NyARException
         */
        public override void detectMarker(NyARBinRaster i_raster)
        {
            NyARLabelingImage limage = this._limage;

            // ラベル数が0ならここまで
            int label_num = this._labeling.labeling(i_raster, this._limage);

            if (label_num < 1)
            {
                return;
            }

            NyARLabelingLabelStack stack = limage.getLabelStack();

            //ラベルをソートしておく
            stack.sortByArea();
            //
            NyARLabelingLabel[] labels = stack.getArray();

            // デカいラベルを読み飛ばし
            int i;

            for (i = 0; i < label_num; i++)
            {
                // 検査対象内のラベルサイズになるまで無視
                if (labels[i].area <= AR_AREA_MAX)
                {
                    break;
                }
            }
            int xsize = this._width;
            int ysize = this._height;
            NyARIntCoordinates coord = this._coord;

            int[] mkvertex = this.__detectMarker_mkvertex;

            NyARLabelOverlapChecker <NyARLabelingLabel> overlap = this._overlap_checker;

            //重なりチェッカの最大数を設定
            overlap.setMaxLabels(label_num);
            for (; i < label_num; i++)
            {
                NyARLabelingLabel label_pt = labels[i];
                int label_area             = label_pt.area;
                // 検査対象サイズよりも小さくなったら終了
                if (label_area < AR_AREA_MIN)
                {
                    break;
                }
                // クリップ領域が画面の枠に接していれば除外
                if (label_pt.clip_l == 1 || label_pt.clip_r == xsize - 2)              // if(wclip[i*4+0] == 1 || wclip[i*4+1] ==xsize-2){
                {
                    continue;
                }
                if (label_pt.clip_t == 1 || label_pt.clip_b == ysize - 2)              // if( wclip[i*4+2] == 1 || wclip[i*4+3] ==ysize-2){
                {
                    continue;
                }
                // 既に検出された矩形との重なりを確認
                if (!overlap.check(label_pt))
                {
                    // 重なっているようだ。
                    continue;
                }
                // 輪郭を取得
                if (!this._cpickup.getContour(limage, limage.getTopClipTangentX(label_pt), label_pt.clip_t, coord))
                {
                    continue;
                }
                //輪郭線をチェックして、矩形かどうかを判定。矩形ならばmkvertexに取得
                if (!this._coord2vertex.getVertexIndexes(coord, label_area, mkvertex))
                {
                    // 頂点の取得が出来なかった
                    continue;
                }
                //矩形を発見したことをコールバック関数で通知
                this.onSquareDetect(coord, mkvertex);

                // 検出済の矩形の属したラベルを重なりチェックに追加する。
                overlap.push(label_pt);
            }
            return;
        }
 /**
  * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。
  * 開始点は、輪郭の一部である必要があります。
  * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。
  * @param i_raster
  * 輪郭線を抽出するラスタを指定します。
  * @param i_th
  * 輪郭とみなす暗点の敷居値を指定します。
  * @param i_entry_x
  * 輪郭抽出の開始点です。
  * @param i_entry_y
  * 輪郭抽出の開始点です。
  * @param o_coord
  * 輪郭点を格納する配列を指定します。i_array_sizeよりも大きなサイズの配列が必要です。
  * @return
  * 輪郭の抽出に成功するとtrueを返します。輪郭抽出に十分なバッファが無いと、falseになります。
  * @
  */
 public bool getContour(INyARGrayscaleRaster i_raster, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
 {
     NyARIntSize s = i_raster.getSize();
     //ラスタドライバの切り替え
     if (i_raster != this._ref_last_input_raster)
     {
         this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver));
         this._ref_last_input_raster = i_raster;
     }
     return this._imdriver.getContour(0, 0, s.w - 1, s.h - 1, i_entry_x, i_entry_y, i_th, o_coord);
 }
 /**
  * この関数は、ラスタの指定点を基点に、画像の特定の範囲内から輪郭線を抽出します。
  * 開始点は、輪郭の一部である必要があります。
  * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。
  * @param i_raster
  * 輪郭線を抽出するラスタを指定します。
  * @param i_area
  * 輪郭線の抽出範囲を指定する矩形。i_rasterのサイズ内である必要があります。
  * @param i_th
  * 輪郭とみなす暗点の敷居値を指定します。
  * @param i_entry_x
  * 輪郭抽出の開始点です。
  * @param i_entry_y
  * 輪郭抽出の開始点です。
  * @param o_coord
  * 輪郭点を格納するオブジェクトを指定します。
  * @return
  * 輪郭線がo_coordの長さを超えた場合、falseを返します。
  * @
  */
 public bool getContour(INyARGrayscaleRaster i_raster, NyARIntRect i_area, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
 {
     //ラスタドライバの切り替え
     if (i_raster != this._ref_last_input_raster)
     {
         this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver));
         this._ref_last_input_raster = i_raster;
     }
     return(this._imdriver.getContour(i_area.x, i_area.y, i_area.x + i_area.w - 1, i_area.h + i_area.y - 1, i_entry_x, i_entry_y, i_th, o_coord));
 }
        /**
         * この関数は、ラスタから矩形を検出して、自己コールバック関数{@link #onSquareDetect}で通知します。
         * @param i_raster
         * 検出元のラスタ画像
         * 入力できるラスタの画素形式は、{@link NyARLabeling_Rle#labeling(INyARRaster, int)}と同じです。
         * @param i_area
         * 検出する範囲。検出元のラスタの内側である必要があります。
         * @param i_th
         * ラベルと判定する敷居値
         * @
         */
        public void detectMarker(INyARGrayscaleRaster i_raster, NyARIntRect i_area, int i_th, NyARSquareContourDetector.CbHandler i_cb)
        {
            Debug.Assert(i_area.w * i_area.h > 0);

            NyARRleLabelFragmentInfoPtrStack flagment = this._labeling.label_stack;
            NyARLabelOverlapChecker <NyARRleLabelFragmentInfo> overlap = this._overlap_checker;

            //ラベルの生成エラーならここまで
            if (!this._labeling.labeling(i_raster, i_area, i_th))
            {
                return;
            }
            // ラベル数が0ならここまで
            int label_num = flagment.getLength();

            if (label_num < 1)
            {
                return;
            }

            //ラベルリストを取得
            NyARRleLabelFragmentInfo[] labels = flagment.getArray();

            NyARIntCoordinates coord = this._coord;

            int[] mkvertex = this.__detectMarker_mkvertex;


            //重なりチェッカの最大数を設定
            overlap.setMaxLabels(label_num);

            for (int i = 0; i < label_num; i++)
            {
                NyARRleLabelFragmentInfo label_pt = labels[i];
                // 既に検出された矩形との重なりを確認
                if (!overlap.check(label_pt))
                {
                    // 重なっているようだ。
                    continue;
                }

                //輪郭を取得
                if (!this._cpickup.getContour(i_raster, i_area, i_th, label_pt.entry_x, label_pt.clip_t, coord))
                {
                    continue;
                }
                int label_area = label_pt.area;
                //輪郭線をチェックして、矩形かどうかを判定。矩形ならばmkvertexに取得
                if (!this._coord2vertex.getVertexIndexes(coord, label_area, mkvertex))
                {
                    // 頂点の取得が出来なかった
                    continue;
                }
                //矩形を発見したことをコールバック関数で通知
                i_cb.detectMarkerCallback(coord, mkvertex);

                // 検出済の矩形の属したラベルを重なりチェックに追加する。
                overlap.push(label_pt);
            }
            return;
        }
        /**
         * ラスタの指定点を基点に、輪郭線を抽出します。開始点は、輪郭の一部、かつ左上のエッジで有る必要があります。
         * @param i_raster
         * 輪郭線を抽出するラスタを指定します。
         * @param i_entry_x
         * 輪郭抽出の開始点です。
         * @param i_entry_y
         * 輪郭抽出の開始点です。
         * @param i_array_size
         * o_coordの有効長を指定します。
         * @param o_coord
         * 輪郭点を格納するオブジェクトを指定します。
         * @return
         * 輪郭線がo_coordの長さを超えた場合、falseを返します。
         * @throws NyARException
         */
        public bool getContour(NyARLabelingImage i_raster, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord)
        {
            int[] xdir = _getContour_xdir;        // static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
            int[] ydir = _getContour_ydir;        // static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};

            int[] i_buf  = (int[])i_raster.getBuffer();
            int   width  = i_raster.getWidth();
            int   height = i_raster.getHeight();

            NyARIntPoint2d[] coord = o_coord.items;
            int i_array_size       = o_coord.items.Length;
            //クリップ領域の上端に接しているポイントを得る。
            int sx = i_entry_x;
            int sy = i_entry_y;

            int coord_num = 1;

            coord[0].x = sx;
            coord[0].y = sy;
            int dir = 5;

            int c = coord[0].x;
            int r = coord[0].y;

            for (;;)
            {
                dir = (dir + 5) % 8;            //dirの正規化
                //ここは頑張ればもっと最適化できると思うよ。
                //4隅以外の境界接地の場合に、境界チェックを省略するとかね。
                if (c >= 1 && c < width - 1 && r >= 1 && r < height - 1)
                {
                    for (;;)                //gotoのエミュレート用のfor文
                                            //境界に接していないとき
                    {
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        dir++;
                        if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0)
                        {
                            break;
                        }
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARException();
                    }
                }
                else
                {
                    //境界に接しているとき
                    int i;
                    for (i = 0; i < 8; i++)
                    {
                        int x = c + xdir[dir];
                        int y = r + ydir[dir];
                        //境界チェック
                        if (x >= 0 && x < width && y >= 0 && y < height)
                        {
                            if (i_buf[(y) * width + (x)] > 0)
                            {
                                break;
                            }
                        }
                        dir++;                    //倍長テーブルを参照するので問題なし
                    }
                    if (i == 8)
                    {
                        //8方向全て調べたけどラベルが無いよ?
                        throw new NyARException();                    // return(-1);
                    }
                }

                dir = dir % 8;         //dirの正規化

                // xcoordとycoordをc,rにも保存
                c = c + xdir[dir];
                r = r + ydir[dir];
                coord[coord_num].x = c;
                coord[coord_num].y = r;
                // 終了条件判定
                if (c == sx && r == sy)
                {
                    coord_num++;
                    break;
                }
                coord_num++;
                if (coord_num == i_array_size)
                {
                    //輪郭が末端に達した
                    return(false);
                }
            }
            o_coord.length = coord_num;
            return(true);
        }