/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- GrpSimBuffer
- resize
- setSrcImage
- setDstImage
- copyDst2Ing
- syncDst
- syncSrc
- getSrcImage
- getDstImage
- getSrcNearPointData
- getDstNearPointData
- getNearPointData
- getSrcNearPointDataN
- getDstNearPointDataN
- getNearPointDataN
- undo
- setRecycle
- chkValidSrc
- chkValidDst
- yuv2rgb
- rgb2yuv
- getWidth
- 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_;
}
}