2006/12/22(金) [n年前の日記]
#3 [prog][iappli] _内分点と画像の拡大・縮小
_線形補間法
_拡大縮小アルゴリズム(バイキュービックとLanczos)
_縮小アルゴリズム(1)
_縮小アルゴリズム(3)- 平均画素法
_縮小アルゴリズム(8)― Lanczos
_画像補間方式
メモ。
iアプリで、小さい画像を読み込んでBGキャッシュに拡大する処理を書いてたのだけど。Nearest Neighbor ではガクガクしてなんだか悲しいなと。ということで Bilinear を試してみたり。…遅い。1ドットずつ計算してるから仕方ないのだろうか。
あ。単に拡大縮小の結果が得たいだけなら、drawScaledImage() を使えばいいのか。なんてこった。
でもまあ、一応該当部分をメモしておこう…。あまり意味は無いけど…。
_拡大縮小アルゴリズム(バイキュービックとLanczos)
_縮小アルゴリズム(1)
_縮小アルゴリズム(3)- 平均画素法
_縮小アルゴリズム(8)― Lanczos
_画像補間方式
メモ。
iアプリで、小さい画像を読み込んでBGキャッシュに拡大する処理を書いてたのだけど。Nearest Neighbor ではガクガクしてなんだか悲しいなと。ということで Bilinear を試してみたり。…遅い。1ドットずつ計算してるから仕方ないのだろうか。
あ。単に拡大縮小の結果が得たいだけなら、drawScaledImage() を使えばいいのか。なんてこった。
でもまあ、一応該当部分をメモしておこう…。あまり意味は無いけど…。
Graphics lg = cacheImage[cn].getGraphics();
switch (cn) {
case 0 :
// タイルパターン
for (int y = 0; y < getHeight(); y += img[IMG_OPTIONBG].getHeight()) {
for (int x = 0; x < getWidth(); x += img[IMG_OPTIONBG].getWidth()) {
lg.drawImage(img[IMG_OPTIONBG], x, y);
}
}
break;
case 1 :
// 拡大・Nearest Neighbor
{
// 元画像
int ign = IMG_BG_B;
int w = img[ign].getWidth();
int h = img[ign].getHeight();
// 倍率
int ratio = getWidth() / img[ign].getWidth();
Image imgSrc = Image.createImage(img[ign].getWidth(), img[ign].getHeight());
Graphics gSrc = imgSrc.getGraphics();
gSrc.drawImage(img[ign], 0, 0);
int dx = 0;
int dy = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int pixel = gSrc.getPixel(x, y);
lg.setColor(pixel);
lg.fillRect(dx, dy, ratio, ratio);
dx += ratio;
}
dy += ratio;
dx = 0;
}
gSrc = null;
imgSrc.dispose();
imgSrc = null;
}
break;
case 2 :
// 拡大・Bilinear
{
// 元画像
int ign = IMG_BG_B;
// src Image 縦横幅取得
int w = img[ign].getWidth();
int h = img[ign].getHeight();
// dst Image 縦横幅取得
int dstW = cacheImage[cn].getWidth();
int dstH = cacheImage[cn].getHeight();
// src Image を、新規作成した Image に描画
// こうしないと Graphics が取得できない = ピクセル値が読めない。
// もっと良い手はないだろうか…
Image imgSrc = Image.createImage(w, h);
Graphics gSrc = imgSrc.getGraphics();
gSrc.drawImage(img[ign], 0, 0);
// 元画像分の r,g,b を入れるためのワークを確保
int[] rgb = new int[w * h];
int[] r = new int[w * h];
int[] g = new int[w * h];
int[] b = new int[w * h];
// 元画像の RGB値(0x00RRGGBB) を配列に全取得
gSrc.getRGBPixels(0, 0, w, h, rgb, 0);
// r,g,b にばらす
// int imax = rgb.length;
for (int i = 0; i < rgb.length; i++) {
int p = rgb[i];
r[i] = (p >> 16) & 0x0ff;
g[i] = (p >> 8) & 0x0ff;
b[i] = p & 0x0ff;
}
// 固定小数点計算用
final int FLV = 0x0100;
// 元画像の読み込み座標を初期化
int xs = 0;
int ys = 0;
// 元画像の読み込み座標の増分を設定
int xs_add = w * FLV / dstW;
int ys_add = h * FLV / dstH;
// 書き込み用ワークを確保
int[] dstrgb = new int[dstW * dstH];
int dstidx = 0;
// 書き込み先の、縦・横dot数分のループ
for (int y = 0; y < dstH; y++) {
int y0 = ys >> 8;
int n = ys & 0x0ff;
int dn = FLV - n;
int ib = w * y0;
boolean yEndFg = false;
if ( y0 + 1 - h >= 0) yEndFg = true;
for (int x = 0; x < dstW; x++) {
// 読み込み座標の整数部を取得
int x0 = xs >> 8;
// 読み込み座標の小数部を取得
int m = xs & 0x0ff;
int dm = FLV - m;
// 配列インデックス値を取得
int i0 = ib + x0;
int i1 = i0 + 1;
int i2 = i0 + w;
int i3 = i2 + 1;
// 画面端の場合はおかしくなる。インデックス値を微調整
if (x0 + 1 - w >= 0) {
i1 = i0;
i3 = i2;
}
if (yEndFg) {
i2 = i0;
i3 = i1;
}
// 線形補間
int rr = (((r[i0] * dm + r[i1] * m) * dn) + ((r[i2] * dm + r[i3] * m) * n)) >> 16;
int gg = (((g[i0] * dm + g[i1] * m) * dn) + ((g[i2] * dm + g[i3] * m) * n)) >> 16;
int bb = (((b[i0] * dm + b[i1] * m) * dn) + ((b[i2] * dm + b[i3] * m) * n)) >> 16;
// 結果を保存
dstrgb[dstidx++] = ((rr << 16) | (gg << 8) | bb);
xs += xs_add;
}
xs = 0;
ys += ys_add;
}
// 描画
lg.setRGBPixels(0, 0, dstW, dstH, dstrgb, 0);
dstrgb = null;
b = null;
g = null;
r = null;
rgb = null;
gSrc = null;
imgSrc.dispose();
imgSrc = null;
}
break;
default :
break;
}
とにかく遅い。もっと速く処理できるように書けないだろうか。…速くしたからといって何がどうなるわけでもないけれど。
[ ツッコむ ]
以上です。