OpenCVで画像のガウシアンフィルタ処理を行うには、GaussianBlur()関数を用います。
ガウシアンフィルタは、「ガウス関数のσの値を変えると、平滑化の効果を変えられる」という説明が多いかと思いますが、ガウシアンフィルタには、それよりも大事な、高周波成分を除去できるという効果があります。
高周波成分を除去するには、σの値は何でもいい訳ではないのですが、OpenCVでは、この高周波成分を除去できるσの値をカーネルのサイズから自動計算で計算させることもできます。
ガウシアンフィルタの構文
GaussianBlur( src, ksize, sigmaX[, dst[, sigmaY[, borderType]]] ) -> dst
引数
src | ガウシアンフィルタ処理を行う画像データを指定します。 データタイプはuint8, uint16, int16, float32, float64に対応しています。 |
ksize | ガウシアンフィルタのカーネルのサイズを(幅, 高さ)で指定します。 幅、高さの値は正の奇数の値である必要があります。 また、幅、高さに0を指定すると、σの値(sigmaX, sigmaY)から自動で計算します。 |
sigmaX | X方向のσの値を指定します。 -1などのマイナスの値を指定するとカーネルのサイズから自動でσの値を計算します。 σ = 0.3 * (ksize – 1) * 0.5 – 1) * 0.8 |
sigmaY | Y方向のσの値を指定します。 指定しないか、0を指定すると、sigmaXと同じσの値を用います。 sigmaXとsigmaYの両方が0の場合は、それぞれ、カーネルの幅と高さからσの値を自動で計算します。 |
borderType | ボーダー処理の種類をBorderTypesのenumで指定します。 |
戻り値
dst | ガウシアンフィルタ処理された画像データ |
サンプルプログラム
ガウシアンフィルタ処理の一般的に行うシンプルなサンプルプログラムを以下に示します。
import cv2
src = cv2.imread("Text.bmp", cv2.IMREAD_UNCHANGED)
# ガウシアンフィルタ
dst = cv2.GaussianBlur(src, (3, 3), -1)
# ガウシアンフィルタ後の画像表示
cv2.imshow("Src Image", src)
cv2.imshow("GaussianBlur", dst)
cv2.waitKey()
実行結果
各種パラメータを設定したガウシアンフィルタ処理の例は以下の通りです。
import cv2
src = cv2.imread("Text.bmp", cv2.IMREAD_UNCHANGED)
# ガウシアンフィルタ
dst1 = cv2.GaussianBlur(
src, # 入力画像
(7, 7), # カーネルのサイズ(幅、高さ)
1.4, # X方向のσの値(-1など負の値を指定するとカーネルサイズから自動計算)
0, # Y方向のσの値(0だとX方向と同じ)
borderType = cv2.BORDER_DEFAULT # ボーダー処理の種類
)
# ガウシアンフィルタ(カーネルサイズを自動計算)
dst2 = cv2.GaussianBlur(
src, # 入力画像
(0, 0), # カーネルのサイズを0にしてσの値からカーネルサイズを自動計算
2 # X方向のσの値
)
# 二値化処理後の画像表示
cv2.imshow("Src Image", src)
cv2.imshow("GaussianBlur1", dst1)
cv2.imshow("GaussianBlur2", dst2)
cv2.waitKey()
実行結果
ガウシアンフィルタのσの値について
高周波成分を除去するためには、σの値を大きくすれば良いという訳ではなく、最適な値があります。
OpenCVでは、sigmaX, sigmaYの値に負の値を指定するとカーネルのサイズ(幅、高さ)から下記の計算式から最適なσの値を計算してくれます。
σ = 0.3 * (ksize – 1) * 0.5 – 1) * 0.8
実際に、ガウシアンフィルタで用いられるカーネルの値は、getGaussianKernel()関数から取得することができます。
いくつか例を示すと
ksize= 3のとき
0.25, 0.5, 0.25
ksize= 5のとき
0.0625, 0.25, 0.375, 0.25, 0.0625
ksize= 7のとき
0.03125, 0.109375, 0.21875, 0.2825, 0.21875, 0.109375, 0.03125
となります。
ガウシアンフィルタのσの値と高周波成分の除去効果について
二次元の画像において、もっとも高周波な画像は、下図のような1画素おきの市松模様の画像となります。
この画像において、σの値を0.6, 0.8(自動計算), 3 と変えながらガウシアンフィルタ処理を行うとどのように変化するのか?を見てみたいと思います。
サンプルプログラム
import numpy as np
import cv2
def create_test_pattern():
# テストパターンの作成
data = np.array([
[0, 255],
[255, 0]
], dtype= np.uint8)
img = np.tile(data, (16, 16))
return img
# テストパターンの作成
src = create_test_pattern()
cv2.namedWindow("Src Image", cv2.WINDOW_NORMAL)
cv2.namedWindow("Gauss 0.3", cv2.WINDOW_NORMAL)
cv2.namedWindow("Gauss -1", cv2.WINDOW_NORMAL)
cv2.namedWindow("Gauss 3", cv2.WINDOW_NORMAL)
# σを変えながらガウシアン処理
gauss1 = cv2.GaussianBlur(src, (3, 3), 0.6) # σ=0.6
gauss2 = cv2.GaussianBlur(src, (3, 3), -1) # σは自動計算(σ=0.8)
gauss3 = cv2.GaussianBlur(src, (3, 3), 3) # σ=3
# ガウシアンフィルタ後の画像表示
cv2.imshow("Src Image", src)
cv2.imshow("Gauss 0.3", gauss1)
cv2.imshow("Gauss -1", gauss2)
cv2.imshow("Gauss 3", gauss3)
cv2.waitKey()
実行結果
左からσ=0.6, σ=0.8(自動計算), σ=3
このように、σの値は、単に大きい方が高周波成分を除去できるという訳ではなく、最適なσの値があり、このσの値は、OpenCVが自動で計算してくれる値を用いた方が高周波成分を除去できる事が確認できます。
参照ページ
https://docs.opencv.org/4.8.0/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1
https://docs.opencv.org/4.8.0/d4/d86/group__imgproc__filter.html#gac05a120c1ae92a6060dd0db190a61afa