Вопрос

Мне нужно создать Numpy 2D массив, который представляет двоичную маску многоугольника, используя стандартные пакеты Python.

  • Вход: Polygon вершины, размеры изображений
  • Выход: двоичная маска многоугольника (Numpy 2D Array)

(Большой контекст: я хочу получить преобразование расстояния этого многоугольника, используя Scipy.ndimage.morphology.distance_transform_edt.)

Может кто-нибудь показать мне, как это сделать?

Это было полезно?

Решение

Ответ оказывается довольно простым:

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)

Другие советы

Как немного больше прямой альтернативы @ Anil's ответ, 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

Который дает (логический мошеннический массив):

[[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 к любому из функций scipy.ndimage.morphology.

Обновление на комментарии Джо. MATPLOTLIB API изменился, поскольку комментарий был опубликован, и теперь вам нужно использовать метод, предоставленный подмодулем 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, и что список вершин для ввода находятся в правильном порядке.

Ввод = [(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. enter image description here

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top