1 package jp.nyatla.nyartoolkit.rpf.tracker.nyartk.status;
\r
4 import jp.nyatla.nyartoolkit.NyARException;
\r
5 import jp.nyatla.nyartoolkit.core.types.*;
\r
6 import jp.nyatla.nyartoolkit.core.utils.NyARMath;
\r
7 import jp.nyatla.nyartoolkit.rpf.sampler.lrlabel.LowResolutionLabelingSamplerOut;
\r
8 import jp.nyatla.nyartoolkit.rpf.tracker.nyartk.INyARVectorReader;
\r
9 import jp.nyatla.nyartoolkit.rpf.utils.VecLinearCoordinates;
\r
14 * このクラスは、RECTステータスのターゲットステータスを格納します。
\r
15 * RECTステータスは、ラベルから推定した矩形の4点座標と、そこから計算できるパラメータを持ちます。
\r
17 public class NyARRectTargetStatus extends NyARTargetStatus
\r
19 private NyARRectTargetStatusPool _ref_my_pool;
\r
22 /** [read only]矩形の頂点情報。4要素です。*/
\r
23 public NyARDoublePoint2d[] vertex=NyARDoublePoint2d.createArray(4);
\r
25 /** [read only]頂点予想値から計算した、頂点速度の二乗値の合計*/
\r
26 public int estimate_sum_sq_vertex_velocity_ave;
\r
28 /** [read only]頂点予測値のクリップ領域。*/
\r
29 public NyARIntRect estimate_rect=new NyARIntRect();
\r
31 /** [read only]頂点予測位置。4要素です。*/
\r
32 public NyARDoublePoint2d[] estimate_vertex=NyARDoublePoint2d.createArray(4);
\r
34 /** [read only]どのような手法で矩形を検出したかを示す値。DT_XXXの値を取ります。*/
\r
35 public int detect_type;
\r
37 /** 定数値。初期矩形検出に成功し、値を更新したことを示す。*/
\r
38 public static final int DT_SQINIT=0;
\r
40 /** 定数値。ラベル情報を元にした検出に成功し、値を更新したことを示す。*/
\r
41 public static final int DT_SQDAILY=1;
\r
43 /** 定数値。直線トレース検出に成功し、値を更新したことを示す。*/
\r
44 public static final int DT_LIDAILY=2;
\r
46 /** 定数値。検出できず、過去のデータをそのまま引き継いだ事を示す。*/
\r
47 public static final int DT_FAILED=-1;
\r
54 * この関数は、所有されるプールオブジェクトが使います。ユーザは使いません。
\r
56 * プールオブジェクトのコントロールインタフェイス
\r
58 public NyARRectTargetStatus(NyARRectTargetStatusPool i_pool)
\r
60 super(i_pool._op_interface);
\r
61 this._ref_my_pool=i_pool;
\r
62 this.detect_type=DT_SQINIT;
\r
66 * 前回のステータスと予想パラメータを計算してセットします。
\r
67 * @param i_prev_param
\r
69 private final void setEstimateParam(NyARRectTargetStatus i_prev_param)
\r
71 NyARDoublePoint2d[] vc_ptr=this.vertex;
\r
72 NyARDoublePoint2d[] ve_ptr=this.estimate_vertex;
\r
73 int sum_of_vertex_sq_dist=0;
\r
74 if(i_prev_param!=null){
\r
76 NyARDoublePoint2d[] vp=i_prev_param.vertex;
\r
78 for(int i=3;i>=0;i--){
\r
79 int x=(int)((vc_ptr[i].x-vp[i].x));
\r
80 int y=(int)((vc_ptr[i].y-vp[i].y));
\r
82 ve_ptr[i].x=(int)vc_ptr[i].x+x;
\r
83 ve_ptr[i].y=(int)vc_ptr[i].y+y;
\r
84 sum_of_vertex_sq_dist+=x*x+y*y;
\r
88 for(int i=3;i>=0;i--){
\r
89 ve_ptr[i].x=(int)vc_ptr[i].x;
\r
90 ve_ptr[i].y=(int)vc_ptr[i].y;
\r
94 this.estimate_sum_sq_vertex_velocity_ave=sum_of_vertex_sq_dist/4;
\r
95 this.estimate_rect.setAreaRect(ve_ptr,4);
\r
96 // this.estimate_rect.clip(i_left, i_top, i_right, i_bottom);
\r
100 * この関数は、輪郭ステータスから矩形パラメータを推定して、インスタンスにセットします。
\r
101 * 関数の成否にかかわらず、入力オブジェクトとインスタンスの状態が変化することに注意してください。
\r
102 * 関数が成功すると、{@link #DT_SQINIT}を{@link #detect_type}にセットします。
\r
103 * @param i_contour_status
\r
104 * 輪郭ステータスを格納したオブジェクト。
\r
105 * 関数を実行すると、この内容は変更されます。
\r
106 * @param i_sample_area
\r
107 * ラベル情報から得たラベルのクリップ範囲です。
\r
109 * 関数が成功するとtrueを返します。
\r
110 * @throws NyARException
\r
112 public boolean setValueWithInitialCheck(NyARContourTargetStatus i_contour_status,NyARIntRect i_sample_area) throws NyARException
\r
114 //ベクトルのマージ(マージするときに、3,4象限方向のベクトルは1,2象限のベクトルに変換する。)
\r
115 i_contour_status.vecpos.limitQuadrantTo12();
\r
116 this._ref_my_pool._vecpos_op.margeResembleCoords(i_contour_status.vecpos);
\r
117 if(i_contour_status.vecpos.length<4){
\r
122 i_contour_status.vecpos.getKeyCoord(this._ref_my_pool._indexbuf);
\r
124 NyARDoublePoint2d[] this_vx=this.vertex;
\r
125 if(!this._ref_my_pool._line_detect.line2SquareVertex(this._ref_my_pool._indexbuf,this_vx)){
\r
130 // for(int i=3;i>=0;i--){
\r
131 // this_sq.line[i].makeLinearWithNormalize(this_sq.sqvertex[i],this_sq.sqvertex[(i+1)%4]);
\r
133 this.setEstimateParam(null);
\r
134 if(!checkInitialRectCondition(i_sample_area))
\r
138 this.detect_type=DT_SQINIT;
\r
142 * この関数は、ラベル情報から矩形パラメータを推定して、インスタンスにセットします。
\r
143 * 関数の成否にかかわらず、インスタンスの状態が変化することに注意してください。
\r
144 * @param i_vec_reader
\r
146 * @param i_prev_status
\r
148 * @throws NyARException
\r
150 private boolean setValueWithDeilyCheck(INyARVectorReader i_vec_reader,LowResolutionLabelingSamplerOut.Item i_source,NyARRectTargetStatus i_prev_status) throws NyARException
\r
152 VecLinearCoordinates vecpos=this._ref_my_pool._vecpos;
\r
154 if(!i_vec_reader.traceConture(i_source.lebeling_th,i_source.entry_pos,vecpos)){
\r
157 //3,4象限方向のベクトルは1,2象限のベクトルに変換する。
\r
158 vecpos.limitQuadrantTo12();
\r
160 this._ref_my_pool._vecpos_op.margeResembleCoords(vecpos);
\r
161 if(vecpos.length<4){
\r
165 vecpos.getKeyCoord(this._ref_my_pool._indexbuf);
\r
167 NyARDoublePoint2d[] this_vx=this.vertex;
\r
168 if(!this._ref_my_pool._line_detect.line2SquareVertex(this._ref_my_pool._indexbuf,this_vx)){
\r
172 rotateVertexL(this.vertex,checkVertexShiftValue(i_prev_status.vertex,this.vertex));
\r
175 if(!checkDeilyRectCondition(i_prev_status)){
\r
179 setEstimateParam(i_prev_status);
\r
183 * この関数は、前回の位置情報と直線検出器で矩形パラメータを推定して、インスタンスにセットします。
\r
184 * 関数の成否にかかわらず、インスタンスの状態が変化することに注意してください。
\r
185 * @param i_vec_reader
\r
186 * @param i_prev_status
\r
188 * @throws NyARException
\r
190 private boolean setValueByLineLog(INyARVectorReader i_vec_reader,NyARRectTargetStatus i_prev_status) throws NyARException
\r
192 //検出範囲からカーネルサイズの2乗値を計算。検出領域の二乗距離の1/(40*40) (元距離の1/40)
\r
193 int d=((int)i_prev_status.estimate_rect.getDiagonalSqDist()/(NyARMath.SQ_40));
\r
194 //二乗移動速度からカーネルサイズを計算。
\r
195 int v_ave_limit=i_prev_status.estimate_sum_sq_vertex_velocity_ave;
\r
198 //移動カーネルサイズより、検出範囲カーネルのほうが大きかったらエラー(動きすぎ)
\r
201 d=(int)Math.sqrt(d);
\r
206 //最大カーネルサイズ(5)を超える場合は5にする。
\r
213 NyARLinear[] sh_l=this._ref_my_pool._line;
\r
214 if(!traceSquareLine(i_vec_reader,d,i_prev_status,sh_l)){
\r
219 for(int i=3;i>=0;i--){
\r
220 if(!sh_l[i].crossPos(sh_l[(i + 3) % 4],this.vertex[i])){
\r
227 rotateVertexL(this.vertex,checkVertexShiftValue(i_prev_status.vertex,this.vertex));
\r
229 setEstimateParam(i_prev_status);
\r
233 * この関数は、2回目以降の矩形検出で、状況に応じた矩形検出処理を実行して、新しい値をインスタンスにセットします。
\r
234 * 関数が成功すると、{@link #detect_type}に値をセットします。
\r
235 * @param i_vec_reader
\r
236 * 画素ベクトルを読みだすためのオブジェクト。
\r
238 * ラべリングから得られたサンプル情報。(存在しないときはNULL)
\r
239 * @param i_prev_status
\r
240 * 前回の状態を格納したステータスオブジェクト。
\r
242 * 値のセットに成功するとtrueを返します。
\r
243 * @throws NyARException
\r
245 public boolean setValueByAutoSelect(INyARVectorReader i_vec_reader,LowResolutionLabelingSamplerOut.Item i_source,NyARRectTargetStatus i_prev_status) throws NyARException
\r
247 int current_detect_type=DT_SQDAILY;
\r
249 int sq_v_ave_limit=i_prev_status.estimate_sum_sq_vertex_velocity_ave/4;
\r
250 //速度が小さい時か、前回LineLogが成功したときはDT_LIDAILY
\r
251 if(((sq_v_ave_limit<10) && (i_prev_status.detect_type==DT_SQDAILY)) || (i_prev_status.detect_type==DT_LIDAILY)){
\r
252 current_detect_type=DT_LIDAILY;
\r
255 //前回の動作ログによる手段の切り替え
\r
256 switch(current_detect_type)
\r
260 if(setValueByLineLog(i_vec_reader,i_prev_status))
\r
263 this.detect_type=DT_LIDAILY;
\r
266 if(i_source!=null){
\r
267 if(setValueWithDeilyCheck(i_vec_reader,i_source,i_prev_status))
\r
270 this.detect_type=DT_SQDAILY;
\r
276 if(i_source!=null){
\r
277 if(setValueWithDeilyCheck(i_vec_reader,i_source,i_prev_status))
\r
279 this.detect_type=DT_SQDAILY;
\r
288 i_prev_status.detect_type=DT_FAILED;
\r
294 * このデータが初期チェック(CoordからRectへの遷移)をパスするかチェックします。
\r
296 * 1.検出四角形の対角点は元の検出矩形内か?
\r
297 * 2.一番長い辺と短い辺の比は、0.1~10の範囲か?
\r
298 * 3.位置倍長い辺、短い辺が短すぎないか?
\r
299 * @param i_sample_area
\r
300 * この矩形を検出するために使った元データの範囲(ターゲット検出範囲)
\r
302 private boolean checkInitialRectCondition(NyARIntRect i_sample_area)
\r
304 NyARDoublePoint2d[] this_vx=this.vertex;
\r
306 //検出した四角形の対角点が検出エリア内か?
\r
307 int cx=(int)(this_vx[0].x+this_vx[1].x+this_vx[2].x+this_vx[3].x)/4;
\r
308 int cy=(int)(this_vx[0].y+this_vx[1].y+this_vx[2].y+this_vx[3].y)/4;
\r
309 if(!i_sample_area.isInnerPoint(cx,cy)){
\r
314 //一番長い辺と短い辺の比を確認(10倍の比があったらなんか変)
\r
315 int max=Integer.MIN_VALUE;
\r
316 int min=Integer.MAX_VALUE;
\r
317 for(int i=0;i<4;i++){
\r
318 int t=(int)this_vx[i].sqDist(this_vx[(i+1)%4]);
\r
323 if(max<(5*5) ||min<(5*5)){
\r
327 if((10*10)*min/max<(3*3)){
\r
333 * 2回目以降の履歴を使ったデータチェック。
\r
335 * 1.一番長い辺と短い辺の比は、0.1~10の範囲か?
\r
336 * 2.位置倍長い辺、短い辺が短すぎないか?
\r
337 * 3.移動距離が極端に大きなものは無いか?(他の物の3倍動いてたらおかしい)
\r
339 * @param i_sample_area
\r
341 private boolean checkDeilyRectCondition(NyARRectTargetStatus i_prev_st)
\r
343 NyARDoublePoint2d[] this_vx=this.vertex;
\r
345 //一番長い辺と短い辺の比を確認(10倍の比があったらなんか変)
\r
346 int max=Integer.MIN_VALUE;
\r
347 int min=Integer.MAX_VALUE;
\r
348 for(int i=0;i<4;i++){
\r
349 int t=(int)this_vx[i].sqDist(this_vx[(i+1)%4]);
\r
354 if(max<(5*5) ||min<(5*5)){
\r
358 if((10*10)*min/max<(3*3)){
\r
361 //移動距離平均より大きく剥離した点が無いか確認
\r
362 return this._ref_my_pool.checkLargeDiff(this_vx,i_prev_st.vertex);
\r
366 * 予想位置を基準に四角形をトレースして、一定の基準をクリアするかを評価します。
\r
368 * @param i_edge_size
\r
371 * @throws NyARException
\r
373 private boolean traceSquareLine(INyARVectorReader i_reader,int i_edge_size,NyARRectTargetStatus i_prevsq,NyARLinear[] o_line) throws NyARException
\r
375 NyARDoublePoint2d p1,p2;
\r
376 VecLinearCoordinates vecpos=this._ref_my_pool._vecpos;
\r
377 //NyARIntRect i_rect
\r
378 p1=i_prevsq.estimate_vertex[0];
\r
379 int dist_limit=i_edge_size*i_edge_size;
\r
381 // int min_th=i_edge_size*2+1;
\r
382 // min_th=(min_th*min_th);
\r
383 for(int i=0;i<4;i++)
\r
385 p2=i_prevsq.estimate_vertex[(i+1)%4];
\r
387 //クリップ付きで予想位置周辺の直線のトレース
\r
388 i_reader.traceLineWithClip(p1,p2,i_edge_size,vecpos);
\r
390 //クラスタリングして、傾きの近いベクトルを探す。(限界は10度)
\r
391 this._ref_my_pool._vecpos_op.margeResembleCoords(vecpos);
\r
392 //基本的には1番でかいベクトルだよね。だって、直線状に取るんだもの。
\r
394 int vid=vecpos.getMaxCoordIndex();
\r
395 //データ品質規制(強度が多少強くないと。)
\r
396 // if(vecpos.items[vid].sq_dist<(min_th)){
\r
400 //角度規制(元の線分との角度を確認)
\r
401 if(vecpos.items[vid].getAbsVecCos(i_prevsq.vertex[i],i_prevsq.vertex[(i+1)%4])<NyARMath.COS_DEG_5){
\r
402 //System.out.println("CODE1");
\r
406 //予想点からさほど外れていない点であるか。(検出点の移動距離を計算する。)
\r
408 dist=vecpos.items[vid].sqDistBySegmentLineEdge(i_prevsq.vertex[i],i_prevsq.vertex[i]);
\r
409 if(dist<dist_limit){
\r
410 o_line[i].setVectorWithNormalize(vecpos.items[vid]);
\r
412 //System.out.println("CODE2:"+dist+","+dist_limit);
\r
421 * 頂点同士の距離から、頂点のシフト量を返します。この関数は、よく似た2つの矩形の頂点同士の対応を取るために使用します。
\r
426 * シフト量はthis-i_squareです。1の場合、this.sqvertex[0]とi_square.sqvertex[1]が対応点になる(shift量1)であることを示します。
\r
428 private final static int checkVertexShiftValue(NyARDoublePoint2d[] i_vertex1,NyARDoublePoint2d[] i_vertex2)
\r
430 assert(i_vertex1.length==4 && i_vertex2.length==4);
\r
432 int min_dist=Integer.MAX_VALUE;
\r
435 for(int i=3;i>=0;i--){
\r
437 for(int i2=3;i2>=0;i2--){
\r
438 xd= (int)(i_vertex1[i2].x-i_vertex2[(i2+i)%4].x);
\r
439 yd= (int)(i_vertex1[i2].y-i_vertex2[(i2+i)%4].y);
\r
452 private final static int[] _gcd_table4={-1,1,2,1};
\r
454 * 頂点を左回転して、矩形を回転させます。
\r
457 private final static void rotateVertexL(NyARDoublePoint2d[] i_vertex,int i_shift)
\r
460 NyARDoublePoint2d vertext;
\r
467 d = _gcd_table4[ll];//NyMath.gcn(4,ll);
\r
469 for (i = 0; i < d; i++) {
\r
470 vertext=i_vertex[i];
\r
471 for (j = 1; j < 4/d; j++) {
\r
472 t1=(i + (j-1)*mk) % 4;
\r
474 i_vertex[t1]=i_vertex[t2];
\r
477 i_vertex[t1]=vertext;
\r
481 * この関数は、矩形の頂点情報をARToolKitのdirectionモデルに従って回転します。
\r
482 * マーカパターンから方位値を得た後に、頂点順序を調整するために使います。
\r
484 * ARToolKitのdirection値
\r
486 public void shiftByArtkDirection(int i_dir)
\r
488 rotateVertexL(this.estimate_vertex,i_dir);
\r
489 rotateVertexL(this.vertex,i_dir);
\r