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

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

DEFINITIONS

This source file includes following definitions.
  1. GrpSimBuffer
  2. resize
  3. setSrcImage
  4. setDstImage
  5. copyDst2Ing
  6. syncDst
  7. syncSrc
  8. getSrcImage
  9. getDstImage
  10. getSrcNearPointData
  11. getDstNearPointData
  12. getNearPointData
  13. getSrcNearPointDataN
  14. getDstNearPointDataN
  15. getNearPointDataN
  16. undo
  17. setRecycle
  18. chkValidSrc
  19. chkValidDst
  20. yuv2rgb
  21. rgb2yuv
  22. getWidth
  23. getHeight

package jp.ac.nime.computer.grpsimulator;

import javax.swing.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

/**
 * 画像処理の為の画像バッファを受け持つクラス。
 * 画像を登録するときに RGB<->YUVを変換して記憶する。
 * 画像バッファを取得するときに RGB,YUVを指定できる。
 * @author Kikuchi
 * @version 1.0.0
 */
public class GrpSimBuffer {
        /**
        * 画像がRGBであることを示す
        */
        public static final int RGB = 0;

        /**
        * 画像がYUVであることを示す
        */
        public static final int YUV = 1;

        
        private static final int IMAGE_NUMBER = 3;
        
        private static final int ING = 0; // 原ファイル
        private static final int SRC = 1;
        private static final int DST = 2;
        private BufferedImage[] imgYuv_;
        private BufferedImage[] imgRgb_;
        private boolean recycle_;       // recycleを示すフラグ TUREのときrecycle
        private int width_;     // imgの横
        private int height_;    // imgの縦
        private Rectangle rect_; // 画像処理が必要な領域
        private boolean[] setflag_; // 読み込まれたどうか
        /**
         * * コンストラクタ
         * バッファの画像サイズを指定する
         *
         * @param width 画像の幅
         * @param height 画像の高さ
         */
        public GrpSimBuffer(int width, int height) {
                recycle_ = false; // no recycle;
                width_ = width;
                height_ = height;
                imgYuv_ = new BufferedImage[IMAGE_NUMBER];
                imgRgb_ = new BufferedImage[IMAGE_NUMBER];
                setflag_ = new boolean[IMAGE_NUMBER];
                for (int i = 0; i < IMAGE_NUMBER; i ++) {
                        imgYuv_[i] = new BufferedImage(width_, height_, BufferedImage.TYPE_INT_ARGB);
                        imgRgb_[i] = new BufferedImage(width_, height_, BufferedImage.TYPE_INT_ARGB);
                        setflag_[i] = false;
                }
                rect_ = new Rectangle();
        }


        /**
         *  
         * バッファの画像サイズをクラスで管理する大きさにリサイズする
         *
         * @param img   画像バッファ,サイズは適当でかまわない
         * @param imo   イメージオブザーバー
         * @return 大きさの変更された画像バッファ
         */
        private BufferedImage resize(BufferedImage img, ImageObserver imo) {
                int w = img.getWidth(imo);
                int h = img.getHeight(imo);
                int w2, h2;
                if ( 4*h > 3*w ) {  // h/w > 3/4 ... 320x240より縦長
                        w2 = height_* w/h;
                        h2 = height_;
                } else {    // 320x240 より横長
                        h2 = width_ * h/w;
                        w2 = width_;
                }
                Image img2 = img.getScaledInstance(w2, h2, Image.SCALE_SMOOTH);
                BufferedImage bimg = new BufferedImage(width_, height_, BufferedImage.TYPE_INT_ARGB);
                
                Graphics2D g = bimg.createGraphics();
                //g.setColor(Color.black);
                g.setColor(new Color(0, 0, 0, 0));
                g.fillRect(0, 0, width_, height_);
                g.drawImage(img2, (width_ - w2) / 2, (height_ - h2) / 2, imo);
                g.dispose();

                // 領域記憶
                rect_.setBounds(((width_ - w2) >> 1), ((height_ - h2) >> 1), w2, h2);

                return bimg;
        }
        
        /**
     * 
         * バッファをSrc画像として登録する。
         *
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param img   画像バッファ,サイズは適当でかまわない
         * @param imo   イメージオブザーバー
         */
        public void setSrcImage(int flag, BufferedImage img, ImageObserver imo) {
                // リサイズ
                BufferedImage img2 = resize(img, imo);
                // バッファ ING に格納
                if (flag == RGB) {
                        img2.copyData(imgRgb_[ING].getRaster());
                        //imgRgb_[ING].setData(img.GetData());
                        // YUVを作る
                        rgb2yuv(ING);
                } else {
                        img2.copyData(imgYuv_[ING].getRaster());
                        //imgYuv_[ING] = img;
                        // RGBを作る
                        yuv2rgb(ING);
                }
                setflag_[ING] = true; // set
        }

        /**
         * バッファをDst画像として登録する。多分使う必要はないはず。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param img   画像バッファ,サイズはコンストラクタで指定されている大きさであることが必要。
         */
        public void setDstImage(int flag, BufferedImage img) {
                // バッファ DST に格納
                if (flag == RGB) {
                        img.copyData(imgRgb_[DST].getRaster());
                        //imgRgb_[DST] = img;
                        // YUVを作る
                        rgb2yuv(DST);
                } else {
                        img.copyData(imgYuv_[DST].getRaster());
                        //imgYuv_[DST] = img;
                        // RGBを作る
                        yuv2rgb(DST);
                }
                setflag_[DST] = true; // set
        }

        /**
         * Dst画像をING,SRC画像とする
         * 
         */
        public void copyDst2Ing() {
                imgRgb_[DST].copyData(imgRgb_[ING].getRaster());
                imgYuv_[DST].copyData(imgYuv_[ING].getRaster());
                imgRgb_[DST].copyData(imgRgb_[SRC].getRaster());
                imgYuv_[DST].copyData(imgYuv_[SRC].getRaster());
        }
        
        /**
         * DstバッファのRGBとYUVの同期を図る
         * 
         * @param flag  変更された画像バッファを示す。RGBを指定すると RGBの内容でYUVを更新する。
         */
        public void syncDst(int flag) {
                if (flag == RGB) { // RGB->YUV
                        rgb2yuv(DST);
                } else {        // YUV->RGB
                        yuv2rgb(DST);
                }
                setflag_[DST] = true; // set
        }

        /**
         * SrcバッファのRGBとYUVの同期を図る
         * 
         * @param flag  変更された画像バッファを示す。RGBを指定すると RGBの内容でYUVを更新する。
         */
        public void syncSrc(int flag) {
                if (flag == RGB) { // RGB->YUV
                        rgb2yuv(SRC);
                } else {        // YUV->RGB
                        yuv2rgb(SRC);
                }
                setflag_[SRC] = true; // set
        }
        
        
        /**
         * 画像処理のソース画像バッファを提供する
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @return 画像バッファ
         */
        public BufferedImage getSrcImage(int flag) {
                // recycle_を見て TRUEなら バッファDSTをバッファSRCにCopyする
                // FALSEなら バッファINGをバッファSRCにCopyする
                if (recycle_) {
                        imgRgb_[DST].copyData(imgRgb_[SRC].getRaster());
                        imgYuv_[DST].copyData(imgYuv_[SRC].getRaster());
                } else {
                        imgRgb_[ING].copyData(imgRgb_[SRC].getRaster());
                        imgYuv_[ING].copyData(imgYuv_[SRC].getRaster());
                }
                setflag_[SRC] = true; // set
                if (flag == RGB) {
                        // バッファSRC RGB を提供
                        return imgRgb_[SRC];
                } else {
                        // バッファSRC YUV を提供
                        return imgYuv_[SRC];
                }
        }
        
        /**
         * 画像処理の結果画像バッファを提供する
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @return 画像バッファ
         */
        public BufferedImage getDstImage(int flag) {
                // バッファ DST を提供
                if (flag == RGB) {
                        // バッファDST RGB を提供
                        return imgRgb_[DST];
                } else {
                        // バッファDST YUV を提供
                        return imgYuv_[DST];
                }
        }

        /**
         * Src画像の指定位置の近傍データ(5x5)を出力する
         * 出力データは、alpha領域をクリアしている
         * 領域外は、 -1 になる。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param x     データが欲しい中心座標のx
         * @param y     データが欲しい中心座標のy
         * @return 画像バッファ
         */
        public int[] getSrcNearPointData(int flag, int x, int y) {
                return getNearPointData(flag, SRC, x, y);
        }

        /**
         * Dst画像の指定位置の近傍データ(5x5)を出力する
         * 出力データは、alpha領域をクリアしている
         * 領域外は、 -1 になる。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param x     データが欲しい中心座標のx
         * @param y     データが欲しい中心座標のy
         * @return 画像バッファ
         */
        public int[] getDstNearPointData(int flag, int x, int y) {
                return getNearPointData(flag, DST, x, y);
        }

        /**
         * 画像の指定位置の近傍データ(5x5)を出力する
         * 出力データは、alpha領域をクリアしている
         * 領域外は、 -1 になる。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param num   データが欲しい画像バッファの番号
         * @param ptx   データが欲しい中心座標のx
         * @param pty   データが欲しい中心座標のy
         * @return 画像バッファ
         */
        private int[] getNearPointData(int flag, int num, int ptx, int pty) {
                int result[] = new int[25];
                BufferedImage img;
                if (flag == RGB) {
                        img = imgRgb_[num];
                } else {
                        img = imgYuv_[num];
                }
                for (int i = 0; i < result.length; i++) result[i] = -1;
                for (int y = 0; y < 5; y++) {
                        int iy = pty + y - 2;
                        if (iy < 0 || iy >= height_) continue;
                        for (int x = 0; x < 5; x++) {
                                int ix = ptx + x - 2;
                                if (ix < 0 || ix >= width_) continue;
                                result[x + y * 5] = img.getRGB(ix,iy) & 0x00FFFFFF;   // 上位8bit(Alpha)をマスク
                        }
                }
                return result;
        }

        /**
         * Src画像の指定位置の近傍データ(NxN)を出力する
         * 出力データは、alpha領域をクリアしている
         * 領域外は、 -1 になる。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param x     データが欲しい中心座標のx
         * @param y     データが欲しい中心座標のy
         * @param nN    近傍のサイズ 3以上の奇数に限る これに当てはまらない場合、全ポイントが領域外となる。
         * @return 画像バッファ
         */
        public int[] getSrcNearPointDataN(int flag, int x, int y, int nN) {
                return getNearPointDataN(flag, SRC, x, y, nN);
        }

        /**
         * Dst画像の指定位置の近傍データ(5x5)を出力する
         * 出力データは、alpha領域をクリアしている
         * 領域外は、 -1 になる。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param x     データが欲しい中心座標のx
         * @param y     データが欲しい中心座標のy
         * @param nN    近傍のサイズ 3以上の奇数に限る これに当てはまらない場合、全ポイントが領域外となる。
         * @return 画像バッファ
         */
        public int[] getDstNearPointDataN(int flag, int x, int y, int nN) {
                return getNearPointDataN(flag, DST, x, y, nN);
        }

        /**
         * 画像の指定位置の近傍データ(NxN)を出力する
         * 出力データは、alpha領域をクリアしている
         * 領域外は、 -1 になる。
         * 
         * @param flag  画像バッファの内容が YUVかRGBを示す。定数で指定すること。
         * @param num   データが欲しい画像バッファの番号
         * @param ptx   データが欲しい中心座標のx
         * @param pty   データが欲しい中心座標のy
         * @param nN    近傍のサイズ 3以上の奇数に限る これに当てはまらない場合、全ポイントが領域外となる。
         * @return 画像バッファ
         */
        private int[] getNearPointDataN(int flag, int num, int ptx, int pty, int nN) {
                // 戻り値を獲得する
                int result[] = new int[nN * nN];
                // 初期化
                for (int i = 0; i < result.length; i++) result[i] = -1;
                if (nN < 3 || ((nN % 2) == 0)) {
                        return result;
                }
                // 調査する画像を決定
                BufferedImage img;
                if (flag == RGB) {
                        img = imgRgb_[num];
                } else {
                        img = imgYuv_[num];
                }
                // データ取得
                int nHalf = nN / 2;
                for (int y = 0; y < nN; y++) {
                        int iy = pty + y - nHalf;
                        if (iy < 0 || iy >= height_) continue;
                        for (int x = 0; x < nN; x++) {
                                int ix = ptx + x - nHalf;
                                if (ix < 0 || ix >= width_) continue;
                                result[x + y * nN] = img.getRGB(ix,iy) & 0x00FFFFFF;   // 上位8bit(Alpha)をマスク
                        }
                }
                return result;
        }


        /**
         * Undoを行う
         * 
         */
        public void undo() {
                // バッファ SRCの内容を DSTにコピー
                imgRgb_[SRC].copyData(imgRgb_[DST].getRaster());
                imgYuv_[SRC].copyData(imgYuv_[DST].getRaster());

                setflag_[DST] = true; // set
        }
        
        /**
         * Recycleを指定する
         * 
         * @param flag True:recycle ON  False:recycle OFF
         */
        public void setRecycle(boolean flag) {
                recycle_ = flag;
        }

        /**
         * ソース画像を読み込んであるかチェックできる
         * 
         * @return 読み込んでいたら 1が帰る
         */
        public boolean chkValidSrc() {
                return setflag_[SRC];
        }

        /**
         * 出力画像を読み込んであるかチェックできる
         * @return 読み込んでいたら 1が帰る
         */
        public boolean chkValidDst() {
                return setflag_[DST];
        }

        /**
     * YUV画像をRGB画像に変換コピーする。
     * R = 1.000Y                + 1.402(V-128)
         * G = 1.000Y - 0.344(U-128) - 0.714(V-128)
         * B = 1.000Y + 1.772(U-128)
         *
         * @param num  画像バッファの番号
         */
        private void yuv2rgb(int num) {
                if (num < 0 || num >= IMAGE_NUMBER) return;
                //WritableRaster rasSrc=imgYuv_[num].getRaster();
                //WritableRaster rasDst=imgRgb_[num].getRaster();
                for (int h = 0; h < height_; h ++) {
                        for (int w = 0; w < width_; w ++) {
                                int yuv = imgYuv_[num].getRGB(w, h) & 0x00ffffff; // ARGB つまり AYUV
                                int a = imgYuv_[num].getRGB(w, h) & 0xff000000;
                                double y = ((yuv & 0x00ff0000) >> 16);
                                double u = ((yuv & 0x0000ff00) >> 8) - 128;
                                double v = ((yuv & 0x000000ff)) - 128;
                                double r = y             + 1.402 * v;
                                double g = y - 0.344 * u - 0.714 * v;
                                double b = y + 1.772 * u;
                                int ir, ig, ib, rgb;
                                ir = (int)(r + 0.5);
                                ig = (int)(g + 0.5);
                                ib = (int)(b + 0.5);
                                ir = Math.max(0, Math.min(ir, 255));
                                ig = Math.max(0, Math.min(ig, 255));
                                ib = Math.max(0, Math.min(ib, 255));
                                rgb = ((ir << 16) + (ig << 8) + ib) | a;
                                imgRgb_[num].setRGB(w, h, rgb);
                        }
                }
        }

        /**
         * RGB画像をYUV画像に変換コピーする。
         * Y =  0.299R + 0.587G + 0.114B
         * U =  (-0.169R - 0.331G + 0.500B) + 128;
         * V =  (0.500R - 0.419G - 0.081B) + 128;
         *
         * @param num  画像バッファの番号
         */
        private void rgb2yuv(int num) {
                if (num < 0 || num >= IMAGE_NUMBER) return;
                WritableRaster rasSrc=imgRgb_[num].getRaster();
                WritableRaster rasDst=imgYuv_[num].getRaster();

                for (int h = 0; h < height_ ; h ++) {
                        for (int w = 0; w < width_; w ++) {
                                int rgb = rasSrc.getDataBuffer().getElem(0, h * width_ + w) & 0x00ffffff;
                                int a = rasSrc.getDataBuffer().getElem(0, h * width_ + w) & 0xff000000;
                                double r = ((rgb & 0x00ff0000) >> 16);
                                double g = ((rgb & 0x0000ff00) >> 8);
                                double b = ((rgb & 0x000000ff));
                                double y = 0.299 * r + 0.587 * g + 0.114 * b;
                                double u = ((-0.169 * r) + (-0.331 * g) + (0.500 * b)) + 128.0;
                                double v = ((0.500 * r) + (-0.419 * g)  + (-0.081 * b)) + 128.0;
                                int iy, iu, iv, yuv;
                                iy = (int)(y + 0.5);
                                iu = (int)(u + 0.5);
                                iv = (int)(v + 0.5);
                                iy = Math.max(0, Math.min(iy, 255));
                                iu = Math.max(0, Math.min(iu, 255));
                                iv = Math.max(0, Math.min(iv, 255));
                                yuv = ((iy << 16) + (iu << 8) + iv) | a;
                                rasDst.getDataBuffer().setElem(0, h * width_ + w, yuv);
                        }
                }

        }

        /**
         * 画像サイズの幅を得る。
         *
         * @return 画像バッファの幅
         */
        public int getWidth() {
                return width_;
        }

        /**
         * 画像サイズの高さを得る。
         *
         * @return 画像バッファの高さ
         */
        public int getHeight() {
                return height_;
        }

}


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