#はじめに
画像処理を簡単に解説していきます。
下部にはJavaでのソースコードも載せているのでぜひご参照ください。
不定期にはなりますが、随時更新していく予定です。
#Maxプーリングとは?
前回説明したモザイク処理の一種です。
具体的には、ブロックごとの代表値にブロックの最大値を採用する方法です。
詳しい説明は以下の記事を参照してください。
#アルゴリズム
- 入力画像をラスタスキャンし、2から5の処理を行う。ただし、移動幅をブロックサイズとする。
- 平均値計算用の変数を初期化する。
- ブロックの中をラスタスキャンし、各画素に4の処理を行う。
- 3のインデックスが画像からはみ出していない場合、画素値を取得し、2の最大値変数と比較して最大値を更新する。
- ブロックの中をラスタスキャンし、各画素に5で取得した値をセットする。
#ソースコード
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;
}
}