2 * PROJECT: NyARToolkit(Extension)
\r
3 * --------------------------------------------------------------------------------
\r
4 * The NyARToolkit is Java version ARToolkit class library.
\r
5 * Copyright (C)2008 R.Iizuka
\r
7 * This program is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation; either version 2
\r
10 * of the License, or (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 framework; if not, write to the Free Software
\r
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
21 * For further information please contact.
\r
22 * http://nyatla.jp/nyatoolkit/
\r
23 * <airmail(at)ebony.plala.or.jp>
\r
26 package jp.nyatla.nyartoolkit.core.labeling.rlelabeling;
\r
28 import jp.nyatla.nyartoolkit.NyARException;
\r
29 import jp.nyatla.nyartoolkit.core.raster.*;
\r
30 import jp.nyatla.utils.*;
\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)
\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
77 // RleImageをラベリングする。
\r
78 public class NyARLabeling_Rle
\r
80 private static final int AR_AREA_MAX = 100000;// #define AR_AREA_MAX 100000
\r
81 private static final int AR_AREA_MIN = 70;// #define AR_AREA_MIN 70
\r
83 private RleInfoStack _rlestack;
\r
84 private RleElement[] _rle1;
\r
85 private RleElement[] _rle2;
\r
86 private int _max_area;
\r
87 private int _min_area;
\r
89 public NyARLabeling_Rle(int i_width,int i_height)
\r
91 this._rlestack=new RleInfoStack(i_width*i_height*2048/(320*240)+32);
\r
92 this._rle1 = RleElement.createArray(i_width/2+1);
\r
93 this._rle2 = RleElement.createArray(i_width/2+1);
\r
94 setAreaRange(AR_AREA_MAX,AR_AREA_MIN);
\r
103 public void setAreaRange(int i_max,int i_min)
\r
105 this._max_area=i_max;
\r
106 this._min_area=i_min;
\r
111 * i_bin_bufのbinイメージをREL圧縮する。
\r
113 * @param i_bin_raster
\r
115 private int toRel(int[] i_bin_buf, int i_st, int i_len, RleElement[] i_out)
\r
121 final int right_edge = i_st + i_len - 1;
\r
122 while (x < right_edge) {
\r
124 if (i_bin_buf[x] != 0) {
\r
130 i_out[current].l = r;
\r
133 while (x < right_edge) {
\r
134 if (i_bin_buf[x] != 0) {
\r
135 // 明点(1)→暗点(0)配列終了>登録
\r
136 i_out[current].r = r;
\r
139 r = -1;// 右端の位置を0に。
\r
148 // 最後の1点だけ判定方法が少し違うの。
\r
149 if (i_bin_buf[x] != 0) {
\r
150 // 明点→rカウント中なら暗点配列終了>登録
\r
152 i_out[current].r = r;
\r
156 // 暗点→カウント中でなければl1で追加
\r
158 i_out[current].r = (r + 1);
\r
161 i_out[current].l = (i_len - 1);
\r
162 i_out[current].r = (i_len);
\r
170 private void addFragment(RleElement i_rel_img, int i_nof, int i_row_index, int i_rel_index,RleInfoStack o_stack) throws NyARException
\r
173 final int len=i_rel_img.r - l;
\r
174 i_rel_img.fid = i_nof;// REL毎の固有ID
\r
175 RleInfoStack.RleInfo v = o_stack.prePush();
\r
179 v.clip_r=i_rel_img.r-1;
\r
180 v.clip_t=i_row_index;
\r
181 v.clip_b=i_row_index;
\r
182 v.pos_x=(len*(2*l+(len-1)))/2;
\r
183 v.pos_y=i_row_index*len;
\r
189 public int labeling(NyARBinRaster i_bin_raster, int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException
\r
192 final RleInfoStack rlestack=this._rlestack;
\r
196 RleElement[] rle_prev = this._rle1;
\r
197 RleElement[] rle_current = this._rle2;
\r
199 int len_current = 0;
\r
200 final int width = i_bin_raster.getWidth();
\r
201 int[] in_buf = (int[]) i_bin_raster.getBufferReader().getBuffer();
\r
207 len_prev = toRel(in_buf, i_top, width, rle_prev);
\r
208 for (int i = 0; i < len_prev; i++) {
\r
209 // フラグメントID=フラグメント初期値、POS=Y値、RELインデクス=行
\r
210 addFragment(rle_prev[i], id_max, i_top, i,rlestack);
\r
215 RleInfoStack.RleInfo[] f_array = rlestack.getArray();
\r
217 for (int y = i_top + 1; y < i_bottom; y++) {
\r
219 len_current = toRel(in_buf, y * width, width, rle_current);
\r
220 int index_prev = 0;
\r
222 SCAN_CUR: for (int i = 0; i < len_current; i++) {
\r
223 // index_prev,len_prevの位置を調整する
\r
225 // チェックすべきprevがあれば確認
\r
226 SCAN_PREV: while (index_prev < len_prev) {
\r
227 if (rle_current[i].l - rle_prev[index_prev].r > 0) {// 0なら8方位ラベリング
\r
228 // prevがcurの左方にある→次のフラグメントを探索
\r
231 } else if (rle_prev[index_prev].l - rle_current[i].r > 0) {// 0なら8方位ラベリングになる
\r
232 // prevがcur右方にある→独立フラグメント
\r
233 addFragment(rle_current[i], id_max, y, i,rlestack);
\r
239 id=rle_prev[index_prev].fid;//ルートフラグメントid
\r
240 RleInfoStack.RleInfo id_ptr = f_array[id];
\r
241 //結合対象(初回)->prevのIDをコピーして、ルートフラグメントの情報を更新
\r
242 rle_current[i].fid = id;//フラグメントIDを保存
\r
244 final int l= rle_current[i].l;
\r
245 final int r= rle_current[i].r;
\r
247 //結合先フラグメントの情報を更新する。
\r
248 id_ptr.area += len;
\r
249 //tとentry_xは、結合先のを使うので更新しない。
\r
250 id_ptr.clip_l=l<id_ptr.clip_l?l:id_ptr.clip_l;
\r
251 id_ptr.clip_r=r>id_ptr.clip_r?r-1:id_ptr.clip_r;
\r
253 id_ptr.pos_x+=(len*(2*l+(len-1)))/2;
\r
254 id_ptr.pos_y+=y*len;
\r
257 while (index_prev < len_prev) {
\r
258 if (rle_current[i].l - rle_prev[index_prev].r > 0) {// 0なら8方位ラベリング
\r
259 // prevがcurの左方にある→prevはcurに連結していない。
\r
261 } else if (rle_prev[index_prev].l - rle_current[i].r > 0) {// 0なら8方位ラベリングになる
\r
262 // prevがcurの右方にある→prevはcurに連結していない。
\r
266 // prevとcurは連結している→ルートフラグメントの統合
\r
269 final int prev_id =rle_prev[index_prev].fid;
\r
270 RleInfoStack.RleInfo prev_ptr = f_array[prev_id];
\r
271 if (id != prev_id){
\r
273 //prevとcurrentのフラグメントidを書き換える。
\r
274 for(int i2=index_prev;i2<len_prev;i2++){
\r
276 if(rle_prev[i2].fid==prev_id){
\r
277 rle_prev[i2].fid=id;
\r
280 for(int i2=0;i2<i;i2++){
\r
281 //currentは0から現在-1まで
\r
282 if(rle_current[i2].fid==prev_id){
\r
283 rle_current[i2].fid=id;
\r
287 //現在のルートフラグメントに情報を集約
\r
288 id_ptr.area +=prev_ptr.area;
\r
289 id_ptr.pos_x+=prev_ptr.pos_x;
\r
290 id_ptr.pos_y+=prev_ptr.pos_y;
\r
292 if (id_ptr.clip_t > prev_ptr.clip_t) {
\r
294 id_ptr.clip_t = prev_ptr.clip_t;
\r
295 id_ptr.entry_x = prev_ptr.entry_x;
\r
296 }else if (id_ptr.clip_t < prev_ptr.clip_t) {
\r
297 // 現在の方が上にある。prevにフィードバック
\r
299 // 水平方向で小さい方がエントリポイント。
\r
300 if (id_ptr.entry_x > prev_ptr.entry_x) {
\r
301 id_ptr.entry_x = prev_ptr.entry_x;
\r
306 if (id_ptr.clip_l > prev_ptr.clip_l) {
\r
307 id_ptr.clip_l=prev_ptr.clip_l;
\r
311 if (id_ptr.clip_r < prev_ptr.clip_r) {
\r
312 id_ptr.clip_r=prev_ptr.clip_r;
\r
317 //結合済のルートフラグメントを無効化する。
\r
327 // curにidが割り当てられたかを確認
\r
330 addFragment(rle_current[i], id_max, y, i,rlestack);
\r
336 RleElement[] tmp = rle_prev;
\r
337 rle_prev = rle_current;
\r
338 len_prev = len_current;
\r
342 o_stack.reserv(label_count);
\r
343 RleLabelFragmentInfoStack.RleLabelFragmentInfo[] o_dest_array=o_stack.getArray();
\r
344 final int max=this._max_area;
\r
345 final int min=this._min_area;
\r
346 int active_labels=0;
\r
347 for(int i=id_max-1;i>=0;i--){
\r
348 final int area=f_array[i].area;
\r
349 if(area<min || area>max){//対象外のエリア0のもminではじく
\r
353 final RleInfoStack.RleInfo src_info=f_array[i];
\r
354 final RleLabelFragmentInfoStack.RleLabelFragmentInfo dest_info=o_dest_array[active_labels];
\r
355 dest_info.area=area;
\r
356 dest_info.clip_b=src_info.clip_b;
\r
357 dest_info.clip_r=src_info.clip_r;
\r
358 dest_info.clip_t=src_info.clip_t;
\r
359 dest_info.clip_l=src_info.clip_l;
\r
360 dest_info.entry_x=src_info.entry_x;
\r
361 dest_info.pos_x=src_info.pos_x/src_info.area;
\r
362 dest_info.pos_y=src_info.pos_y/src_info.area;
\r
366 o_stack.pops(label_count-active_labels);
\r
368 return active_labels;
\r