本日はガウシアンフィルタを用いた画像のノイズ除去について紹介したいと思います。
ガウシアンフィルタ
ガウシアンフィルタは前回紹介した平均値フィルタに類似したフィルタで、平均値フィルタに重みづけを行い、対象とする画素に近いほど大きい重みを付与できるように重みを設定したフィルタとなります。
この重みが、対象画素からの距離と反比例するようなガウス分布に従うように重みを設定したものをガウシアンフィルタと呼びます。
前回紹介した重みが均一な平均値フィルタとの違いは、対象画素に近い画素ほど重視されるため、重みが均一の平均値フィルタと違い画像がぼけてしまう副作用を軽減することができます。
3×3と5×5のガウシアンフィルタのフィルタの重みを以下に示します。


平均値フィルタ同様、画像のノイズ除去等に利用することができます。こちらのガウシアンフィルタを画像に適用し、ノイズの除去を行うプログラムをPythonで書きましたので、以下で見ていきます。
画像へのガウシアンフィルタによるノイズ除去プログラム(Python+OpenCV)
ガウシアンフィルタはOpenCVの関数で簡単に実現することができます。以下にPythonとOpenCVで書いたプログラムを紹介します。
動作環境:OpenCV 4.5.5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np
import cv2
import sys
def main():
print("OpenCV Version: " + str(cv2.__version__) + "\n")
# Loading image data (COLOR)
filename = "data/lenna.png"
gt_image = cv2.imread(filename, cv2.IMREAD_COLOR)
if gt_image is None:
print("Cannot find image data : " + filename)
sys.exit()
# Generation of noisy image
noisy_image = AddGaussianNoise(gt_image, 0, 30)
# Denoising with Gaussian filter
# Gaussian Filter (3*3)
kernel1 = np.array([[1/16, 2/16, 1/16],
[2/16, 4/16, 2/16],
[1/16, 2/16, 1/16]])
denoised_image1 = cv2.filter2D(noisy_image, -1, kernel1)
# Gaussian Filter (5*5)
kernel2 = np.array([[1/256, 4/256, 6/256, 4/256, 1/256],
[4/256, 16/256, 24/256, 16/256, 4/256],
[6/256, 24/256, 36/256, 24/256, 6/256],
[4/256, 16/256, 24/256, 16/256, 4/256],
[1/256, 4/256, 6/256, 4/256, 1/256]])
denoised_image2 = cv2.filter2D(noisy_image, -1, kernel2)
# Evaluation with PSNR and SSIM
PSNREval(gt_image, noisy_image, 255)
SSIMEval(gt_image, noisy_image)
PSNREval(gt_image, denoised_image1, 255)
SSIMEval(gt_image, denoised_image1)
PSNREval(gt_image, denoised_image2, 255)
SSIMEval(gt_image, denoised_image2)
cv2.imwrite('noisy_image.png',noisy_image)
cv2.imwrite('denoised_image1.png',denoised_image1)
cv2.imwrite('denoised_image2.png',denoised_image2)
def AddGaussianNoise(image, mean, sigma):
noise = np.random.normal(mean, sigma, np.shape(image))
noisy_image = image + noise
noisy_image[noisy_image > 255] = 255
noisy_image[noisy_image < 0] = 0
noisy_image = noisy_image.astype(np.uint8) # Float -> Uint
return noisy_image
def PSNREval(image1, image2, R):
PSNR_opencv, _ = cv2.quality.QualityPSNR_compute(image1, image2)
print("PSNR Evaluation Results")
print(" PSNR (Blue): " + str(round(PSNR_opencv[0],3)))
print(" PSNR (Green): " + str(round(PSNR_opencv[1],3)))
print(" PSNR (Red): " + str(round(PSNR_opencv[2],3)))
print(" PSNR (RGB Average): " + str(round(((PSNR_opencv[0] + PSNR_opencv[1] + PSNR_opencv[2]) / 3),3)) + "\n")
def SSIMEval(image1, image2):
SSIM_opencv, _ = cv2.quality.QualitySSIM_compute(image1, image2)
print("SSIM Evaluation Results")
print(" SSIM (Blue): " + str(round(SSIM_opencv[0],3)))
print(" SSIM (Green): " + str(round(SSIM_opencv[1],3)))
print(" SSIM (Red): " + str(round(SSIM_opencv[2],3)))
print(" SSIM (RGB Average): " + str(round(((SSIM_opencv[0] + SSIM_opencv[1] + SSIM_opencv[2]) / 3),3)) + "\n")
if __name__ == "__main__":
main()
入力データとしては、以下の画像を用いました。

プログラム内のgt_imageがGroundTruthの画像(正解画像)であり、noisy_imageがノイズが付与された画像となります。
画像には全チャネルにガウシアンノイズを付与しています。ガウシアンノイズに関してはこちらの記事を参照してください。
今回は、このnoisy_imageに対してガウシアンフィルタを適用することで、どれだけ正解に近づけることができるのか(ノイズ除去の効果)を確認します。
プログラムの動作結果
ノイズレベルを表すσの値をプログラムの18行目「noisy_image = AddGaussianNoise(gt_image, 0, 30)」で変更することができます。
現在はσ=30に設定されていますが、この値を大きくすると、より大きいノイズが付与されます。
実行すると上記で紹介した3×3及び5×5のガウシアンフィルタが動作し、以下のような出力が得られます。ノイズは乱数なので、実行結果は実行の度に若干異なる可能性があります。
PSNR Evaluation Results PSNR (Blue): 18.617 PSNR (Green): 18.897 PSNR (Red): 19.078 PSNR (RGB Average): 18.864 SSIM Evaluation Results SSIM (Blue): 0.255 SSIM (Green): 0.349 SSIM (Red): 0.31 SSIM (RGB Average): 0.305 PSNR Evaluation Results PSNR (Blue): 25.92 PSNR (Green): 25.379 PSNR (Red): 26.156 PSNR (RGB Average): 25.818 SSIM Evaluation Results SSIM (Blue): 0.576 SSIM (Green): 0.641 SSIM (Red): 0.635 SSIM (RGB Average): 0.618 PSNR Evaluation Results PSNR (Blue): 26.9 PSNR (Green): 25.435 PSNR (Red): 26.639 PSNR (RGB Average): 26.325 SSIM Evaluation Results SSIM (Blue): 0.668 SSIM (Green): 0.702 SSIM (Red): 0.714 SSIM (RGB Average): 0.695
上から順に
- ノイズ画像のPSNR
- ノイズ画像のSSIM
- 3×3のガウシアンフィルタ適用時のPSNR
- 3×3のガウシアンフィルタ適用値のSSIM
- 5×5のガウシアンフィルタ適用値のPSNR
- 5×5のガウシアンフィルタ適用値のSSIM
となります。
実験結果
各ノイズレベルでの結果を表にまとめたものが以下となります。PSNRとSSIM共に値が大きいほど品質が良い(正解画像に類似している)ことを示します。

ノイズレベルが小さい(σ=3)の場合は、ガウシアンフィルタを掛けると画質は劣化するという結果が出ました。これは、ノイズが少ないのにも関わらずガウシアンフィルタを掛けることで、ノイズ除去による改善よりも、副作用である画像全体がボケてしまうという部分が強く出てしまったためだと思います。
一方、ノイズレベルが大きめのものでは改善効果が見られていることがわかります。
また、以下がσ=30の実験結果となります。確かに視覚的にも3×3や5×5の方がノイズが少ないように見えますが、輪郭は若干ぼやけているようにも見えます。

まとめ
本日はガウシアンフィルタを用いたノイズ除去を紹介しました。
このようなノイズ除去ができるフィルタは多数提案されていますので、他も今後紹介してみたいと思います。