Scipy créer un masque de polygone 2D

je dois créer un tableau 2D numpy qui représente un masque binaire d'un polygone, en utilisant des paquets Python standard.

  • entrée: polygone de sommets, les dimensions de l'image
  • sortie: masque binaire de polygone (numpy tableau 2D)

(contexte plus large: je veux obtenir la transformation de distance de ce polygone en utilisant scipy.ndimage.morphologie.distance_transform_edt.)

quelqu'un Peut-il me montrer comment faire cela?

24
demandé sur Isaac Sutherland 2010-09-07 01:05:16

5 réponses

la réponse s'avère assez simple:

import numpy
from PIL import Image, ImageDraw

# polygon = [(x1,y1),(x2,y2),...] or [x1,y1,x2,y2,...]
# width = ?
# height = ?

img = Image.new('L', (width, height), 0)
ImageDraw.Draw(img).polygon(polygon, outline=1, fill=1)
mask = numpy.array(img)
44
répondu Isaac Sutherland 2010-09-17 01:35:44

comme alternative un peu plus directe à la réponse de @Anil, matplotlib a matplotlib.nxutils.points_inside_poly qui peut être utilisé pour rastérider rapidement un polygone arbitraire. E. g.

import numpy as np
from matplotlib.nxutils import points_inside_poly

nx, ny = 10, 10
poly_verts = [(1,1), (5,1), (5,9),(3,2),(1,1)]

# Create vertex coordinates for each grid cell...
# (<0,0> is at the top left of the grid in this system)
x, y = np.meshgrid(np.arange(nx), np.arange(ny))
x, y = x.flatten(), y.flatten()

points = np.vstack((x,y)).T

grid = points_inside_poly(points, poly_verts)
grid = grid.reshape((ny,nx))

print grid

ce Qui donne (un booléen tableau numpy):

[[False False False False False False False False False False]
 [False  True  True  True  True False False False False False]
 [False False False  True  True False False False False False]
 [False False False False  True False False False False False]
 [False False False False  True False False False False False]
 [False False False False  True False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]]

Vous devriez être en mesure de passer grid à l'un des scipy.ndimage.la morphologie fonctionne très bien.

23
répondu Joe Kington 2010-09-07 21:19:40

une mise à jour sur le commentaire de Joe. L'API Matplotlib a changé depuis que le commentaire a été posté, et maintenant vous devez utiliser une méthode fournie par un sous-module matplotlib.path.

le code de travail est ci-dessous.

import numpy as np
from matplotlib.path import Path

nx, ny = 10, 10
poly_verts = [(1,1), (5,1), (5,9),(3,2),(1,1)]

# Create vertex coordinates for each grid cell...
# (<0,0> is at the top left of the grid in this system)
x, y = np.meshgrid(np.arange(nx), np.arange(ny))
x, y = x.flatten(), y.flatten()

points = np.vstack((x,y)).T

path = Path(poly_verts)
grid = path.contains_points(points)
grid = grid.reshape((ny,nx))

print grid
11
répondu Yusuke N. 2016-04-21 04:01:11

Vous pouvez essayer d'utiliser la bibliothèque d'images de python, PIL. D'abord l'initialisation de la toile. Ensuite, vous créez un objet de dessin, et commencer à faire des lignes. Ceci suppose que le polygone réside dans R^2 et que la liste des sommets pour l'entrée est dans le bon ordre.

Entrée = [(x1, y1), (x2, y2), ..., (xn, yn)] , (largeur, hauteur)

from PIL import Image, ImageDraw

img = Image.new('L', (width, height), 0)   # The Zero is to Specify Background Color
draw = ImageDraw.Draw(img)

for vertex in range(len(vertexlist)):
    startpoint = vertexlist[vertex]
    try: endpoint = vertexlist[vertex+1]
    except IndexError: endpoint = vertexlist[0] 
    # The exception means We have reached the end and need to complete the polygon
    draw.line((startpoint[0], startpoint[1], endpoint[0], endpoint[1]), fill=1)

# If you want the result as a single list
# You can make a two dimensional list or dictionary by iterating over the height and width variable
list(img.getdata())

# If you want the result as an actual Image
img.save('polgon.jpg', 'JPEG')

C'est ce que vous cherchiez, ou vous demandiez quelque chose de différent?

2
répondu Anil 2010-09-06 21:30:15

comme une légère alternative à @Yusuke N. réponse en utilisant matplotlib.path, tout aussi efficace que celui par from PIL import Image, ImageDraw(pas besoin d'installer Pillow, ,pas besoin d'envisager d' integer ou float. utile moi, Ha?)

le code de travail est ci-dessous:

import pylab as plt
import numpy as np
from matplotlib.path import Path

width, height=2000, 2000

polygon=[(0.1*width, 0.1*height), (0.15*width, 0.7*height), (0.8*width, 0.75*height), (0.72*width, 0.15*height)]
poly_path=Path(polygon)

x, y = np.mgrid[:height, :width]
coors=np.hstack((x.reshape(-1, 1), y.reshape(-1,1))) # coors.shape is (4000000,2)

mask = poly_path.contains_points(coors)
plt.imshow(mask.reshape(height, width))
plt.show()

et l'image de résultat est ci-dessous, où zone sombreFalse,zone lumineuseTrue. enter image description here

1
répondu Alpha 2018-07-06 10:46:44