LoginSignup
1
1

More than 1 year has passed since last update.

【画像処理解説】Maxプーリング(Javaソース付き)

Last updated at Posted at 2021-08-15

はじめに

画像処理を簡単に解説していきます。
下部にはJavaでのソースコードも載せているのでぜひご参照ください。
不定期にはなりますが、随時更新していく予定です。

Maxプーリングとは?

前回説明したモザイク処理の一種です。
具体的には、ブロックごとの代表値にブロックの最大値を採用する方法です。
詳しい説明は以下の記事を参照してください。

アルゴリズム

  1. 入力画像をラスタスキャンし、2から5の処理を行う。ただし、移動幅をブロックサイズとする。
  2. 平均値計算用の変数を初期化する。
  3. ブロックの中をラスタスキャンし、各画素に4の処理を行う。
  4. 3のインデックスが画像からはみ出していない場合、画素値を取得し、2の最大値変数と比較して最大値を更新する。
  5. ブロックの中をラスタスキャンし、各画素に5で取得した値をセットする。

Maxプーリング処理結果の例

元画像(カラー画像)
imori_256x256.png

結果画像(モザイク画像)
out008.png

ソースコード

Mosaic.java
public static SImage maxPooling(SImage oriImg, int ksize) {
    // カーネルサイズが偶数なら奇数にする
    if (ksize % 2 == 0)
        ksize++;

    // グレースケール画像の場合
    if (oriImg.channel == 1) {
        // モザイク画像用を生成
        var mosaicImg = new SImage(oriImg.width(), oriImg.height(), 1);

        // 画像をラスタスキャン(カーネルサイズ単位で移動)
        for (int y = ksize / 2; y < oriImg.height() + ksize / 2; y += ksize)
            for (int x = ksize / 2; x < oriImg.width() + ksize / 2; x += ksize) {
                // 最大値用変数の初期化
                int max = 0;

                // カーネル範囲をスキャン
                for (int dy = -ksize / 2; dy <= ksize / 2; dy++)
                    for (int dx = -ksize / 2; dx <= ksize / 2; dx++) {
                        // 画像内である場合のみ集計
                        if (x + dx < oriImg.width() && y + dy < oriImg.height())
                            max = Math.max(max, oriImg.getGray(x + dx, y + dy));
                    }

                // カーネル範囲を再スキャン
                for (int dy = -ksize / 2; dy <= ksize / 2; dy++)
                    for (int dx = -ksize / 2; dx <= ksize / 2; dx++) {
                        // 画像内である場合のみ最大値をセット
                        if (x + dx < oriImg.width() && y + dy < oriImg.height())
                            mosaicImg.setGray(x + dx, y + dy, max);
                    }
            }
        return mosaicImg;

        // RGBカラー画像の場合
    } else if (oriImg.channel == 3) {
        // モザイク画像用を生成
        var mosaicImg = new SImage(oriImg.width(), oriImg.height(), 3);

        // 画像をラスタスキャン(カーネルサイズ単位で移動)
        for (int y = ksize / 2; y < oriImg.height() + ksize / 2; y += ksize)
            for (int x = ksize / 2; x < oriImg.width() + ksize / 2; x += ksize) {
                // 最大値用変数の初期化
                int[] max = new int[3];

                // カーネル範囲をスキャン
                for (int dy = -ksize / 2; dy <= ksize / 2; dy++)
                    for (int dx = -ksize / 2; dx <= ksize / 2; dx++) {
                        // 画像内である場合のみ集計
                        if (x + dx < oriImg.width() && y + dy < oriImg.height()) {
                            int[] rgb = oriImg.getRGB(x + dx, y + dy);
                            for (int i = 0; i < 3; i++)
                                max[i] = Math.max(max[i], rgb[i]);
                        }
                    }

                // カーネル範囲を再スキャン
                for (int dy = -ksize / 2; dy <= ksize / 2; dy++)
                    for (int dx = -ksize / 2; dx <= ksize / 2; dx++) {
                        // 画像内である場合のみ平均値をセット
                        if (x + dx < oriImg.width() && y + dy < oriImg.height())
                            mosaicImg.setRGB(x + dx, y + dy, max);
                    }
            }
        return mosaicImg;

        // アルファチャネルを持つ場合
    } else {
        var mosaicImg = new SImage(oriImg.width(), oriImg.height(), 4);

        for (int y = ksize / 2; y < oriImg.height() + ksize / 2; y += ksize)
            for (int x = ksize / 2; x < oriImg.width() + ksize / 2; x += ksize) {
                int[] max = new int[4];

                for (int dy = -ksize / 2; dy <= ksize / 2; dy++)
                    for (int dx = -ksize / 2; dx <= ksize / 2; dx++) {
                        if (x + dx < oriImg.width() && y + dy < oriImg.height()) {
                            int[] rgb = oriImg.getARGB(x + dx, y + dy);
                            for (int i = 0; i < 4; i++)
                                max[i] = Math.max(max[i], rgb[i]);
                        }
                    }

                for (int dy = -ksize / 2; dy <= ksize / 2; dy++)
                    for (int dx = -ksize / 2; dx <= ksize / 2; dx++) {
                        if (x + dx < oriImg.width() && y + dy < oriImg.height())
                            mosaicImg.setARGB(x + dx, y + dy, max);
                    }
            }
        return mosaicImg;
    }
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1