Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

/*
 * PROJECT: NyARToolkit
 * --------------------------------------------------------------------------------
 * This work is based on the original ARToolKit developed by
 *   Hirokazu Kato
 *   Mark Billinghurst
 *   HITLab, University of Washington, Seattle
 * http://www.hitl.washington.edu/artoolkit/
 *
 * The NyARToolkit is Java version ARToolkit class library.
 * Copyright (C)2008 R.Iizuka
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this framework; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For further information please contact.
 *      http://nyatla.jp/nyatoolkit/
 *      <airmail(at)ebony.plala.or.jp>
 *
 */

package jp.nyatla.nyartoolkit.core;

import jp.nyatla.nyartoolkit.NyARException;
import jp.nyatla.nyartoolkit.core.raster.*;


interface NyARLabeling{
    /**
     * 検出したラベルの数を返す
     * @return
     */

    public int getLabelNum();
    /**
     *
     * @return
     * @throws NyARException
     */

    public int[] getLabelRef() throws NyARException;
    /**
     * 検出したラベル配列
     * @return
     * @throws NyARException
     */

    public NyARLabel[] getLabel() throws NyARException;
    /**
     * ラベリング済みイメージを返す
     * @return
     * @throws NyARException
     */

    public int[][] getLabelImg() throws NyARException;
    /**
     * static ARInt16 *labeling2( ARUint8 *image, int thresh,int *label_num, int **area, double **pos, int **clip,int **label_ref, int LorR )
     * 関数の代替品
     * ラスタimageをラベリングして、結果を保存します。
     * Optimize:STEP[1514->1493]
     * @param image
     * @param thresh
     * @throws NyARException
     */

    public void labeling(NyARRaster image,int thresh) throws NyARException;
}




/**
 * NyARLabeling_O2のworkとwork2を可変長にするためのクラス
 *
 *
 */

class NyARWorkHolder
{
    private final static int ARRAY_APPEND_STEP=256;
    public final int[] work;
    public final int[][] work2;
    private int allocate_size;
    /**
     * 最大i_holder_size個の動的割り当てバッファを準備する。
     * @param i_holder_size
     */

    public NyARWorkHolder(int i_holder_size)
    {
        //ポインタだけははじめに確保しておく
        this.work=new int[i_holder_size];
        this.work2=new int[i_holder_size][];
        this.allocate_size=0;
    }
    /**
     * i_indexで指定した番号までのバッファを準備する。
     * @param i_index
     */

    public final void reserv(int i_index) throws NyARException
    {
        //アロケート済みなら即リターン
        if(this.allocate_size>i_index){
            return;
        }
        //要求されたインデクスは範囲外
        if(i_index>=this.work.length){
            throw new NyARException();
        }      
        //追加アロケート範囲を計算
        int range=i_index+ARRAY_APPEND_STEP;
        if(range>=this.work.length){
            range=this.work.length;
        }
        //アロケート
        for(int i=this.allocate_size;i<range;i++)
        {
            this.work2[i]=new int[7];
        }
        this.allocate_size=range;
    }
}

class NyARLabel
{
    public int area;
    public int clip0;
    public int clip1;
    public int clip2;
    public int clip3;
    public double pos_x;
    public double pos_y;
}


class NyARLabelHolder
{
    private final static int ARRAY_APPEND_STEP=128;
    public final NyARLabel[] labels;
    private int allocate_size;
    /**
     * 最大i_holder_size個の動的割り当てバッファを準備する。
     * @param i_holder_size
     */

    public NyARLabelHolder(int i_holder_size)
    {
        //ポインタだけははじめに確保しておく
        this.labels=new NyARLabel[i_holder_size];
        this.allocate_size=0;
    }
    /**
     * i_indexで指定した番号までのバッファを準備する。
     * @param i_index
     */

    private final void reserv(int i_index) throws NyARException
    {
        //アロケート済みなら即リターン
        if(this.allocate_size>i_index){
            return;
        }
        //要求されたインデクスは範囲外
        if(i_index>=this.labels.length){
            throw new NyARException();
        }      
        //追加アロケート範囲を計算
        int range=i_index+ARRAY_APPEND_STEP;
        if(range>=this.labels.length){
            range=this.labels.length;
        }
        //アロケート
        for(int i=this.allocate_size;i<range;i++)
        {
            this.labels[i]=new NyARLabel();
        }
        this.allocate_size=range;
    }
    /**
     * i_reserv_sizeまでのバッファを、初期条件i_lxsizeとi_lysizeで初期化する。
     * @param i_reserv_size
     * @param i_lxsize
     * @param i_lysize
     * @throws NyARException
     */

    public final void init(int i_reserv_size,int i_lxsize,int i_lysize) throws NyARException
    {
        reserv(i_reserv_size);
        NyARLabel l;
        for(int i=0;i<i_reserv_size;i++){
            l=this.labels[i];
            l.area=0;
            l.pos_x=0;
            l.pos_y=0;
            l.clip0= i_lxsize;//wclip[i*4+0] = lxsize;
            l.clip1= 0;//wclip[i*4+0] = lxsize;
            l.clip2= i_lysize;//wclip[i*4+2] = lysize;
            l.clip3= 0;//wclip[i*4+3] = 0;
        }      
    }
}


/**
 * ラベリングクラス。NyARRasterをラベリングして、結果値を保持します。
 * 構造を維持して最適化をしたバージョン
 *
 */

class NyARLabeling_O2 implements NyARLabeling
{
    private static final int WORK_SIZE=1024*32;//#define WORK_SIZE   1024*32
    private final int[][] glabel_img;//static ARInt16 l_imageL[HARDCODED_BUFFER_WIDTH*HARDCODED_BUFFER_HEIGHT];

    private final NyARWorkHolder work_holder=new NyARWorkHolder(WORK_SIZE);
    private final NyARLabelHolder label_holder=new NyARLabelHolder(WORK_SIZE);

    private int label_num;
    //
    private final int width;
    private final int height;
    /**
     * @param i_width
     * ラベリング画像の幅。解析するラスタの幅より大きいこと。
     * @param i_height
     * ラベリング画像の高さ。解析するラスタの高さより大きいこと。
     */

    public NyARLabeling_O2(int i_width,int i_height)
    {
        width =i_width;
        height=i_height;
        glabel_img=new int[height][width];
        this.wk_reservLineBuffer_buf=new int[width];
        label_num=0;


        //ワークイメージに枠を書く
        int[][] label_img=this.glabel_img;
        for(int i = 0; i < i_width; i++){
            label_img[0][i]=0;
            label_img[i_height-1][i]=0;
        }
        //</Optimize>
        for(int i = 0; i < i_height; i++) {
            label_img[i][0]=0;
            label_img[i][i_width-1]=0;                     
        }
       
       
       
       
    }
    /**
     * 検出したラベルの数を返す
     * @return
     */

    public int getLabelNum()
    {
        return label_num;
    }
    /**
     * 検出したエリア配列?
     * @return
     * @throws NyARException
     */

    public NyARLabel[] getLabel() throws NyARException
    {
        if(label_num<1){
            throw new NyARException();
        }
        return this.label_holder.labels;
    }    
    /**
     *
     * @return
     * @throws NyARException
     */

    public int[] getLabelRef() throws NyARException
    {
        if(label_num<1){
            throw new NyARException();
        }
        return work_holder.work;
    }
    /**
     * ラベリング済みイメージを返す
     * @return
     * @throws NyARException
     */

    public int[][] getLabelImg() throws NyARException
    {
        return glabel_img;
    }
    //コンストラクタで作ること
    private int[] wk_reservLineBuffer_buf=null;

    /**
     * static ARInt16 *labeling2( ARUint8 *image, int thresh,int *label_num, int **area, double **pos, int **clip,int **label_ref, int LorR )
     * 関数の代替品
     * ラスタimageをラベリングして、結果を保存します。
     * Optimize:STEP[1514->1493]
     * @param image
     * @param thresh
     * @throws NyARException
     */

    public void labeling(NyARRaster image,int thresh) throws NyARException
    {
        int wk_max;                   /*  work                */
        int m,n;                      /*  work                */
        int lxsize, lysize;
        int thresht3 = thresh * 3;
        int i,j,k;
        lxsize=image.getWidth();//lxsize = arUtil_c.arImXsize;
        lysize=image.getHeight();//lysize = arUtil_c.arImYsize;
        //画素数の一致チェック
        if(lxsize!=this.width || lysize!=this.height){
            throw new NyARException();
        }      
        //ラベル数を0に初期化
        this.label_num=0;



        int[][] label_img=this.glabel_img;
       

        //枠作成はインスタンスを作った直後にやってしまう。
       
        int[] work2_pt;
        wk_max = 0;

        int label_pixel;
       
        int[] work=this.work_holder.work;
        int[][] work2=this.work_holder.work2;
        int[] line_bufferr=this.wk_reservLineBuffer_buf;
       
        int[] label_img_pt0,label_img_pt1;
        for(j = 1; j < lysize - 1; j++) {//for (int j = 1; j < lysize - 1; j++, pnt += poff*2, pnt2 += 2) {
            label_img_pt0=label_img[j];
            label_img_pt1=label_img[j-1];
            image.getPixelTotalRowLine(j,line_bufferr);

            for(i = 1; i < lxsize-1; i++) {//for(int i = 1; i < lxsize-1; i++, pnt+=poff, pnt2++) {
                //RGBの合計値が閾値より大きいかな?
                if(line_bufferr[i]<=thresht3){
                    //pnt1 = ShortPointer.wrap(pnt2, -lxsize);//pnt1 = &(pnt2[-lxsize]);
                    if(label_img_pt1[i]>0){//if( *pnt1 > 0 ) {
                        label_pixel=label_img_pt1[i];//*pnt2 = *pnt1;


                        work2_pt=work2[label_pixel-1];
                        work2_pt[0]++;//work2[((*pnt2)-1)*7+0] ++;
                        work2_pt[1]+=i;//work2[((*pnt2)-1)*7+1] += i;
                        work2_pt[2]+=j;//work2[((*pnt2)-1)*7+2] += j;
                        work2_pt[6]=j;//work2[((*pnt2)-1)*7+6] = j;
                    }else if(label_img_pt1[i+1]> 0 ) {//}else if( *(pnt1+1) > 0 ) {
                        if(label_img_pt1[i-1] > 0 ) {//if( *(pnt1-1) > 0 ) {
                            m = work[label_img_pt1[i+1]-1];//m = work[*(pnt1+1)-1];
                            n = work[label_img_pt1[i-1]-1];//n = work[*(pnt1-1)-1];
                            if( m > n ){
                                label_pixel=n;//*pnt2 = n;
                                //wk=IntPointer.wrap(work, 0);//wk = &(work[0]);
                                for(k = 0; k < wk_max; k++) {
                                    if(work[k] == m ){//if( *wk == m )
                                        work[k]=n;//*wk = n;
                                    }
                                }
                            }else if( m < n ) {
                                label_pixel=m;//*pnt2 = m;
                                //wk=IntPointer.wrap(work,0);//wk = &(work[0]);
                                for(k = 0; k < wk_max; k++){
                                    if(work[k]==n){//if( *wk == n ){
                                        work[k]=m;//*wk = m;
                                    }
                                }
                            }else{
                                label_pixel=m;//*pnt2 = m;
                            }
                            work2_pt=work2[label_pixel-1];
                            work2_pt[0] ++;
                            work2_pt[1] += i;
                            work2_pt[2] += j;
                            work2_pt[6] = j;
                        }else if( (label_img_pt0[i-1]) > 0 ) {//}else if( *(pnt2-1) > 0 ) {
                            m = work[(label_img_pt1[i+1])-1];//m = work[*(pnt1+1)-1];
                            n = work[label_img_pt0[i-1]-1];//n = work[*(pnt2-1)-1];
                            if( m > n ) {

                                label_pixel=n;//*pnt2 = n;
                                for(k = 0; k < wk_max; k++) {
                                    if(work[k]==m){//if( *wk == m ){
                                        work[k]=n;//*wk = n;
                                    }
                                }
                            }else if( m < n ) {
                                label_pixel=m;//*pnt2 = m;
                                for(k = 0; k < wk_max; k++) {
                                    if(work[k]==n){//if( *wk == n ){
                                        work[k]=m;//*wk = m;
                                    }
                                }
                            }else{
                                label_pixel=m;//*pnt2 = m;
                            }
                            work2_pt=work2[label_pixel-1];
                            work2_pt[0] ++;//work2[((*pnt2)-1)*7+0] ++;
                            work2_pt[1] += i;//work2[((*pnt2)-1)*7+1] += i;
                            work2_pt[2] += j;//work2[((*pnt2)-1)*7+2] += j;
                        }else{

                            label_pixel=label_img_pt1[i+1];//*pnt2 = *(pnt1+1);

                            work2_pt=work2[label_pixel-1];
                            work2_pt[0] ++;//work2[((*pnt2)-1)*7+0] ++;
                            work2_pt[1] += i;//work2[((*pnt2)-1)*7+1] += i;
                            work2_pt[2] += j;//work2[((*pnt2)-1)*7+2] += j;
                            if( work2_pt[3] > i ){//if( work2[((*pnt2)-1)*7+3] > i ){          
                                work2_pt[3] = i;//      work2[((*pnt2)-1)*7+3] = i;
                            }
                            work2_pt[6] = j;//work2[((*pnt2)-1)*7+6] = j;
                        }
                    }else if( (label_img_pt1[i-1]) > 0 ) {//}else if( *(pnt1-1) > 0 ) {
                        label_pixel=label_img_pt1[i-1];//*pnt2 = *(pnt1-1);

                        work2_pt=work2[label_pixel-1];
                        work2_pt[0] ++;//work2[((*pnt2)-1)*7+0] ++;
                        work2_pt[1] += i;//work2[((*pnt2)-1)*7+1] += i;
                        work2_pt[2] += j;//work2[((*pnt2)-1)*7+2] += j;
                        if( work2_pt[4] < i ){//if( work2[((*pnt2)-1)*7+4] < i ){
                            work2_pt[4] = i;//  work2[((*pnt2)-1)*7+4] = i;
                        }
                        work2_pt[6] = j;//work2[((*pnt2)-1)*7+6] = j;
                    }else if(label_img_pt0[i-1] > 0) {//}else if( *(pnt2-1) > 0) {
                        label_pixel=label_img_pt0[i-1];//*pnt2 = *(pnt2-1);

                        work2_pt=work2[label_pixel-1];
                        work2_pt[0] ++;//work2[((*pnt2)-1)*7+0] ++;
                        work2_pt[1] += i;//work2[((*pnt2)-1)*7+1] += i;
                        work2_pt[2] += j;//work2[((*pnt2)-1)*7+2] += j;
                        if(work2_pt[4] < i ){//if( work2[((*pnt2)-1)*7+4] < i ){
                            work2_pt[4] = i;//  work2[((*pnt2)-1)*7+4] = i;
                        }
                    }else{
                        //現在地までの領域を予約
                        this.work_holder.reserv(wk_max);
                        wk_max++;
                        work[wk_max-1] = wk_max;
                        label_pixel=wk_max;//work[wk_max-1] = *pnt2 = wk_max;
                        work2_pt=work2[wk_max-1];
                        work2_pt[0] = 1;
                        work2_pt[1] = i;
                        work2_pt[2] = j;
                        work2_pt[3] = i;
                        work2_pt[4] = i;
                        work2_pt[5] = j;
                        work2_pt[6] = j;
                    }
                    label_img_pt0[i]=label_pixel;
                }else {
                    label_img_pt0[i]=0;//*pnt2 = 0;
                }
               
            }
        }
        j = 1;
        for(i = 0; i < wk_max; i++){//for(int i = 1; i <= wk_max; i++, wk++) {
            work[i]=(work[i]==i+1)? j++: work[work[i]-1];//*wk = (*wk==i)? j++: work[(*wk)-1];
        }

        int wlabel_num=j - 1;//*label_num = *wlabel_num = j - 1;

        if(wlabel_num==0){//if( *label_num == 0 ) {
            //発見数0
            return;
        }

       
       
        //ラベルバッファを予約&初期化
        this.label_holder.init(wlabel_num, lxsize, lysize);
//     
//      putZero(warea,wlabel_num);//put_zero( (ARUint8 *)warea, *label_num *     sizeof(int) );
//      for(i=0;i<wlabel_num;i++){
//          wpos[i*2+0]=0;
//          wpos[i*2+1]=0;
//      }
//      for(i = 0; i < wlabel_num; i++) {//for(i = 0; i < *label_num; i++) {
//          wclip[i][0] = lxsize;//wclip[i*4+0] = lxsize;
//          wclip[i][1] = 0;//wclip[i*4+1] = 0;
//          wclip[i][2] = lysize;//wclip[i*4+2] = lysize;
//          wclip[i][3] = 0;//wclip[i*4+3] = 0;
//      }
        NyARLabel label_pt;
        NyARLabel[] labels=this.label_holder.labels;
       
        for(i = 0; i < wk_max; i++){
            label_pt=labels[work[i] - 1];
            work2_pt=work2[i];
            label_pt.area  += work2_pt[0];
            label_pt.pos_x += work2_pt[1];
            label_pt.pos_y += work2_pt[2];
            if( label_pt.clip0 > work2_pt[3] ){
                label_pt.clip0 = work2_pt[3];
            }
            if( label_pt.clip1 < work2_pt[4] ){
                label_pt.clip1 = work2_pt[4];
            }
            if(label_pt.clip2 > work2_pt[5] ){
                label_pt.clip2 = work2_pt[5];
            }
            if( label_pt.clip3 < work2_pt[6] ){
                label_pt.clip3 = work2_pt[6];
            }
        }

        for(i = 0; i < wlabel_num; i++ ) {//for(int i = 0; i < *label_num; i++ ) {
            label_pt=labels[i];
            label_pt.pos_x /= label_pt.area;
            label_pt.pos_y /= label_pt.area;
        }

        label_num=wlabel_num;
        return;
    }
}