今回はエッジを残しつつノイズ除去できる画像処理手法であるバイラテラルフィルタについて説明していきます。
目次
バイラテラルフィルタの特徴・効果
輪郭などの大きいエッジを残しつつノイズを除去する手法です。
ガウシアンフィルタだと輪郭などエッジもぼやけてしまいますが、バイラテラルフィルタは輪郭・エッジもぼやける欠点を補います。
バイラテラルフィルタの仕組み
バイラテラルフィルタの数式を見てみましょう。
パラメータは以下の通りです。
- 周辺の何ピクセルを見るかを示す w
- 距離の分散値 σ1
- 色の分散値 σ2
全体的に、周辺のピクセルが距離遠い or 画素値が対象ピクセルと離れている なら重みを小さくするというルールで値を合成するといった感じです。
ガウシアンフィルタと似ているが、画素値の違いと距離を考慮することでエッジを残してノイズ除去することができます。
指定した分散パラメータが大きければ重みが大きくなるため平滑化の効果が大きくなる。

次に詳細を見ていきます
①は対象ピクセルの周囲何ピクセルを見るかを表す。この範囲が広いほど平滑化が強くなる。
②は対象ピクセルとの距離を考慮した重みです。
遠いほど重みが小さくなる。パラメータσ1が大きければ距離の影響が受けにくくなるため周囲のピクセルからの影響が強くなり、より平滑化される。
③は対象ピクセルとの画素値の差を考慮した重みです。
差が大きいほどほど重みが小さくなる。パラメータσ2が大きければ色の影響が受けにくくなるため周囲のピクセルからの影響が強くなり、より平滑化される。
どういうノイズ除去に使えるか・デメリット
雪をノイズと考えて、雪の中にトラがいる画像を例にしてみます。
以下の2枚は元画像とバイラテラルフィルタをかけた画像。
バイラテラルフィルタをかけると、輪郭を残しつつ雪がある程度消えます。

一方で、ガウシアンフィルタを用いると多少雪が消えるものの全体的に少しぼやけてしまいます。

Python/OpenCVを使った実装
Python、OpenCVならこれだけで済みます。
import cv2
img = cv2.imread(ファイルパス)
img = cv2.bilateralFilter(img, d=9, sigmaColor=100, sigmaSpace=100).astype("uint8")
補足
一応バイラテラルフィルタの数式のLaTexコード貼っておきます。
\begin{align*}
g(i, j) = \frac{\sum_{n=-w}^{w} \sum_{m=-w}^{w} f(i+m, j+n) exp (-\frac{m^2+n^2}{2\sigma_1^2}) exp(-\frac{(f(i,j)-f(i+m,j+n))^2}{2\sigma_2^2}) }
{\sum_{n=-w}^{w} \sum_{m=-w}^{w} exp(-\frac{m^2+n^2}{2\sigma_1^2}) exp(-\frac{(f(i,j)-f(i+m,j+n))^2}{2\sigma_2^2})}
\end{align*}