OSDN Git Service

[backup]NyARToolkit
[nyartoolkit-and/nyartoolkit-and.git] / trunk / src / jp / nyatla / nyartoolkit / core / labeling / rlelabeling / NyARLabeling_Rle.java
index 8d412f2..00f00cf 100644 (file)
@@ -1,14 +1,58 @@
-/* このソースは実験用のソースです。\r
- * 動いたり動かなかったりします。\r
+/* \r
+ * PROJECT: NyARToolkit(Extension)\r
+ * --------------------------------------------------------------------------------\r
+ * The NyARToolkit is Java edition ARToolKit class library.\r
+ * Copyright (C)2008-2009 Ryo Iizuka\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+ * \r
+ * For further information please contact.\r
+ *     http://nyatla.jp/nyatoolkit/\r
+ *     <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
  * \r
  */\r
 package jp.nyatla.nyartoolkit.core.labeling.rlelabeling;\r
 \r
 import jp.nyatla.nyartoolkit.NyARException;\r
 import jp.nyatla.nyartoolkit.core.raster.*;\r
+import jp.nyatla.nyartoolkit.core.types.stack.NyARObjectStack;\r
 \r
+class RleInfoStack extends NyARObjectStack<RleInfoStack.RleInfo>\r
+{\r
+       public class RleInfo\r
+       {\r
+               //継承メンバ\r
+               public int entry_x; // フラグメントラベルの位置\r
+               public int area;\r
+               public int clip_r;\r
+               public int clip_l;\r
+               public int clip_b;\r
+               public int clip_t;\r
+               public long pos_x;\r
+               public long pos_y;              \r
+       }       \r
+       public RleInfoStack(int i_length) throws NyARException\r
+       {\r
+               super(i_length, RleInfoStack.RleInfo.class);\r
+               return;\r
+       }\r
 \r
-\r
+       protected RleInfoStack.RleInfo createElement()\r
+       {\r
+               return new RleInfoStack.RleInfo();\r
+       }\r
+}\r
 /**\r
  * [strage class]\r
  */\r
@@ -18,7 +62,7 @@ class RleElement
 {\r
        int l;\r
        int r;\r
-       short id;\r
+       int fid;\r
        public static RleElement[] createArray(int i_length)\r
        {\r
                RleElement[] ret = new RleElement[i_length];\r
@@ -29,28 +73,53 @@ class RleElement
        }\r
 }\r
 \r
+\r
 // RleImageをラベリングする。\r
 public class NyARLabeling_Rle\r
 {\r
+       private static final int AR_AREA_MAX = 100000;// #define AR_AREA_MAX 100000\r
+       private static final int AR_AREA_MIN = 70;// #define AR_AREA_MIN 70\r
+       \r
+       private RleInfoStack _rlestack;\r
        private RleElement[] _rle1;\r
-\r
        private RleElement[] _rle2;\r
+       private int _max_area;\r
+       private int _min_area;\r
 \r
-       private short number_of_fragment; // 現在のフラグメントの数\r
-\r
-       public NyARLabeling_Rle(int i_width)\r
+       public NyARLabeling_Rle(int i_width,int i_height) throws NyARException\r
        {\r
+               this._rlestack=new RleInfoStack(i_width*i_height*2048/(320*240)+32);\r
                this._rle1 = RleElement.createArray(i_width/2+1);\r
                this._rle2 = RleElement.createArray(i_width/2+1);\r
+               setAreaRange(AR_AREA_MAX,AR_AREA_MIN);\r
+\r
+               return;\r
+       }\r
+       /**\r
+        * 対象サイズ\r
+        * @param i_max\r
+        * @param i_min\r
+        */\r
+       public void setAreaRange(int i_max,int i_min)\r
+       {\r
+               this._max_area=i_max;\r
+               this._min_area=i_min;\r
                return;\r
        }\r
 \r
        /**\r
-        * i_bin_bufのbinイメージをREL圧縮する。\r
-        * \r
-        * @param i_bin_raster\r
+        * i_bin_bufのgsイメージをREL圧縮する。\r
+        * @param i_bin_buf\r
+        * @param i_st\r
+        * @param i_len\r
+        * @param i_out\r
+        * @param i_th\r
+        * BINラスタのときは0,GSラスタの時は閾値を指定する。\r
+        * この関数は、閾値を暗点と認識します。\r
+        * 暗点<=th<明点\r
+        * @return\r
         */\r
-       private int toRel(int[] i_bin_buf, int i_st, int i_len, RleElement[] i_out)\r
+       private int toRel(int[] i_bin_buf, int i_st, int i_len, RleElement[] i_out,int i_th)\r
        {\r
                int current = 0;\r
                int r = -1;\r
@@ -59,8 +128,8 @@ public class NyARLabeling_Rle
                final int right_edge = i_st + i_len - 1;\r
                while (x < right_edge) {\r
                        // 暗点(0)スキャン\r
-                       if (i_bin_buf[x] != 0) {\r
-                               x++;\r
+                       if (i_bin_buf[x] > i_th) {\r
+                               x++;//明点\r
                                continue;\r
                        }\r
                        // 暗点発見→暗点長を調べる\r
@@ -69,7 +138,7 @@ public class NyARLabeling_Rle
                        r++;// 暗点+1\r
                        x++;\r
                        while (x < right_edge) {\r
-                               if (i_bin_buf[x] != 0) {\r
+                               if (i_bin_buf[x] > i_th) {\r
                                        // 明点(1)→暗点(0)配列終了>登録\r
                                        i_out[current].r = r;\r
                                        current++;\r
@@ -84,7 +153,7 @@ public class NyARLabeling_Rle
                        }\r
                }\r
                // 最後の1点だけ判定方法が少し違うの。\r
-               if (i_bin_buf[x] != 0) {\r
+               if (i_bin_buf[x] > i_th) {\r
                        // 明点→rカウント中なら暗点配列終了>登録\r
                        if (r >= 0) {\r
                                i_out[current].r = r;\r
@@ -96,8 +165,8 @@ public class NyARLabeling_Rle
                                i_out[current].r = (r + 1);\r
                        } else {\r
                                // 最後の1点の場合\r
-                               i_out[current].l = (i_st + i_len - 1);\r
-                               i_out[current].r = (i_st + i_len);\r
+                               i_out[current].l = (i_len - 1);\r
+                               i_out[current].r = (i_len);\r
                        }\r
                        current++;\r
                }\r
@@ -105,60 +174,91 @@ public class NyARLabeling_Rle
                return current;\r
        }\r
 \r
-       private void addFragment(RleElement i_rel_img, short i_nof, int i_row_index, int i_rel_index,RleLabelFragmentInfoStack o_stack) throws NyARException\r
+       private void addFragment(RleElement i_rel_img, int i_nof, int i_row_index,RleInfoStack o_stack) throws NyARException\r
        {\r
                int l=i_rel_img.l;\r
                final int len=i_rel_img.r - l;\r
-               i_rel_img.id = i_nof;// REL毎の固有ID\r
-               RleLabelFragmentInfoStack.RleLabelFragmentInfo v = o_stack.prePush();\r
-               v.id = i_nof;\r
+               i_rel_img.fid = i_nof;// REL毎の固有ID\r
+               RleInfoStack.RleInfo v = o_stack.prePush();\r
                v.entry_x = l;\r
                v.area =len;\r
                v.clip_l=l;\r
-               v.clip_r=i_rel_img.r;\r
+               v.clip_r=i_rel_img.r-1;\r
                v.clip_t=i_row_index;\r
                v.clip_b=i_row_index;\r
-               v.pos_x+=len*(2*l+(len-1)*1);\r
-               v.pos_y+=i_row_index*len;\r
+               v.pos_x=(len*(2*l+(len-1)))/2;\r
+               v.pos_y=i_row_index*len;\r
 \r
-               \r
                return;\r
        }\r
-\r
-       //\r
-       public void labeling(NyARBinRaster i_bin_raster, int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException\r
+       //所望のラスタからBIN-RLEに変換しながらの低速系も準備しようかな\r
+       \r
+       /**\r
+        * 単一閾値を使ってGSラスタをBINラスタに変換しながらラベリングします。\r
+        * @param i_gs_raster\r
+        * @param i_top\r
+        * @param i_bottom\r
+        * @param o_stack\r
+        * @return\r
+        * @throws NyARException\r
+        */\r
+       public int labeling(NyARBinRaster i_bin_raster, int i_top, int i_bottom,NyARRleLabelFragmentInfoStack o_stack) throws NyARException\r
+       {\r
+               assert(i_bin_raster.isEqualBufferType(NyARBufferType.INT1D_BIN_8));\r
+               return this.imple_labeling(i_bin_raster,0,i_top,i_bottom,o_stack);\r
+       }\r
+       /**\r
+        * BINラスタをラベリングします。\r
+        * @param i_gs_raster\r
+        * @param i_th\r
+        * 画像を2値化するための閾値。暗点<=th<明点となります。\r
+        * @param i_top\r
+        * @param i_bottom\r
+        * @param o_stack\r
+        * @return\r
+        * @throws NyARException\r
+        */\r
+       public int labeling(NyARGrayscaleRaster i_gs_raster,int i_th, int i_top, int i_bottom,NyARRleLabelFragmentInfoStack o_stack) throws NyARException\r
+       {\r
+               assert(i_gs_raster.isEqualBufferType(NyARBufferType.INT1D_GRAY_8));\r
+               return this.imple_labeling(i_gs_raster,i_th,i_top,i_bottom,o_stack);\r
+       }\r
+       private int imple_labeling(INyARRaster i_raster,int i_th,int i_top, int i_bottom,NyARRleLabelFragmentInfoStack o_stack) throws NyARException\r
        {\r
                // リセット処理\r
-               this.number_of_fragment = 0;\r
-               o_stack.clear();\r
+               final RleInfoStack rlestack=this._rlestack;\r
+               rlestack.clear();\r
+\r
                //\r
                RleElement[] rle_prev = this._rle1;\r
                RleElement[] rle_current = this._rle2;\r
                int len_prev = 0;\r
                int len_current = 0;\r
-               final int width = i_bin_raster.getWidth();\r
-               int[] in_buf = (int[]) i_bin_raster.getBufferReader().getBuffer();\r
+               final int width = i_raster.getWidth();\r
+               int[] in_buf = (int[]) i_raster.getBuffer();\r
 \r
-               short nof = this.number_of_fragment;\r
+               int id_max = 0;\r
+               int label_count=0;\r
                // 初段登録\r
 \r
-               len_prev = toRel(in_buf, i_top, width, rle_prev);\r
+               len_prev = toRel(in_buf, i_top, width, rle_prev,i_th);\r
                for (int i = 0; i < len_prev; i++) {\r
                        // フラグメントID=フラグメント初期値、POS=Y値、RELインデクス=行\r
-                       addFragment(rle_prev[i], nof, i_top, i,o_stack);\r
-                       nof++;\r
+                       addFragment(rle_prev[i], id_max, i_top,rlestack);\r
+                       id_max++;\r
                        // nofの最大値チェック\r
+                       label_count++;\r
                }\r
-               RleLabelFragmentInfoStack.RleLabelFragmentInfo[] f_array = o_stack.getArray();\r
+               RleInfoStack.RleInfo[] f_array = rlestack.getArray();\r
                // 次段結合\r
                for (int y = i_top + 1; y < i_bottom; y++) {\r
                        // カレント行の読込\r
-                       len_current = toRel(in_buf, y * width, width, rle_current);\r
+                       len_current = toRel(in_buf, y * width, width, rle_current,i_th);\r
                        int index_prev = 0;\r
 \r
                        SCAN_CUR: for (int i = 0; i < len_current; i++) {\r
                                // index_prev,len_prevの位置を調整する\r
-                               short id = -1;\r
+                               int id = -1;\r
                                // チェックすべきprevがあれば確認\r
                                SCAN_PREV: while (index_prev < len_prev) {\r
                                        if (rle_current[i].l - rle_prev[index_prev].r > 0) {// 0なら8方位ラベリング\r
@@ -167,31 +267,29 @@ public class NyARLabeling_Rle
                                                continue;\r
                                        } else if (rle_prev[index_prev].l - rle_current[i].r > 0) {// 0なら8方位ラベリングになる\r
                                                // prevがcur右方にある→独立フラグメント\r
-                                               addFragment(rle_current[i], nof, y, i,o_stack);\r
-                                               nof++;\r
+                                               addFragment(rle_current[i], id_max, y,rlestack);\r
+                                               id_max++;\r
+                                               label_count++;\r
                                                // 次のindexをしらべる\r
                                                continue SCAN_CUR;\r
                                        }\r
-                                       // 結合対象->prevのIDをコピーして、対象フラグメントの情報を更新\r
-                                       id = f_array[rle_prev[index_prev].id].id;\r
-                                       RleLabelFragmentInfoStack.RleLabelFragmentInfo prev_ptr;\r
-                                       final RleLabelFragmentInfoStack.RleLabelFragmentInfo id_ptr = f_array[id];\r
-                                       prev_ptr = f_array[rle_prev[index_prev].id];\r
-                                       rle_current[i].id = id;\r
+                                       id=rle_prev[index_prev].fid;//ルートフラグメントid\r
+                                       RleInfoStack.RleInfo id_ptr = f_array[id];\r
+                                       //結合対象(初回)->prevのIDをコピーして、ルートフラグメントの情報を更新\r
+                                       rle_current[i].fid = id;//フラグメントIDを保存\r
                                        //\r
                                        final int l= rle_current[i].l;\r
                                        final int r= rle_current[i].r;\r
-                                       final int len=rle_current[i].r - rle_current[i].l;\r
+                                       final int len=r-l;\r
+                                       //結合先フラグメントの情報を更新する。\r
                                        id_ptr.area += len;\r
-                                       id_ptr.entry_x = prev_ptr.entry_x;\r
-                                       id_ptr.clip_l=l<prev_ptr.clip_l?l:prev_ptr.clip_l;\r
-                                       id_ptr.clip_r=r>prev_ptr.clip_r?r:prev_ptr.clip_r;\r
-                                       //id_ptr.clip_tは変更無し。\r
+                                       //tとentry_xは、結合先のを使うので更新しない。\r
+                                       id_ptr.clip_l=l<id_ptr.clip_l?l:id_ptr.clip_l;\r
+                                       id_ptr.clip_r=r>id_ptr.clip_r?r-1:id_ptr.clip_r;\r
                                        id_ptr.clip_b=y;\r
-                                       id_ptr.pos_x+=len*(2*l+(len-1)*1);\r
+                                       id_ptr.pos_x+=(len*(2*l+(len-1)))/2;\r
                                        id_ptr.pos_y+=y*len;\r
-                                       // 多重リンクの確認\r
-\r
+                                       //多重結合の確認(2個目以降)\r
                                        index_prev++;\r
                                        while (index_prev < len_prev) {\r
                                                if (rle_current[i].l - rle_prev[index_prev].r > 0) {// 0なら8方位ラベリング\r
@@ -202,41 +300,62 @@ public class NyARLabeling_Rle
                                                        index_prev--;\r
                                                        continue SCAN_CUR;\r
                                                }\r
-                                               // prevとcurは連結している。\r
-                                               final short prev_id = rle_prev[index_prev].id;\r
-                                               prev_ptr = f_array[prev_id];\r
-                                               if (id != prev_id) {\r
-                                                       id_ptr.area += prev_ptr.area;\r
-                                                       prev_ptr.area = 0;\r
-                                                       // 結合対象->現在のidをインデクスにセット\r
-                                                       prev_ptr.id = id;\r
+                                               // prevとcurは連結している→ルートフラグメントの統合\r
+                                               \r
+                                               //結合するルートフラグメントを取得\r
+                                               final int prev_id =rle_prev[index_prev].fid;\r
+                                               RleInfoStack.RleInfo prev_ptr = f_array[prev_id];\r
+                                               if (id != prev_id){\r
+                                                       label_count--;\r
+                                                       //prevとcurrentのフラグメントidを書き換える。\r
+                                                       for(int i2=index_prev;i2<len_prev;i2++){\r
+                                                               //prevは現在のidから最後まで\r
+                                                               if(rle_prev[i2].fid==prev_id){\r
+                                                                       rle_prev[i2].fid=id;\r
+                                                               }\r
+                                                       }\r
+                                                       for(int i2=0;i2<i;i2++){\r
+                                                               //currentは0から現在-1まで\r
+                                                               if(rle_current[i2].fid==prev_id){\r
+                                                                       rle_current[i2].fid=id;\r
+                                                               }\r
+                                                       }\r
+                                                       \r
+                                                       //現在のルートフラグメントに情報を集約\r
+                                                       id_ptr.area +=prev_ptr.area;\r
+                                                       id_ptr.pos_x+=prev_ptr.pos_x;\r
+                                                       id_ptr.pos_y+=prev_ptr.pos_y;\r
                                                        //tとentry_xの決定\r
                                                        if (id_ptr.clip_t > prev_ptr.clip_t) {\r
                                                                // 現在の方が下にある。\r
                                                                id_ptr.clip_t = prev_ptr.clip_t;\r
                                                                id_ptr.entry_x = prev_ptr.entry_x;\r
                                                        }else if (id_ptr.clip_t < prev_ptr.clip_t) {\r
-                                                               // 現在の方が上にある。なにもしない。\r
+                                                               // 現在の方が上にある。prevにフィードバック\r
                                                        } else {\r
                                                                // 水平方向で小さい方がエントリポイント。\r
                                                                if (id_ptr.entry_x > prev_ptr.entry_x) {\r
                                                                        id_ptr.entry_x = prev_ptr.entry_x;\r
+                                                               }else{\r
                                                                }\r
-                                                       }                                                       \r
-                                                       //bの決定(現状のまま)\r
+                                                       }\r
                                                        //lの決定\r
                                                        if (id_ptr.clip_l > prev_ptr.clip_l) {\r
                                                                id_ptr.clip_l=prev_ptr.clip_l;\r
+                                                       }else{\r
                                                        }\r
                                                        //rの決定\r
                                                        if (id_ptr.clip_r < prev_ptr.clip_r) {\r
                                                                id_ptr.clip_r=prev_ptr.clip_r;\r
+                                                       }else{\r
                                                        }\r
-                                                       id_ptr.pos_x+=prev_ptr.pos_x;\r
-                                                       id_ptr.pos_y+=prev_ptr.pos_y;                                                   \r
-                                                       \r
+                                                       //bの決定\r
 \r
+                                                       //結合済のルートフラグメントを無効化する。\r
+                                                       prev_ptr.area=0;\r
                                                }\r
+\r
+\r
                                                index_prev++;\r
                                        }\r
                                        index_prev--;\r
@@ -244,9 +363,10 @@ public class NyARLabeling_Rle
                                }\r
                                // curにidが割り当てられたかを確認\r
                                // 右端独立フラグメントを追加\r
-                               if (id < 0) {\r
-                                       addFragment(rle_current[i], nof, y, i,o_stack);\r
-                                       nof++;\r
+                               if (id < 0){\r
+                                       addFragment(rle_current[i], id_max, y,rlestack);\r
+                                       id_max++;\r
+                                       label_count++;\r
                                }\r
                        }\r
                        // prevとrelの交換\r
@@ -255,8 +375,34 @@ public class NyARLabeling_Rle
                        len_prev = len_current;\r
                        rle_current = tmp;\r
                }\r
-               // フラグメントの数を更新\r
-               this.number_of_fragment = nof;\r
+               //対象のラベルだけ転写\r
+               o_stack.init(label_count);\r
+               NyARRleLabelFragmentInfoStack.RleLabelFragmentInfo[] o_dest_array=o_stack.getArray();\r
+               final int max=this._max_area;\r
+               final int min=this._min_area;\r
+               int active_labels=0;\r
+               for(int i=id_max-1;i>=0;i--){\r
+                       final int area=f_array[i].area;\r
+                       if(area<min || area>max){//対象外のエリア0のもminではじく\r
+                               continue;\r
+                       }\r
+                       //\r
+                       final RleInfoStack.RleInfo src_info=f_array[i];\r
+                       final NyARRleLabelFragmentInfoStack.RleLabelFragmentInfo dest_info=o_dest_array[active_labels];\r
+                       dest_info.area=area;\r
+                       dest_info.clip_b=src_info.clip_b;\r
+                       dest_info.clip_r=src_info.clip_r;\r
+                       dest_info.clip_t=src_info.clip_t;\r
+                       dest_info.clip_l=src_info.clip_l;\r
+                       dest_info.entry_x=src_info.entry_x;\r
+                       dest_info.pos_x=src_info.pos_x/src_info.area;\r
+                       dest_info.pos_y=src_info.pos_y/src_info.area;\r
+                       active_labels++;\r
+               }\r
+               //ラベル数を再設定\r
+               o_stack.pops(label_count-active_labels);\r
+               //ラベル数を返却\r
+               return active_labels;\r
        }       \r
 }\r
 \r