画像のノイズ除去のために、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つは本当によくなる場合があって良いなと思いました。