2014.12.27.
石立 喬
OpenCVとVisual C++による画像処理と認識(6)
----- いろいろな平滑化フィルタで画像を加工する -----
フィルタリングは、無用なノイズを除去したり、物体の輪郭を取り出したりして、画像認識の前処理に重要な役割を果たす。ここでは、OpenCVの関数を使って、いろいろな平滑化フィルタリングを試みる。
フィルタリングは、カーネルと呼ばれるマトリックスを用いるので、自作カーネルによるフィルタリングも紹介する。
フィルタリングとは
フィルタリング(filtering)とは、注目するピクセルの周辺(たとえば、3
x 3の範囲)を含む複数のピクセルに対して、それぞれの場所に応じて決められた個別の係数を乗じ、その和を取って(積和演算、convolution)目的とするピクセル値とするものであり、その係数の集まり(3
x 3のマトリックス状)を、カーネル(kernel)と呼ぶ。カーネルはフィルタやマスクと呼ばれる。
以上の説明は狭義のフィルタリングで、線形フィルタを使用する。実際には、積和演算を行った後に、非線形のしきい値処理を行ったり、積和演算を行わないで、中心値を求めたり、二値画像に対して、1か0かを判定するだけの場合もあり、これらは非線形フィルタである。これらを含めたものが広義のフィルタリングとなる。
フィルタのいろいろ
OpenCVの関数として用意されている広義のフィルタの主なものを目的別に分けると、
平滑化フィルタ ----- blur、GaussianBlur、medianBlur、bilateralFilter
鮮鋭化フィルタ ----- Laplacian
エッジ検出 -------- Sobel、Scharr、Canny
形態学的変換 ----- dilate、erode
があるので、まず平滑化フィルタについて紹介し、その他は次項に譲る。
平滑化フィルタの比較プログラム
図1のプログラムは下記から成っている。
1)原画像を、画像src_imageとして読み込んで表示する。
2)ゴマ塩ノイズを付加する。黒ノイズと白ノイズを、それぞれ1000個、乱数によって座標を与えて発生させる。ノイズを発生させない場合には、この部分をコメントアウトしておく。
3)いろいろなOpenCVの関数を使って平滑化を行い、表示する。
使用したOpenCV関数の説明
◎blur関数
原画像を平滑化するのに用いる。カーネルサイズ内のピクセルの平均を取るnormalized
box filterと同じである。原理的に単純で、処理速度が速い。
blur(原画像、結果画像、カーネルサイズ、アンカーポイント、周辺処理法);
のように引数を与えて使用する。カーネルサイズはSize(3, 3)などで、アンカーポイントはPoint(-1,
-1)がデフォルトで、周辺処理法もBORDER_DEFAULTがデフォルトのため、一般的には、
blur(原画像、結果画像、カーネルサイズ);
で良い。
アンカーポイントのPoint(-1, -1)は、カーネルの縦横共に中心を原画像の注目するピクセルに合わせて関和演算を行うことを意味し、周辺処理法の主要なものには、
BORDER_CONSTANT ------- 0
BORDER_REPLICATE ------- 1
BORDER_REFLECT --------- 2
BORDER_WRAP ------------ 3
BORDER_DEFAULT --------- 4
BORDER_REFLECT101 ------ 4
がある。デフォルトは、BORDER_REFLECT101と同じで、dcb | ABCD ---- WXYZ |
yxwのように、端部でピクセルを折り返す。 これを使っておけば、まず問題はない。
◎GaussianBlur関数
原画像を、Gaussian分布の係数を持つカーネルで平滑化する。同じカーネルサイズなら、blueよりも平滑化の程度は控えめで、自然なボケ味が得られる。シグマ値を設定することで、ボケ具合を調節できる。
GaussianBlur(原画像、結果画像、カーネルサイズ、シグマx、シグマy、周辺処理法);
のように引数を与えて使用する。カーネルサイズはSize(3, 3)などで与える。Size(0,
0)とすると、シグマ値から自動的にサイズが設定され、シグマ値を0にすると、逆に、カーネルサイズからシグマ値が決まる。シグマxはX方向の標準偏差で、シグマyを0(デフォルト)にしておくと、シグマyがシグマxと同じであることを意味する。周辺処理法はBORDER_DEFAULTがデフォルトのため、一般的には、
GaussianBlur(原画像、結果画像、カーネルサイズ、0);
で良い。
◎medianBlur関数
原画像を平滑化する効果があるが、特にゴマ塩(salt-and-pepper)ノイズを除去するのに優れている。
medianBlur(原画像、結果画像、カーネルサイズ)
のように引数を与えて使用する。カーネルサイズは縦横同じに決まっているので、単に3などint型を用いる。デフォルト値はない。
カーネルサイズの範囲内のピクセル値を調べて、そのmedian(中央値)を結果画像に出力する。白や黒の極端なノイズは、中央値になることは無く、無視されて結果的に除去される。線形的な演算ではない。
特にbilateralFilter関数について
bilateralFilter関数は、OpenCVに備わっている関数の中でも特に優れていて、特記しておく。基本的には、ピクセルの空間的な距離に依存するGaussianBlurであるが、ピクセルの色濃度的な距離も加味されるところに、bilareralの名称がある。すなわち、近傍ピクセルとの間で色濃度的に距離が離れていると(エッジ部分などのように)、カーネルの係数がぐっと下がり、平滑化を抑制する。
このことから、変化の激しくない部分には平滑化が適宜に行われ、エッジ部分はそのまま維持されるので特徴抽出の前処理用として優れている。
この関数は、
bilateralFilter(原画像、結果画像、-1、カラー空間のシグマ、座標空間のシグマ、周辺処理法);
のようにして使用する。-1は、座標空間のシグマで考慮する周辺ピクセルとの直径が決められることを意味し、一般的にはこれを使用する。
カラー空間のシグマ(輝度値) ------- これが大きいと、濃淡差の大きいエッジでないと保存効果がなくなる。
座標空間のシグマ(座標距離) ------ これが大きいと、エッジ以外でのボケ具合が強くなるが、時間がかかる。
周辺処理法は、BORDER_DEFAULTがデフォルトであり、記述の必要はない。
線形的な関和演算ではない。
原画像と結果画像とを同一にしてはいけない(inplace処理は不可)。
図1 いろいろなフィルタを比較するプログラム
図2に示す二種類の原画像に対してフィルタを行った結果を図3および図4に示す。medianBlurは、ゴマ塩ノイズに極めて有効で、完全に除去されている。blurやGaussianBlurでは、ゴマ塩ノイズを取り切れてなく、bilateralFilterは、急激な変化は残るために、ゴマ塩ノイズに対しては、全く無力である。

図2 原画像と、ゴマ塩ノイズを付加した原画像の表示
図3 ノイズのない原画像に対するフィルタ結果

図4 ノイズありの原画像に対するフィルタ結果
カーネルを自作しfilter2Dを使ったプログラム
OpenCVに関数として備わっているblurとGaussianBlurと同等の処理を、自作のカーネルとfilter2D関数を用いて作成したプログラムを図5に示す。
filter2D関数は、
filter2D(原画像、結果画像、-1、カーネル);
のようにして使用する。
-1は、原画像と結果画像のddepth(この場合はCV_8UC3)が同一であることを指定している。アンカーポイントのPoint(-1,
-1)、オフセットの0、周辺処理法のBORDER_DEFAULTはデフォルトのため省略してある。
図5 カーネルとfilter2Dを用いたプログラム
なお、これによって得られた結果は、図3と全く同じであったので、省略する。
結 論
平滑化フィルタは、原画像から、認識の邪魔になる情報を除去するのに用いる。blur関数は最も簡単で、実行速度は速い。GaussianBlurはボケ味がきれいで、ボケ具合をコントロールできるので多く用いられる。medianBlurは、ゴマ塩ノイズに威力を発揮する。bilateralFilterは、エッジを保存したまま平滑化ができるので、エッジ検出の前処理に向いている。
OpenCVに準備されている関数以外のフィルタリングも、カーネルを自作することで実現できる。
「Visual C++の勉強部屋」(目次)へ