外周画像の処理

平滑化フィルタやメディアンフィルタなどの注目画素の周辺画素を用いた画像フィルタ処理では、画像の外周部分が下図のように画像の外側を参照してしまうため、処理ができなくなります。

 

 

この外周部分を処理する方法はいくつかあるのですが、代表的な方法を紹介します。
以下、5×5サイズのカーネルを用いた場合の処理を例にとって紹介します。

 

■外周部分の輝度値を画像の外側にコピーして補間する方法

5×5サイズのカーネルの場合、画像の外側に2画素分、画像の輝度値を参照
してしまうので、この2画素分の輝度値を画像の外周部分の輝度値をコピーして
輝度値を参照します。

 

おそらく?この手法が一般的だと思います。

 

■外周部分を中心にして対称の位置にある輝度値を外側にコピーして補間する方法

例えば、カーネルが座標(-1、-2)の画素を参照する場合は座標(1、2)の画素の輝度値を参照するようにします。

 

 

他にも、単純に外周部分は処理をしないで黒(輝度値=0)でマスクしたり、カーネルが画像の外側を参照する場合にカーネルを形を変えて画像の外側を参照しないようにしたりする方法などもあります。

 

画像処理アルゴリズムへ戻る

 

画像の回転

画像を回転する場合、任意点周りの回転移動でも紹介したように回転行列を使って、例えば、画像の中心周りに画像を回転させると、下図のように回転後の画像が虫食い状態になってしまいます。

 

回転前の画像 回転後の画像

 

こうならないようにするためには、回転前の画像の座標を回転行列を使って回転後の座標を計算するのではなく、回転後の座標が回転前の画像のどの座標を参照しているのかを計算し、画像を変換します。

つまり、画素を置きに行くのではなく、拾いに行くようにします。

 

【回転前の画像を回転行列を使って変換】

 

【回転後の座標が回転前のどの座標を参照しているかを計算して変換】

 

実際の変換処理は以下のように行います。

 

回転前の画像の座標を(x,y)、回転後の画像の座標を(X,Y)、画像の中心座標を(Cx,Cy)とすると単純に画像の中心周りに座標を回転すると以下のような行列で表されます。

 

 

この行列を回転前の画像の座標(x、y)に関して解けばいいので、行列の式の両辺にそれぞれ逆行列をかければいいので、以下のような手順で行列を解いていきます。

 

これで、回転前の座標(x、y)に関して解くことができます。
でも、逆行列を解くのは面倒と思う事なかれ。
(+Cx,+Cy)の平行移動の逆行列は(-Cx、-Cy)方向への移動と同じ、+θ方向への回転の逆行列は-θ方向への回転と同じなので、

 

 

とすれば、逆行列を解くことなく回転後の座標(x、y)に関して座標を解くことができます。
このようにして画像の回転処理を行うと、このようになります。

 

回転前の画像 回転後の画像

 

でも、回転後の画像はなんかギザギザしてしまっていますが、これは回転前の画像の座標を計算するとほとんどの場合、画素の画素の間の座標となってしまいますが、上図の例ではこの座標を四捨五入して輝度値を参照しているためで、bilinearやbicubicなどの補間を使うと少しは滑らかな画像となります。

今回は画像の回転について紹介していますが、画像の拡大縮小についても同様の考え方で処理することができます。

 

画像処理アルゴリズムへ戻る

 

関連記事

アフィン変換(平行移動、拡大縮小、回転、スキュー行列)

任意点周りの回転移動(アフィン変換)

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

アフィン変換(平行移動、拡大縮小、回転、スキュー行列)

画像の拡大縮小、回転、平行移動などを行列を使って座標を変換する事をアフィン変換と呼びます。

X,Y座標の二次元データをアフィン変換するには、変換前の座標を(x, y)、変換後の座標を(x’,y’)とすると回転や拡大縮小用の2行2列の行列と、平行移動用に2行1列の行列を使って

$$\left(\begin{array}{c}x^{‘}\\ y^{‘}\end{array}\right)=
\left(\begin{array}{c}a & b\\ c & d\end{array}\right)
\left(\begin{array}{c}x\\ y\end{array}\right)
+ \left(\begin{array}{c}T_{x}\\ T_{y}\end{array}\right)$$

のように表現される場合もありますが、回転、拡大縮小、平行移動を1つの3x3の行列にまとめて

$$\left(\begin{array}{c}x^{‘}\\ y^{‘} \\ 1\end{array}\right)=
\left(\begin{array}{c}a & b & c\\ d & e & f\\ 0 & 0 & 1\end{array}\right)
\left(\begin{array}{c}x\\ y\\ 1\end{array}\right)$$

と3x3の行列で表現する場合もあります。

この表現を同次座標系と呼びます。

同次座標系では一見、3行目は無駄なようにも見えるのですが、この意味の無いような1行を追加する事で、平行移動も同じ行列の積で表現でき、逆行列を使う事で、アフィン変換後の座標からアフィン変換前の座標も簡単に求める事ができるようになります。

私は3行3列の行列を用いた同次座標系のアフィン変換しかしていない、というか断然おススメなので、同次座標系で説明したいと思います。

後半でアフィン変換の実用例を示しているので、その部分で、同次座標系の恩恵を感じてもらえると嬉しいです。

 

変換前の画像を以下のようにすると、

各種変換は以下の通りとなります。

 

拡大縮小

X軸方向の拡大率をSx、Y軸方向の拡大率をSyとすると拡大縮小のアフィン変換は

 

 

と表されます。

 

例)X軸方向に2倍

 

例)Y軸方向に2倍

 

例)X軸、Y軸方向に2倍

 

例)Y軸方向に-1倍

このように、ある軸(上記の例ではX軸)に対して反転する処理の事を鏡映と呼びます。

 

平行移動

X軸方向にTx、Y軸方向にTyだけ移動するアフィン変換は

 

 

のように表されます。

 

 

回転

原点を中心に反時計回りにθ°回転する時のアフィン変換は

 

 

のように表されます。

 

 

スキュー(せん断)

四角形の画像を平行四辺形に変形する処理をスキューまたはせん断といいます。
このアフィン変換は

 

 

アフィン変換の実用方法

画像処理で使われるアフィン変換は、下図のようにピクチャボックスなどの左上が原点[座標が(0, 0)]で右方向が+X、下方向が+Y、時計周りが+θ方向となる場合が多いかと思います。

また、平行移動、拡大縮小、回転などの行列を紹介しましたが、これらの行列を1回だけで処理する事はまれで、それぞれの行列を組み合わせてアフィン変換を行います。
さらに、拡大縮小、回転、スキューのアフィン変換行列は、あくまでも原点を基点として、変換される事に注意が必要です。

例えば、画像が原点の位置に無い場合、画像をX,Y方向に2倍の大きさにしようとしたとき、単に拡大縮小のアフィン変換行列で座標を計算すると、表示位置も2倍、原点の位置から離れた位置に移動します。

これらの事を踏まえ、画像を幅方向に2倍、高さ方向に3倍し、画像を反時計方向に90°回転、さらに、画像の左上の座標が(50, 50)から(30,180)へ移動するアフィン変換を例題にとって考えたいと思います。

この変換は、一発で変換するアフィン変換行列を考えるのではなく、平行移動拡大縮小回転に分けて、アフィン変換の順番を考えます。


拡大縮小と回転が原点を基点とするため、画像を原点の位置へ移動するため、x方向に-50、y方向に-50の平行移動します。

平行移動のアフィン変換行列は

$$\begin{pmatrix} 1 & 0 & -50 \\ 0 & 1 & -50 \\ 0 & 0 & 1 \end{pmatrix}$$


拡大縮小か回転のどちらからでも構いませんが、x方向に2倍、y方向に3倍の拡大縮小を行います。

拡大縮小のアフィン変換行列は

$$\begin{pmatrix} 2 & 0 & 0 \\ 0 & 3 & 0 \\ 0 & 0 & 1 \end{pmatrix}$$


反時計周りに90°回転(ー90°回転)を行います。

回転のアフィン変換行列は

$$\begin{pmatrix} cos(-90) & -sin(-90) & 0 \\ sin(-90) & cos(-90) & 0 \\ 0 & 0 & 1 \end{pmatrix}$$


最後に目的の位置へ移動するのに、x方向に+30、y方向に+180の平行移動します。

平行移動のアフィン変換行列は

$$\begin{pmatrix} 1 & 0 & 30 \\ 0 & 1 & 180 \\ 0 & 0 & 1 \end{pmatrix}$$


このようにアフィン変換を平行移動、拡大縮小、回転に分解して、変換の手順を考える事が大事です。
今回の場合は

変換前 → 平行移動 → 拡大縮小 → 回転 → 平行移動 → 変換後

としています。

画像に対してアフィン変換を行う場合、考え方としては、平行移動や拡大縮小などに分解して考えますが、画像データを毎回変換するのではなく、アフィン変換行列をまとめて計算し、一発でアフィン変換処理を行います。

具体的には、今回のアフィン変換処理を行列で表すと

$$\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 1 & 0 & 30 \\ 0 & 1 & 180 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} cos(-90) & -sin(-90) & 0 \\ sin(-90) & cos(-90) & 0 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} 2 & 0 & 0 \\ 0 & 3 & 0 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} 1 & 0 & -50 \\ 0 & 1 & -50 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$

行列部分をまとめて計算し

$$\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$

となり、アフィン変換行列を一発で処理する事ができます。

さらに、変換後の座標(x’, y’)から、変換前の座標(x, y)を求める場合があるのですが、その時は、行列の左側からアフィン変換行列の逆行列を掛けて、

$$\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}^{ -1 }\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}^{ -1 }\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$

$$\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}^{ -1 }\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}$$

$$\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & -0.5 & 140 \\ 0.333 & 0 & 40 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}$$

として、変換前の座標を求める事ができます。

まとめ

  • アフィン変換は平行移動、拡大縮小、回転、スキューに分けて、変換の順番を考える
  • 実際のアフィン変換は、アフィン変換行列をまとめて計算し、一発で処理を行う
  • 変換前の座標は逆行列を使うと、求めることができる

この順番の考え方は、ほとんどの場合、画像を原点へ平行移動し、拡大縮小、回転を行ってから、目的の位置へ移動すると、アフィン変換行列が求まりますが、他にも、特定の点を基準に拡大縮小や回転を行う場合は、その点を原点へ移動すればアフィン変換行列が求まります。

(参考)

 

注意点

アフィン変換では任意の3×3(2×3)の行列で表す事ができるので、任意形状に変換できそうにも思えるのですが、四角形が平行四辺形にまでは変形できるものの、台形には変形できないのでご注意願います。
この台形に変形できる処理は射影変換(ホモグラフィ)と呼びます。

アフィン変換は今回の説明のように、画像を移動、変形させるための手法として説明されますが、もう少し汎用的に座標変換として捉えると応用範囲が広がります。

例えば、データのグラフを表示する時に、横方向、縦方向に拡大/縮小した時に、表示するデータの範囲を求める場合などに応用すると、少し便利です。

 

画像処理アルゴリズムへ戻る

 

関連記事

実際にOpenCVを使って行うアフィン変換については、こちらのページ↓にまとめました。

【OpenCV-Python】アフィン変換(同次座標系を使用)

 

マイクロソフトの.NETやDirectXで扱うアフィン変換行列は、行と列が逆になり、行列を掛ける順番も逆(右側から掛ける)になります。
この仕様については、下記ページ↓にまとめました。

【C#.NET】マイクロソフト仕様のアフィン変換

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

画像を拡大や回転する場合など、画像の画素と画素の間の輝度値を参照する必要が出てきますが、その参照方法を紹介します。
この画素を画素の間を参照する事を一般に補間内挿(Interpolation)と言います。

 

最近傍補間(ニアレストネイバー Nearest neighbor)

Nearest neighborをそのまま訳すと、最も近いご近所、という事で参照する位置に最も近い位置にある画素の輝度値を参照します。

 

 

求める画素間の座標が(x,y)の位置の輝度値を Dst(x,y) とし、もともとの画像の輝度値をSrc(i,j) とすると

 

 

で表されます。(ただし、[  ] は小数部分の切り捨てを表します。)
つまるとこ、座標を四捨五入し、その画素の輝度値を参照します。

 

双一次補間(バイリニア補間 Bilinear)

バイリニア補間では求める位置(x,y)の周辺の2×2画素(4画素)を使って、輝度値を直線的に補間して、輝度値を求めます。

 

直線的に補間する方法は、たとえば下図のようにX座標が180と181の2点間の180.8の位置の輝度値を求めるのは、2点の位置の輝度値の比から簡単に求まります。

 

 

この処理を手前の2点間、奥の2点間についてX軸方向に補間処理を行い、さらに補間した2点の輝度値を用いて、さらにY軸方向に補間処理することで、目的の輝度値を求めます。
(Y軸方向から先に処理を行っても結果は同じです。)

 

ちなみに、このBilinearの接頭語のbi-ですが、『二つの、双方向』というような意味があるそうです。
ということで、双方向からリニア(直線的)に補間したのが、このBilinearで、次に出てくるBicubicは双方向から三次関数で補間したのが、Bicubicです。

 

 

この補間処理を式で表すと、

 

 

となります。

 

双三次補間(バイキュビック補間 Bicubic)

バイキュービック補間では求める位置(x,y)の周辺の4×4画素(16画素)を使って、輝度値を三次式で補間して輝度値を求めます。

 

 

この変換を式で書くと

 

 

となります。

 

ただし、Src(i,j)は求める座標(x,y)の周辺の輝度値を表し、下図のような配置とします。

 

 

また、1、X2、X3、X4、Y1、Y2、Y3、Y4 は求める位置から参照する画素までの距離を表し、

 

 

と定義します。
関数h(t)はsinc関数(sinc(t) = sin(πt)/πt) をテイラー展開により三次の項まで近似した関数で

 

 

だそうで...(詳細は良く分かってません。)
の値には-1前後がよく用いられます。

 

まとめ

各補間方法を使って、画像を拡大表示すると以下のようになります。

 

【元の画像】

 

赤い四角の部分を拡大表示します。

 

【Nearest neighbor】

 

【Bilinear】

 

【Bicubic】

 

これらの画像を見ても分かるようにNearest neighbor⇒Bilinear⇒Bicubicの順でギザギザなのがなめらかに拡大表示されます。

 

この変換を1次元的に輝度値のグラフで見てみると

 

 

となります。
ここで注意しないといけないのが、Bicubic補間がおおむね滑らかに輝度値を補間することが
できますが、最後のグラフを見ても分かるように、輝度値がオーバーシュート(アンダーシュート)ぎみ
になる場合があります。その場合は補間の式の  の値を -0.2 程度のよりに近い値に
すると回避することができます。

 

画像処理アルゴリズムへ戻る

 

円形度

輪郭追跡を行うと周囲長を求めることができますが、この周囲長を用いた代表的な特徴量の円形度を紹介します。

 

円形度とは円らしさを表す値で値が1となる時、もっとも円に近くなります。
定義は面積(画素数)をS周囲長Lとすると、

 

円形度 = 4πS/L2

 

となります。

 

【円形度の例】

面積S = 96
周囲長L = 34.627円形度 = 1.006
面積S = 87
周囲長L = 33.456円形度 = 0.977

なぜそうなるのか?理屈は簡単で、
円の半径とすると、円の面積Sπr周囲長L2πrより、

 

円形度 = 4πS / L2 = 4π(πr2) / (2πr)2 = 1

 

となり、円形度4πS/L2に近いときもっとも円らしいということになります。

 

画像処理アルゴリズムへ戻る

関連記事

【OpenCV-Python】円形度

輪郭追跡処理アルゴリズム

二値化された画像において、各連結部分の境界部分を求める事を輪郭追跡といいます。
この輪郭追跡を行う事で周囲長や連結領域の高さなどを求めることが出来ます。

 

以下、この輪郭追跡の処理アルゴリズムを紹介します。

 

まず、左上からラスタスキャンを行い、白の部分を見つけます。

 

 

最初の白の部分(上図の赤丸の部分)をスタート地点として、反時計回りに輪郭の部分を検出します。
最初の白の部分は左上からラスタスキャンしたため、スタート地点の右上、上、左上、左には白の部分が無い事が確定しているので、最初に左下の部分から反時計回りに白の部分を検索し、白の部分が見つかったら次の輪郭へ検索を続けます。
最後にスタート地点に戻ったら処理は終了です。

 

この時、輪郭の向きを下図のように定義しておくと、

 

最初の図の輪郭は

 

0→0→1→0→2→3→4→3→2→5→5→6→4→0→6→5

 

の順で変化しています。(この番号はチェインコードといいます。)
ここにちょっとした規則があります。
例えば、の次に5、1の次に6、・・・などは絶対に来ません。(なぜかは、ちょっと考えると分かります。)
一般的に表現すると、
一つ前の輪郭の向きから時計回りに3つ分の向きには輪郭が存在しない。
という事になります。
この性質を利用して、輪郭を検索するときは、
一つ前の輪郭の向きの値をVold
輪郭の検索を開始する向きの値を Vnew
とすると、
Vnew = (Vold + 6) % 8; (%は8で割った時の余りの計算)
となるVnew の向きから輪郭を検索すれば効率的に輪郭を検索することが可能となります。

 

また、輪郭の周囲長を求める時、縦、横方向の輪郭は長さ、斜め方向の輪郭は√2 として
長さを足していくと、周囲長が求まります。

 

そして、ここからがあまり書かれていない注意点!
スタート地点の白の画素のパターンが以下のパターンとなる場合、スタート地点を2回通る事になるので、ご注意下さい。

※グレーの部分は白でも黒でもよい部分

 

画像処理アルゴリズムへ戻る

 

ラベリング

二値化画像処理された画像において、白の部分(または黒の部分)が連続した画素に同じ番号を割り振る処理を
ラベリングと言います。

 

通常、同じ番号ごとの面積(画素数)や幅、高さなどの特徴量を求めて欠陥検査や分類処理などに用いられます。

 

ラベリングには、二値化された画像の縦、横方向に連続している部分を同じラベルにする4連結と、
縦、横、斜め方向に連続している部分を同じラベルにする8連結との2種類の処理があります。
(4近傍、8近傍という場合もあります。)

【二値化画像】
【4連結】 【8連結】

以下、8連結の場合において、ラベリング処理アルゴリズムを紹介します。

 

まず、画像全ての画素のラベル番号を0(ゼロ)で初期化しておき、ラベリングで番号を割り付けるための
ラベリング番号のルックアップテーブルを用意しておきます。(テーブルの使い方の詳細は後ほど)

 

そして、画像の左上からラスタスキャンを行い、画素の色がの位置を検索します。

 

白の画素の左上、上、右上、左の画素のラベル番号を参照し、全て0(ゼロ)の場合は、最後に割り振った番号+1のラベル番号を割り振ります。
もし、参照した画素のラベル番号が複数存在した場合は、最小の番号を割り振ります。

 

最初に番号を割り振った様子↓

 

この処理を左上からラスタスキャンして続けていきます。

 

新しい番号が割り振られるとき↓

 

新しい番号が割り振られるとき↓ その2

 

参照した画素のラベル番号が複数存在した場合、最小の番号を割り振ります。
このとき、用いなかったラベル番号(下図の例では3)のルックアップテーブルの番号を最小の番号に書き換えます。

 

同様に、処理を続けていきます↓

 

全ての白の画素に番号が割り振れれた様子↓

 

ただし、よ~く見ると、ラベル番号の2や3など、連続していない部分が存在している事に気がつきます。
そこで、ルックアップテーブルの出番です。

 

処理の途中でルックアップテーブルの番号を変更した番号を
2→1、3→1、6→5
に変更すると、連続した領域は同じ番号になります。

 

このまま番号を変更しても良いのですが、ラベル番号が虫食いになるのも気持ちが悪いので、以下のようにルックアップテーブルの番号を詰め直してから、ルックアップテーブルを参照し、全画素のラベル番号を修正すると、以下のようになります。

 

基本的なアルゴリズムは上記、紹介したアルゴリズムで良いのですが、ラベリング処理を行う画像のパターンによってはうまくラベル番号が割り振られない場合があります。
そこは、何とかして(ちょっと説明が難しい部分)うまく割り振られるようにチャレンジしてみて下さい。

 

参考までに、ラベリング処理をすると失敗しやすい特徴的な画像を添付しておきます。↓

◆Level.1

 

◆Level.2

 

◆Level.Max!?

 

ラベリング処理のアルゴリズムには、この手法の他にも輪郭線を追跡し、閉じた領域を1つのラベルとする手法や、ランレングス的に求める方法もあります。

 

画像処理アルゴリズムへ戻る

 

細線化

二値化された画像において、線の中心1画素分だけを残すように線を細くする処理を細線化といいます。細線化のアルゴリズムにはHilditch、田村の方法、Zhang Suenなど、いろいろあるのですが、ここでは田村の方法について説明します。
細線化は黒の線を細くする場合と白の線を細くする場合が考えられますが、以下では白の線を細くするのを前提として説明しますので、黒の線を細くする場合は白と黒を読み替えて下さい。

 

細線化処理前 細線化処理後

 

ざっくり言うと、収縮処理をすると線幅が細くなりますが、線の長さが短くなったり、細い線は消えてしまったりするので、線の端点や交点、線幅が1となった画素などを除去しないように条件を付けながら収縮処理を行います。

 

処理をフローチャートを以下に示します。

 

 

画像全体にラスタスキャンを行い、注目画素の3×3画素の並びがパターン1に該当する場合は中心の画素を除去(白から黒に変える)します。ただし、除去しないパターンに該当する場合は除去を行いません。

パターン1に該当する画素が1画素も無ければその時点で終了です。

次にパターン1の時と同様に3×3画素の並びがパターン2に該当する場合は中心の画素を除去(白から黒に変える)します。ただし、除去しないパターンに該当する場合は除去を行いません。

パターン2に該当する画素が1画素も無ければその時点で終了です。そうでない場合はパターン1の処理に戻り、除去する画素がなくなるまでパターン1、パターン2の除去処理を繰り返します。

 

 

 

画像処理アルゴリズムへ戻る

 

膨張・収縮・オープニング・クロージング

膨張・収縮処理では一般的に二値化された白黒の画像に対して処理が行われ、

注目画素の周辺に1画素でも白い画素があれば白に置き換える処理を膨張(Dilation)
逆に周辺に1画素でも黒い画素があれば黒に置き換える処理を収縮(Erosion)といいます。

 

【元画像】

 

【膨張処理】

 

【収縮処理】

二値化された画像ではなく、グレー画像に対して処理を行う場合は、膨張の場合、注目画素の近傍の最大輝度値を注目画素の輝度値に置き換えます。
収縮の場合は最小輝度値に置き換えることでグレー画像に対して処理を行います。
この処理を二値化画像と区別するために、それぞれ最大値フィルタ最小値フィルタと呼ぶ場合もあります。

 

【処理例】

元画像 膨張 膨張
膨張 収縮 収縮
収縮 収縮 収縮
収縮 膨張 膨張
膨張 連続処理

膨張・収縮処理は単独で処理を行う事はまれで、膨張・収縮を繰り返し処理を行う場合が多くあります。
とくに、同じ回数分だけ膨張して収縮する処理をクロージング(Closing)

同じ回数分だけ収縮して膨張する処理をオープニング(Opening)とよびます。

 

元画像 クロージング
元画像 オープニング

 

この処理例を見てもわかるように、オープニング、クロージング処理では小さいパターン細いパターンの除去を行います。

 

さらに、クロージングした画像から元画像を差し引いた処理をブラックハット(Black-Hat)
元画像からオープニングした画像を差し引いた処理をトップハット(Top-Hat)といいます。

 

元画像 ブラックハット
元画像 トップハット

 

これらの処理を見ても分かるように、膨張・収縮処理を用いることで、欠け、断線、ホコリやゴミといった欠陥の検査や、細い線状のパターンの文字や線などの抽出への応用が考えられます。

 

画像処理アルゴリズムへ戻る

 

アンシャープマスキング(鮮鋭化フィルタ)

アンシャープマスキング【unsharp masking】とは、画像のボヤけた輪郭を強調するフィルタ処理です。

アンシャープマスキング処理前 アンシャープマスキング処理後

 

【処理アルゴリズム】

元画像データ
元画像データの平滑化処理を行い、元画像から平滑化データを差し引きます。
差し引いた分を元画像に上乗せします

 

この処理により、平滑化処理でボヤけてしまう分だけ、逆に輪郭をくっきりさせる事ができます。

 

この処理をカーネルで表現すると

となります。
kは任意レートで、値が大きいほど、輪郭が鮮明になる効果が高くなります。
(後半の元画像から平滑化画像を引いている部分の処理はラプラシアンフィルタと呼ばれます。)

 

今回は3×3のマスクサイズを例にとって紹介しましたが、マスクサイズを大きくするとマスクサイズよりも小さなパターンを強調する効果を得る事もできます。

 

 

画像処理アルゴリズムへ戻る

 

エッジ抽出(Sobel,Prewittなど)

下図のように画像の輪郭(エッジ)を抽出する方法を紹介します。

エッジ抽出前 エッジ抽出後

上図はソーベルフィルタの例です。

 

微分フィルタ

画像の輝度値に対して、隣り合う画素の輝度差が大きいほど、画像のエッジだと考えることができ、
画像の輝度値データ 画像輝度値データに対して

 

横方向の差分(偏微分)以下のカーネルで求めることができる。

0 0 0
0 -1 1
0 0 0

 

縦方向の差分(偏微分)下のは以下のカーネルで求めることができる。

0 1 0
0 -1 0
0 0 0

または

0 0 0
0 -1 0
0 1 0

※画像データの並びがボトムアップかボトムダウンかにより使い分けます。

 

このとき、エッジの強さは

 

エッジの傾きは

として求めることができる。

 

プリューウィットフィルタ(Prewitt filter)

微分フィルタではノイズに弱いため、横方向(または縦方向)のエッジを計算してから
縦方向(または横方向)に平均化処理を行う手法です。カーネルには以下とおりです。

 

横方向の差分

-1 0 1
-1 0 1
-1 0 1

 

縦方向の差分

1 1 1
0 0 0
-1 -1 -1

または

-1 -1 -1
0 0 0
1 1 1

 

ソーベルフィルタ(Sobel filter)

プリューウィットフィルタではノイズを除去するのに平滑化処理を行っていましたが、ガウシアン平滑化処理を行ったのがソーベルフィルタとなります。カーネルには以下とおりです。

 

横方向の差分

-1 0 1
-2 0 2
-1 0 1

 

縦方向の差分

1 2 1
0 0 0
-1 -2 -1

または

-1 -2 -1
0 0 0
1 2 1

 

画像処理アルゴリズムへ戻る

 

メディアンフィルタ

平滑化フィルタでは注目画素の周辺画素の輝度値を平均し、ノイズを除去していましたが、画像の輪郭もボケてしまう欠点がありました。それに対し、メディアンフィルタでは周辺輝度値の大きさを順に並べ、メディアン(中央値)を注目画素に置き換えることでノイズを除去します。
特に周辺画素の輝度値よりも大きく異なるノイズ(ゴマ塩ノイズとかスパイクノイズという)を除去するのに効果を発揮します。

 

メディアンフィルタ処理前 メディアンフィルタ処理後

輝度値の3D表示

輝度値の3D表示

 

処理の詳細


 

注目画素(画像中央の輝度値165の部分)周辺の輝度値を取得します。
61、96、41、57、165、34、24、30、31

 

この輝度値を順番に並べます。

 

24、30、31、34、41、57、61、96、165

 

並べた輝度値のメディアン(中央値)の41で輝度値165を置き換えます。

この処理を全画素について行うと、ノイズを除去することができます。

 

 

ただし、平滑化処理に比べ、処理が重い...

 

もう少し具体例でいうとこんな感じ

【メディアン処理前】

 

【メディアン処理後】


画像処理アルゴリズムへ戻る

 

ガウシアンフィルタの処理アルゴリズムとその効果

移動平均フィルタでは注目画素周辺の輝度値を単に平均していましが、一般的な画像では 注目画素に近い画素の輝度値は注目画素の輝度値と近い場合が多いですが、注目画素から遠くなればなるほど、注目画素の輝度値とは差が大きくなる場合が多くなります。
この事を考慮し、注目画素に近いほど、平均値を計算するときの重みを大きくし、遠くなるほど重みを小さくなるようにガウス分布の関数

を用いてレートを計算しているのがガウシアンフィルタです。
σの値が小さいほど平滑化の効果は小さくなり、大きいほど効果が大きくなりますが、
よく以下のカーネルが用いられます。

 

3×3の場合

 

5×5の場合

 

ガウシアンフィルタにはローパスフィルタと同様の効果があるそうです。

ということで、フィルタ処理した画像をフーリエ変換し、確かめてみました。

 

オリジナル(処理前)の画像はこちら↓

オリジナル画像 二次元フーリエ変換画像

 

上記の画像にノイズ除去系のガウシアンフィルタ、移動平均フィルタ、メディアンフィルタの
処理を行い、二次元フーリエ変換を行い確認してみました。

 

上記画像に5×5のガウシアンフィルタ処理を行うと

5×5のガウシアンフィルタ処理 二次元フーリエ変換画像

 

5×5の移動平均処理を行うと

5×5の移動平均処理 二次元フーリエ変換画像

 

5×5のメディアンフィルタ処理を行うと

5×5のメディアンフィルタ処理 二次元フーリエ変換画像

 

確かに処理結果を見てみると、ガウシアンフィルタが最も高周波成分を除去できているように
思います。

 

なぜ、そうなるのか?
本には数式においても、この効果が証明できるような事が書いてありましたが、ちょっと難しいので、
カーネルの値について見てみたいと思います。

 

そもそも、ある特定の周期の成分を消すためには、どうすれば良いか?というと、
周期の半分の離れた2点のデータを平均していけば、その周波数の成分を消す事が出来ます。

 

 

ここで、画像で表すことのできる最も高い周波数は

 

 

となる2画素周期のパターンで、このパターンを消すためには、隣り合う2画素の輝度値を
平均すると、画像データから最も高周波の成分を除去する事が出来ます。
しかし、隣り合う2画素の平均の結果は、画素間の位置の輝度値を示してしまうので、
この平均のさらに平均値を取ります。

 

連続する5つの輝度値の値をI-2~I2とすると、平均した値の平均値は

 

となり、なんとこの結果が3×3のガウシアンフィルタの横方向(縦方向)の係数と等しくなります。
さらに、平均の平均を取ると、5×5のガウシアンフィルタの係数と同じ。
7×7のガウシアンフィルタまで確認してみましたが、この平均の平均で表すことが出来るようです。

 

という訳で、ガウシアンフィルタの式

 

 

で表される係数なら何でも良いと思いつつも、

 

 

の係数が良く使われるのかも?しれませんね。

 

さらにこの係数、半分の半分で求めるのは、ちょっと面倒。
これがまた都合よく、(a+b)nの式を展開したときの係数に使われる
パスカルの三角形
の値

 

 

と一次元のガウシアンフィルタの係数と等しくなります。(少なくとも7×7ぐらいまでは)
これを以下のように二次元的に掛け合わせて、係数の合計で割ればガウシアンフィルタの係数となります。
例えば7×7のガウシアンフィルタの係数では下図のようになります。

 

 

この値を係数の合計(=4096)で割ればガウシアンフィルタの係数の出来上がり!!!
(このときσの値は約1.3となります。)

 

画像処理アルゴリズムへ戻る

 

平滑化(移動平均)フィルタ

平滑化フィルタは読んで字のごとく、画像の輝度値を平らに滑らかにするための手法です。
画像中のノイズを除去するために用いられます。

平滑化処理前 平滑化処理後

移動平均フィルタ(別名:平均化フィルタ、単に平滑化フィルタともいう)では、注目画素のその周辺の輝度値を用いて、

輝度値を平均し、処理後画像の輝度値とする手法です。

例えば、注目画素とその周辺の輝度値に以下のようなレートを掛け合わせて輝度値を求めます。

この3×3のレートの組合せの事をカーネル、オペレータ、マスクなどと言います。

とくに3×3である必要はなく、5×5の場合では

となります。

ただし、全てのレートを足し合わせてになるように調整して下さい。

 

画像処理アルゴリズムへ戻る

 

関連記事

フィルタ処理の高速化アルゴリズム(重複した計算を行わない)

判別分析法(大津の二値化)

判別分析法【discriminant analysis method】は大津の二値化とも言われ、分離度(separation metrics)

という値が最大となるしきい値を求め、自動的に二値化を行う手法です。

 

分離度はクラス間分散(between-class variance)とクラス内分散(within-class variance)
との比で求める事ができ、以下の様に求めます。

しきい値  で二値化したとき、しきい値よりも輝度値が小さい側(黒クラス)の画素数をω1
平均をm1、分散をσ1、輝度値が大きい側(白クラス)の画素数を画素数をω2、平均をm2
分散をσ2、画像全体の画素数をωt、平均をmt、分散をσtとしたときクラス内分散σw2

 

 

クラス間分散σb2

 

としてあらわす事ができる。

 

ここで、全分散(total variance)σt

 

としてあらわす事ができることから、求めるクラス間分散とクラス内分散との比である分離度

  

となり、この分離度が最大となるしきい値 t を求めればよい。
ここで、全分散σtはしきい値に関係なく一定なので、クラス間分散σb2が最大となるしきい値を
求めればよい事が分かる。
さらにクラス間分散の式の分母もしきい値に関係なく一定なので、クラス間分散の分子

 

  ω1 ω2 (m1 – m2)2

 

が最大となるしきい値 t を求めればよい。
結局、分散とか関係なく、黒、白それぞれの領域のヒストグラムから、画素数ωと輝度値の
平均値mから上記の値が最大となるしきい値 t をしらみつぶしに求めればいいので、以外と簡単...

 

【処理例】

上記例のように、判別分析法はおおむね良好な結果を得る事ができます。

 

画像処理アルゴリズムへ戻る

 

Pタイル法

Pタイル法【Percentile Method】は、画像の二値化したい領域が全画像の領域に占める割合をパーセント(%)で指定し二値化する手法です。

【処理例】

Pタイル法処理前

Pタイル法処理後

(二値化する割合を23%で指定)

【処理アルゴリズム】

まず最初に画像のヒストグラムを取得します。

 

このヒストグラムを見ると、輝度値でおおよそ160前後で二値化すると、目的の画像が得られそうな 事が分かります。

次にヒストグラムの輝度値が高い方から頻度を足していき、その頻度の合計が指定した割合を超える 輝度値をしきい値とし、二値化処理を行います。

 

実際の処理では、例えば画像サイズが640×480画素だとすると、全画素数は307,200画素なので、 二値化する割合が23%のときは23%に相当する画素数は

307,200 × 0.23 = 70,656画素

なので、ヒストグラムの頻度を輝度値の高い方から(黒側の面積を指定する場合は低い方から)足していった時に70,656画素を初めて超える輝度値を二値化のしきい値とします。 Pタイル法では、二値化する領域の大きさが一定の場合、画像の明るさが変動しても、二値化された 画像は変わらない事がメリットです。

 

一般にカメラから得られる画像の輝度値はカメラ本体の温度変化により変動し、LEDなどの照明も 長時間使用していると暗くなる傾向があるので、固定しきい値による二値化処理よりも安定的に 二値化処理を行うことが可能となります。 もっとも、二値化する領域の大きさの変動が大きい場合は不向きです。

 

画像処理アルゴリズムへ戻る