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; }とにかく遅い。もっと速く処理できるように書けないだろうか。…速くしたからといって何がどうなるわけでもないけれど。
[ ツッコむ ]
以上です。