OpenCVのfindContours hierarchy(輪郭の階層情報)の解説


OpenCVのfindContours hierarchy(輪郭の階層情報)の解説

前回の記事はOpenCVでの直線検出図形検出、図形数えるについて説明しました。今回はOpenCVのfindContours hierarchy(輪郭の階層情報)について解説したいと思います。

目次

1.  OpenCVのfindContours hierarchy(輪郭の階層情報)
2.  RETR_LIST
3.  RETR_TREE
4.  RETR_CCOMP
5.  RETR_EXTERNAL

1.  findContours hierarchy(輪郭の階層情報)

OpenCVのPython版のfindcontours関数はオブジェクトの輪郭を検出する関数です。時には物体が難しい場所に位置,ある形状の中に別の形状が観測されることもあります。画像中に含まれるすべてのオブジェクトを検出して、それぞれのオブジェクトにラベル番号を振り分けています。輪郭線の情報およびオブジェクトの階層構造情報を返します。この関数表現方法を 階層情報 と呼びます。

第一引数に入力画像、第二引数に抽出モード、第三引数に近似手法を取ります。

image, contours, hierarchy = cv2.findContours(入力画像, 抽出モード, 近似手法)

実験

環境:Google Colab (CPU)でfindContours hierarchyの関数を実験します。

先ず、入力画像を表示します。

import cv2
import numpy as np
from IPython.display import Image

img_file = "box_a.png"
Image(img_file)

findContoursのhierarchy の関数を作成します。画像をロードして加工します。そして、輪郭の階層情報を出します。最後は輪郭を可視化します。

def findContours_summary(img, method, output):
    img_file = img
    img = cv2.imread(img_file)
    img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(img_gray, 127, 255,0)
    contours, hierarchy = cv2.findContours(thresh, method, cv2.CHAIN_APPROX_SIMPLE)

    print(method) 
    print("Number of Contours found = " + str(len(contours))) 
    print(hierarchy)

    item_no = 0
    font = cv2.FONT_HERSHEY_DUPLEX

    # 図形の設定
    img1 = img.copy()
    flattened_hierarchy = [y for x in hierarchy for y in x]

    for cnt, h in zip(contours, flattened_hierarchy): 
    approx = cv2.approxPolyDP(cnt, 0.01*cv2.arcLength(cnt, True), True)
    cv2.drawContours(img, [approx], 0, (0), 2)
    x = approx.ravel()[0]
    y = approx.ravel()[1]
    if len(approx) == 4:
        item_no +=1
        cv2.putText(img1, "{}.{}".format(item_no, h), (x, y), font, 0.4, (0))

    # 結果の画像作成
    global output_img
    output_img = output
    cv2.imwrite(output_img, img1)
    Image(output_img)

2. RETR_LIST

RETR_LISTの抽出モードは最も単純なものです。画像の中全ての輪郭を検出しますが,輪郭の包含関係は無視されます。つまり,全ての輪郭が同一階層に属することになります。

ここでは3番目と4番目の値が常に―1となり,NextとPreviousには対応するインデックスが格納されることになります。一行目は輪郭0を表しており,次の輪郭が輪郭1であるためNext = 1となっています.一方で,前の輪郭は無いのでPrevious = 0となります.上述したように,残りの二つの数値は-1となります.

findContours_summary(img_file, cv2.RETR_LIST, "output1.jpg")
Image(output_img)

1
Number of Contours found = 4
[[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[ 3 1 -1 -1]
[-1 2 -1 -1]]]

3.  RETR_TREE

RETR_LISTの抽出モードは全包含要素が、無視され最も外側の輪郭のみが返されます。このルールの下では,包含関係の最も外のモノのみが残り,その他の下の階層は無視されると言えます。画像中では最も外側の輪郭,すなわち階層レベルが0の輪郭は3個あります。

findContours_summary(img_file, cv2.RETR_TREE, "output2.jpg")
Image(output_img)

Number of Contours found = 4
[[[-1 -1 1 -1]
[ 2 -1 -1 0]
[-1 1 3 0]
[-1 -1 -1 2]]]

4.  RETR_CCOMP

RETR_LISTの抽出モードは全輪郭を検出し,2レベルの階層に分類します。物体の外側の輪郭は階層1,物体の内側の穴などの輪郭は階層2と分類されます。

findContours_summary(img_file, cv2.RETR_CCOMP, "output3.jpg")
Image(output_img)

Number of Contours found = 4
[[[ 1 -1 -1 -1]
[-1 0 2 -1]
[ 3 -1 -1 1]
[-1 2 -1 1]]]

5.  RETR_EXTERNAL

RETR_EXTERNALの抽出モードは全子要素が、無視され最も外側の輪郭のみが返されます。このルールの下では,階層の最も上のモノのみが残り,その下の輪郭は無視されると言えます。
画像中では最も外側の輪郭,すなわち階層レベルが0の輪郭は1個あります。

findContours_summary(img_file, cv2.RETR_EXTERNAL, "output4.jpg")
Image(output_img)

Number of Contours found = 1
[[[-1 -1 -1 -1]]]