このチュートリアルでは,
モルフォロジー変換は主に二値画像を対象とし,画像上に写っている図形に対して作用するシンプルな処理のことである.モルフォロジー変換には入力画像と 処理の性質を決める 構造的要素 ( カーネル )の二つを入力とする.基本的なモルフォロジー処理として,収縮(Erosion)と膨張(Dilation)が挙げられる.この他に,この二つの処理を組み合わせたオープニングとクロージングといった処理もある.このチュートリアルでは,これらの処理を一つ一つ紹介していく.
収縮のアイディアは縮む珪藻から来ており、前景物体の境界が浸食されていくような処理を指す(常に白色の前景物体を残すようにする).どうすればこのような処理を実現できるのだろうか?画像に対して(フィルタリング,2D convolutionに使われる)カーネルをスライドさせていきいく.原画像中の(1か0のどちらかの値を持つ)画素は,カーネルの領域に含まれる画素の画素値が全て1であれば1となり,そうでなければ0として出力される.
カーネルのサイズによって物体の境界付近の全画素が白(1)から黒(0)になり,消えてしまう.結果として白い画素(前景物体)が占める領域が収縮するように見えるため、収縮と呼ばれている.この収縮処理は,(色空間のチュートリアルで紹介した)画像中の白色雑音(ノイズ)の除去や、連結している複数の物体を分割する時などに有効である.
ここでは全要素の値が1の5x5サイズのカーネルを例に使う.早速どのような結果になるか見てみよう(対象画像) :
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('erosion')
plt.imshow(erosion,cmap='gray')
plt.show()
膨張は収縮の逆の処理である.カーネル内に画素値が 1
の画素が一つでも含まれれば,出力画像の注目画素の画素値を1
にします.画像中の白色の領域を増やすとも言えるし、前景物体のサイズを増やすとも言える.普通は収縮の後に膨張させるノイズの除去方法で使われる.つまり、前景物体を膨張させるわけである.一度ノイズを消してしまえば,ノイズが再び発生することは無くなり,物体の領域が増える.また、ばらばらのパーツをくっつけたりするのにも便利である
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(img,kernel,iterations = 1)
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('dilation')
plt.imshow(dilation,cmap='gray')
plt.show()
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j-noised.png',0)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 第2引数に'cv2.MORPH_OPEN'を指定
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('opening')
plt.imshow(opening,cmap='gray')
plt.show()
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j-noised2.png',0)
kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) # 第2引数が異なる
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('closing')
plt.imshow(closing,cmap='gray')
plt.show()
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('gradient')
plt.imshow(gradient,cmap='gray')
plt.show()
入力画像とオープニング画像の差を取る処理である.次の例では9x9サイズのカーネルを使っている:
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j.png',0)
kernel = np.ones((9,9),np.uint8) # サイズを変更している
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('tophat')
plt.imshow(tophat,cmap='gray')
plt.show()
入力画像とクロージング画像の差を取る処理である
%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('j.png',0)
kernel = np.ones((9,9),np.uint8)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.title('original')
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.title('blackhat')
plt.imshow(blackhat,cmap='gray')
plt.show()
前の例ではNumpyを使用して手作業で構造的要素(カーネル)を作成した.作成したカーネルは矩形であったが,時には楕円形や円形カーネルが必要になる時がある.このようなカーネルの作成をする時は cv2.getStructuringElement() 関数を使う.カーネルの形状とサイズを指定するだけで,期待するカーネルを取得できる.
# 矩形カーネル
cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
# 楕円形カーネル
cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
# 十字型カーネル
cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))