2 * PROJECT: NyARToolkit(Extension)
\r
3 * --------------------------------------------------------------------------------
\r
4 * The NyARToolkit is Java edition ARToolKit class library.
\r
5 * Copyright (C)2008-2009 Ryo Iizuka
\r
7 * This program is free software: you can redistribute it and/or modify
\r
8 * it under the terms of the GNU General Public License as published by
\r
9 * the Free Software Foundation, either version 3 of the License, or
\r
10 * (at your option) any later version.
\r
12 * This program is distributed in the hope that it will be useful,
\r
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 * GNU General Public License for more details.
\r
17 * You should have received a copy of the GNU General Public License
\r
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
20 * For further information please contact.
\r
21 * http://nyatla.jp/nyatoolkit/
\r
22 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
\r
25 package jp.nyatla.nyartoolkit.core.labeling.rlelabeling;
\r
27 import jp.nyatla.nyartoolkit.NyARException;
\r
28 import jp.nyatla.nyartoolkit.core.raster.*;
\r
29 import jp.nyatla.nyartoolkit.core.rasterreader.INyARBufferReader;
\r
30 import jp.nyatla.nyartoolkit.core.types.stack.NyObjectStack;
\r
32 class RleInfoStack extends NyObjectStack<RleInfoStack.RleInfo>
\r
34 public class RleInfo
\r
37 public int entry_x; // フラグメントラベルの位置
\r
46 public RleInfoStack(int i_length) throws NyARException
\r
48 super(i_length, RleInfoStack.RleInfo.class);
\r
52 protected RleInfoStack.RleInfo createElement()
\r
54 return new RleInfoStack.RleInfo();
\r
67 public static RleElement[] createArray(int i_length)
\r
69 RleElement[] ret = new RleElement[i_length];
\r
70 for (int i = 0; i < i_length; i++) {
\r
71 ret[i] = new RleElement();
\r
78 // RleImageをラベリングする。
\r
79 public class NyARLabeling_Rle
\r
81 private static final int AR_AREA_MAX = 100000;// #define AR_AREA_MAX 100000
\r
82 private static final int AR_AREA_MIN = 70;// #define AR_AREA_MIN 70
\r
84 private RleInfoStack _rlestack;
\r
85 private RleElement[] _rle1;
\r
86 private RleElement[] _rle2;
\r
87 private int _max_area;
\r
88 private int _min_area;
\r
90 public NyARLabeling_Rle(int i_width,int i_height) throws NyARException
\r
92 this._rlestack=new RleInfoStack(i_width*i_height*2048/(320*240)+32);
\r
93 this._rle1 = RleElement.createArray(i_width/2+1);
\r
94 this._rle2 = RleElement.createArray(i_width/2+1);
\r
95 setAreaRange(AR_AREA_MAX,AR_AREA_MIN);
\r
104 public void setAreaRange(int i_max,int i_min)
\r
106 this._max_area=i_max;
\r
107 this._min_area=i_min;
\r
112 * i_bin_bufのgsイメージをREL圧縮する。
\r
118 * BINラスタのときは0,GSラスタの時は閾値を指定する。
\r
119 * この関数は、閾値を暗点と認識します。
\r
123 private int toRel(int[] i_bin_buf, int i_st, int i_len, RleElement[] i_out,int i_th)
\r
129 final int right_edge = i_st + i_len - 1;
\r
130 while (x < right_edge) {
\r
132 if (i_bin_buf[x] > i_th) {
\r
138 i_out[current].l = r;
\r
141 while (x < right_edge) {
\r
142 if (i_bin_buf[x] > i_th) {
\r
143 // 明点(1)→暗点(0)配列終了>登録
\r
144 i_out[current].r = r;
\r
147 r = -1;// 右端の位置を0に。
\r
156 // 最後の1点だけ判定方法が少し違うの。
\r
157 if (i_bin_buf[x] > i_th) {
\r
158 // 明点→rカウント中なら暗点配列終了>登録
\r
160 i_out[current].r = r;
\r
164 // 暗点→カウント中でなければl1で追加
\r
166 i_out[current].r = (r + 1);
\r
169 i_out[current].l = (i_len - 1);
\r
170 i_out[current].r = (i_len);
\r
178 private void addFragment(RleElement i_rel_img, int i_nof, int i_row_index,RleInfoStack o_stack) throws NyARException
\r
181 final int len=i_rel_img.r - l;
\r
182 i_rel_img.fid = i_nof;// REL毎の固有ID
\r
183 RleInfoStack.RleInfo v = o_stack.prePush();
\r
187 v.clip_r=i_rel_img.r-1;
\r
188 v.clip_t=i_row_index;
\r
189 v.clip_b=i_row_index;
\r
190 v.pos_x=(len*(2*l+(len-1)))/2;
\r
191 v.pos_y=i_row_index*len;
\r
195 //所望のラスタからBIN-RLEに変換しながらの低速系も準備しようかな
\r
198 * 単一閾値を使ってGSラスタをBINラスタに変換しながらラベリングします。
\r
199 * @param i_gs_raster
\r
204 * @throws NyARException
\r
206 public int labeling(NyARBinRaster i_bin_raster, int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException
\r
208 assert(i_bin_raster.getBufferReader().isEqualBufferType(INyARBufferReader.BUFFERFORMAT_INT1D_BIN_8));
\r
209 return this.imple_labeling(i_bin_raster,0,i_top,i_bottom,o_stack);
\r
213 * @param i_gs_raster
\r
215 * 画像を2値化するための閾値。暗点<=th<明点となります。
\r
220 * @throws NyARException
\r
222 public int labeling(NyARGrayscaleRaster i_gs_raster,int i_th, int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException
\r
224 assert(i_gs_raster.getBufferReader().isEqualBufferType(INyARBufferReader.BUFFERFORMAT_INT1D_GRAY_8));
\r
225 return this.imple_labeling(i_gs_raster,i_th,i_top,i_bottom,o_stack);
\r
227 private int imple_labeling(INyARRaster i_raster,int i_th,int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException
\r
230 final RleInfoStack rlestack=this._rlestack;
\r
234 RleElement[] rle_prev = this._rle1;
\r
235 RleElement[] rle_current = this._rle2;
\r
237 int len_current = 0;
\r
238 final int width = i_raster.getWidth();
\r
239 int[] in_buf = (int[]) i_raster.getBufferReader().getBuffer();
\r
245 len_prev = toRel(in_buf, i_top, width, rle_prev,i_th);
\r
246 for (int i = 0; i < len_prev; i++) {
\r
247 // フラグメントID=フラグメント初期値、POS=Y値、RELインデクス=行
\r
248 addFragment(rle_prev[i], id_max, i_top,rlestack);
\r
253 RleInfoStack.RleInfo[] f_array = rlestack.getArray();
\r
255 for (int y = i_top + 1; y < i_bottom; y++) {
\r
257 len_current = toRel(in_buf, y * width, width, rle_current,i_th);
\r
258 int index_prev = 0;
\r
260 SCAN_CUR: for (int i = 0; i < len_current; i++) {
\r
261 // index_prev,len_prevの位置を調整する
\r
263 // チェックすべきprevがあれば確認
\r
264 SCAN_PREV: while (index_prev < len_prev) {
\r
265 if (rle_current[i].l - rle_prev[index_prev].r > 0) {// 0なら8方位ラベリング
\r
266 // prevがcurの左方にある→次のフラグメントを探索
\r
269 } else if (rle_prev[index_prev].l - rle_current[i].r > 0) {// 0なら8方位ラベリングになる
\r
270 // prevがcur右方にある→独立フラグメント
\r
271 addFragment(rle_current[i], id_max, y,rlestack);
\r
277 id=rle_prev[index_prev].fid;//ルートフラグメントid
\r
278 RleInfoStack.RleInfo id_ptr = f_array[id];
\r
279 //結合対象(初回)->prevのIDをコピーして、ルートフラグメントの情報を更新
\r
280 rle_current[i].fid = id;//フラグメントIDを保存
\r
282 final int l= rle_current[i].l;
\r
283 final int r= rle_current[i].r;
\r
285 //結合先フラグメントの情報を更新する。
\r
286 id_ptr.area += len;
\r
287 //tとentry_xは、結合先のを使うので更新しない。
\r
288 id_ptr.clip_l=l<id_ptr.clip_l?l:id_ptr.clip_l;
\r
289 id_ptr.clip_r=r>id_ptr.clip_r?r-1:id_ptr.clip_r;
\r
291 id_ptr.pos_x+=(len*(2*l+(len-1)))/2;
\r
292 id_ptr.pos_y+=y*len;
\r
295 while (index_prev < len_prev) {
\r
296 if (rle_current[i].l - rle_prev[index_prev].r > 0) {// 0なら8方位ラベリング
\r
297 // prevがcurの左方にある→prevはcurに連結していない。
\r
299 } else if (rle_prev[index_prev].l - rle_current[i].r > 0) {// 0なら8方位ラベリングになる
\r
300 // prevがcurの右方にある→prevはcurに連結していない。
\r
304 // prevとcurは連結している→ルートフラグメントの統合
\r
307 final int prev_id =rle_prev[index_prev].fid;
\r
308 RleInfoStack.RleInfo prev_ptr = f_array[prev_id];
\r
309 if (id != prev_id){
\r
311 //prevとcurrentのフラグメントidを書き換える。
\r
312 for(int i2=index_prev;i2<len_prev;i2++){
\r
314 if(rle_prev[i2].fid==prev_id){
\r
315 rle_prev[i2].fid=id;
\r
318 for(int i2=0;i2<i;i2++){
\r
319 //currentは0から現在-1まで
\r
320 if(rle_current[i2].fid==prev_id){
\r
321 rle_current[i2].fid=id;
\r
325 //現在のルートフラグメントに情報を集約
\r
326 id_ptr.area +=prev_ptr.area;
\r
327 id_ptr.pos_x+=prev_ptr.pos_x;
\r
328 id_ptr.pos_y+=prev_ptr.pos_y;
\r
330 if (id_ptr.clip_t > prev_ptr.clip_t) {
\r
332 id_ptr.clip_t = prev_ptr.clip_t;
\r
333 id_ptr.entry_x = prev_ptr.entry_x;
\r
334 }else if (id_ptr.clip_t < prev_ptr.clip_t) {
\r
335 // 現在の方が上にある。prevにフィードバック
\r
337 // 水平方向で小さい方がエントリポイント。
\r
338 if (id_ptr.entry_x > prev_ptr.entry_x) {
\r
339 id_ptr.entry_x = prev_ptr.entry_x;
\r
344 if (id_ptr.clip_l > prev_ptr.clip_l) {
\r
345 id_ptr.clip_l=prev_ptr.clip_l;
\r
349 if (id_ptr.clip_r < prev_ptr.clip_r) {
\r
350 id_ptr.clip_r=prev_ptr.clip_r;
\r
355 //結合済のルートフラグメントを無効化する。
\r
365 // curにidが割り当てられたかを確認
\r
368 addFragment(rle_current[i], id_max, y,rlestack);
\r
374 RleElement[] tmp = rle_prev;
\r
375 rle_prev = rle_current;
\r
376 len_prev = len_current;
\r
380 o_stack.init(label_count);
\r
381 RleLabelFragmentInfoStack.RleLabelFragmentInfo[] o_dest_array=o_stack.getArray();
\r
382 final int max=this._max_area;
\r
383 final int min=this._min_area;
\r
384 int active_labels=0;
\r
385 for(int i=id_max-1;i>=0;i--){
\r
386 final int area=f_array[i].area;
\r
387 if(area<min || area>max){//対象外のエリア0のもminではじく
\r
391 final RleInfoStack.RleInfo src_info=f_array[i];
\r
392 final RleLabelFragmentInfoStack.RleLabelFragmentInfo dest_info=o_dest_array[active_labels];
\r
393 dest_info.area=area;
\r
394 dest_info.clip_b=src_info.clip_b;
\r
395 dest_info.clip_r=src_info.clip_r;
\r
396 dest_info.clip_t=src_info.clip_t;
\r
397 dest_info.clip_l=src_info.clip_l;
\r
398 dest_info.entry_x=src_info.entry_x;
\r
399 dest_info.pos_x=src_info.pos_x/src_info.area;
\r
400 dest_info.pos_y=src_info.pos_y/src_info.area;
\r
404 o_stack.pops(label_count-active_labels);
\r
406 return active_labels;
\r