投稿者 tel | 2011年7月19日

画像処理プログラミング – 幾何学変換(拡大縮小)

ひさしぶりに画像処理プログラミング。画像の拡大、縮小について。
画像を拡大、縮小でリサンプリングするときに補間(interpolation)する必要がある。補間の方法として最近傍補間、バイリニア、バイキュービック、Lanczosなどがある。
以下の元画像を拡大してみる。

元画像

最近傍補間(nearest neighbor)は最も近い画素を選択する。最も近い画素を求めるために四捨五入をするが、ちょうど2倍したときに存在しない画素を参照してしまうので0.5足さずに0.4999足すことにした。以下実装コード。

template <typename T>
void NearestNeighbor(const Image<T> *src, Image<T> *dst, int width, int height)
{
    int w = src->width;
    int h = src->height;
    float sx = w / static_cast<float>(width);
    float sy = h / static_cast<float>(height);

    dst->Create(width, height);

    for(int i = 0; i < height; i++) {
        int y = static_cast<int>(i * sy + 0.4999f);
        for(int j = 0; j < width; j++) {
            int x = static_cast<int>(j * sx + 0.4999f);
            dst->lines[i][j] = src->lines[y][x];
        }
    }
}

最近傍補間で2倍に拡大した画像

2倍に拡大した画像。ドットが目立つ。

バイリニア(bilinear)補間。RGBフォーマットの画像しか対応していないが以下実装コード。

template <typename T>
void Bilinear(const Image<T> *src, Image<T> *dst, int width, int height)
{
    int w = src->width;
    int h = src->height;
    float sx = w / static_cast<float>(width);
    float sy = h / static_cast<float>(height);

    dst->Create(width, height);

    for(int i = 0; i < height; i++) {
        float yy = i * sy;
        int y0 = static_cast<int>(yy);
        float fy = yy - y0;
        int y1 = y0 + 1 >= h ? y0 : y0 + 1;
        for(int j = 0; j < width; j++) {
            float xx = j * sx;
            int x0 = static_cast<int>(xx);
            float fx = xx - x0;

            float f0 = (1.0f - fx) * (1.0f - fy);
            float f1 = fx * (1.0f - fy);
            float f2 = (1.0f - fx) * fy;
            float f3 = fx * fy;

            int x1 = x0 + 1 >= w ? x0 : x0 + 1;

            T c0 = src->lines[y0][x0];
            T c1 = src->lines[y0][x1];
            T c2 = src->lines[y1][x0];
            T c3 = src->lines[y1][x1];

            float r = c0.r * f0 + c1.r * f1 + c2.r * f2 + c3.r * f3;
            float g = c0.g * f0 + c1.g * f1 + c2.g * f2 + c3.g * f3;
            float b = c0.b * f0 + c1.b * f1 + c2.b * f2 + c3.b * f3;
            dst->lines[i][j].r = r;
            dst->lines[i][j].g = g;
            dst->lines[i][j].b = b;
        }
    }
}

バイリニア補間で2倍に拡大した画像

2倍に拡大した画像。最近傍補間よりはましな感じ。

ピクセルフォーマットに依存せずに処理を書きたいがなかなか難しい。


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

カテゴリー

%d人のブロガーが「いいね」をつけました。