ここではOpenCVを使ったPythonでの画像処理について、膨張処理、収縮処理といったモルフォロジー処理についてみていきます。形態演算(Morphological Operators)とも呼ばれます。
モルフォロジー変換は主に白黒画像のような二値画像を対象として、画像上に写っている図形などに対してシンプルな処理を施します。
ここでは、erode()、dilate()、morphologyEx() について扱ってみます。
モルフォロジー変換の処理
モルフォロジー変換には入力画像と処理の性質を決めるカーネル(構造的要素)の二つを使います。基本的なモルフォロジー処理には、収縮(Erosion)、膨張(Dilation)があり、この二つの処理を組み合わせたオープニングとクロージングといった処理もあります。
入力画像である二値画像を用意していきます。
jupyter notebookを使って試していきましょう。まず、各ライブラリをインポートします。
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
ここはもうお決まりのインポートですね。
ここで使う白黒の画像を用意しますが、画像を生成する関数と、表示する関数をここでまとめて定義しておきます。
def load_img():
blank_img =np.zeros((600,600))
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(blank_img,text='OpenCV',org=(55,350), fontFace=font,fontScale= 4,color=(255,255,255),thickness=20,lineType=cv2.LINE_AA)
return blank_img
load_img()として画像を作る関数を定義します。zeros()を使ってサイズが600×600の無地の画像blank_imgを用意します。zeros()を使っているので黒色の画像データになります。ここに文字を表示しますが、そのfontを選択します。putText()でblank_imgの上に、「OpenCV」の文字を表示させます。orgで位置を設定し、fontFaceで先ほど選択したfontを指定します。fontScaleでフォントの大きさ、colorで色(ここでは白)、thicknessで文字の太さ、lineTypeでここではcv2.LINE_AAのアンチエイリアスタイプの角が丸く表示されるものをここでは指定してみました。
def display_img(img):
fig = plt.figure(figsize=(12,10))
ax = fig.add_subplot(111)
ax.imshow(img,cmap='gray')
img画像を表示する関数をdisplay_img(img)で定義します。figure()で表示領域のアスペクト比を指定し、add_subplot()で画像を表示する位置を指定します。ここでは111なので左上の角を基準に配置します。imshow()でcmapをgrayにして画像を表示します。
実際に表示してみましょう。
img = load_img()
display_img(img)
この画像にモルフォロジー変換の処理をしていくことになります。
収縮(Erison)- erode()
erode()を使って、前面にあるオブジェクトの境界を侵食するような処理を施します。前面のオブジェクトが明るい色(白)で、背景が暗いときに行うのに適した処理です。
次のように処理します。
kernel = np.ones((5,5),np.uint8)
erosion1 = cv2.erode(img,kernel,iterations = 1)
display_img(erosion1)
カーネルを全要素が1の5×5で使うように、ここではones()を使っています。cv2.erode()に上で作成したimg、kernelを渡します。iterationsは収縮処理の回数で、ここでは1としてみます。
表示してみましょう。
表示した文字の部分が収縮しているのがわかります。
同様の処理を、今度は複数回施してみます。
img = load_img()
kernel = np.ones((5,5),np.uint8)
erosion3 = cv2.erode(img,kernel,iterations = 3)
やっていることは同じで、iterationsを3にして、収縮処理の反復を3にしてみます。
実行するとこうなります。
文字表示がさらに収縮しているのがわかります。
膨張(Dilation)- dilate()
今度はdilate()を使って膨張処理をしてみます。これは、上の収縮と逆の処理で、白い部分、前面にある部分の領域を増やします。
dilate()を使って、これまでと同様に処理します。
img = load_img()
kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(img,kernel,iterations = 3)
display_img(dilation)
itarationsを3にしてみました。
表示するとこうなります。
文字が膨張しているのがわかります。
オープニング(Opening)
オープニング処理とは収縮の後に膨張をする処理です。これはホワイトのノイズ除去に有効な処理で、cv2.morphologyEx() を使って処理をします。
まずホワイトノイズのある画像を準備します。
img = load_img()
white_noise = np.random.randint(low=0,high=2,size=(600,600))
white_noise
randint()を使ってノイズを作ります。0以上2未満の整数、つまり0か1の乱数を600×600のサイズに合わせてノイズを作っています。
ノイズの配列ができているのがわかります。
white_noise = white_noise*255
white_noise.shape
img.shape
noise_img = white_noise+img
ホワイトのノイズなので255を乗算しています。このノイズデータを元の画像に加えています。
元イメージとノイズイメージのサイズが同じなので、加えているわけです。
display_img()で表示します。
display_img(noise_img)
表示するとこうなります。
ようやくOpening処理ができます。
cv2.morphologyEx()を使って処理をしていきます。
opening = cv2.morphologyEx(noise_img, cv2.MORPH_OPEN, kernel)
display_img(opening)
cv2.morphologyEx()にnoise_imgを渡して、Opening処理にcv2.MORPH_OPENを指定します。カーネルはこれまで使ってきたものと同じものを使ってみます。
表示するとこうなります。
ホワイトノイズが除去されているのがわかります。
クロージング(Closing)
クロージング処理はオープニング処理と逆の処理です。膨張の後に収縮する処理です。これは前面にある白いオブジェクトに黒いノイズがある時にノイズ除去するのに有効な処理です。オープニング処理と同様にcv2.morphologyEx() を使いますが、引数にcv2.MORPH_CLOSEを使うというところに違いがあります。
黒いノイズを発生させた画像をまず用意してみます。
img = load_img()
black_noise = np.random.randint(low=0,high=2,size=(600,600))
black_noise
ノイズの発生はオープニングと同様の処理です。
このままだとほぼ真っ黒になってしまうので、白以外のノイズを発生させないように負の値を乗算します。
black_noise= black_noise * -255
black_noise_img = img + black_noise
black_noise_img
元の画像にノイズを加えています。
ただ、負の値ではカラー表示が表現できないので、負の値の部分に0を代入して黒いノイズを表現します。
black_noise_img[black_noise_img==-255] = 0
display_img(black_noise_img)
表示するとこうなります。
白い文字の部分に黒いノイズが表現されました。
このノイズをクロージングで消去していきましょう。
closing = cv2.morphologyEx(black_noise_img, cv2.MORPH_CLOSE, kernel)
display_img(closing)
オープニングと同様の処理でcv2.morphologyEx() を使いますが、最初に示しておいたように引数にcv2.MORPH_CLOSEを使います。
表示するとこうなります。
黒いノイズが除去されているのがわかります。
モルフォロジー勾配
モルフォロジー勾配(Morphological Gradient)とは、膨張した画像と収縮した画像の差分をとる処理です。結果としては、物体の輪郭(境界線)を得ることができ、これもcv2.morphologyEx()を使いますが、引数にcv2.MORPH_GRADIENTを使います。
比較する為に、元のイメージを読み込み直してみます。
img = load_img()
display_img(img)
これをモルフォロジー勾配処理をしてみます。
gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
display_img(gradient)
cv2.morphologyEx()を使ってimgを渡し、引数にcv2.MORPH_GRADIENTを使っています。
画像を表示してみます。
文字の輪郭だけが取り出されているのがわかります。
最後に
ここではOpenCVを使ったPythonでの画像処理について、膨張処理、収縮処理といったモルフォロジー変換についてみてきました。
モルフォロジー変換は主に白黒画像のような二値画像を対象に、シンプルな処理を施します。ノイズの除去などにも利用できます。
ここでは、 cv2.erode()、cv2.dilate()、cv2.morphologyEx()の関数の使い方をみてきました。