OSDN Git Service

[NyARToolKit for java]update document
[nyartoolkit-and/nyartoolkit-and.git] / lib / src / jp / nyatla / nyartoolkit / core / squaredetect / NyARContourPickup.java
1 /* \r
2  * PROJECT: NyARToolkit\r
3  * --------------------------------------------------------------------------------\r
4  * This work is based on the original ARToolKit developed by\r
5  *   Hirokazu Kato\r
6  *   Mark Billinghurst\r
7  *   HITLab, University of Washington, Seattle\r
8  * http://www.hitl.washington.edu/artoolkit/\r
9  *\r
10  * The NyARToolkit is Java edition ARToolKit class library.\r
11  * Copyright (C)2008-2009 Ryo Iizuka\r
12  *\r
13  * This program is free software: you can redistribute it and/or modify\r
14  * it under the terms of the GNU General Public License as published by\r
15  * the Free Software Foundation, either version 3 of the License, or\r
16  * (at your option) any later version.\r
17  * \r
18  * This program is distributed in the hope that it will be useful,\r
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
21  * GNU General Public License for more details.\r
22  *\r
23  * You should have received a copy of the GNU General Public License\r
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
25  * \r
26  * For further information please contact.\r
27  *      http://nyatla.jp/nyatoolkit/\r
28  *      <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
29  * \r
30  */\r
31 package jp.nyatla.nyartoolkit.core.squaredetect;\r
32 \r
33 import jp.nyatla.nyartoolkit.NyARException;\r
34 import jp.nyatla.nyartoolkit.core.raster.*;\r
35 import jp.nyatla.nyartoolkit.core.types.*;\r
36 \r
37 /**\r
38  * このクラスは、輪郭線の抽出クラスです。\r
39  * 画像中の1点を開始点として、8方位探索で輪郭線を抽出します。出力は輪郭点の配列です。\r
40  * <p>入力できる画素形式 - {@link #getContour}に入力できる画素形式に制限があります。<br/>\r
41  * {@link NyARBinRaster}\r
42  * <ul>\r
43  * <li>{@link NyARBufferType#INT1D_BIN_8}\r
44  * </ul>\r
45  * {@link NyARGrayscaleRaster}\r
46  * <ul>\r
47  * <li>{@link NyARBufferType#INT1D_GRAY_8}\r
48  * </ul>\r
49  * </p>\r
50  */\r
51 public class NyARContourPickup\r
52 {\r
53         //巡回参照できるように、テーブルを二重化\r
54         //                                           0  1  2  3  4  5  6  7   0  1  2  3  4  5  6\r
55         /** 8方位探索の座標マップ*/\r
56         protected final static int[] _getContour_xdir = { 0, 1, 1, 1, 0,-1,-1,-1 , 0, 1, 1, 1, 0,-1,-1};\r
57         /** 8方位探索の座標マップ*/\r
58         protected final static int[] _getContour_ydir = {-1,-1, 0, 1, 1, 1, 0,-1 ,-1,-1, 0, 1, 1, 1, 0};\r
59 \r
60         /**\r
61          * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。\r
62          * 開始点は、輪郭の一部である必要があります。\r
63          * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。\r
64          * @param i_raster\r
65          * 輪郭線を抽出するラスタを指定します。\r
66          * @param i_entry_x\r
67          * 輪郭抽出の開始点です。\r
68          * @param i_entry_y\r
69          * 輪郭抽出の開始点です。\r
70          * @param o_coord\r
71          * 輪郭点を格納するオブジェクトを指定します。\r
72          * @return\r
73          * 輪郭線がo_coordの長さを超えた場合、falseを返します。\r
74          * @throws NyARException\r
75          */\r
76         public boolean getContour(NyARBinRaster i_raster,int i_entry_x,int i_entry_y,NyARIntCoordinates o_coord) throws NyARException\r
77         {\r
78                 assert(i_raster.isEqualBufferType(NyARBufferType.INT1D_BIN_8));\r
79                 NyARIntSize s=i_raster.getSize();\r
80                 return impl_getContour(i_raster,0,0,s.w-1,s.h-1,0,i_entry_x,i_entry_y,o_coord);\r
81         }\r
82         /**\r
83          * この関数は、ラスタの指定点を基点に、画像の特定の範囲内から輪郭線を抽出します。\r
84          * 開始点は、輪郭の一部である必要があります。\r
85          * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。\r
86          * @param i_raster\r
87          * 輪郭線を抽出するラスタを指定します。\r
88          * @param i_area\r
89          * 輪郭線の抽出範囲を指定する矩形。i_rasterのサイズ内である必要があります。\r
90          * @param i_entry_x\r
91          * 輪郭抽出の開始点です。\r
92          * @param i_entry_y\r
93          * 輪郭抽出の開始点です。\r
94          * @param o_coord\r
95          * 輪郭点を格納するオブジェクトを指定します。\r
96          * @return\r
97          * 輪郭線がo_coordの長さを超えた場合、falseを返します。\r
98          * @throws NyARException\r
99          */     \r
100         public boolean getContour(NyARBinRaster i_raster,NyARIntRect i_area,int i_entry_x,int i_entry_y,NyARIntCoordinates o_coord) throws NyARException\r
101         {\r
102                 assert(i_raster.isEqualBufferType(NyARBufferType.INT1D_BIN_8));\r
103                 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,0,i_entry_x,i_entry_y,o_coord);\r
104         }\r
105         /**\r
106          * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。\r
107          * 開始点は、輪郭の一部である必要があります。\r
108          * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。\r
109          * @param i_raster\r
110          * 輪郭線を抽出するラスタを指定します。\r
111          * @param i_th\r
112          * 輪郭とみなす暗点の敷居値を指定します。\r
113          * @param i_entry_x\r
114          * 輪郭抽出の開始点です。\r
115          * @param i_entry_y\r
116          * 輪郭抽出の開始点です。\r
117          * @param o_coord\r
118          * 輪郭点を格納する配列を指定します。i_array_sizeよりも大きなサイズの配列が必要です。\r
119          * @return\r
120          * 輪郭の抽出に成功するとtrueを返します。輪郭抽出に十分なバッファが無いと、falseになります。\r
121          * @throws NyARException\r
122          */\r
123         public boolean getContour(NyARGrayscaleRaster i_raster,int i_th,int i_entry_x,int i_entry_y,NyARIntCoordinates o_coord) throws NyARException\r
124         {\r
125                 assert(i_raster.isEqualBufferType(NyARBufferType.INT1D_GRAY_8));\r
126                 NyARIntSize s=i_raster.getSize();\r
127                 return impl_getContour(i_raster,0,0,s.w-1,s.h-1,i_th,i_entry_x,i_entry_y,o_coord);\r
128         }\r
129         /**\r
130          * この関数は、ラスタの指定点を基点に、画像の特定の範囲内から輪郭線を抽出します。\r
131          * 開始点は、輪郭の一部である必要があります。\r
132          * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。\r
133          * @param i_raster\r
134          * 輪郭線を抽出するラスタを指定します。\r
135          * @param i_area\r
136          * 輪郭線の抽出範囲を指定する矩形。i_rasterのサイズ内である必要があります。\r
137          * @param i_th\r
138          * 輪郭とみなす暗点の敷居値を指定します。\r
139          * @param i_entry_x\r
140          * 輪郭抽出の開始点です。\r
141          * @param i_entry_y\r
142          * 輪郭抽出の開始点です。\r
143          * @param o_coord\r
144          * 輪郭点を格納するオブジェクトを指定します。\r
145          * @return\r
146          * 輪郭線がo_coordの長さを超えた場合、falseを返します。\r
147          * @throws NyARException\r
148          */\r
149         public boolean getContour(NyARGrayscaleRaster i_raster,NyARIntRect i_area,int i_th,int i_entry_x,int i_entry_y,NyARIntCoordinates o_coord) throws NyARException\r
150         {\r
151                 assert(i_raster.isEqualBufferType(NyARBufferType.INT1D_GRAY_8));\r
152                 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);\r
153         }\r
154         \r
155         /**\r
156          * 輪郭線抽出関数の実体です。\r
157          * @param i_raster\r
158          * @param i_l\r
159          * @param i_t\r
160          * @param i_r\r
161          * @param i_b\r
162          * @param i_th\r
163          * @param i_entry_x\r
164          * @param i_entry_y\r
165          * @param o_coord\r
166          * @return\r
167          * @throws NyARException\r
168          */\r
169         private boolean impl_getContour(INyARRaster i_raster,int i_l,int i_t,int i_r,int i_b,int i_th,int i_entry_x,int i_entry_y,NyARIntCoordinates o_coord) throws NyARException\r
170         {\r
171                 assert(i_t<=i_entry_x);\r
172                 NyARIntPoint2d[] coord=o_coord.items;\r
173                 final int[] xdir = _getContour_xdir;// static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};\r
174                 final int[] ydir = _getContour_ydir;// static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};\r
175 \r
176                 final int[] buf=(int[])i_raster.getBuffer();\r
177                 final int width=i_raster.getWidth();\r
178                 //クリップ領域の上端に接しているポイントを得る。\r
179 \r
180 \r
181                 int max_coord=o_coord.items.length;\r
182                 int coord_num = 1;\r
183                 coord[0].x = i_entry_x;\r
184                 coord[0].y = i_entry_y;\r
185                 int dir = 5;\r
186 \r
187                 int c = i_entry_x;\r
188                 int r = i_entry_y;\r
189                 for (;;) {\r
190                         dir = (dir + 5) % 8;//dirの正規化\r
191                         //ここは頑張ればもっと最適化できると思うよ。\r
192                         //4隅以外の境界接地の場合に、境界チェックを省略するとかね。\r
193                         if(c>i_l && c<i_r && r>i_t && r<i_b){\r
194                                 for(;;){//gotoのエミュレート用のfor文\r
195                                         //境界に接していないとき(暗点判定)\r
196                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
197                                                 break;\r
198                                         }\r
199                                         dir++;\r
200                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
201                                                 break;\r
202                                         }\r
203                                         dir++;\r
204                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
205                                                 break;\r
206                                         }\r
207                                         dir++;\r
208                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
209                                                 break;\r
210                                         }\r
211                                         dir++;\r
212                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
213                                                 break;\r
214                                         }\r
215                                         dir++;\r
216                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
217                                                 break;\r
218                                         }\r
219                                         dir++;\r
220                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
221                                                 break;\r
222                                         }\r
223                                         dir++;\r
224                                         if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
225                                                 break;\r
226                                         }\r
227 \r
228                                         //8方向全て調べたけどラベルが無いよ?\r
229                                         throw new NyARException();                      \r
230                                 }\r
231                         }else{\r
232                                 //境界に接しているとき\r
233                                 int i;\r
234                                 for (i = 0; i < 8; i++){                                \r
235                                         final int x=c + xdir[dir];\r
236                                         final int y=r + ydir[dir];\r
237                                         //境界チェック\r
238                                         if(x>=i_l && x<=i_r && y>=i_t && y<=i_b){\r
239                                                 if (buf[(y)*width+(x)] <= i_th) {\r
240                                                         break;\r
241                                                 }\r
242                                         }\r
243                                         dir++;//倍長テーブルを参照するので問題なし\r
244                                 }\r
245                                 if (i == 8) {\r
246                                         //8方向全て調べたけどラベルが無いよ?\r
247                                         throw new NyARException();// return(-1);\r
248                                 }                               \r
249                         }\r
250 \r
251                         // xcoordとycoordをc,rにも保存\r
252                         c = c + xdir[dir];\r
253                         r = r + ydir[dir];\r
254                         coord[coord_num].x = c;\r
255                         coord[coord_num].y = r;\r
256                         //終了条件判定\r
257                         if (c == i_entry_x && r == i_entry_y){\r
258                                 //開始点と同じピクセルに到達したら、終点の可能性がある。\r
259                                 coord_num++;\r
260                                 //末端のチェック\r
261                                 if (coord_num == max_coord) {\r
262                                         //輪郭bufが末端に達した\r
263                                         return false;\r
264                                 }                               \r
265                                 //末端候補の次のピクセルを調べる\r
266                                 dir = (dir + 5) % 8;//dirの正規化\r
267                                 int i;\r
268                                 for (i = 0; i < 8; i++){                                \r
269                                         final int x=c + xdir[dir];\r
270                                         final int y=r + ydir[dir];\r
271                                         //境界チェック\r
272                                         if(x>=i_l && x<=i_r && y>=i_t && y<=i_b){\r
273                                                 if (buf[(y)*width+(x)] <= i_th) {\r
274                                                         break;\r
275                                                 }\r
276                                         }\r
277                                         dir++;//倍長テーブルを参照するので問題なし\r
278                                 }\r
279                                 if (i == 8) {\r
280                                         //8方向全て調べたけどラベルが無いよ?\r
281                                         throw new NyARException();\r
282                                 }\r
283                                 //得たピクセルが、[1]と同じならば、末端である。\r
284                                 c = c + xdir[dir];\r
285                                 r = r + ydir[dir];\r
286                                 if(coord[1].x ==c && coord[1].y ==r){\r
287                                         //終点に達している。\r
288                                         o_coord.length=coord_num;\r
289                                         break;\r
290                                 }else{\r
291                                         //終点ではない。\r
292                                         coord[coord_num].x = c;\r
293                                         coord[coord_num].y = r;\r
294                                 }\r
295                         }\r
296                         coord_num++;\r
297                         //末端のチェック\r
298                         if (coord_num == max_coord) {\r
299                                 //輪郭が末端に達した\r
300                                 return false;\r
301                         }\r
302                 }\r
303                 return true;\r
304         }\r
305 }\r