.. _Morphological_Ops: モルフォロジー変換 ******************************* 目的 ====== このチュートリアルでは, * 膨張処理,収縮処理といったモルフォロジー処理について学びます. * 以下の関数の使い方を学びます : **cv2.erode()**, **cv2.dilate()**, **cv2.morphologyEx()** etc. 理論 ======== モルフォロジー変換は主に二値画像を対象とし,画像上に写っている図形に対して作用するシンプルな処理を指します.モルフォロジー変換には入力画像と 処理の性質を決める **構造的要素** ( **カーネル** )の二つを入力とします.基本的なモルフォロジー処理として,収縮(Erosion)と膨張(Dilation)が挙げられます.他には,この二つの処理を組み合わせたオープニングとクロージングといった処理も挙げられます.このチュートリアルでは,これらの処理を一つ一つ紹介していきます. .. image:: images/j.png :alt: Input Image :align: center 1. 収縮(Erosion) ---------------------------- 収縮のアイディアは縮む珪藻から来ており,前景物体の境界が浸食されていくような処理を指します(常に白色の前景物体を残すようにする).何をすればこのような処理を実現できるのでしょうか?画像に対して(フィルタリング,2D convolutionに使われる)カーネルをスライドさせていきいます.原画像中の(1か0のどちらかの値を持つ)画素は,カーネルの領域に含まれる画素の画素値が全て1であれば1となり,そうでなければ0として出力されます. カーネルのサイズに依存して物体の境界付近の全画素が白(1)から黒(0)になり,消えてしまいます.結果として白い画素(前景物体)が占める領域が収縮するように見えるため収縮と呼ばれています.この収縮処理は,(色空間のチュートリアルで紹介した)画像中の白色雑音(ノイズ)の除去やつながっている複数物体を分割する時などに有効です. ここでは全要素の値が1の5x5サイズのカーネルを例に使います.早速どのような結果になるか見てみましょう : :: import cv2 import numpy as np img = cv2.imread('j.png',0) kernel = np.ones((5,5),np.uint8) erosion = cv2.erode(img,kernel,iterations = 1) 結果: .. image:: images/erosion.png :alt: 収縮 :align: center 2. 膨張(Dilation) ---------------------------- 収縮の逆の処理です.カーネル内に画素値が '1' の画素が一つでも含まれれば,出力画像の注目画素の画素値を '1' にします.画像中の白色の領域を増やすと言えますし,前景物体のサイズを増やすとも考えられます.普通は収縮の後に膨張させるノイズの除去方法で使われます.前景物体を膨張させるわけです.一度ノイズを消してしまえば,ノイズが再び発生することは無くなりますし,物体の領域も増えます.物体から離れてしまった部分を再び付けたい時に便利です.It is also useful in joining broken parts of an object. :: dilation = cv2.dilate(img,kernel,iterations = 1) 結果: .. image:: images/dilation.png :alt: 膨張 :align: center 3. オープニング(Opening) ---------------------------- オープニング処理は **収縮の後に膨張** をする処理です.上述したようにノイズ除去に有効です.関数は **cv2.morphologyEx()** を使います. :: opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) 結果: .. image:: images/opening.png :alt: Opening :align: center 4. クロージング(Closing) ---------------------------- クロージング処理はオープニング処理の逆の処理を指し, **膨張の後に収縮** をする処理です.前景領域中の小さな(黒い)穴を埋めるのに役立ちます.オープニングと同様 **cv2.morphologyEx()** 関数を使いますが,第2引数のフラグに ``cv2.MORPH_CLOSE`` を指定する点が違います. :: closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) 結果: .. image:: images/closing.png :alt: Closing :align: center 5. モルフォロジー勾配 ----------------------------- 膨張した画像と収縮した画像の差分をとる処理です. 結果として物体の外郭(境界線)が得られます. :: gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel) 結果: .. image:: images/gradient.png :alt: Gradient :align: center 6. トップハット変換 ---------------------- 入力画像とオープニングした画像の差を取る処理です.以下の例では9x9サイズのカーネルを使っています. :: tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) 結果: .. image:: images/tophat.png :alt: Top Hat :align: center 7. ブラックハット変換 ------------------------ 入力画像とクロージングした画像の差を取る処理です. :: blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) 結果: .. image:: images/blackhat.png :alt: Black Hat :align: center 構造的要素 ======================== 前の例ではNumpyを使用して手作業で構造的要素(カーネル)を作成しました.作成したカーネルは矩形でしたが,時には楕円形や円形カーネルが必要になる時があります.このようなカーネルの作成をする時は **cv2.getStructuringElement()** 関数を使います.カーネルの形状とサイズを指定するだけで,期待するカーネルを取得できます. .. code-block:: python # 矩形カーネル >>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]], dtype=uint8) # 楕円形カーネル >>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) array([[0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0]], dtype=uint8) # 十字型カーネル >>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5)) array([[0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]], dtype=uint8) 補足資料 ======================= #. `モルフォロジカル処理(英語) `_ at HIPR2 課題 ==========