Home > Back-end >  trouble with findContours and hierarchy (tell if a contour is a hole or not)
trouble with findContours and hierarchy (tell if a contour is a hole or not)

Time:08-04

We have multiple contours. Some are positive and some are negative (holes). Here is the code i'm using

def get_corners(grid: np.ndarray, show=False):

    corners = set()
    hole_corners = set()

    # Filter using contour hierarchy
    cnts, hierarchy = cv.findContours(grid, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)[-2:]

    hierarchy = hierarchy[0]
    for component in zip(cnts, hierarchy):
        currentContour = component[0]
        currentHierarchy = component[1]
        # x,y,w,h = cv.boundingRect(currentContour)
        # Has hole which means it is IN
        if currentHierarchy[2] < 0:
            for corner in currentContour[:, 0, :]:
                corner_coords = tuple(corner.tolist())
                hole_corners.add(corner_coords)
            # cv.putText(image, 'IN', (x,y-10), cv.FONT_HERSHEY_SIMPLEX, 0.7, (36,255,12), 2)
        # No child which means it is OUT
        elif currentHierarchy[3] < 0:
            for corner in currentContour[:, 0, :]:
                corner_coords = tuple(corner.tolist())
                corners.add(corner_coords)

the problem with it is that, when there is more than one positive contour, it doesn't work as expected. every positive contour > 1 gets counted as a hole. here is it displayed.

  • Red: positive contours
  • Green: negatives/holes

As you can see its not working as expected.

all counted as holes

all counted as holes

one counted correctly, rest mostly incorrectly

one counted correctly, rest mostly incorrectly

image with contours labelled correctly (ignore corner color here)

image with contours labelled correctly (ignore corner color here)

Another failure case with islands with no child being counted as holes

 hierarchy for this: [[ 1 -1 -1 -1]
 [ 3  0  2 -1]
 [-1 -1 -1  1]
 [-1  1 -1 -1]]

CodePudding user response:

Figured it out. using RETR_CCOMP and checking for currentHierarchy[3] worked for me. Corners is a set with all corners of the outer contours, hole_corners is a set with all corners of the inner, or hole contours.

(cnts, hierarchy) = cv.findContours(grid,mode=cv.RETR_CCOMP, method=cv.CHAIN_APPROX_TC89_KCOS)

corners = set()
hole_corners = set()

# Filter using contour hierarchy

hierarchy = hierarchy[0]
for component in zip(cnts, hierarchy):
    currentContour = component[0]
    currentHierarchy = component[1]
    (hnext, hprev, hchild, hparent) = currentHierarchy

    if hparent < 0:
        # Has no parent, which means it is not a hole
        for corner in currentContour[:, 0, :]:
            corner_coords = tuple(corner.tolist())
            corners.add(corner_coords)
    else:
        # Has a parent, which means it is a hole
        for corner in currentContour[:, 0, :]:
            corner_coords = tuple(corner.tolist())
            hole_corners.add(corner_coords)
  • Related