エンジニアリングとお絵描き

お絵描きが趣味のエンジニアが、誰かの為になりそうなことや未来の自分の助けになりそうなことを書き残します.

ガウシアンフィルタ

作業の流れ

ハフ変換を行う前にCanny法というものを使ってエッジ検出を行います。 Canny法ではまずガウシアンフィルタによるぼかしの処理を行います。

よってPythonの練習もかねて、まずガウシアンフィルタを実装しようと思います。

ガウシアンフィルタを使う例

ガウシアンフィルタは趣味のお絵描きでもよく使用している便利な処理です。 以下にガウシアンフィルタがイラスト制作に使われる例を示します。 (プログラム書く前に絵の制作で時間を溶かしたのは内緒...)

f:id:pengin_0_maru:20200529143849p:plainf:id:pengin_0_maru:20200529144038p:plain
ガウスぼかしの使い方

このように、イラストの背景にガウスぼかしをかけることによって主役の人物が見やすくなります。 この処理はお絵かきソフトClipStudioで行いました。

このガウスぼかしに使用するガウシアンフィルタを実装していきます。

ガウシアンフィルタの原理

ガウシアンフィルタではガウス分布というものを利用して、注目画素からの距離に応じて近傍の画素値に重みをかける処理を行っています。以下にガウス分布の式を載せます。

\displaystyle{
g(x,y,σ)=\frac{1}{2πσ^2}exp\left(-\frac{x^2+y^2}{2σ^2} \right)
}

ガウス分布は確率統計とかでよく出てくる正規分布と同じものみたいです。偏差値の計算など、色々なところで使われるみたいです。 このガウス分布によって注目画素の周りの画素の画素値に重みを付けることでぼかしていきます。

プログラム

実際にガウシアンフィルタを行うプログラムです。 グレースケール化は無くても良いのですが勉強の過程で書いてみて、今後も必要なので載せました。

import cv2
import numpy as np

#グレースケール化
def BGR2GRAY(img):
    b = img[:,:,0].copy()
    g = img[:,:,1].copy()
    r = img[:,:,2].copy()

    print(b)

    out =  0.2126*r + 0.7152*g + 0.0722*b

    #整数に変換
    out = out.astype(np.uint8)
    return out

#ガウシアンフィルタ
def gaussian_filter(img,k_range=7,sigma=1.3):
    #入力画像がカラーかグレー化を判定し、グレーなら要素を増やす
    if len(img.shape) == 3:
            H,W,C = img.shape
    else:
            img = np.expand_dims(img,axis=-1)
            H,W,C = img.shape

    #//は切り捨て除算
    pad = k_range//2

    #隅の画素でも重み付けができるように0パディング
    out = np.zeros((H + pad *2,W + pad * 2,C),dtype=np.float)
    #入力画像を0パディング付きで複製
    out[pad: pad + H,pad: pad + W] = img.copy().astype(np.float)

    #カーネルの準備
    K = np.zeros((k_range,k_range),dtype=np.float)
    for x in range(-pad,-pad + k_range):
        for y in range(-pad, -pad + k_range):
            #ここで肝のガウス分布の式が登場
            K[y + pad,x + pad] = np.exp(-(x ** 2 + y ** 2)/(2 * (sigma ** 2)))
    K /= (2*np.pi * sigma * sigma)
    #最後にカーネルの合計で割る
    K /= K.sum()

    tmp = out.copy()

    for y in range(H):
        for x in range(W):
            for c in range(C):
                out[pad + y,pad + x,c] = np.sum(K * tmp[y: y + k_range,x:x + k_range,c])

    #0から255の範囲に収める
    out = np.clip(out,0,255)
    out = out[pad: pad + H,pad:pad + W].astype(np.uint8)

    return out


img = cv2.imread("hough.png").astype(np.float)

out = gaussian_filter(img)

cv2.imshow("result",out)
cv2.waitKey(0)

gaussian_filter内の画像はこのような感じになっているはずです。

f:id:pengin_0_maru:20200530134729p:plain
解説みたいな図

このサイトのコードをガッツリ参考にしました github.com

結果はこんな感じです。

f:id:pengin_0_maru:20200530135724p:plain
出力結果

このガウシアンフィルタ、実はOpenCVのメソッドを使うと10行で実装できてしまいます。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('hough.png')

#kernel = np.ones((5,5),np.float32)/25
out = cv2.GaussianBlur(img,(7,7),1.3)
cv2.imshow("result",out)
cv2.waitKey(0)

次はこのガウシアンフィルタを使ってCanny法を実装しようと思います。