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?
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)
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.
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
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?
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.
