MENU

python 画像の領域の抽出(輪郭)

 

 

f:id:hanamichi_sukusuku:20201226201602p:plain

モジュールインポートと画像読み込みは省く。

・色空間の二値化

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
im2 = cv2.threshold(gray, 140, 240, cv2.THRESH_BINARY_INV)[1]

画像の平滑化(ぼかし処理)について

ぼかす処理を行うのは複雑で細かい模様などを検出しないように、画像をぼかしている。opencvには画像をぼかすための関数がいろいろ用意されていて今回使用するのはcv2.GaussianBlur()関数である。この関数はホワイトノイズの除去に適している。

 

平滑化(ぼかし処理を行った場合)

f:id:hanamichi_sukusuku:20201226204326p:plain

平滑化を行わなかった場合

f:id:hanamichi_sukusuku:20201226204355p:plain

今回のcv2.GaussianBlur()では上記の画像を見てわかる通り、画像をぼかし細かい模様を除去していることがわかる。

 

記述については

cv2.GaussianBlur(img, (ax, ay), sigma_x)

第一引数には画像、第二引数には平滑化(ぼかし処理)をする画素の周囲のサイズをピクセル指定する、この時値は奇数でないといけない。第三引数には横方向の標準偏差を指定する。0の場合はカーネルサイズから自動で計算される。

 

第二引数(1,1)の時

f:id:hanamichi_sukusuku:20201226213551p:plain

第二引数(7,7)の時(今回)

f:id:hanamichi_sukusuku:20201226213626p:plain

第二引数(33,33)の時

f:id:hanamichi_sukusuku:20201226213604p:plain

第二引数(55,55)の時

f:id:hanamichi_sukusuku:20201226213535p:plain

 


そして、画像の平滑化を行った後にデータをcv2.threshold()関数で二値化している。二値化とは画像のしきい値より大きければ白、小さければ黒を割り当てる処理、要するに白か黒に分ける。

画像の二値化を行うにはcv2.threshold()関数を使い、第一引数にはグレースケールの画像を指定、第二引数にはしきい値を指定、第三引数にはしきい値以上の値を持つ値に対して割り当てる値を指定、第四引数にはどのように二値化を行うのかを指定し、THRESH_BINARY_INVを指定した場合、しきい値よりも大きな値であれば0、それ以外はmaxval(第三引数)の値にする。

 

・画面左側に上記で処理した画像を描画

plt.subplot(1, 2, 1)
plt.imshow(im2, cmap="gray")

subplotでは複数のプロットを一枚の画像に貼り付けており

subplot(行,列,左上から何番目に貼り付けるか)のように指定している。

 

・輪郭の抽出

cnts = cv2.findContours(im2,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)[1]

輪郭を抽出するにはcv2.findContours()関数を使用する。

cv2.findColtours(image, mode, method)のように記述する。

第一引数は入力画像、第二引数は抽出方法、第三引数は近似手法を指定する。

返り値は輪郭リスト、階層情報が返される。

 

第二引数は輪郭の抽出方法を指定していて、今回のcv2.RETR_LISTは単純に輪郭を検出するものである。

 

第三引数の近似手法で指定しているcv2.CHAIN_APPROX_SIMPLEは不必要な点を削除し必要最低限の点だけを返す。cv2.CHAIN_APPROX_NONEもあるがそれは輪郭上の全ての点を保持するものである。近似手法についてはふんわり分かった気がするがここでは一般的にCHAIN_APPROX_SIMPLEを使用することが多いらしい。

 

・抽出した輪郭を描画

for pt in cnts:
 x, y, w, h = cv2.boundingRect(pt)
 # 大きすぎたり小さすぎたり領域を除去
 if w < 30 or w > 200: continue
 print(x,y,w,h) # 結果を出力
 cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.boundingRect()で輪郭に外接する長方形を計算できる。

引数

・numpy配列、輪郭を渡す。

返り値

・(左上のx座標,y座標, 幅, 高さ)のタプル(タプルは(0,1,2,3)こんなやつ)。輪郭に外接する長方形の値。

 

cv2.rectangleで枠を描画。

 

・画面右側に抽出結果を描画

plt.subplot(1, 2, 2)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.savefig("find_contours.png", dpi=200)
plt.show()

savefig()で画像を保存しているがdpiパラメータに値を指定することで高解像度で保存することができる。

例  

dpiを指定しない場合(デフォルト)

f:id:hanamichi_sukusuku:20201226212042p:plain

dpi=200を指定した場合

f:id:hanamichi_sukusuku:20201226212148p:plain