Ejemplo n.º 1
0
        /**
         * 内部関数です。
         * この関数は、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
                }
            }
        }
        /**
         * コンストラクタです。
         * 入力画像のサイズを指定して、インスタンスを生成します。
         * @param i_size
         * 入力画像のサイズ
         */
        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;
        }
Ejemplo n.º 3
0
        /**
         * コンストラクタです。
         * 入力画像のサイズを指定して、インスタンスを生成します。
         * @param i_size
         * 入力画像のサイズ
         */
        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;
        }
        public bool traceConture(int i_th,
                                 NyARIntPoint2d i_entry, VecLinearCoordinates o_coord)
        {
            NyARIntCoordinates coord = this._coord_buf;

            // Robertsラスタから輪郭抽出
            if (!this._cpickup.getContour(this._ref_rob_raster, i_th, i_entry.x, i_entry.y,
                                          coord))
            {
                // 輪郭線MAXならなにもできないね。
                return(false);
            }
            // 輪郭線のベクトル化
            return(traceConture(coord, this._rob_resolution,
                                this._rob_resolution * 2, o_coord));
        }
        public bool traceLine(NyARDoublePoint2d i_pos1, NyARDoublePoint2d i_pos2, int i_edge, VecLinearCoordinates o_coord)
        {
            NyARIntCoordinates coord  = this._coord_buf;
            NyARIntSize        base_s = this._ref_base_raster.getSize();
            // (i_area*2)の矩形が範囲内に収まるように線を引く
            // 移動量

            // 点間距離を計算
            int dist = (int)Math.Sqrt(i_pos1.sqDist(i_pos2));

            // 最低AREA*2以上の大きさが無いなら、ラインのトレースは不可能。
            if (dist < 4)
            {
                return(false);
            }
            // dist最大数の決定
            if (dist > 12)
            {
                dist = 12;
            }
            // サンプリングサイズを決定(移動速度とサイズから)
            int s  = i_edge * 2 + 1;
            int dx = (int)(i_pos2.x - i_pos1.x);
            int dy = (int)(i_pos2.y - i_pos1.y);
            int r  = base_s.w - s;
            int b  = base_s.h - s;

            // 最大24点を定義して、そのうち両端の2個を除いた点を使用する。
            for (int i = 1; i < dist - 1; i++)
            {
                int x = (int)(i * dx / dist + i_pos1.x - i_edge);
                int y = (int)(i * dy / dist + i_pos1.y - i_edge);
                // limit
                coord.items[i - 1].x = x < 0 ? 0 : (x >= r ? r : x);
                coord.items[i - 1].y = y < 0 ? 0 : (y >= b ? b : y);
            }

            coord.length = dist - 2;
            // 点数は10点程度を得る。
            return(traceConture(coord, 1, s, 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);
        }
Ejemplo n.º 7
0
 public void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index)
 {
     this._parent.updateSquareInfo(i_coord, i_vertex_index);
 }
Ejemplo n.º 8
0
        /**
         * この関数は、輪郭点集合からay+bx+c=0の直線式を計算します。
         * @param i_st
         * 直線計算の対象とする、輪郭点の開始インデックス
         * @param i_ed
         * 直線計算の対象とする、輪郭点の終了インデックス
         * @param i_coord
         * 輪郭点集合のオブジェクト。
         * @param o_line
         * 直線式を受け取るオブジェクト
         * @return
         * 直線式の計算に成功すると、trueを返します。
         * @
         */
        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);
        }
            /**
             * 矩形が見付かるたびに呼び出されます。
             * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。
             */
            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 void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index)
            {
                NyARMatchPattResult mr = this.__detectMarkerLite_mr;

                //輪郭座標から頂点リストに変換
                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);

                //最も一致するパターンを割り当てる。
                int    square_index, direction;
                double confidence;

                this._match_patt[0].evaluate(this._deviation_data, mr);
                square_index = 0;
                direction    = mr.direction;
                confidence   = mr.confidence;
                //2番目以降
                for (int i = 1; i < this._match_patt.Length; i++)
                {
                    this._match_patt[i].evaluate(this._deviation_data, mr);
                    if (confidence > mr.confidence)
                    {
                        continue;
                    }
                    // もっと一致するマーカーがあったぽい
                    square_index = i;
                    direction    = mr.direction;
                    confidence   = mr.confidence;
                }
                //最も一致したマーカ情報を、この矩形の情報として記録する。
                NyARDetectMarkerResult result = this.result_stack.prePush();

                result.arcode_id  = square_index;
                result.confidence = confidence;

                NyARSquare sq = result.square;

                //directionを考慮して、squareを更新する。
                for (int i = 0; i < 4; i++)
                {
                    int idx = (i + 4 - 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
                    }
                }
            }
Ejemplo n.º 11
0
        /**
         * この関数は、ラスタから矩形を検出して、自己コールバック関数{@link #onSquareDetect}で通知します。
         * 実装クラスでは、矩形検出処理をして、結果を通知する処理を実装してください。
         * @param i_raster
         * 検出元のラスタ画像
         * @
         */
        public void detectMarker(NyARBinRaster i_raster, NyARSquareContourDetector.CbHandler i_cb)
        {
            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;
                }
                //矩形を発見したことをコールバック関数で通知
                i_cb.detectMarkerCallback(coord, mkvertex);

                // 検出済の矩形の属したラベルを重なりチェックに追加する。
                overlap.push(label_pt);
            }
            return;
        }
        /**
         * この関数は、輪郭点集合からay+bx+c=0の直線式を計算します。
         * @param i_st
         * 直線計算の対象とする、輪郭点の開始インデックス
         * @param i_ed
         * 直線計算の対象とする、輪郭点の終了インデックス
         * @param i_coord
         * 輪郭点集合のオブジェクト。
         * @param o_line
         * 直線式を受け取るオブジェクト
         * @return
         * 直線式の計算に成功すると、trueを返します。
         * @
         */
        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;
        }
Ejemplo n.º 13
0
 protected override void onSquareDetect(NyARIntCoordinates i_coord, int[] i_vertex_index)
 {
     this._parent.updateSquareInfo(i_coord, i_vertex_index);
 }
        /**
         * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。
         * 開始点は、輪郭の一部である必要があります。
         * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。
         * @param i_raster
         * 輪郭線を抽出するラスタを指定します。
         * @param i_entry_x
         * 輪郭抽出の開始点です。
         * @param i_entry_y
         * 輪郭抽出の開始点です。
         * @param o_coord
         * 輪郭点を格納するオブジェクトを指定します。
         * @return
         * 輪郭線がo_coordの長さを超えた場合、falseを返します。
         * @
         */
        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;
        }
        /**
         * この関数は、座標集合から頂点候補になりそうな場所を4箇所探して、そのインデクス番号を返します。
         * @param i_coord
         * 輪郭点集合を格納したオブジェクト。
         * @param i_area
         * 矩形判定のヒント値。矩形の大きさを、そのラベルを構成するピクセルの数で指定します。
         * (注)このパラメータは、マーカノデザイン、枠の大きさが影響等、ラベルの大きさに影響を受けます。
         * @param o_vertex
         * 4頂点のインデクスを受け取る配列です。4要素以上の配列を指定してください。
         * @return
         * 頂点が見つかるとtrueを返します。
         */
        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;
        }
Ejemplo n.º 16
0
        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 NyARRuntimeException();//まずない。ありえない。
                    }
                }
            }
            else
            {
                //この矩形は検出対象にマークされなかったので、解除
                this._sq_stack.pop();
            }
        }
Ejemplo n.º 17
0
            /**
             * 矩形が見付かるたびに呼び出されます。
             * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。
             */
            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
                    }
                }
            }
Ejemplo n.º 18
0
        /**
         * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。
         * 開始点は、輪郭の一部である必要があります。
         * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。
         * @param i_raster
         * 輪郭線を抽出するラスタを指定します。
         * @param i_entry_x
         * 輪郭抽出の開始点です。
         * @param i_entry_y
         * 輪郭抽出の開始点です。
         * @param o_coord
         * 輪郭点を格納するオブジェクトを指定します。
         * @return
         * 輪郭線がo_coordの長さを超えた場合、falseを返します。
         * @
         */
        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);
        }
        /**
         * この関数は、座標集合から頂点候補になりそうな場所を4箇所探して、そのインデクス番号を返します。
         * @param i_coord
         * 輪郭点集合を格納したオブジェクト。
         * @param i_area
         * 矩形判定のヒント値。矩形の大きさを、そのラベルを構成するピクセルの数で指定します。
         * (注)このパラメータは、マーカノデザイン、枠の大きさが影響等、ラベルの大きさに影響を受けます。
         * @param o_vertex
         * 4頂点のインデクスを受け取る配列です。4要素以上の配列を指定してください。
         * @return
         * 頂点が見つかるとtrueを返します。
         */
        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);
        }