OpenCVで ノイズ 除去 ― 画像の後処理編 ―

GAN&画像処理
ペイ
ペイ

NFT アート Dress Up Gorillaの仕上げの ノイズ 処理について過程を公開します。
地味で細かい作業ですが、このようなディテールにこだわることができなければアートとして意味がない、と考えています。(=神は細部に宿る・・・と信じてます)
また、Cycle GAN という技術は(学習画像の数、質にもよりますが) ノイズ が乗りやすく、今回紹介するような、後処理は必須となっております!

今回紹介する ノイズ 除去の画像処理は Python 環境があればわずか数行のコードで処理可能です。
ちなみに私はpython超初心者ですが、わずか30分ほどの作業量で画像の後処理ができちゃいました。

画像の後処理

ノイズ って?

そもそも ノイズ とは?
日本語で言うと、”雑音”のことです。

実際に、GANで生成ホヤホヤの画像を例に見てみましょう。

・・・だいぶ引き延ばして画像表示している、ということもありますが、全体的にガビガビしてる感じしませんか?

これこそがいわゆる ノイズ が乗った状態です。

ちなみに、↑の画像の制作過程はこちらの記事

画像の後処理の目的

ノイズ が乗った画像は見栄えが悪いため、 ノイズ を取り除いてあげる必要があります。

今回は Python の OpenCV を使って、 ノイズ を取り除いていきます。

↓公式ドキュメントはこちら

OpenCV: Image Filtering

平滑化処理( ノイズ 除去)

では、どうやって ノイズ を取り除くのか?
それはズバリ、画像をぼかすことで平滑化を行います。
ノイズ やエッジ(画素の急激な変化)をぼやかして、目立たなくします。

OpenCV では、この画像の”ぼかし方”にいろいろな種類があります。

実際に ノイズ 除去やってみた

OpenCV には4種類の 平滑化処理 が用意されています。

それぞれの処理について、下記の順で解説します。
① 簡単な特徴
② コード&パラメータ
③ 処理結果(Before & After)

どのフィルタをかけるとどんな結果が得られるのか?
という視覚的&直感的なイメージだけ持っていただけたらと思います。

平均 cv2.blur

① 簡単な特徴
最も一般的なフィルタです。「ぼかす」と聞いて一番想像できうるぼかし方と思っていただいてOKです。

カーネルサイズというパラメータで設定する領域内の画素を平均化することでぼかします。

②コード例

import cv2

#画像を指定
img = cv2.imread(".\\test_image.png")

#ぼかし処理
img_blur1 = cv2.blur(img, ksize=(10, 10))
img_blur2 = cv2.blur(img, ksize=(20, 20))
img_blur3 = cv2.blur(img, ksize=(30, 30))

#4つ並べた画像を保存
imgs = cv2.hconcat([img, img_blur1, img_blur2, img_blur3])
cv2.imwrite('.\\test_blur_out.png', imgs)
パラメータ説明
カーネルサイズ
(ksize)
画像の中の1画素の周囲どれだけの領域をぼかすか

③ 処理結果

ペイ
ペイ

original → カーネルサイズが大きくなるごとにぼけ具合が強くなってますね。

「ぼかす」のイメージそのままではないでしょうか?

Gaussianフィルタ cv2.GaussianBlur

① 簡単な特徴
元画像の特徴をより残しやすいぼかし処理です。

cv2.blurではカーネル内の画素を平均値という一定値で塗りつぶす、という特徴がありましたが、
ガウシアンフィルタでは、画素の中心から離れていくにつれて値が小さくなるという特徴があります。

②コード例

import cv2

#画像を指定
img = cv2.imread(".\\test_image.png")

#ぼかし処理
img_blur1 = cv2.GaussianBlur(img, ksize=(9, 9), sigmaX=10)
img_blur2 = cv2.GaussianBlur(img, ksize=(9, 9), sigmaX=20)
img_blur3 = cv2.GaussianBlur(img, ksize=(9, 9), sigmaX=30)

#4つ並べた画像を保存
imgs = cv2.hconcat([img, img_blur1, img_blur2, img_blur3])

cv2.imwrite('.\\test_blur_gau_out.png', imgs)
パラメータ説明
カーネルサイズ
(ksize)
画像の中の1画素の周囲どれだけの領域をぼかすか
シグマ
(sigmaX)
標準偏差
・値が小さいとき … カーネルの中心に強くぼかす
・値が大きいとき … カーネル全体を均一にぼかす

③ 処理結果

ペイ
ペイ

正直、平均処理(blur.cv)と違いがよくわからん・・・

medianフィルタ cv2.medianBlur

① 簡単な特徴
”ゴマ塩ノイズ”と呼ばれる、点々のノイズ除去に強い

②コード例

import cv2

#画像を指定
img = cv2.imread(".\\test_image2.png")

#ぼかし処理
img_blur1 = cv2.medianBlur(img,ksize=11)
img_blur2 = cv2.medianBlur(img,ksize=21)
img_blur3 = cv2.medianBlur(img,ksize=31)

#4つ並べた画像を保存
imgs = cv2.hconcat([img, img_blur1, img_blur2, img_blur3])

cv2.imwrite('.\\test_blur_med_out.png', imgs)
パラメータ説明
カーネルサイズ
(ksize)
画像の中の1画素の周囲どれだけの領域をぼかすか
medianBlurではカーネルサイズは1つのみ指定。(自動的にx,yは同じになる)

③ 処理結果
(今回、original画像はあえて点々のノイズを乗せてみました。)

ペイ
ペイ

きれいに ノイズ が消えました!
ただし、カーネルサイズを大きくしすぎると、エッジが死んでいくので注意が必要。

bilateralフィルタ cv2.bilateralFilter

① 簡単な特徴
エッジを残したまま、平滑化をする

②コード例

import cv2

#画像を指定
img = cv2.imread(".\\test_image.png")

#ぼかし処理
img_blur1 = cv2.bilateralFilter(img, d=11, sigmaColor=75, sigmaSpace=75)
img_blur2 = cv2.bilateralFilter(img, d=31, sigmaColor=75, sigmaSpace=75)
img_blur3 = cv2.bilateralFilter(img, d=31, sigmaColor=175, sigmaSpace=75)

#4つ並べた画像を保存
imgs = cv2.hconcat([img, img_blur1, img_blur2, img_blur3])

cv2.imwrite('.\\test_blur_bil_out.png', imgs)
パラメータ説明
d画素をぼかすために使われる領域。
(カーネルサイズみたいなもんかな?)
色の標準偏差
sigmaColor
値が大きくなるほど、より違う色も混合する
距離空間の標準偏差
sigmaSpace
ちょっと不明
(dが0以下のときのみ計算に使用されるとか・・・)

③ 処理結果

ペイ
ペイ

元画像の特徴を一番損なわずに色彩だけをぼかしてくれる感じになってます。
元がピクセルアートなので、このようなエッジを残したまま ノイズ 処理できるのはありがたいですね!

まとめ

☑ シンプルなぼかしなら cv2.blur

☑ 元画像の特徴を残しながらぼかすなら cv2.GaussianBlur

☑ ”ゴマ塩ノイズ”を消すなら cv2.medianBlur

☑ エッジを残しつつ、ぼかしたいなら cv2.bilateralFilter

ペイ
ペイ

用途に合わせてぼかし処理を使い分けましょう!
組み合わせて使うとさらにきれいな画像に仕上げることができます!

ちなみに私は、medianblurとbilateralFilterを併用してます。
(= ピクセルアート感を残したいからエッジを残したままぼかしたい)

コメント

タイトルとURLをコピーしました