メディアン・フィルタ1 : メディアン・フィルタの動作を理解する
FPGA(Nexys4 DDR)を使ったリアルタイムエッジ検出 - メモ置き場
では,カメラから取り込んだ画像の平滑化としてメディアン・フィルタを使っている.メディアン・フィルタの動作について説明する.
メディアン・フィルタの原理
メディアン・フィルタは画像の平滑化に使われるフィルタである.メディアンとは中央値の意味である.
注目している画素の周辺にある画素を取得し(例えば3×3のフィルタだと注目画素1個+周辺画素8個),注目画素の値を9個の値の中央値に置き換える操作を行う.
赤枠に入っている値は1, 1, 3, 3, 3, 4, 4, 5, 6なので,中央値の3がフィルタから出力される.
メディアン・フィルタは中央値を使っているため周辺画素の外れ値に左右されにくく,ごま塩ノイズに強いらしい.
ごま塩ノイズというのは下の画像のように,飛び飛びに画素の値が壊れてしまっているものを言うそう*1.
画像はいらすとや様からお借りしています*2.
メディアン・フィルタの動作
実際にメディアン・フィルタでごま塩ノイズがどれくらい削減できるのか確認してみた.確認にはOpenCVを使った.
元画像に対してノイズを与え,それをメディアン・フィルタで平滑化している.ノイズは0個,10000個,20000個,…,90000個与えたものを準備した.フィルタのサイズは3×3である.
結果を示す.
ノイズが30000個くらいならなんとか元の画像を復元できているといって良いのではないか.画像サイズは660×400だったので,全画素264,000個の約11%程度のノイズなら処理しきれるといったところだった.フィルタ中の画素9個のうち1個程度ならノイズに変わっても大丈夫と思えばそれっぽい結果ではある*3.
フィルタサイズを5×5と7×7に変更した結果も示す.
フィルタサイズが大きくなると,ノイズ数が増えても元画像を正しく復元できるようになる.しかし,トレードオフとして元画像のシャープさが失われてしまう.実際7×7の結果をみると,顔や服のラインが大分崩れてしまっていることがわかる.
もっとフィルタサイズを増やすと,下に示すように元の画像とはかけ離れたものが出力されてしまう.
ソースコード
実験で使ったコードを貼っておく.
import cv2 import numpy as np #画像読み込み gray = cv2.imread("input.jpg", 0) row,col = gray.shape kernel = 3 for i in range(11): num = i * 10000 noise = gray #ノイズを付加 for j in range(num): pos_x = np.random.randint(0, col-1) pos_y = np.random.randint(0, row-1) color = np.random.randint(0,255) noise[pos_y, pos_x] = color #メディアン・フィルタを適応.ノイズの画像と並べた画像を作成 med = cv2.medianBlur(noise, ksize=kernel) h_img = cv2.hconcat([noise, med]) cv2.putText(h_img, "noise %d ksize %d" %(num, kernel), (20,row-50),cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0,0,200), 2, cv2.LINE_AA) #画像を出力 outname = "img_" + str(num).zfill(7) + "ksize" + str(kernel) + ".jpg" cv2.imwrite(outname, h_img)
*1:ちなみに僕はこう言う状態を「じゃみじゃみ」と表現するが,これは方言らしい
*2:デーモンコアのイラスト | かわいいフリー素材集 いらすとや
*3:この考察だと,フィルタサイズが大きくなった時に処理できるノイズの数が減る(例えば5×5なら25個中1個など)ので間違っていると思う