2010-09-06 47 views
20

Tôi cần tạo một mảng 2D dạng khối đại diện cho mặt nạ nhị phân của đa giác, sử dụng các gói Python chuẩn.SciPy Tạo Mặt nạ đa giác 2D

  • đầu vào: các đỉnh đa giác, kích thước hình ảnh
  • đầu ra: mặt nạ nhị phân của đa giác (mảng 2D NumPy)

(bối cảnh lớn hơn: Tôi muốn để có được những khoảng cách biến đổi của đa giác này bằng scipy. ndimage.morphology.distance_transform_edt.)

Có ai có thể chỉ cho tôi cách thực hiện việc này không?

Trả lời

39

Câu trả lời hóa ra là khá đơn giản:

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

Tôi sử dụng chế độ hình ảnh 'L', không phải '1', vì Numpy-1.5.0/PIL-1.1.7 không hỗ trợ 'numpy.array (img) 'chuyển đổi độc đáo cho hình ảnh bivalue. Phần trên cùng của mảng chứa 8 subimages nhỏ 1/8 kích thước mặt nạ dự kiến, với 7/8 còn lại của mảng chứa đầy rác. Có lẽ việc chuyển đổi không giải nén dữ liệu nhị phân đúng cách? –

+1

Tôi nghĩ rằng phương pháp này chỉ hoạt động với các tọa độ nguyên mặc dù (tức là tọa độ lưới). Nếu tọa độ đỉnh là nổi, thì giải pháp kia vẫn hoạt động. –

+0

từ: @jmetz "Chỉ cần FYI: Tôi đã làm một thử nghiệm thời gian đơn giản và cách tiếp cận PIL là ~ 70 lần nhanh hơn so với phiên bản matplotlib !!!" – Jakobovski

2

Bạn có thể thử sử dụng Thư viện hình ảnh của python, PIL. Trước tiên, bạn khởi tạo canvas. Sau đó, bạn tạo một đối tượng vẽ và bạn bắt đầu tạo các dòng. Điều này giả định rằng đa giác nằm trong R^2 và danh sách đỉnh cho đầu vào theo đúng thứ tự.

Input = [(x1, y1), (x2, y2), ..., (xn, yn)], (chiều rộng, chiều cao)

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

này những gì bạn đang tìm kiếm là, hoặc bạn hỏi cái gì khác?

+1

Cảm ơn Anil, đó là những gì tôi đang tìm kiếm. Sẽ tốt hơn nếu bạn sử dụng phương thức ImageDraw.polygon (ImageDraw.Draw (img) .polygon (đỉnh, phác thảo = 1, điền = 1)), và tôi đã sử dụng hàm numpy.reshape để lấy một mảng 2D từ dữ liệu ảnh một cách hiệu quả (import numpy, M = numpy.reshape (danh sách (img.getdata()), (chiều cao, chiều rộng))). Tôi sẽ chấp nhận câu trả lời của bạn nếu bạn chỉnh sửa nó để bao gồm những thứ này. –

22

Là một thay thế trực tiếp hơn một chút cho câu trả lời của @ Anil, matplotlib có matplotlib.nxutils.points_inside_poly có thể được sử dụng để nhanh chóng rasterize một đa giác tùy ý. Ví dụ.

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 

nào mang lại (một mảng NumPy boolean):

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

Bạn sẽ có thể vượt qua grid với bất kỳ chức năng scipy.ndimage.morphology khá độc đáo.

+0

Tôi đã tránh sử dụng points_inside_poly bởi vì nó hoạt động với một danh sách các tọa độ chứ không phải là hoạt động trên một hình ảnh nhị phân trực tiếp. Bởi vì điều này, và bởi vì PIL có thể sử dụng khả năng tăng tốc phần cứng để render đa giác của tôi, nó xuất hiện với tôi rằng giải pháp của Anil hiệu quả hơn. –

+1

@Issac - Đủ công bằng. Theo như tôi biết, PIL không sử dụng tăng tốc phần cứng của bất kỳ loại nào, mặc dù ... (Có thay đổi gần đây?) Ngoài ra, nếu bạn sử dụng PIL, không cần phải làm 'M = numpy.reshape (danh sách (img .getdata()), (chiều cao, chiều rộng))) 'như bạn đã đề cập trong nhận xét ở trên. 'numpy.array (img)' thực hiện chính xác điều đó, hiệu quả hơn nhiều. –

+1

Rất xa! Cảm ơn bạn đã chỉ ra chức năng numpy.array (img). Và, đúng, PIL có lẽ vẫn không sử dụng tăng tốc phần cứng. –

8

Cập nhật về bình luận của Joe. API Matplotlib đã thay đổi kể từ khi nhận xét đã được đăng và bây giờ bạn cần sử dụng phương thức được cung cấp bởi một mô-đun con matplotlib.path.

Mã hoạt động bên dưới.

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 
Các vấn đề liên quan