root/graph/JavaPopWeb/src/jp/ac/nime/computer/grpsimulator/ImgPr/MeasureArea.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. MeasureArea
  2. makeWB
  3. init
  4. labeling
  5. checkCalcEnd
  6. calcStep
  7. getArea
  8. MeasureAreaThread
  9. getArea
  10. init
  11. labeling
  12. writeLabel
  13. run
  14. calc
  15. chase8

package jp.ac.nime.computer.grpsimulator.ImgPr;

import java.awt.*;
import java.awt.image.*;
import java.util.*;

/** 画像計測 面積計算
 * @author Kikuchi
 * @version 1.0.0
 */
public class MeasureArea {
        /** スレッド変数
         */
        MeasureAreaThread th_;
        
        /** 画像計測面積計算
         */
        public MeasureArea() {
        }

        /** 白黒画像作成
         * @param flag  1のとき白黒反転する
         * @param imgSrc        YUV形式画像
         * @param imgDst        YUV形式画像
         */
        public void makeWB(int flag, BufferedImage imgSrc, BufferedImage imgDst) {
                MeasureOp.makeWhiteBlack(flag, imgSrc, imgDst);
        }
        
        /** 計算に必要なパラメタ設定
         * @param nOp   0:操作対象が黒 1:操作対象が白
         * @param imgSrc        YUV形式画像(二値化されていることが前提)
         * @param imgDst        YUV形式画像
         */
        public void init(int nOp, BufferedImage imgSrc, BufferedImage imgDst) {
                th_ = new MeasureAreaThread();
                th_.init(nOp, imgSrc, imgDst);
        }
        
        /** 前処理 ラベリング処理
         */
        public void labeling() {
                th_.labeling();
                th_.writeLabel();
                // スレッドスタート
                th_.start();
        }       
        
        /** 面積計算が最後まで進んだか返す
         */
        public boolean checkCalcEnd() {
                return th_.isContinue();
        }
        
        /** 面積計算の探索を一回行う
         */
        public void calcStep() {
                if (th_.isContinue()) {
                        th_.waitReady();                // 子がreadyになるまでビジーウェイト
                        th_.next();
                }
        }
        
        /** 面積データを取得
         */
        public int[] getArea() {
                return th_.getArea();
        }
        
        /** 面積計算スレッドクラス
         */     
        class MeasureAreaThread extends MeasureOp {
                private int nMaxX_;
                private int nMaxY_;
                private int[] naLabel_;  // ラベリングデータ
                private int[] nPalette_;
                private int     nPaletteNum_;
                private int nLabelMax_; // ラベル数
                private int[] nArea_;   // 面積配列
                /** コンストラクタ
                 */
                public MeasureAreaThread() {
                        super();
                        nMaxX_ = 0;
                        nMaxY_ = 0;
                }
                /** 面積データを取得
                 */
                public int[] getArea() {
                        return nArea_;
                }
                
                /** 初期化 計算に必要なパラメータを全て渡す
                 * @param nOp   0:操作対象が黒 1:操作対象が白
                 * @param imgSrc        YUV形式画像(二値化されていることが前提)
                 * @param imgDst        YUV形式画像
                 * @param nCutoff       遮断次数
                 */
                public void init(int nOp, BufferedImage imgSrc, BufferedImage imgDst) {
                        super.init(nOp, imgSrc, imgDst);
                        nMaxX_ = imgSrc.getWidth();
                        nMaxY_ = imgSrc.getHeight();
                        naLabel_ = new int [nMaxX_ * nMaxY_];
                        // 色の設定
                        nPaletteNum_ = 64;
                        nPalette_ = new int [nPaletteNum_];
                        int y[] = {64 << 16, 128 << 16, 192 << 16, 255 << 16};
                        int u[] = { 0 <<  8,  64 <<  8, 192 <<  8, 255 <<  8};
                        int v[] = { 0      ,  64      , 192      , 255      };
                        int c = 0;
                        for (int i = 0; i < 4; i ++) {
                                for (int j = 0; j < 4;  j++) {
                                        for (int k = 0; k < 4; k ++) {
                                                nPalette_[c] = y [i] | u [j] | v[k];
                                                c ++;
                                        }
                                }
                        }                                                                                
                }
                
                /** 前処理 ラベリング処理
                 */
                public void labeling() {
                        // ラベリングデータ初期化
                        int nLabel = 0;         // ラベル番号
                        Arrays.fill(naLabel_, 0);
                        nLabelMax_ = 0;
                        // 始点の検索
                        for (int y = 0; y < nMaxY_; y ++) {
                                for (int x = 0; x < nMaxX_; x ++) {
                                        // 注目点が有効かつ未検索データだったら始点とする
                                        if ((getPointData(x, y) == 1) && (naLabel_[x + (y * nMaxX_)] == 0)) {
                                                // 外側境界 or 内側境界
                                                if (getPointData(x - 1, y) == 0) {
                                                        // 外側境界探索
                                                        nLabel ++;      // ラベル番号更新
                                                        chase8(x, y, 7, nLabel);
                                                } else if (getPointData(x + 1, y) == 0) {
                                                        // 対応する外側境界のラベル番号を探す
                                                        int nSoto = 0;
                                                        for (int xx = x + 1; xx < nMaxX_; xx ++) {
                                                                nSoto = naLabel_[xx + y * nMaxX_];
                                                                if (nSoto > 0) break;
                                                        }
                                                        // 内側境界探索
                                                        chase8(x, y, 3, nSoto);
                                                }
                                        }
                                }
                        }
                        // ラベリングの個数を記憶
                        nLabelMax_ = nLabel;
                        // 面積配列
                        nArea_ = new int [nLabelMax_];
                        Arrays.fill(nArea_, 0);
                }
                
                /** ラベリングデータを出力画像に反映
                 */
                public void writeLabel() {
                        for (int y = 0; y < nMaxY_; y ++) {
                                for (int x = 0; x < nMaxX_; x ++) {
                                        int nLabel = naLabel_[x + (y * nMaxX_)];
                                        if (nLabel > 0) {
                                                // 色で境界を塗りつぶす
                                                int pal = (nLabel - 1) % 64;
                                                setPointData(imgDst_, x, y, nPalette_[pal]);
                                        }
                                }
                        }
                }

                
                
                /** スレッドメイン ルーチン
                 */
                public void run() {
                        int nCount = 1; // calcを呼んだ回数
                        while (contflag_) {
                                int area = calc(nCount);
                                nArea_[nCount - 1] = area;
//System.out.println("Label("+ (nCount - 1) + ") = " + area);
                                nCount ++;
                                if (nCount > nLabelMax_) {
                                        contflag_ = false; // 終了
                                } else {
                                }
                        }
                }

                /** 1つの図形の面積計算
                 * @param nCount 対象とするラベル番号
                 */             
                private synchronized int calc(int nLabel) {
                        // 境界で区切られている領域をlabelデータで塗りこむループ
                        for (int y = 0; y < nMaxY_; y ++) {
                                for (int x = 0; x < nMaxX_; x ++) {
                                        // 注目点が有効だったら左のデータで塗りこむ
                                        if ((getPointData(x, y) == 1) && (naLabel_[(x - 1) + (y * nMaxX_)] == nLabel)) {
                                                naLabel_[ x + (y * nMaxX_)] = nLabel;
                                        }
                                }
                        }
                        // 表示データ更新しながらWaitする
                        // 面積も数える
                        int area = 0;
                        boolean chk = false; // データを書き換えたか
                        for (int y = 0; y < nMaxY_; y ++) {
                                for (int x = 0; x < nMaxX_; x ++) {
                                        int nLabel2 = naLabel_[x + (y * nMaxX_)];
                                        if (nLabel2 == nLabel) {
                                                // 色で境界を塗りつぶす
                                                int pal = (nLabel2 - 1) % 64;
                                                setPointData(imgDst_, x, y, nPalette_[pal]);
                                                // Area
                                                area ++;
                                                chk = true;
                                        }
                                }
                                // ボタン待ち
                                if (chk) {
                                        waitNext();
                                        chk = false;
                                }
                        }
                        return area;
                }
                
                
                /** 8連結探索しながらラベリング
                 * @param x     始点x
                 * @param y 始点y
                 * @param nChase 最初の探索方向
                 * @param nLabel ラベル番号
                 */
                private void chase8(int x, int y, int nChase, int nLabel) {
                        int x0 = x, y0 = y;
                        int x1, y1, x2, y2;
                        boolean chk;    // 探索でみつかったか
                        // 初期化
                        x1 = x0; y1 = y0;
                        x2 = -1; y2 = -1;
                        chk = false;
                        // 探索ループ 初期座標に帰ってくるまでのループ
                        while ((x2 != x0) || y2 != y0) {
                                chk = false;
                                switch (nChase) {
                                case 0:         // 下を探索
                                        x2 = x1;
                                        y2 = y1 + 1;                                    
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 6;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 1;
                                        }
                                        break;
                                case 1:         // 右下
                                        x2 = x1 + 1;
                                        y2 = y1 + 1;                                    
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 7;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 2;
                                        }
                                        break;
                                case 2:         // 右
                                        x2 = x1 + 1;
                                        y2 = y1;                                        
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 0;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 3;
                                        }
                                        break;
                                case 3:         // 右上
                                        x2 = x1 + 1;
                                        y2 = y1 - 1;                                    
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 1;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 4;
                                        }
                                        break;
                                case 4:         // 上
                                        x2 = x1;
                                        y2 = y1 - 1;                                    
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 2;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 5;
                                        }
                                        break;
                                case 5:         // 左上
                                        x2 = x1 - 1;
                                        y2 = y1 - 1;                                    
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 3;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 6;
                                        }
                                        break;
                                case 6:         // 左
                                        x2 = x1 - 1;
                                        y2 = y1;                                        
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 4;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 7;
                                        }
                                        break;
                                case 7:         // 左下
                                        x2 = x1 - 1;
                                        y2 = y1 + 1;                                    
                                        if (getPointData(x2, y2) == 1) {
                                                // あった
                                                nChase = 5;
                                                chk = true;
                                        } else {
                                                // 無かった
                                                nChase = 0;
                                        }
                                        break;
                                }
                                // ラベリング
                                if (chk) {
                                        naLabel_[x2 + y2 * nMaxX_] = nLabel;
                                        // 座標移動
                                        x1 = x2;
                                        y1 = y2;
                                }
                        }
                }
        }
        
}

/* [<][>][^][v][top][bottom][index][help] */