Python入門トップページ


目次

  1. scikit-image のインストール
  2. Matplotlib による画像の表示
  3. 表示関数の定義
  4. RGBA から RGB への変換
  5. グレースケールをイメージする
  6. RGB からグレースケールへの変換
    1. RGB 平均
    2. ITU-R Rec BT.602
    3. Contemporary CRT phosphors (Rec 709)
    4. 3種類の比較
    5. scikit-image の rgb2gray 関数
  7. 平均化フィルタ
    1. 平均化フィルタの自作
    2. 平均化フィルタの一般化
    3. scikit-image の平均化フィルタ関数
  8. ガウシアンフィルタ
  9. バイラテラルフィルタ
  10. ランダムノイズとフィルタ
  11. ソーベルフィルタ
    1. ソーベルフィルタの自作
    2. scikit-image の sobel 関数
    3. 平均化/ガウシアンフィルタとソーベルフィルタの併用

画像フィルタの作成と利用

平均化フィルタ

平均化フィルタの一般化

前のページでは合計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)
オリジナル
filters_20_gray.png

引数に n=1 を指定して平均化フィルタを適用します.これは 3 x 3 = 9 画素の近傍領域を使用しています.


mean_filter_img1 = mean_filter(gray_img, n=1)
show(mean_filter_img1)
(3x3)
filters_21_mean1.png

同様に n=2 (つまり,5 x 5 = 25画素)の場合の結果を示します.

(5x5)
filters_21_mean2.png

さらに,n=3, 4, ..., 9 の結果も示します.

(7x7)
filters_21_mean3.png
(9x9)
filters_21_mean4.png
(11x11)
filters_21_mean5.png
(13x13)
filters_21_mean6.png
(15x15)
filters_21_mean7.png
(17x17)
filters_21_mean8.png
(19x19)
filters_21_mean9.png

近傍領域のサイズを大きくするほどより平滑化されていることがわかります.ただし,画像上下左右の端の部分についての処理はできておらず,処理された部分のサイズは小さくなっていることにも注意してください.画像の全ての領域を平滑化するには,入力画像の外側に「縁」をつけて画像を大きくするパディングと言われる処理が必要になります.パディングの方法もいくつかあるのでここでは割愛します.

拡大図についても作成して確認します.まずは,オリジナルの画像です.


show_zoom_with_color(
    gray_img, xlim=(50.5,59.5), ylim=(89.5, 80.5),
    figsize=(6,6), fontsize=6, show_color=False
)
オリジナル
filters_22_zoom.png

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)
filters_22_mean1_zoom.png

さらに異なる近傍領域のサイズについても拡大図を示します.

(5x5)
filters_22_mean2_zoom.png

なお,この 7x7 の結果は,次のページで利用する scikit-image の filters.threshold_local で得られる結果と(少なくとも画像の縁付近でない場合は)同じなるはずです.

(7x7)
filters_22_mean3_zoom.png
(9x9)
filters_22_mean4_zoom.png
(11x11)
filters_22_mean5_zoom.png
(13x13)
filters_22_mean6_zoom.png
(15x15)
filters_22_mean7_zoom.png
(17x17)
filters_22_mean8_zoom.png
(19x19)
filters_22_mean9_zoom.png

このページでは平均化フィルタを一般化した関数を自作してみました.しかしながら,画像の隅の部分のパディング処理までは記述していませんでした.実際には scikit-image の中で平均化フィルタ関数が提供されておりパディングも行えるので,次のページではそれを使ってみよう.

目次に戻る