rawpyの現像関数、postprocess関数の引数のmedian filter passesに関して確認します。
postprocessに関しての詳細はこちら。
正体としてはメディアンフィルタの適応回数を指定するオプションでした。このメディアンフィルタですが、単純にRGBそれぞれにメディアンフィルタを当てるわけではなく、少しだけ凝った処理をしてそうな気配です。
メディアンフィルタ
いわゆるノイズ除去を目的としたフィルタです。処理としては単純で、注目画素とその周りのウィンドウ(カーネル)の中の画素値をソートして、その中の中央値(平均値ではない)を出力する。というもの。
画素値を変更するわけではなく、画素値の入れ替えなので、例えばスパイク状のノイズが1画素ぽつんとある時など、ぼかすことなくそのノイズはなくなります。とはいえ見た目の印象はやはり眠くなりますけどね。
パラメータは、ウィンドウの大きさを指定するのが一般的で、ウィンドウが大きくなればなるほど大きなノイズも除去することができます。が眠くなります。OpenCVのメディアンフィルタも
median = cv2.medianBlur(img,3)
のようにウィンドウサイズを奇数で指定します。これで3×3の9画素の中央値を出してくれます。たぶん。
あまり凝った処理ではないです。個人的にはノイズ除去するのであれば、バイラテラルフィルタとかそっち系のフィルタの方が、ディテールを保持しながらノイズを取ってくれるので好みです。ちなみにバイラテラルフィルタに関してはこちらで以前考察したのでご参考まで。
median_filter_passes
rawpyではこのメディアンフィルタのウィンドウサイズではなく、適応回数を引数として指定するようです。ちょっと変わってます。処理時間を計測すると、回数を増やす毎に固定値で処理時間が延びて行ったので、間違いないと思います。
デフォルトは0回です。1回くらいしてもいいのではないかと思ってしまいます。いくらでも大きい値が入れられそうで、試しに20とか入れたらプログラムが返ってこなくなったので、頑張り続けそうです。
ウィンドウサイズはたぶん3です。たぶん。効果確認で検証します。
効果確認
回数による変化の確認
ただ効果確認をすると、少し思った通りにならなかったです。確かに値を増やせば、じょじょにノイズ量は減っていくのですが、効きが弱いです。
左上0回、右上1回、左下2回、右下3回を指定して現像した結果です。色変換(3×3の行列演算)はOFFにしています。またガンマはON(2.2乗)にしています。確かにノイズ取れていることが見て取れます。
img = raw.postprocess(half_size=True, demosaic_algorithm=rawpy.DemosaicAlgorithm.LINEAR, output_color=rawpy.ColorSpace.raw, median_filter_passes = 1 )
こんな感じで現像してみました。処理時間がかかってしょうがなかったので、half_size=Trueで実験しました。(Falseでも同傾向でした)
赤系の被写体だからなのか、RGBの色毎に比べてみるとノイズの取れ方が偏っているように見えます。
上記は同じ位置のRedの面です。Redはつるつるにノイズ除去されているのに対して、
Greenです。Greenの効きは弱いように見えます。BlueもGreenと同傾向です。色毎独立にフィルタを当てているわけではないかもしれません。
説明文にも明確に、
色のアーティファクトを取るため( to reduce color artifacts )
とあるので、何か別の色空間(Labとか)にした後に、色の面(Labであればab)にだけフィルタを当てているようです。
OpenCVとの比較
続いて、OpenCVの結果と比べてみます。コードとしては以下のように、通常のメディアンフィルタをかけたものと、Labに変換したのちにabにだけメディアンをかけたものを比べてみました。ウィンドウサイズは最小の3にしました。
import rawpy import cv2 raw = rawpy.imread(filename) img1 = raw.postprocess(half_size=True, demosaic_algorithm=rawpy.DemosaicAlgorithm.LINEAR, output_color=rawpy.ColorSpace.raw, median_filter_passes = 0 )[:,:,[2,1,0]] img2 = raw.postprocess(half_size=True, demosaic_algorithm=rawpy.DemosaicAlgorithm.LINEAR, output_color=rawpy.ColorSpace.raw, median_filter_passes = 1 )[:,:,[2,1,0]] rgb = cv2.medianBlur(img1,3) # rgbに対してメディアン lab = cv2.cvtColor(img1, cv2.COLOR_BGR2Lab) # Labへ変換 lab[:,:,1] = cv2.medianBlur(lab[:,:,1],3) # abにだけメディアン lab[:,:,2] = cv2.medianBlur(lab[:,:,2],3) lab = cv2.cvtColor(lab, cv2.COLOR_Lab2BGR) # rgbへ戻す
結果がこれです。左上がメディアン無し。右上がrawpyでメディアン1回。左下がOpenCVでRGBへメディアン。右下がOpenCVでLabのabへメディアン。
左下のRGBすべてにメディアンフィルタをかけたものが一番ノイズ除去量が多いです。つるつるです。に対してLabのab面にフィルタをかけたものは少しざらつきが残っています。が、色ノイズは取れています。雰囲気rawpyのそれと近い結果です。色毎に見てみます。
Redです。ノイズ除去効果は3ついずれも同傾向です。
Greenです。左下のRGBすべてに対してOpenCVでメディアンフィルタをかけたものが一番つるつるです。に対して右上のrawpyのそれと、右下のLabのab面にだけメディアンフィルタをかけたものは近い気がします。
rawpyの中でも、OpenCVの色変換と等価ではない、何かLabに類する色変換をして、色の面にだけ3×3のメディアンフィルタをかけている。とみてよさそうな気がします。輝度(明るさ)の面に対しては処理しない。というポリシーのようです。
まとめ
median filter passesで指定するパラメータは、色ノイズ除去を行うためのパラメータである。数字の意味は、現像後の画像に対するメディアンフィルタの適応回数である。その際ウィンドウサイズは3×3固定。
メディアンフィルタは、色に対して行われ、RGBを一度Lab等の輝度色差系の色空間へ変換したのち、色の面に対してのみ処理される。
だと予想しました。
コメント