findContours,hierarchy
OpenCVの輪郭検出機能にfindContoursがある
これを使うと返り値にコンターと階層構造が取得できる
試しに以下のような画像を用意して
次のコードを実行する
import cv2 img = cv2.imread("./test.png") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, contours, hierarchy = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE )
findContoursの第二引数にRETR_TREEを指定することで階層構造を保持した輪郭が検出される
ここでcontoursとhierarchyの中身を確認
print("contours=",len(contours), "hierarchy=",len(hierarchy) )
結果は、
contours= 7 hierarchy= 1
この場合は7本の輪郭を検出した
元画像に閉曲線は3つしか描いてないが、黒線の外側境界と内側境界で2つづつ検出されている
drawContoursを使って色分けしてみる
cv2.drawContours(img, contours[0], -1,(255, 0, 0),3) cv2.drawContours(img, contours[1], -1,( 0,255, 0),3) cv2.drawContours(img, contours[2], -1,( 0, 0,255),3) cv2.drawContours(img, contours[3], -1,(255,255, 0),3) cv2.drawContours(img, contours[4], -1,( 0,255,255),3) cv2.drawContours(img, contours[5], -1,(255, 0,255),3) cv2.drawContours(img, contours[6], -1,( 0, 0, 0),3) cv2.imshow("img", img)
結果
外側の青線が0番目のコンターで、番号が大きいのが内側
hierarchyの中身をリスト表示
print(hierarchy)
[[[-1 -1 1 -1] [-1 -1 2 0] [-1 -1 3 1] [-1 -1 4 2] [-1 -1 5 3] [-1 -1 6 4] [-1 -1 -1 5]]]
数字の意味は
[next, previous, fist_child, parent]のコンターの番号を返す
この場合階層内に閉曲線が一つなのでnext,previousは-1
0番目のコンターは親を持たないので-1、子のコンター番号は1
コンターの面積
for i in range(0, len(contours)): print(cv2.contourArea(contours[i]))
741105.0 188691.0 179718.0 59741.0 54736.0 22727.0 19664.0
地図の等高線で色分けとかしたいので
子のコンターの面積差で判定して境界線残して塗りつぶし
for i in range(2, len(contours)): area1 = cv2.contourArea(contours[i]) area2 = cv2.contourArea(contours[int(hierarchy[0][i][2:3])]) if( area1 - area2 > 10000 ) or ( area1 - area2 == 0 ): cv2.fillConvexPoly(img, contours[i], (255,255-i*40,255-i*40)) else: cv2.fillConvexPoly(img, contours[i], (0,0,0))