Search code examples
pythonopencvimage-processingmask

How to make mask from all contours with fillConvexPoly


I'm trying to make a mask from contours. Here's my full df

Here's a glimpse of first 7 rows

>>> df
      contour.ID        xrT        yrT        xlT        ylT
1057          20  6259.2300  4620.7845  5670.1260  4651.4670
1058          20  6253.0935  4620.7845  5682.3990  4651.4670
1059          20  6253.0935  4633.0575  5694.6720  4657.6035
1060          20  6240.8205  4633.0575  5694.6720  4657.6035
1061          20  6228.5475  4645.3305  5700.8085  4669.8765
1062          20  6228.5475  4645.3305  5700.8085  4669.8765
1063          20  6216.2745  4645.3305  5713.0815  4669.8765

I can draw all contours I care about using a function.

def display_all_contours(img, df, grouping_var):
    # display with matplotlib

    # Create figure and axes
    fig, ax = plt.subplots(1)

    # Display the image
    ax.imshow(img)

    # split by contour
    grouped_frame = df.groupby(grouping_var)
    li = [grouped_frame.get_group(x) for x in grouped_frame.groups]

    # for every contour
    for i in range(len(li)):
        poly = patches.Polygon(np.array([li[i].xrT, li[i].yrT]).T,
                               fill=False)
        ax.add_patch(poly)

    for i in range(len(li)):
        poly = patches.Polygon(np.array([li[i].xlT, li[i].ylT]).T,
                               fill=False, color="white")
        ax.add_patch(poly)

    return("Displaying " + str(len(np.unique(df[grouping_var]))) + " contours.")

This is the result of drawing the contorus on something that has the shape of my image.

mask = np.zeros((9373, 12273), dtype=np.uint8)

display_all_contours(mask, df, "contour.ID")

enter image description here

Problem

Now, I want to create a mask of all the polygons (in this case the left side). So I create a mask and burn into it each polygon using cv2.fillConvexPoly

mask = np.zeros((9373, 12273), dtype=np.uint8)

display_all_contours(mask, df, "contour.ID")

for poly in np.unique(df["contour.ID"]):
    # subset
    sub_df = df[df["contour.ID"] == poly]
    # burn into the mask
    # explicitly burn into the mask
    mask = cv2.fillConvexPoly(mask, np.array(sub_df[["xlT", "ylT"]], 'int32'), 1)

For some reason I don't understand, this does not produce the result I intended.

plt.imshow(mask)

enter image description here


Solution

  • Solved it, the function I was actually looking for is fillPoly

    Replacing this line solves the problem

    # mind the np.array(..., "int32") is wrapped in [] because that's how fillPoly likes it
    mask = cv2.fillPoly(mask, [np.array(sub_df[["xlT", "ylT"]], 'int32')], 1)