2010-09-06 25 views
20

Standart Python paketlerini kullanarak bir çokgenin ikili maskesini temsil eden sayısal bir 2D dizi oluşturmam gerekiyor.SciPy 2B Poligon Maskesi Oluşturun

  • girişi: çokgen özet olarak, resim boyutları
  • çıkışı: çokgenin ikili maske (numpy 2D dizi)

(büyük içerik: I mesafe scipy kullanarak bu çokgen dönüşümü elde etmek istiyorum. ndimage.morphology.distance_transform_edt.)

Bunu nasıl yapacağımı bana kimse gösterebilir mi?

cevap

39

cevap oldukça basit olduğu ortaya çıkıyor:

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) 
+0

float tipindeysem ne yapmalıyım? 'L' değil, '1' görüntü modunu kullanıyorum çünkü Numpy-1.5.0/PIL-1.1.7 'numpy.array öğesini desteklemiyor (img) 'bivalue görüntüler için güzel bir dönüşüm. Dizinin üst kısmı, beklenen maske boyutunun 1/8'inde 8 küçük alt görüntü içerir ve dizinin kalan 7/8'i çöple doldurulur. Belki de dönüşüm ikili verileri düzgün bir şekilde açmaz mı? –

+1

Bu yöntemin yalnızca tamsayı koordinatlarıyla birlikte çalıştığını düşünüyorum (ör. Izgara koordinatları). Köşe koordinatları yüzerse, diğer çözüm hala çalışır. –

+0

from: @jmetz "Just FYI: Basit bir zamanlama testi yaptım ve PIL yaklaşımı matplotlib versiyonundan ~ 70 kat daha hızlı!" – Jakobovski

2

Python'un Image Library, PIL. Önce tuvali başlatırsın. Sonra bir çizim nesnesi oluşturursun ve çizgiler yapmaya başlarsın. Bu, poligonun R^2'de bulunduğunu ve girişin köşe listesinin doğru sırada olduğunu varsayar.

Girdi = [(x1, y1), (x2, y2), ..., (xn yn)], (genişlik, yükseklik)

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

sen aradığını bu, mi ya da farklı bir şey mi soruyordun?

+1

Teşekkürler Anil, temel olarak aradığım şey buydu. ImageDraw.polygon yöntemini (ImageDraw.Draw (img) .polygon (vertices, anahat = 1, fill = 1)) kullanırsanız ve görüntü verisinden bir 2D dizisini verimli bir şekilde almak için numpy.reshape işlevini kullandım. (import numpy, M = numpy.reshape (liste (img.getdata()), (yükseklik, genişlik))). Bunları dahil etmek için düzenlerseniz cevabınızı kabul edeceğim. –

22

@ Anil'ın yanıtına biraz daha doğrudan bir alternatif olarak, matplotlib hızlı bir şekilde rasgele bir çokgeni rasterleştirmek için kullanılabilen matplotlib.nxutils.points_inside_poly'a sahiptir. Örneğin. verir

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 

(bir boolean numpy dizisi):

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

Oldukça güzel scipy.ndimage.morphology özelliklerden herhangi bir grid geçmesi gerekir.

+0

points_inside_poly'yi kullanmaktan kaçınıyordum çünkü doğrudan bir ikili görüntü üzerinde çalışmak yerine bir koordinat listesiyle çalışıyor. Bu nedenle ve PIL poligonumu oluşturmak için donanım hızlandırmayı kullanabileceğinden, bana Anıl'ın çözümünün daha verimli olduğunu görün. –

+1

@Issac - Yeterince adil. Bildiğim kadarıyla PIL, herhangi bir türdeki donanım ivmesini kullanmıyor, ancak ... (Son zamanlarda değişti mi?) Ayrıca, PIL kullanıyorsanız, M = numpy.reshape (list (img) yapmanıza gerek yoktur. .getdata()), (yükseklik, genişlik))) Yukarıdaki yorumunuzda belirtildiği gibi. numpy.array (img), aynı şeyi çok daha verimli bir şekilde yapar. –

+1

Uzakta! Numpy.array (img) işlevselliğini işaretlediğiniz için teşekkür ederiz. Ve gerçek, PIL muhtemelen donanım hızlandırmayı hala kullanmıyor. –

8

Joe'nun yorumun ilgili bir güncelleme. Matplotlib API, yorum gönderildikten sonra değişti ve şimdi bir alt modülden matplotlib.path tarafından sağlanan bir yöntemi kullanmanız gerekiyor.

Çalışma kodu aşağıdadır.

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