【Python/OpenCV】非局所的平均フィルタ(NLM Filter)でノイズ除去

Python版OpenCVで非局所的平均フィルタ(NLM Filter)を実装し、画像のノイズを除去する方法をソースコード付きで解説します。

非局所的平均フィルタとは

非局所的平均フィルタ (Non-Local Means Filter, NLMフィルタ) は、画像のノイズ除去を行う空間フィルタの1つです。バイラテラルフィルタと同様、輪郭(エッジ)を保持しながらノイズを除去できる特徴があります。
非局所的平均フィルタは、各画素に対して、類似する画素の重み付き平均を計算してノイズを除去します。原理については、以下ページで別途解説しています。

非局所的平均フィルタ(NLM)の原理・特徴・計算式
画像処理における非局所的平均フィルタ(Non-Local Means Filter, NLMフィルタ) の原理や計算式についてまとめました。

今回は、Python版OpenCVを用いて非局所的平均フィルタを実装し、画像のノイズを除去する方法を解説します。

サンプルコード① cv2.bilateralFilterで実装

OpenCVのcv2.bilateralFilterで実装した例です。


実行結果

以下は、天体写真(オリオン大星雲、M42)に対してサンプルプログラムを実行した結果です。

■入力画像(左)と出力画像(右)

背景ノイズを除去しつつ、星雲の輪郭は保持されています。

コード解説

以下の部分で画像imgにフィルタを適用し、フィルタ処理された画像をfilteredという変数に保存しています。

filtered = cv.fastNlMeansDenoisingColored(img, None, h, ForColorComponents, templateWindowSize, searchWindowSize)
パラメータ 説明
src 入力画像。
filtered 出力画像。入力画像と同じサイズと型を持つ。
h フィルタの強さ。値が大きいほどノイズ除去効果が強くなるが、輪郭も失われやすい。
hForColorComponents カラーフィルタの強さ。値が大きいほどカラーノイズ除去効果が強くなる。
templateWindowSize 部分画像ウのサイズ。デフォルトは7。
searchWindowSize 探索窓のサイズ。デフォルトは21。

サンプルコード② パラメータをスライドバーで調整

以下は、フィルタのパラメータをスライドバーで調整し、リアルタイムで処理結果を表示するサンプルプログラムです。画像によって最適なパラメータは異なるため、このようにさまざまな設定を試してみると良いでしょう。


実行結果

以下は、天体写真(オリオン大星雲、M42)に対してサンプルプログラムを実行した結果です。

コード解説

以下のupdate関数は、トラックバーの位置に基づいてフィルタのパラメータを取得し、フィルタを適用します。この関数が呼び出されるたびにフィルタが更新され、画像が再表示されます。

def update(val):
    # トラックバーの位置に基づいてパラメータを取得
    d = cv.getTrackbarPos('d', 'Bilateral Filter')
    sigmaColor = cv.getTrackbarPos('sigmaColor', 'Bilateral Filter')
    sigmaSpace = cv.getTrackbarPos('sigmaSpace', 'Bilateral Filter')

    # フィルタを適用
    filtered = cv.fastNlMeansDenoisingColored(img, None, h, hForColor, templateWindowSize, searchWindowSize)

    # フィルタ処理後の画像を表示
    cv.imshow('Bilateral Filter', filtered)

以下で新しいウィンドウを作成し、3つのトラックバーを追加します。トラックバーはそれぞれdsigmaColorsigmaSpaceのパラメータを調整するためのものです。

# ウィンドウを作成
cv.namedWindow('Bilateral Filter')

# トラックバーを作成
cv.createTrackbar('d', 'Bilateral Filter', 9, 50, update)
cv.createTrackbar('sigmaColor', 'Bilateral Filter', 75, 200, update)
cv.createTrackbar('sigmaSpace', 'Bilateral Filter', 75, 200, update)

createTrackbarについても引数の役割を簡単に解説します。

cv.createTrackbar('h', 'Non-Local Means Filter', 10, 50, update)
パラメータ 説明
d ラックバーのラベル(名前)を指定します。このラベルはトラックバーの識別に使用されます。ここでは、hという名前が使われています。
10 トラックバーの初期位置(初期値)を指定します。
50 トラックバーの最大値を指定します。
update トラックバーが変更されたときに呼び出されるコールバック関数を指定します。ここでは、update関数が指定されています。この関数は、トラックバーの値が変更されるたびに実行され、フィルタのパラメータが更新されます。

トラックバーの位置を変更するたびにupdate関数が呼び出され、トラックバーの新しい位置に基づいてフィルタのパラメータが再計算され、画像に適用されます。
これにより、リアルタイムでhの値を変更しながらフィルタの効果を確認することができます。他のトラックバーについても同様です。

以下は、初期表示とメインループの部分です。最初にupdate関数が呼び出され、初期表示が行われます。その後、ユーザーがqキーを押すまでメインループが実行され続け、ループ内でキー入力を待機します。qキーが押されると、すべてのウィンドウが閉じられ、プログラムが終了します。

# 初期表示
update(0)

# ユーザーが 'q' キーを押すまで待機
while True:
    if cv.waitKey(1) & 0xFF == ord('q'):
        break

cv.destroyAllWindows()

関連ページ

【Python版OpenCV入門】画像処理の基礎〜応用例までサンプルコード付きで徹底解説
Python版OpenCVで画像処理プログラミングを行う方法を入門者向けにソースコード付きで解説するページです。
この記事を書いた人
西住技研

Python使用歴10年以上。研究、仕事、趣味でデータ分析や作業自動化などに活用してきたノウハウを情報発信しています。
詳しいプロフィールやお問合せはこちらのページまで。
YoutubeX(旧Twitter)でも情報発信中です!

西住技研をフォローする
OpenCV

コメント