Составляющей создания 2D многоугольник Маска
Мне нужно создать numpy 2D массив, который представляет собой двоичную маску полигона, используя стандартные пакеты Python.
- входные данные: вершины многоугольника, размеры изображения
- вывод: двоичная маска полигона (numpy 2D array)
(более широкий контекст: я хочу получить преобразование расстояния этого полигона с помощью scipy.ndimage.морфология.distance_transform_edt.)
Может ли кто-нибудь показать мне, как это сделать?5 ответов:
Ответ оказывается довольно простым:
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)
В качестве немного более прямая альтернатива ответа @Анила, библиотек matplotlib имеет
matplotlib.nxutils.points_inside_poly
что можно использовать для быстрого растеризовать произвольный многоугольник. Например,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
Который дает (логический массив 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]]
Вы должны быть в состоянии передать
grid
любому из Сципионов.ndimage.морфология функционирует довольно хорошо.
Обновление комментария Джо. API Matplotlib изменился с момента публикации комментария, и теперь вам нужно использовать метод, предоставляемый подмодулем
matplotlib.path
.Рабочий код приведен ниже.
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
Вы можете попробовать использовать библиотеку изображений python, PIL. Сначала вы инициализируете холст. Затем вы создаете объект чертежа и начинаете делать линии. Это предполагает, что полигон находится в R^2 и что список вершин для входных данных находится в правильном порядке.
Input = [(x1, y1), (x2, y2),..., (xn, yn)], (ширина, высота)
Это то, что вы искали, или вы спрашивали что-то другое?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')
В качестве небольшой альтернативы @Yusuke N. ответ с помощью
matplotlib.path
, так же эффективно, как и с помощьюfrom PIL import Image, ImageDraw
(нет необходимости устанавливатьPillow
, нет необходимости рассматриватьinteger
илиfloat
. пригодится мне, а?)Рабочий код приведен ниже:
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()
И изображение результата ниже, где темная область
False
, яркая область - этоTrue
.