SciPy Erstellen von 2D-Polygon-Maske
-
01-10-2019 - |
Frage
Ich brauche einen numpy 2D-Array zu erstellen, die eine binäre Maske eines Polygons darstellt, unter Verwendung von Standard-Python-Paketen.
- Eingabe: Polygon-Scheitelpunkte, Bildabmessungen
- Ausgabe: binäre Maske von Polygon (numpy 2D-Array)
(größerer Kontext. Ich mag die Distanz verwandelt dieses Polygons erhalten scipy.ndimage.morphology.distance_transform_edt verwenden)
Kann jemand mir zeigen, wie dies zu tun?
Lösung
Die Antwort stellt sich heraus, ganz einfach sein:
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)
Andere Tipps
Als eine etwas direktere Alternative zu @ Anil Antwort, matplotlib hat
Ein Update auf Joes Kommentar.
Matplotlib API hat sich geändert seit der Kommentar geschrieben wurde, und jetzt müssen Sie eine Methode von einem Submodul Arbeits Code ist unten. matplotlib.path
nutzen. 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
Sie könnten auf die Nutzung Python versuchen Bild-Bibliothek, PIL. Zuerst die Leinwand initialisieren. Dann erstellen Sie ein Zeichnungsobjekt, und Sie beginnen, Linien zu machen. Dies wird unter der Annahme, daß das Polygon besteht in R ^ 2, und dass die Scheitelpunktliste für die Eingabe in der richtigen Reihenfolge ist.
Input = [(x1, y1), (x2, y2), ..., (xn, yn)], (Breite, Höhe)
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')
Ist das, was Sie suchen, oder waren Sie etwas anderes fragen?
Als leicht Alternative zu @Yusuke N. Antwort von matplotlib.path
verwenden, ebenso effizient wie die von from PIL import Image, ImageDraw
(keine Notwendigkeit Pillow
zu installieren, keine Notwendigkeit integer
oder float
zu betrachten. Nützlich ich, Ha?)
Arbeitscode ist unter:
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()
Und das Ergebnis Bild ist unten, wobei dunkler Bereich ist False
, heller Bereich True
ist.