OpenCVノイズ除去

投稿者: | 2020/05/05

画像のノイズ除去のために、OpenCVによるノイズ除去について調べました。
今の時代は自前の環境を作らずともColaboratoryなどを使ってすぐに動作確認できて本当に素晴らしいですね。

モルフォロジー変換

画像を拡大縮小して点々などを消すことができる

移動平均フィルター(平均値を取る)

周辺の画素の平均を取る。ぼやける。

メディアンフィルター(中央値フィルター)

周辺の画素を並べて真ん中を取る。

from matplotlib import pyplot as plt
import cv2 as cv

image_name = '/content/123456789.jpg'

# ファイルを読み込み
img = cv.imread(image_name)

# opencvとmatplotで色の並びが違うのでmatplot様に並べ替える
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

dst = cv.medianBlur(img,5)

fig = plt.figure(figsize=(10.0, 8.0))
plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(dst)
plt.show()

Non-Local Means Denoising

似た小領域の平均を取る

from matplotlib import pyplot as plt
import cv2 as cv

image_name = '/content/123456789.jpg'

# ファイルを読み込み
img = cv.imread(image_name)

# opencvとmatplotで色の並びが違うのでmatplot様に並べ替える
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# src : 
# dst : 
# h : フィルタの強さを決定するパラメータ.hの値が大きいとノイズをより消せますが,画像の詳細な部分も失ってしまいます(10であればOK).
# hForColorComponents : カラー画像用のフィルタの強さを決定するパラメータ(hと同様10はOK).
# templateWindowSize : テンプレートとなるウィンドウの大きさ.奇数でなければならない(7が推奨されている).
# searchWindowSize : 探索ウィンドウの大きさ.奇数でなければならない(21が推奨されている).
dst = cv.fastNlMeansDenoisingColored(img,None,10,10,7,21)
#cv.imwrite('result.jpg', dst)

# plot
fig = plt.figure(figsize=(10.0, 8.0))
plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(dst)
plt.show()

Inpainting

うーん、難しい。リンク先を参照。ものによっては結構よい結果を出せそう。

from matplotlib import pyplot as plt
import cv2 as cv

image_name = '/content/123456789.jpg'

# ファイルを読み込み
img = cv.imread(image_name)

# opencvとmatplotで色の並びが違うのでmatplot様に並べ替える
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)


# グレースケール画像を作成
gray_img = cv.cvtColor(img, cv.COLOR_RGB2GRAY);
#plt.imshow(gray_img, cmap='gray')

# マスクを作成
#ret,mask = cv.threshold(gray_img,127,255,cv.THRESH_BINARY)
ret,mask = cv.threshold(gray_img,127,255,cv.THRESH_BINARY_INV)
#ret,mask = cv.threshold(gray_img,127,255,cv.THRESH_TRUNC)
#ret,mask = cv.threshold(gray_img,127,255,cv.THRESH_TOZERO)
#ret,mask = cv.threshold(gray_img,127,255,cv.THRESH_TOZERO_INV)
#plt.imshow(mask, cmap='gray')


# src	Input 8-bit, 16-bit unsigned or 32-bit float 1-channel or 8-bit 3-channel image.
# inpaintMask	Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted.
# inpaintRadius	Radius of a circular neighborhood of each point inpainted that is considered by the algorithm.
# flags	Inpainting method that could be cv::INPAINT_NS or cv::INPAINT_TELEA
dst = cv.inpaint(img,mask,5,cv.INPAINT_TELEA)
#dst = cv.inpaint(img,mask,3,cv.INPAINT_NS)

# plot
fig = plt.figure(figsize=(10.0, 8.0))
plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(dst)
plt.show()

上3つはざっくりやりすぎて画像の品質が劣化しやすいです。
下2つは本当によくなる場合があって良いなと思いました。


コメントを残す

メールアドレスが公開されることはありません。