Создание заполненного массива единиц из точек многоугольника Python

Я был бы очень признателен, если бы кто-нибудь мог помочь мне найти более быстрое решение моей проблемы.

Вот сценарий: - У меня есть многоугольник точек с плавающей запятой, который я хочу сопоставить с сеткой. Ячейки сетки могут быть разной ширины и высоты, а не однородными, как показано на моем изображении. то есть прямоугольный.

Я пытался использовать рисование изображений, но он использует только целые числа. Преобразование чисел с плавающей запятой в целые означает, что мне нужно увеличить число с плавающей запятой и удалить десятичное число, чтобы сохранить некоторую точность, но рисование изображения не будет работать с большим многоугольником точек.

Есть ли более красноречивый и быстрый способ получить массив единиц (синий) для заполненной области многоугольника и нулей (красный) для остальных. Я немного читал о сетчатой ​​сетке, но не понимаю, как это может быть полезно для этого сценария.

Большое спасибо

Результаты кода

cols = 4
rows = 4
points = [[1535116L, 1725047L], [1535116L, 2125046L], [-464884L, 2125046L], [-464884L, 125046L]]    

bbCut = getPythonBoundBox(points)
cutWidth =  bbCut[1][0]-bbCut[0][0]
scale = float(cutWidth) / float(rows)
###Center data to origin
for p in range(len(points)):
    points[p][0] -= (bbCut[1][0] - bbCut[0][0])/2
    points[p][1] -= (bbCut[1][1] - bbCut[0][1])/2
    points[p][0] /= scale
    points[p][1] /= scale


##move points to Zero
bbCut = getPythonBoundBox(points)

for p in range(len(points)):
    points[p][0] -=bbCut[0][0]
    points[p][1] -=bbCut[0][1]

pointToTuple= []
for p in range(len(points)):
  pointToTuple.append((points[p][0], points[p][1]))

imgWidth = float(rows)
imgHeight = float(cols)

img = Image.new('L', (int(imgWidth), int(imgHeight)), 0) 
draw = ImageDraw.Draw(img)

draw.polygon(pointToTuple, fill=1)

array =  np.reshape(list(img.getdata()), (cols, rows))

############This is the result from the array############
##If you compare this array to the coloured scaled image ive have drawn
##its missing a 1 on the second value in the first row
##and another 1 on the second row 3rd value
##I'm assuming there is some parsing happening here with float to int?                       
array([1, 0, 0, 0])
array([1, 1, 0, 0])
array([1, 1, 1, 1])
array([1, 1, 1, 1])
#########################################################

def getPythonBoundBox(points):
    bigNumber = 10e10
    xmin = bigNumber
    xmax = -bigNumber
    ymin = bigNumber
    ymax = -bigNumber
    g = []
    a = len(points)
    for i in xrange(a):
        if points[i][0] < xmin: xmin = points[i][0]
        if points[i][0] > xmax: xmax = points[i][0]
        if points[i][1] < ymin: ymin = points[i][1]
        if points[i][1] > ymax: ymax = points[i][1]
    p1 = [xmin,ymin]
    g.append(p1)
    p2 = [xmax,ymax]
    g.append(p2)
    return (g)

форма многоугольника над сеткой


person daniel    schedule 03.04.2017    source источник
comment
Можете ли вы опубликовать код, который вы использовали для создания изображения?   -  person Michael    schedule 03.04.2017
comment
добавил код спасибо за ответ   -  person daniel    schedule 03.04.2017


Ответы (1)


matplotlib.path.Path имеет метод contains_points. Следовательно, просто создайте путь с точками многоугольника, а затем проверьте координаты сетки, если они попадают в этот путь. Ваша сетка может иметь любое разрешение. Это контролируется nx и ny (или, альтернативно, dx и dy) в приведенном ниже коде.

Код:

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.patches import PathPatch
from matplotlib.path import Path

# create a matplotlib path
points = [[1535116L, 1725047L],
          [1535116L, 2125046L],
          [-464884L, 2125046L],
          [-464884L, 125046L],
          [1535116L, 1725047L]]
codes = [Path.MOVETO,
         Path.LINETO,
         Path.LINETO,
         Path.LINETO,
         Path.CLOSEPOLY,
         ]
path = Path(points, codes)

# check the path
fig, (ax1, ax2, ax3) = plt.subplots(1,3)
patch = PathPatch(path, facecolor='k')
ax1.add_patch(patch)
xmin, ymin = np.min(points, axis=0)
xmax, ymax = np.max(points, axis=0)
ax1.set_ylim(ymin,ymax)
ax1.set_xlim(xmin,xmax)
ax1.set_aspect('equal')

# create a grid
nx, ny = 1000, 1000
x = np.linspace(xmin, xmax, nx)
y = np.linspace(ymin, ymax, ny)
xgrid, ygrid = np.meshgrid(x, y)
pixel_coordinates = np.c_[xgrid.ravel(), ygrid.ravel()]

# find points within path
img = path.contains_points(pixel_coordinates).reshape(nx,ny)

# plot
ax2.imshow(img, cmap='gray_r', interpolation='none', origin='lower')

# repeat, but this time specify pixel widths explicitly
dx, dy = 2000, 2000
x = np.arange(xmin, xmax, dx)
y = np.arange(ymin, ymax, dy)
xgrid, ygrid = np.meshgrid(x, y)
pixel_coordinates = np.c_[xgrid.ravel(), ygrid.ravel()]
img = path.contains_points(pixel_coordinates).reshape(len(x), len(y))
ax3.imshow(img, cmap='gray_r', interpolation='none', origin='lower')

введите здесь описание изображения

ОБНОВИТЬ:

Итак, теперь это проверяет, находятся ли какие-либо углы каждой плитки в пределах пути. По какой-то причине я все еще получаю другой ответ, чем предполагает картинка. Насколько вы уверены, что точки, которые вы предоставляете, точны?

Код + изображение:

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.patches import PathPatch
from matplotlib.path import Path

# create a matplotlib path
points = [[1535116L, 1725047L],
          [1535116L, 2125046L],
          [-464884L, 2125046L],
          [-464884L, 125046L],
          [1535116L, 1725047L]]

codes = [Path.MOVETO,
         Path.LINETO,
         Path.LINETO,
         Path.LINETO,
         Path.CLOSEPOLY,
         ]
path = Path(points, codes)

fig, (ax1, ax2) = plt.subplots(1,2)
patch = PathPatch(path, facecolor='k')
ax1.add_patch(patch)
xmin, ymin = np.min(points, axis=0)
xmax, ymax = np.max(points, axis=0)
ax1.set_ylim(ymin,ymax)
ax1.set_xlim(xmin,xmax)
ax1.set_aspect('equal')

nx, ny = 4, 4
x = np.linspace(xmin, xmax, nx)
y = np.linspace(ymin, ymax, ny)
xgrid, ygrid = np.meshgrid(x, y)
pixel_centers = np.c_[xgrid.ravel(), ygrid.ravel()]

def pixel_center_to_corners(x, y, dx, dy, precision=0.):
    """
    Returns array indexed by (pixel, corner, (x,y))
    """

    # make dx and dy ever so slightly smaller,
    # such that the points fall **inside** the path (not **on** the path)
    dx -= precision
    dy -= precision

    return np.array([(x - dx/2., y - dy/2.), # lower left
                     (x + dx/2., y - dy/2.), # lower right
                     (x + dx/2., y + dy/2.), # upper right
                     (x - dx/2., y + dy/2.), # upper left
    ]).transpose([2,0,1])

# get pixel corners
dx = (xmax - xmin) / float(nx)
dy = (ymax - ymin) / float(ny)
pixel_corners = pixel_center_to_corners(pixel_centers[:,0], pixel_centers[:,1], dx, dy)

# test corners of each pixel;
# set img to True, iff any corners within path;
img = np.zeros((len(pixel_corners)))
for ii, pixel in enumerate(pixel_corners):
    is_inside_path = path.contains_points(pixel)
    img[ii] = np.any(is_inside_path)

img = img.reshape(len(x), len(y))
ax2.imshow(img, cmap='gray_r', interpolation='none', origin='lower')

введите здесь описание изображения

person Paul Brodersen    schedule 03.04.2017
comment
Спасибо, что указали мне новое направление. Очень ценю. Я попробую код. - person daniel; 04.04.2017
comment
Пол Кажется, что результаты, отличные от правильных результатов в моем прикрепленном красно-синем чертеже в масштабе блока. В многоугольнике 4 точки, но ваш код дает треугольник? Также код очень медленный. Я могу представить, что на больших полигонах это увеличит время выполнения. - person daniel; 04.04.2017
comment
Попробуйте код для массива 4x4, который соответствует реальным размерам 50 см (ширина и высота повторения узора) в комнате треугольной формы 2 м x 2,5 м, это для использования с алгоритмом подгонки ковра, который я пытаюсь создать. - person daniel; 04.04.2017
comment
Извините, забыл одну LINETO и правильную точку для CLOSEPOLY. Должна теперь получиться трапеция. У меня код выполняется гораздо меньше секунды. contains_points() - это очень тонкая оболочка вокруг C, iirc, поэтому не уверен, сколько вы получите от любого другого наивного подхода (вы запрашиваете точки в произвольных формах; если вы знаете, что форма всегда будет трапецией, вы можете сделать лучше). Кроме того, как точно вы можете разрезать свои ковры? Вы не должны запускать код с точностью, превышающей вашу максимальную точность. Ложимся спать сейчас, вернемся утром (через 8+ часов). - person Paul Brodersen; 04.04.2017
comment
Пол, это блестяще работает как шарм. Большое спасибо за ответ. - person daniel; 04.04.2017
comment
Рад помочь. Если у вас все работает, можете ли вы принять ответ, пожалуйста? - person Paul Brodersen; 04.04.2017
comment
Павел, извините за боль, все еще есть проблема с первой частью кода. - person daniel; 04.04.2017
comment
Я виню пользователя. ;-Р Что это? - person Paul Brodersen; 04.04.2017
comment
img = path.contains_points(pixel_coordinates).reshape(nx,ny). Это дает неправильные результаты по сравнению с рисованием этого многоугольника вручную по сетке 4x4, как показано на моем рисунке выше. За пределами формы должно быть 3 ячейки, а не 7, которые создает эта часть кода. Извините за это, но это то, на что я тоже натыкаюсь. - person daniel; 04.04.2017
comment
Хорошо, я думаю, что наконец правильно понял вашу проблему. Дай мне пару минут; это потребует некоторой перезаписи. - person Paul Brodersen; 04.04.2017
comment
Пол эти точки одинаковы [[0L,0L], [400L,350L], [400L,400L], [0L,400L], [0L, 0L]] также x на моих шнурах справа, а y внизу не что это имеет какое-то значение. Как видно из моего эскиза, первая и вторая точки явно пересекают следующий набор ячеек. Проверка кода, спасибо, Мэти - person daniel; 04.04.2017