【Python・OpenCV】画像のノイズを効果的に除去するには(cv2.fastNlMeansDenoising, cv2.fastNlMeansDenoisingColored)

※当サイトではアフィリエイト広告を利用しています

Python プログラミング 画像処理

【Python・OpenCV】画像のノイズを効果的に除去するには(cv2.fastNlMeansDenoising, cv2.fastNlMeansDenoisingColored)

はじめに

画像処理において、ノイズの除去は重要な前処理の一つです。
OpenCVには、効果的なノイズ除去アルゴリズムが実装されており、その中でも特に優れているのがcv2.fastNlMeansDenoising関数とcv2.fastNlMeansDenoisingColored関数です。
この記事では、この関数の使い方と特徴について詳しく解説します。

(広告) OpenCV関連書籍をAmazonで探す

ノイズ除去処理

cv2.fastNlMeansDenoising関数とcv2.fastNlMeansDenoisingColored関数が使用されるのは、次のような場面です。

  1. 写真の品質向上
    • デジタルカメラやスマートフォンで撮影した低光量環境下の写真
    • 高ISO感度で撮影された画像のノイズ除去
  2. 医療画像処理
    • MRIやCTスキャンなどの医療画像のノイズ除去
    • 画像診断の精度向上
  3. 監視カメラ映像の処理
    • 低解像度や低光量環境下での監視カメラ映像の品質向上
  4. 古い写真や映像の修復
    • スキャンした古い写真のノイズやグレイン除去
    • デジタル化された古いフィルム映像のクリーニング

また、cv2.fastNlMeansDenoising関数とcv2.fastNlMeansDenoisingColored関数は次のような特徴があります。

特徴

  • Non-Local Meansアルゴリズムにより、画像の構造を保持しながら効果的にノイズを除去
  • RGBチャンネルを考慮したノイズ除去が可能(cv2.fastNlMeansDenoisingColored関数のみ)
  • フィルタ強度や窓サイズを調整することで、様々なノイズレベルに対応可能
  • 画像のエッジや細かい構造を保持しながらノイズを除去
  • 高品質な結果を得られる一方で、他の単純なフィルタに比べて処理時間が長い

cv2.fastNlMeansDenoising関数

OpenCVに実装されているノイズ除去アルゴリズムの一つです。
この関数は、Non-Local Means Denoising(非局所平均法)アルゴリズムの高速バージョン(http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/)を実装しています。
主にグレースケール画像のノイズ除去に使用されます。

cv2.fastNlMeansDenoising関数の引数と戻り値は下の通りです。

cv2.fastNlMeansDenoising(入力画像[, dst[, h[, templateWindowSize[, searchWindowSize]]]])

引数

名称説明
入力画像(必須)グレースケールまたはカラーの入力画像データ。numpy.ndarrayオブジェクト。
dst(オプション)結果がこの変数に格納されます。指定しない場合は、入力画像と同じサイズ・型で新しい配列が作成されて結果が格納され、戻り値として取得できます。
h(オプション)フィルタリングの強さを決定するパラメータ(大きい値ほど強くノイズ除去される)
templateWindowSize(オプション)テンプレートパッチのサイズ(奇数、デフォルト:7)
searchWindowSize(オプション)各ピクセル周辺の検索窓サイズ(奇数、デフォルト:21)

ポイント

  1. 動作原理
    • 画像内の各ピクセルに対して、周辺の類似したパッチを探索します。
    • 類似度に基づいて重み付けを行い、これらのパッチの加重平均を計算します。
    • 上記により、ノイズを抑制しつつ、画像の構造や細部を保持します。
  2. 特徴
    • エッジや細部を保持しながら効果的にノイズを除去できます。
    • 通常のNon-Local Means Denoisingアルゴリズムよりも高速に動作します。
    • グレースケール画像に特化しています。
      カラー画像の場合はcv2.fastNlMeansDenoisingColored関数を使用)。
    • この関数は主にグレースケール画像用ですが、3チャンネルのカラー画像にも適用可能です(ただし、各チャンネルが独立して処理されます)。

戻り値

ノイズ除去が適用された画像データをnumpy.ndarrayオブジェクトで返します。

使い方

以下にサンプルコードを示します。

ノイズ除去を行うのは下の画像(左)にGIMPでフィルタのRGBノイズを適用した画像(右)を使用しました。

引用元
https://pixabay.com/ja/photos/小屋-木材-木製-ビーチ-8064061/

この画像にcv2.fastNlMeansDenoising関数を適用した結果が以下となります。
引数のh10, 15, 20と変化させています。
hの値が大きいほど、ノイズ除去の効果が強く得られていることが確認できます。
h=20でもエッジがしっかり保持されていますが、木材の並びに表れる壁の横線などが消えかかっていることが確認できます。
細部の表現は、hの値が大きいほど消されてしまうことがわかります。

フィルタリングの強さhは画像ごとに調整が必要ですね。

import cv2

# 画像の読み込み
image = cv2.imread("gray_noized_image.jpg")

# ノイズ除去の実行
denoised_image_h10 = cv2.fastNlMeansDenoising(image, None, h=10, templateWindowSize=5, searchWindowSize=21)
denoised_image_h15 = cv2.fastNlMeansDenoising(image, None, h=15, templateWindowSize=5, searchWindowSize=21)
denoised_image_h20 = cv2.fastNlMeansDenoising(image, None, h=20, templateWindowSize=5, searchWindowSize=21)

# 画像を保存する
cv2.imwrite("gray_denoized_h10.jpg", denoised_image_h10)
cv2.imwrite("gray_denoized_h15.jpg", denoised_image_h15)
cv2.imwrite("gray_denoized_h20.jpg", denoised_image_h20)

cv2.fastNlMeansDenoisingColored関数

cv2.fastNlMeansDenoisingColored関数はcv2.fastNlMeansDenoising関数のカラー画像に対応した関数です。
両関数とも、Non-Local Means(NLM)ノイズ除去アルゴリズムの高速実装版を基盤していることについては共通です。

cv2.fastNlMeansDenoisingColored関数の引数と戻り値は下の通りです。

cv2.fastNlMeansDenoisingColored(入力画像[, dst[, h[, hColor[, templateWindowSize[, searchWindowSize]]]]])

引数

名称説明
入力画像(必須)グレースケールまたはカラーの入力画像データ。numpy.ndarrayオブジェクト。
dst(オプション)結果がこの変数に格納されます。指定しない場合は、入力画像と同じサイズ・型で新しい配列が作成されて結果が格納され、戻り値として取得できます。
h(オプション)輝度チャンネルに対するフィルタ強度(大きい値ほど強くノイズ除去される)
hColor(オプション)色チャンネルに対するフィルタ強度(デフォルト:3)
templateWindowSize(オプション)テンプレートパッチのサイズ(奇数、デフォルト:7)
searchWindowSize(オプション)各ピクセル周辺の検索窓サイズ(奇数、デフォルト:21)

ポイント

cv2.fastNlMeansDenoising関数でもカラー画像の処理を行うことは出来ますが、cv2.fastNlMeansDenoisingColored関数を使うメリットとして、以下が挙げられます。

  • 各色チャンネル間の相関関係を維持しながらノイズ除去を行うため、色の歪みが少なくなります。
  • また、画像をYUV色空間に変換し、輝度(Y)と色彩(U, V)を分離して処理します。 人間の目は輝度の変化に敏感であるため、この分離処理により視覚的に自然な結果が得られやすくなります。
  • hColorパラメータにより、色チャンネルに対するフィルタ強度を個別に制御できます。
  • カラー画像特有の色ノイズ(例:高ISO撮影時のクロマノイズ)に効果的な結果が得られます。
  • カラー画像処理に特化した最適化が施されているため、単純に各チャンネルを個別処理するよりも効率的です。
  • 色情報を考慮することで、エッジや細部の保持がより効果的に行われ、特に色の境界がはっきりしている部分での性能が向上します。

cv2.fastNlMeansDenoisingColored関数を使用することで、カラー画像特有の課題に対応した、より高品質で自然なノイズ除去結果を得ることができます。cv2.fastNlMeansDenoising関数のカラー対応した拡張と最適化が施された関数と言えるのではないでしょうか。

戻り値

ノイズ除去が適用された画像データをnumpy.ndarrayオブジェクトで返します。

使い方

以下にサンプルコードを示します。

ノイズ除去を行うのは、筆者が高ISOで撮影に失敗した夜空の写真です。😅
かなりノイズが入って、ざらついている画像です。

この画像にcv2.fastNlMeansDenoisingColored関数を適用した結果が以下となります。
引数のh10, 15, 20に、hColor3, 7に変化させています。
の値が大きいほど、ノイズ除去の効果が強く得られていることが確認できます。
h=20では、小さな星が消えてしまいます。
赤っぽいノイズ、緑っぽいノイズが確認出来ますが、hColorの値を7に上げると赤と緑のノイズが除去されますが、他の部分が不自然になることは無いようです。

import cv2

# 画像の読み込み
image = cv2.imread("color_noized_image.jpg")

# ノイズ除去の実行
denoised_image_h10_hc3 = cv2.fastNlMeansDenoisingColored(image, None, h=10, hColor=3, templateWindowSize=5, searchWindowSize=21)
denoised_image_h15_hc3 = cv2.fastNlMeansDenoisingColored(image, None, h=15, hColor=3, templateWindowSize=5, searchWindowSize=21)
denoised_image_h20_hc3 = cv2.fastNlMeansDenoisingColored(image, None, h=20, hColor=3, templateWindowSize=5, searchWindowSize=21)
denoised_image_h10_hc7 = cv2.fastNlMeansDenoisingColored(image, None, h=10, hColor=7, templateWindowSize=5, searchWindowSize=21)
denoised_image_h15_hc7 = cv2.fastNlMeansDenoisingColored(image, None, h=15, hColor=7, templateWindowSize=5, searchWindowSize=21)
denoised_image_h20_hc7 = cv2.fastNlMeansDenoisingColored(image, None, h=20, hColor=7, templateWindowSize=5, searchWindowSize=21)

# 画像を保存する
cv2.imwrite("color_denoised_image_h10_hc3.jpg", denoised_image_h10_hc3)
cv2.imwrite("color_denoised_image_h15_hc3.jpg", denoised_image_h15_hc3)
cv2.imwrite("color_denoised_image_h20_hc3.jpg", denoised_image_h20_hc3)
cv2.imwrite("color_denoised_image_h10_hc7.jpg", denoised_image_h10_hc7)
cv2.imwrite("color_denoised_image_h15_hc7.jpg", denoised_image_h15_hc7)
cv2.imwrite("color_denoised_image_h20_hc7.jpg", denoised_image_h20_hc7)

おわりに

cv2.fastNlMeansDenoisingColored関数、cv2.fastNlMeansDenoising関数のどちらも、CPUでの処理時間はそれなりにかかってしまう印象ですが、GPU処理や並列処理を導入することで、処理速度を向上させることもできます。

バイラテラル フィルタに近い結果が得られますが、ノイズ除去に関しては、これらの関数を使う方が適しているかもしれません。
バイラテラル フィルタはこの記事で紹介しています。
また、両関数とも、使いこなすためには引数に設定する値の最適化が重要となりますので、試行錯誤が必要かもしれませんが、どちらも使い方や特徴はとても似ているので、使い分けは容易ではないかと思います。

ご質問や取り上げて欲しい内容などがありましたら、コメントをお願いします。
最後までご覧いただきありがとうございました。

参考リンク

■(広告)OpenCVの参考書としてどうぞ!■

-Python, プログラミング, 画像処理
-