前のページでは合計9画素の近傍領域で平均値を計算する平均化フィルタを作成しました.ここでは,9(=3x3)画素,25(=5x5)画素,49(=7x7)画素で処理できるように一般化してみよう.
関数 mean_filter を定義します.引数 n
は上下左右に n 画素ずつ拡大した近傍領域を使用することを意味します.なお,あらかじめ「表示関数の定義」ページを参照し,ライブラリのインポートと関数の定義を実行しておいてください.
"""
上下左右 n 画素ずつ拡大した近傍領域で平均値を取る
つまり,
n = 1 のとき 3 x 3 = 9
n = 2 のとき 5 x 5 = 25
n = 3 のとき 7 x 7 = 49
"""
def mean_filter(img, n=1):
h = gray_img.shape[0]
w = gray_img.shape[1]
filtered_img = np.copy(img)
for j in range(n, h-n):
for i in range(n, w-n):
gs = 0.0
for y in range(j-n, j+n+1):
for x in range(i-n, i+n+1):
gs += img[y, x]
filtered_img[j, i] = gs / (2 * n + 1) / (2 * n + 1)
return filtered_img
RGBA形式の png 画像ファイルを RGB 形式に変換したのち,さらにグレースケールに変換して表示します.
ink_img = plt.imread('ink.png')
img = color.rgba2rgb(ink_img)
gray_img = color.rgb2gray(img)
show(gray_img)
オリジナル
引数に n=1
を指定して平均化フィルタを適用します.これは 3 x 3 = 9 画素の近傍領域を使用しています.
mean_filter_img1 = mean_filter(gray_img, n=1)
show(mean_filter_img1)
(3x3)
同様に n=2
(つまり,5 x 5 = 25画素)の場合の結果を示します.
(5x5)
さらに,n=3, 4, ..., 9
の結果も示します.
(7x7)
(9x9)
(11x11)
(13x13)
(15x15)
(17x17)
(19x19)
近傍領域のサイズを大きくするほどより平滑化されていることがわかります.ただし,画像上下左右の端の部分についての処理はできておらず,処理された部分のサイズは小さくなっていることにも注意してください.画像の全ての領域を平滑化するには,入力画像の外側に「縁」をつけて画像を大きくするパディングと言われる処理が必要になります.パディングの方法もいくつかあるのでここでは割愛します.
拡大図についても作成して確認します.まずは,オリジナルの画像です.
show_zoom_with_color(
gray_img, xlim=(50.5,59.5), ylim=(89.5, 80.5),
figsize=(6,6), fontsize=6, show_color=False
)
オリジナル
9画素での平均化フィルタによる結果も拡大して表示します.
show_zoom_with_color(
mean_filter_img1, xlim=(50.5,59.5), ylim=(89.5, 80.5),
figsize=(6,6), fontsize=6, show_color=False
)
(3x3)
さらに異なる近傍領域のサイズについても拡大図を示します.
(5x5)
なお,この 7x7 の結果は,次のページで利用する scikit-image の filters.threshold_local
で得られる結果と(少なくとも画像の縁付近でない場合は)同じなるはずです.
(7x7)
(9x9)
(11x11)
(13x13)
(15x15)
(17x17)
(19x19)
このページでは平均化フィルタを一般化した関数を自作してみました.しかしながら,画像の隅の部分のパディング処理までは記述していませんでした.実際には scikit-image の中で平均化フィルタ関数が提供されておりパディングも行えるので,次のページではそれを使ってみよう.