edo1z blog

プログラミングなどに関するブログです

畳み込みフィルターで画像をぼかしてみる

畳み込みニューラルネットワークは、畳み込みフィルターを使ってますが、畳み込みフィルターを使うと画像を加工出来ます。ぼかすには、画像の明るさを周辺の明るさの平均をとってそれで埋めていくことでぼけます。

適当な画像をぼかしてみようと思います。

まずこの画像をNumpy配列として取得します。画像は、幅800px、高さ600pxです。

import numpy as np
from PIL import Image

img = np.array(Image.open('sample_pic.jpg'))
print(img.shape)

結果

(600, 800, 3)

次に5x5のフィルターを作ります。フィルターの全領域の合計が1になるようにします。

filter_size = 5
filter = np.zeros((filter_size, filter_size))
filter += 1 / (filter_size * filter_size)
print(filter)

結果

[[ 0.04  0.04  0.04  0.04  0.04]
 [ 0.04  0.04  0.04  0.04  0.04]
 [ 0.04  0.04  0.04  0.04  0.04]
 [ 0.04  0.04  0.04  0.04  0.04]
 [ 0.04  0.04  0.04  0.04  0.04]]

このフィルターをチャンネル毎に画像の左から順に適用していきます。

new_img = np.zeros(img.shape)
for h in range(0, img.shape[0], filter.shape[0]):
    for w in range(0, img.shape[1], filter.shape[1]):
        for c in range(img.shape[2]):
            num = 0
            for hi in range(filter.shape[0]):
                for wi in range(filter.shape[1]):
                    num += img[h + hi][w + wi][c]
            num /= filter.size
            for hi in range(filter.shape[0]):
                for wi in range(filter.shape[1]):
                    new_img[h + hi][w + wi][c] = num

画像を表示します。

Image.fromarray(np.uint8(new_img)).show()

これだとモザイクって感じなので、全体的にぼやっとさせるには、下記のようにしたらいいと思います。効率性はよろしくないと思いますが、とりあえず出来ました。変えたところは、全ピクセルで別々に平均を計算するようにしたところです。

new_img = np.zeros(img.shape)
for h in range(img.shape[0] - filter_size):
    for w in range(img.shape[1] - filter_size):
        for c in range(img.shape[2]):
            num = 0
            for hi in range(filter.shape[0]):
                for wi in range(filter_size):
                    num += img[h + hi][w + wi][c]
            num /= filter.size
            for hi in range(filter_size):
                for wi in range(filter.shape[1]):
                    new_img[h + hi][w + wi][c] = num