ノイズ除去#

ノイズ除去(noise removal / denoising) は、画像に混入した不要な変動成分(ノイズ)を取り除き、元の信号をできるだけ忠実に復元する処理のこと。

カメラのセンサーの熱雑音、低照度環境での量子ノイズ、伝送路でのビット誤りなど、様々な原因でノイズが発生する。ノイズ除去は画像処理パイプラインの前処理として広く使われており、後続の特徴抽出・認識精度に大きく影響する。

本節では代表的なノイズの種類と、それぞれに対して有効なフィルタリング手法を学ぶ。

評価指標:PSNR#

ノイズ除去の効果を定量的に評価するために PSNR(Peak Signal-to-Noise Ratio、最大信号対雑音比) を使う。

PSNR

\[ \text{PSNR} = 20 \log_{10} \frac{255}{\sqrt{\text{MSE}}} \]

ここで MSE(Mean Squared Error)は:

\[ \text{MSE} = \frac{1}{HW} \sum_{i,j} \left( I(i,j) - \hat{I}(i,j) \right)^2 \]
  • \(I\):元画像(ノイズなし)

  • \(\hat{I}\):処理後の画像(復元画像)

  • 単位は dB(デシベル)

  • 値が大きいほど元画像に近い(高品質)

  • 一般的に 30 dB 以上であれば視覚的に良好とされる

1. ノイズの種類#

ガウシアンノイズ(Gaussian Noise)#

最も一般的なノイズモデル。各ピクセルに平均 0・標準偏差 \(\sigma\) の正規分布に従う乱数が加算される。

カメラの熱雑音・アンプのランダムノイズなどを模している。\(\sigma\) が大きいほどノイズが強くなる。

ガウシアンノイズモデル

\[ I_{\text{noisy}}(x, y) = I(x, y) + \eta(x, y), \quad \eta \sim \mathcal{N}(0, \sigma^2) \]

ソルト&ペッパーノイズ(Salt & Pepper Noise)#

画像のランダムな位置に、真っ白(255)または真っ黒(0)の画素が散在するノイズ。インパルスノイズとも呼ばれる。センサーの欠陥や伝送エラーで発生する。

スペックルノイズ(Speckle Noise)#

超音波画像やレーダー画像に特有のノイズ。画素値に乗算的に加わる。

スペックルノイズモデル

\[ I_{\text{noisy}}(x, y) = I(x, y) + I(x, y) \cdot \eta(x, y), \quad \eta \sim \mathcal{U}(0, \sigma) \]

ガウシアンノイズが 加算的 であるのに対し、スペックルノイズは 乗算的 であるため、明るい領域ほどノイズも大きくなる特性がある。

../_images/ac8e563fd7cfaaa36da915a31d08926081cd955c7ca3298166a56b76ff273fec.png

2. 線形フィルタ#

線形フィルタ は、注目画素とその周辺画素の線形結合(重み付き平均)で出力値を計算するフィルタ。演算が単純で高速だが、エッジもぼかしてしまう欠点がある。

平均フィルタ(Box / Mean Filter)#

カーネル内の全画素の 単純平均 を取る最もシンプルなフィルタ。

平均フィルタ

\[ I_{\text{out}}(x, y) = \frac{1}{k^2} \sum_{(i,j) \in \mathcal{N}(x,y)} I(i, j) \]
  • \(k \times k\):カーネルサイズ

  • \(\mathcal{N}(x,y)\)\((x,y)\) を中心とした \(k \times k\) の近傍領域

  • カーネルサイズが大きいほど平滑化が強まるが、ぼけも大きくなる

OpenCV: cv2.blur(src, ksize)

# 平均フィルタ:カーネルサイズの比較
kernel_sizes = [3, 5, 9]

blurred_mean = {k: cv2.blur(noisy_gaussian, (k, k)) for k in kernel_sizes}

fig, axes = plt.subplots(1, 4, figsize=(18, 4))

axes[0].imshow(noisy_gaussian)
axes[0].set_title(f"ガウシアンノイズ\nPSNR={psnr(img, noisy_gaussian):.1f} dB", fontsize=11)
axes[0].axis('off')

for ax, k in zip(axes[1:], kernel_sizes):
    result = blurred_mean[k]
    ax.imshow(result)
    ax.set_title(f"平均フィルタ ({k}×{k})\nPSNR={psnr(img, result):.1f} dB", fontsize=11)
    ax.axis('off')

fig.suptitle("平均フィルタ:カーネルサイズの影響", fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
../_images/a65e0505fead0c715db55e5226de04d7ce4a2efacfe618eb2901541b47340877.png

ガウシアンフィルタ(Gaussian Filter)#

カーネルの重みを ガウス関数(正規分布) に従って設定したフィルタ。中心画素に大きな重みを置き、周辺になるほど重みが小さくなる。単純平均より自然なぼかしが得られる。

ガウシアンカーネル

\[ G(x, y) = \frac{1}{2\pi\sigma^2} \exp\!\left(-\frac{x^2 + y^2}{2\sigma^2}\right) \]
  • \(\sigma\):ガウス分布の標準偏差。大きいほど広い範囲を平滑化する

  • カーネルサイズ \(k\) は通常 \(k = 2\lceil 3\sigma \rceil + 1\) で自動決定される

OpenCV: cv2.GaussianBlur(src, ksize, sigmaX)

../_images/a62654ed8aa0dcdae73062f20ebee70fa4063b26b519c1f90d091f40bdddd4ae.png
../_images/bae17b287a0e537fec3f2f7e29e8da18fc34e289bc245a7abad9379405b52bb2.png

3. 非線形フィルタ#

非線形フィルタ は、近傍画素の統計量(中央値など)や画素値の類似度に基づいて出力を決めるフィルタ。計算コストは高いが、エッジを保ちながらノイズを除去できるものが多い。

メディアンフィルタ(Median Filter)#

カーネル内の全画素を並べ替えて 中央値(メジアン) を出力する。外れ値(極端に白・黒なピクセル)を自動的に排除するため、ソルト&ペッパーノイズに対して特に強い。

メディアンフィルタの特徴

  • 外れ値の影響を受けない(ロバスト統計)

  • 平均フィルタより エッジを保持しやすい

  • S&P ノイズ除去において平均・ガウシアンフィルタを大幅に上回る

  • ただし、ガウシアンノイズには平均/ガウシアンフィルタの方が有効なことが多い

OpenCV: cv2.medianBlur(src, ksize)

../_images/c2e576c1086c87b8f5a83c4066fc3c3f093fda0772c3d38b25c8c00892485a5d.png
../_images/4ad691ed18915dbd348606a18c290735ea41f66fcc76dbf6cf20e255b1655f66.png

バイラテラルフィルタ(Bilateral Filter)#

ガウシアンフィルタの弱点である「エッジのぼけ」を解消するために開発されたフィルタ。空間的な近さだけでなく、画素値の類似度 も重みに組み込む。

バイラテラルフィルタ

\[ I_{\text{out}}(x, y) = \frac{1}{W} \sum_{(i,j) \in \mathcal{N}} I(i,j) \cdot G_s(\|\mathbf{p}-\mathbf{q}\|) \cdot G_r(|I(\mathbf{p})-I(\mathbf{q})|) \]
  • \(G_s\):空間カーネル(距離が遠いほど重みが小さい)、パラメータ \(\sigma_s\)

  • \(G_r\):値域カーネル(画素値が違うほど重みが小さい)、パラメータ \(\sigma_r\)

  • \(W\):正規化定数

エッジ近傍では値域カーネルの重みが急落するため、エッジを越えた平滑化が抑制される。

OpenCV: cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace)

  • d:フィルタ径(-1 で sigmaSpace から自動計算)

  • sigmaColor:色空間のσ(大きいほど色差が大きくても平均化)

  • sigmaSpace:座標空間のσ

../_images/ffaee70d6423f8ce9e285035525c05212e11e14a40f77042c59d1f606ed3a5ac.png
../_images/7adc7cf70450065fd1d3ad6b5c111831776d66ca95ab211985473d72d9fbc3bb.png

Non-Local Means(NLM)#

「画像内の類似したパッチ(局所領域)は同じ信号から生成されている」という仮定に基づく手法。注目画素の近傍だけでなく、画像全体から類似パッチを探して 重み付き平均を取る。

Non-Local Means の原理

\[ \text{NLM}(I)(\mathbf{p}) = \frac{1}{C(\mathbf{p})} \sum_{\mathbf{q} \in \Omega} w(\mathbf{p}, \mathbf{q}) \cdot I(\mathbf{q}) \]

重みは近傍パッチの類似度から計算する:

\[ w(\mathbf{p}, \mathbf{q}) = \exp\!\left(-\frac{\| P(\mathbf{p}) - P(\mathbf{q}) \|^2}{h^2}\right) \]
  • \(P(\mathbf{p})\):画素 \(\mathbf{p}\) を中心とするパッチ(小領域)

  • \(h\):ノイズレベルに対応するフィルタリング強度パラメータ

  • \(\Omega\):探索窓(search window)

局所フィルタより高品質だが、計算コストが高い(OpenCVでは高速実装を提供)。

OpenCV: cv2.fastNlMeansDenoisingColored(src, None, h, hForColorComponents, templateWindowSize, searchWindowSize)

  • h:輝度成分のフィルタ強度(10 が典型値)

  • hForColorComponents:色成分のフィルタ強度

  • templateWindowSize:パッチサイズ(奇数、推奨 7)

  • searchWindowSize:探索窓サイズ(奇数、推奨 21)

../_images/def5fcebf3976752f393b75c5501ed7b742a180dfa3b5ad9bfa8ae83d0598d79.png

まとめ:全手法の比較#

各ノイズに対してすべてのフィルタを適用し、PSNR で定量比較する。

../_images/ea89641e037942aa4f51e0de5e4ae4b48c45a06965fb7498eb7d7844b111108e.png
../_images/885a77e65b4e35becd3a5eb40406861e5a210425396bce5c8379a54b350698d7.png
../_images/4f432532bc40655454354eb3ad93e1cf8d07c03017b7b020cbaa3937516d7652.png

各手法のまとめ#

手法

計算コスト

エッジ保持

ガウシアン

S&P

特徴

平均フィルタ

弱い

最もシンプル

ガウシアンフィルタ

弱い

自然なぼかし

メディアンフィルタ

中程度

S&P に最強

バイラテラルフィルタ

強い

エッジを保ちながら平滑化

Non-Local Means

非常に高

強い

最高品質(遅い)

手法の選び方

  • ガウシアンノイズを素早く除去したい → ガウシアンフィルタ(σ を調整)

  • ソルト&ペッパーノイズを除去したい → メディアンフィルタ(カーネル 3〜5)

  • エッジを保ちながら平滑化したい → バイラテラルフィルタ

  • 最高品質のノイズ除去が必要(処理時間を許容できる) → Non-Local Means