mieki256's diary



2006/12/22(金) [n年前の日記]

#3 [prog][iappli] _内分点と画像の拡大・縮小

_線形補間法
_拡大縮小アルゴリズム(バイキュービックと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;
    }
とにかく遅い。もっと速く処理できるように書けないだろうか。…速くしたからといって何がどうなるわけでもないけれど。

以上です。

過去ログ表示

Prev - 2006/12 - Next
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project