SciPy twórz maskę wielokąta 2D

Muszę utworzyć tablicę numpy 2D, która reprezentuje binarną maskę wielokąta, używając standardowych pakietów Pythona.

  • wejście: wierzchołki wielokątów, wymiary obrazu
  • Wyjście: binarna Maska wielokąta (tablica numpy 2D)

(większy kontekst: chcę uzyskać transformację odległości tego wielokąta za pomocą scipy.ndimage.morfologia.distance_transform_edt.)

Czy ktoś może mi pokazać jak to się robi?

Author: Isaac Sutherland, 2010-09-07

5 answers

ODPOWIEDŹ okazuje się dość prosta:

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
Author: Isaac Sutherland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-17 01:35:44

Jako nieco bardziej bezpośrednia alternatywa dla odpowiedzi @Anil, matplotlib ma matplotlib.nxutils.points_inside_poly które mogą być użyte do szybkiego rasteryzowania dowolnego wielokąta. Np.

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

Co daje (boolean numpy array):

[[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]]

Powinieneś być w stanie przekazać grid każdemu z scypiów.ndimage.morfologia funkcjonuje całkiem ładnie.

 23
Author: Joe Kington,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-07 21:19:40

Aktualizacja komentarza Joego. API Matplotlib zmieniło się od czasu opublikowania komentarza i teraz musisz użyć metody dostarczonej przez podmodule matplotlib.path.

Roboczy kod znajduje się poniżej.

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
Author: Yusuke N.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-21 04:01:11

Możesz spróbować użyć biblioteki obrazów Pythona, PIL. Najpierw zainicjuj płótno. Następnie tworzysz obiekt rysunkowy i zaczynasz tworzyć linie. Przy założeniu, że wielokąt znajduje się w R^2 i że lista wierzchołków dla danych wejściowych jest w odpowiedniej kolejności.

Input = [(x1, y1), (x2, y2),..., (xn, yn)], (szerokość, wysokość)

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')
Tego szukałeś, czy pytałeś o coś innego?
 2
Author: Anil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-06 21:30:15

Jako lekka alternatywa dla @Yusuke N. odpowiedz używając matplotlib.path, tak samo wydajnego jak ten przez from PIL import Image, ImageDraw (nie ma potrzeby instalowania Pillow,, nie ma potrzeby rozważania integer lub float. przyda mi się, co?)

Kod roboczy znajduje się poniżej:

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()

I obraz wynikowy jest poniżej, gdzie ciemny obszar jest False, jasny obszar to True. Tutaj wpisz opis obrazka

 1
Author: Alpha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-06 10:46:44