Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - convert binary mask to polygon

Given a simple binary mask (e.g. the boundary of a rectangle).

binary mask

How can I use a polygon to get the x-y coordinates?

This is what I have tried so far:

coords = np.transpose(np.nonzero(mask))

However, this approach generates a filled object and not the desired boundary.

plt.plot(coords[:, 1], coords[:,0])

unwanted output

Basically, I want a list of x-y coordinates of the white pixels to use this list to re-draw the rectangle (not filled).

like image 293
Kamu Avatar asked Oct 19 '25 03:10

Kamu


2 Answers

Using cv2.findContours works both for complex shapes and multiple objects. Polygons list contains coords lists each looking like this [x1, y1, x2, y2, x3, y3, ...].

contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
polygons = []

for obj in contours:
    coords = []
        
    for point in obj:
        coords.append(int(point[0][0]))
        coords.append(int(point[0][1]))

    polygons.append(coords)
like image 188
Andrej_Rbr Avatar answered Oct 21 '25 18:10

Andrej_Rbr


You can use np.column_stack() + np.where(). The idea is to determine the white pixels in the binary image then order then in corresponding (x, y) order

coords = np.column_stack(np.where(image > 0))

Another way is to find the coordinates of the bounding rectangle using OpenCV's cv2.boundingRect(). This will give you the width, height, and top-left (x,y) coordinates. Here's an example finding the coordinates then drawing the polygon onto a blank mask

import cv2
import numpy as np

image = cv2.imread('1.png', 0)
x,y,w,h = cv2.boundingRect(image)
mask = np.ones(image.shape, dtype=np.uint8) * 255
mask = cv2.merge([mask,mask,mask])
cv2.rectangle(mask, (x, y), (x + w, y + h), (36,255,12), 2)

cv2.imshow('mask', mask)
cv2.waitKey()
like image 41
nathancy Avatar answered Oct 21 '25 17:10

nathancy