簡體   English   中英

如何獲取python中多邊形內的點列表?

[英]How to get list of points inside a polygon in python?

我搜索了很多,無法找到我的問題的任何實際答案。 我有一個多邊形。 例如:

    [(86, 52), (85, 52), (81, 53), (80, 52), (79, 48), (81, 49), (86, 53),
     (85, 51), (82, 54), (84, 54), (83, 49), (81, 52), (80, 50), (81, 48),
     (85, 50), (86, 54), (85, 54), (80, 48), (79, 50), (85, 49), (80, 51),
     (85, 53), (82, 49), (83, 54), (82, 53), (84, 49), (79, 49)]

我想得到這個邊界多邊形內的所有點的列表。 我聽說很多關於多邊形三角測量技術或線性/泛光/交叉/ ......填充算法。 但我真的想出一個有效的方法來實現這一點。 這個多邊形很小,想象一個有10億個點的多邊形。 我現在使用PIL繪制多邊形用紅色填充多邊形並在其中循環以找到紅點。 這是一種非常緩慢的技術:

def render(poly, z):
    xs = [i[0] for i in poly]
    ys = [i[1] for i in poly]
    minx, maxx = min(xs), max(xs)
    miny, maxy = min(ys), max(ys)
    X = maxx - minx + 1
    Y = maxy - miny + 1
    newPoly = [(x - minx, y - miny) for (x, y) in polygons]
    i = Image.new("RGB", (X, Y))
    draw = ImageDraw.Draw(i)
    draw.polygon(newPoly, fill="red")
    # i.show()
    tiles = list()
    w, h = i.size
    print w, h
    for x in range(w):
        for y in range(h):
            data = i.getpixel((x, y))
            if data != (0, 0, 0):
                tiles.append((x + minx, y + miny))

    return tiles

我正在尋找一種解決這個問題的Pythonic方法。 謝謝你們。

我建議使用matplotlib contains_points()

from matplotlib.path import Path

tupVerts=[(86, 52), (85, 52), (81, 53), (80, 52), (79, 48), (81, 49), (86, 53),
 (85, 51), (82, 54), (84, 54), (83, 49), (81, 52), (80, 50), (81, 48),
 (85, 50), (86, 54), (85, 54), (80, 48), (79, 50), (85, 49), (80, 51),
 (85, 53), (82, 49), (83, 54), (82, 53), (84, 49), (79, 49)]


x, y = np.meshgrid(np.arange(300), np.arange(300)) # make a canvas with coordinates
x, y = x.flatten(), y.flatten()
points = np.vstack((x,y)).T 

p = Path(tupVerts) # make a polygon
grid = p.contains_points(points)
mask = grid.reshape(300,300) # now you have a mask with points inside a polygon

我認為繪制多邊形並填充它是一個很好的開始,無論如何你都需要這樣的東西,這些算法通常在C中進行微調。但是不要使用RGB圖像,使用黑/白圖像,使用numpy.where()來查找它為1的像素。

根據這個問題mahotas庫有一個fill_polygon函數,可以使用numpy數組。

我從你的函數開始下面的代碼(我也會減去minxmaxx )但請注意我根本無法測試它,我不在我的開發機器上。

import numpy as np
import mahotas

def render(poly): # removed parameter 'z'
    xs = [i[0] for i in poly]
    ys = [i[1] for i in poly]
    minx, maxx = min(xs), max(xs)
    miny, maxy = min(ys), max(ys)
    X = maxx - minx + 1
    Y = maxy - miny + 1
    newPoly = [(x - minx, y - miny) for (x, y) in poly]           

    grid = np.zeros((X, Y), dtype=np.int8)
    mahotas.polygon.fill_polygon(newPoly, grid)

    return [(x + minx, y + miny) for (x, y) in np.where(grid)]

您可以使用像二進制圖像這樣的numpy矩陣,例如可以與Opencv或其他圖像處理庫一起使用, 解決方案1因此矩陣的大小為L x H

L=max(x) - min (x)
H=max(y) - min (y)

作為條目我們有你的元組列表(x,y),你在上面給出了哪個名稱為poly ,例如:

import numpy as np
matrix =np.zeros((L,H),dtype=np.int32) # you can use np.uint8 if unsigned x ,y

所以我們現在有一個填充0的大小為L x H的矩陣,我們現在將1放在多邊形點位置

我想你可以這么簡單

matrix[poly]=1  # which will put 1 at each (x,y) of the list **poly**

我們將其解釋為二進制(黑/白)圖像,其上繪制有輪廓。假設我們想要檢測這個新輪廓

import cv2 # opencv import
ContoursListe,hierarchy = cv2.findContours(self.thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
poly2=ContoursListe[0] # we take the first only contour

注意: poly2包含多邊形的點列表以及形成它的所有點,我的意思是你需要的多邊形的每個頂點的所有點都可以找到有用的!! 您可以使用cv2.CHAIN_APPROX_SIMPLE參數來獲取僅包含多邊形線的端點的poly2,它更輕,這是我們的輸入:) 重要 :poly2的類型是numpy數組,它的形狀是(n,1,2)而不是(N,2)

現在我們在這個圖像(矩陣)上繪制這個輪廓並填充它:)

cv2.drawContours(matrix,[poly2],-1,(1),thickness=-1) thickness=-1

現在我們有一個矩陣,其中每個點上形成1並填充多邊形,“thickness = -1”強制填充此輪廓,如果要翻譯,可以設置厚度= 1以僅獲取邊框,可以通過添加參數偏移量(xtran,ytrans)來實現

得到所有這些點的索引只需調用

list_of_points_indices=numpy.nonzero(matrix)

解決方案2

更聰明的是直接將點列表(poly)轉換為輪廓格式(poly2)並將其繪制在矩陣上

poly2=poly.reshape(-1,1,2).astype(np.int32)

並在Matrix矩陣上繪制它

matrix =np.zeros((L,H),dtype=np.int32)

cv2.drawContours(matrix,[poly2],-1,(1),thickness=-1)

並獲得這些點的列表:

list_of_points_indices=numpy.nonzero(matrix)

使用厚度來填充或不填充多邊形,請參閱解決方案1以獲取更多詳細信息。

基於RemcoGerlich的答案,這是一個經過驗證的函數:

import numpy as np
import mahotas

def render(poly):
    """Return polygon as grid of points inside polygon.

    Input : poly (list of lists)
    Output : output (list of lists)
    """
    xs, ys = zip(*poly)
    minx, maxx = min(xs), max(xs)
    miny, maxy = min(ys), max(ys)

    newPoly = [(int(x - minx), int(y - miny)) for (x, y) in poly]

    X = maxx - minx + 1
    Y = maxy - miny + 1

    grid = np.zeros((X, Y), dtype=np.int8)
    mahotas.polygon.fill_polygon(newPoly, grid)

    return [(x + minx, y + miny) for (x, y) in zip(*np.nonzero(grid))]

例:

poly = [
    [0, 0],
    [0, 10],
    [10, 10],
    [10, 0]
]

plt.figure(None, (5, 5))
x, y = zip(*render(poly))
plt.scatter(x, y)
x, y = zip(*poly)
plt.plot(x, y, c="r")
plt.show()

在此輸入圖像描述

試試這個代碼。 poly_coords是多邊形的坐標,'coord'是要檢查它是否在多邊形內部的點的坐標。

def testP(coord, poly_coords):
    """
    The coordinates should be in the form of list of x and y
    """
    test1 = n.array(poly_coords)
    test2 = n.vstack((poly_coords[1:], poly_coords[:1]))
    test  = test2-test1
    m = test[:,1]/test[:,0]
    c = test1[:,1]-m*test1[:,0]
    xval = (coord[1]-c)/m
    print 'xVal:\t'; print xval
    print (test1[:,0]-xval)*(test2[:,0]-xval)
    check = n.where((xval>=coord[0])&((test1[:,0]-xval)*(test2[:,0]-xval)<0))[0]
    print check
    print len(check)
    if len(check)%2==0:
        return False
    else:
        return True

如果你想讓它更快,請取出與多邊形,斜率和偏移相關的算法部分,並使用“map”函數運行其余代碼。 像這樣的東西:

test1 = n.array( your polygon)
test2 = n.vstack((test1[1:], test1[:1]))
test  = test2-test1
m = test[:,1]/test[:,0]
c = test1[:,1]-m*test1[:,0]

def testP(coord):
    """
    The coordinates should be in the form of list of x and y
    """
    global test, test1, test2, m,c
    xval = (coord[1]-c)/m
    check = n.where((xval>=coord[0])&((test1[:,0]-xval)*(test2[:,0]-xval)<0))[0]
    if len(check)%2==0:
        return False
    else:
        return True
coords = n.array(( your coords in x,y ))
map (testP, coords)

如果需要,您可以刪除'print'命令。 此代碼是為python 2.7而制作的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM