OpenCV

【OpenCV-Python】findContoursによる輪郭検出

OpenCV(Python)で二値化された画像中の白の部分または黒の部分の輪郭のデータを取得するにはfindContours()関数を用います。

findContours()関数で取得できる情報は、輪郭を構成している点の座標群と輪郭の内側、外側の情報となります。

さらに、これらの情報を用いて、輪郭の長さや、輪郭の内側の面積、重心、輪郭部分の矩形領域などを取得できる関数も別途、用意されています。

処理例

(入力画像)

【OpenCV-Python】findContoursによる輪郭検出、処理

(処理結果)

【OpenCV-Python】findContoursによる輪郭検出、処理

※結果は画像データとしては得られず、上図の色付きの線で書いた部分の情報を取得します。

 

構文

findContours(image, mode, method[, contours[, hierarchy[, offset]]]) ->contours, hierarchy
image 輪郭抽出する画像データ
mode 輪郭構造の取得方法
method 輪郭座標の取得方法
(戻り値)contours 輪郭座標
(戻り値)hierarchy 輪郭の階層情報

 

image

輪郭抽出する画像データを指定します。

画像は8bitのグレースケールで、基本的に二値化された画像を指定します。

一部、32bit1チャンネルのデータ(ラベリングデータ)も指定可能です。

二値化されていない場合は、輝度値が0で無い部分に関しての輪郭情報を取得します。

mode

輪郭の階層情報の取得方法をRETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE, RETR_FLOODFILLの中から指定します。

最初に見つける輪郭が白の外側の輪郭となります。

そのため、入力画像は黒色背景の画像を指定します。

白色背景の画像を指定した場合、最初の輪郭は画像全体となります。

modeで指定した輪郭情報は戻り値のhierarchyに格納されます。

●RETR_TREE

輪郭の階層情報をツリー形式で取得します。

この輪郭の階層情報をというのは、下図を用いて説明します。

【OpenCV-Python】findContoursによる輪郭検出、処理

まず、一番外側の輪郭(白の領域の外側の輪郭)にがあります。

の内側の輪郭にはがあり、の内側にはがあります。

さらに、

の内側にはがあり、の内側には

の内側には

の内側には

の輪郭があります。

この構造をツリーで表現すると、このようになります。

【OpenCV-Python】findContoursによる輪郭検出、処理

modeRETR_TREEを指定するとhierarchyの中にこの階層構造が格納されます。

 

●RETR_CCOMP

白の輪郭(外側の輪郭)と黒の輪郭(内側の輪郭)の情報だけを取得し、白の輪郭のさらに内側の輪郭かどうか?の情報は失われます。

【OpenCV-Python】findContoursによる輪郭検出、処理

この構造をツリーで表現すると、このようになります。

【OpenCV-Python】findContoursによる輪郭検出、処理

●RETR_LIST

白(外側)、黒(内側)の区別なく、すべての輪郭を同じ階層として取得します。

【OpenCV-Python】findContoursによる輪郭検出、処理

この構造をツリーで表現すると、このようになります。

【OpenCV-Python】findContoursによる輪郭検出、処理

●RETR_EXTERNAL

一番外側の白の輪郭だけを取得します。

【OpenCV-Python】findContoursによる輪郭検出、処理

この構造をツリーで表現すると、このようになります。

【OpenCV-Python】findContoursによる輪郭検出、処理

method

輪郭を構成する点の座標の取得方法をCHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE, CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOSの中から指定します。

取得した座標は戻り値のcontoursに格納されます。

 

●CHAIN_APPROX_NONE

輪郭上のすべての座標を取得します。

【OpenCV-Python】findContoursによる輪郭検出、処理

●CHAIN_APPROX_SIMPLE

縦、横、斜め45°方向に完全に直線の部分の輪郭の点を省略します。

【OpenCV-Python】findContoursによる輪郭検出、処理

 

●CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS

輪郭の座標を直線で近似できる部分の輪郭の点を省略します。

【OpenCV-Python】findContoursによる輪郭検出、処理

 

(戻り値)contours

輪郭上の座標を取得します。

実際にどのような座標を取得するかは、methodの設定により異なります。

contoursのデータは以下のような配列となります。

contours[輪郭番号][点の番号][0][X座標, Y座標]

 

(戻り値)hierarchy

輪郭の階層情報を取得します。

取得する構造はmodeの設定により異なります。

contoursのデータは以下のような配列となります。

hierarchy[0][輪郭番号][次の輪郭番号, 前の輪郭番号, 最初子供(内側)の輪郭番号, 親(外側)の輪郭番号]

となります。

下図の例について説明します。

輪郭番号の親はで、最初の子供の番号はとなります。

の次の輪郭番号はで、の前の輪郭番号はとなります。

該当する輪郭番号が無い時は -1 になります。

【OpenCV-Python】findContoursによる輪郭検出、処理

上図の階層情報の例で言うと、

hierarchy[0][0] は [ 3, -1,  1, -1]
hierarchy[0][1] は [-1, -1,  2,  0]
hierarchy[0][2] は [-1, -1, -1,  1]
hierarchy[0][3] は [-1,  0,  4, -1]
hierarchy[0][4] は [-1, -1,  5,  3]
hierarchy[0][5] は [ 6, -1, -1,  4]
hierarchy[0][6] は [-1,  5,  7,  4]
hierarchy[0][7] は [-1, -1,  8,  6]
hierarchy[0][8] は [ 9, -1, -1,  7]
hierarchy[0][9] は [-1,  8, -1,  7]

となります。

 

輪郭座標(contours)の注意点

contoursで取得できる座標は、白の領域を構成する外側の座標、もしくは内側の座標となります。

例えば、下図のような図形の輪郭座標を取得するとき、

【OpenCV-Python】findContoursによる輪郭検出、処理

白の輪郭を取得するときは、一番、外側の画素の座標(下図の赤い点)がcontoursに格納されます。

【OpenCV-Python】findContoursによる輪郭検出、処理

しかし、白の内側の黒の輪郭座標は、黒の画素の座標にはなりません

黒の輪郭座標は、輪郭を構成している黒の画素の4近傍の白の画素の座標となります。
黒の輪郭座標は下図の青い点の座標となります。

【OpenCV-Python】findContoursによる輪郭検出、処理

輪郭の描画

findContours()関数で取得した輪郭(contours)はdrawContours()関数を用いて描画します。

drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) ->image
image 描画先の画像データ
contours 輪郭座標
contourIdx 描画する輪郭の番号
-1にすると、すべての輪郭を描画
color 描画の色を(b, g, r)のタプルで指定します
thickness 線幅
-1を指定すると塗りつぶしになります。
lineType 線の描画スタイルをFILLED, LINE_4, LINE_8, LINE_AAの中から指定します。
hierarchy 輪郭の階層情報を指定します。
maxLevel 輪郭をどの階層まで表示するかを指定します。
0のとき、最初の輪郭のみ
1以降は数値の階層の輪郭すべてが表示されます。
offset

 

サンプルプログラム

import cv2

# 8ビット1チャンネルのグレースケールとして画像を読み込む
img = cv2.imread("sample.bmp", cv2.IMREAD_GRAYSCALE) 

contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE ) 

# 画像表示用に入力画像をカラーデータに変換する
img_disp = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

# 全ての輪郭を描画
cv2.drawContours(img_disp, contours, -1, (0, 0, 255), 2)

# 輪郭の点の描画
for contour in contours:
    for point in contour:
        cv2.circle(img_disp, point[0], 3, (0, 255, 0), -1)

cv2.imshow("Image", img_disp)

# キー入力待ち(ここで画像が表示される)
cv2.waitKey()

(実行結果)

【OpenCV-Python】findContoursによる輪郭検出、処理

 

関連記事

【OpenCV-Python】輪郭(contour)の面積(contourArea)
OpenCVで二値化された領域の輪郭座標は、findContours関数を使えば取得することができます。 このときの戻り値である輪郭情報(contours)をcontourArea関数へ渡し面積を求めます。 ただし、求まる面積は...
【OpenCV-Python】輪郭(contour)の矩形領域の取得
OpenCVのfindContours関数などで得られた点の座標から、点を囲う矩形領域(四角形の領域)を取得するにはboundingRect関数を用います。 さらに、傾きを考慮した矩形領域を取得するにはminAreaRect関数を用い...
【OpenCV-Python】輪郭の周囲長(arcLength)
findContours()関数などで取得した輪郭の座標から輪郭の長さを求めるにはarcLength()関数を用います。 構文 arcLength(curve, closed) ->retval curve ...

コメント

タイトルとURLをコピーしました