2012-04-05 60 views
22

Tôi muốn tạo ra một mảng có kích thước 200x200 kích thước và đặt vào nó một vòng tròn tập trung vào 100,100 tọa độ, bán kính 80 và độ rộng nét 3 pixel. Làm thế nào để làm điều này trong python 2,7 mà không liên quan đến hoạt động tập tin? Có thể sử dụng thư viện hình học hoặc hình ảnh để cho phép khái quát hóa các hình dạng khác.Làm thế nào để viết các hình dạng hình học đơn giản thành mảng numpy

Trả lời

17

Cairo là một thư viện đồ họa 2D hiện đại, linh hoạt và nhanh chóng. Nó có Python bindings và cho phép tạo ra "bề mặt" dựa trên mảng NumPy:

import numpy 
import cairo 
import math 
data = numpy.zeros((200, 200, 4), dtype=numpy.uint8) 
surface = cairo.ImageSurface.create_for_data(
    data, cairo.FORMAT_ARGB32, 200, 200) 
cr = cairo.Context(surface) 

# fill with solid white 
cr.set_source_rgb(1.0, 1.0, 1.0) 
cr.paint() 

# draw red circle 
cr.arc(100, 100, 80, 0, 2*math.pi) 
cr.set_line_width(3) 
cr.set_source_rgb(1.0, 0.0, 0.0) 
cr.stroke() 

# write output 
print data[38:48, 38:48, 0] 
surface.write_to_png("circle.png") 

Mã này in

[[255 255 255 255 255 255 255 255 132 1] 
[255 255 255 255 255 255 252 101 0 0] 
[255 255 255 255 255 251 89 0 0 0] 
[255 255 255 255 249 80 0 0 0 97] 
[255 255 255 246 70 0 0 0 116 254] 
[255 255 249 75 0 0 0 126 255 255] 
[255 252 85 0 0 0 128 255 255 255] 
[255 103 0 0 0 118 255 255 255 255] 
[135 0 0 0 111 255 255 255 255 255] 
[ 1 0 0 97 254 255 255 255 255 255]] 

hiển thị một số đoạn ngẫu nhiên của vòng tròn. Nó cũng tạo PNG này:

Red circle

+0

Vì tôi đang làm việc với dữ liệu màu xám (8bit) đang sử dụng các mục sau: \ dữ liệu = numpy.zeros ((200, 200), dtype = numpy.uint8) \ surface = cairo.ImageSurface.create_for_data (dữ liệu, cairo.FORMAT_A8, 200, 200) \ #to vẽ một bề mặt màu xám 50% (giá trị alpha được sử dụng) \ cr.set_source_rgba (0, 0, 0, 0.5) – a1an

+0

Nếu ai đó đang cố gắng sử dụng ví dụ này với thư viện cairocffi, nó sẽ không hoạt động. Đây là một vấn đề trên repo cairocffi mà đi vào chi tiết hơn: https: // github.com/Kozea/cairocffi/issues/51 – neelshiv

6

opencv bindings python mới import cv2 tạo mảng NumPy như là định dạng hình ảnh mặc định

Chúng bao gồm drawing functions

+0

Mảng đầu ra có định dạng nào? Chỉ cần một danh sách các tọa độ hoặc một mạng lưới nhị phân? –

+0

Đó là một hình ảnh = ví dụ điển hình là một mảng numpy 2d, bạn có thể thực hiện tất cả các hoạt động bình thường trên chúng và lưu ở mọi định dạng hình ảnh –

+0

Tuyệt vời, cảm ơn bạn đã cập nhật @Martin –

31

Cách thông thường là để xác định một điều phối lưới và áp dụng phương trình của hình dạng của bạn. Để làm điều đó một cách đơn giản nhất là sử dụng numpy.mgrid:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.mgrid.html

# xx and yy are 200x200 tables containing the x and y coordinates as values 
# mgrid is a mesh creation helper 
xx, yy = numpy.mgrid[:200, :200] 
# circles contains the squared distance to the (100, 100) point 
# we are just using the circle equation learnt at school 
circle = (xx - 100) ** 2 + (yy - 100) ** 2 
# donuts contains 1's and 0's organized in a donut shape 
# you apply 2 thresholds on circle to define the shape 
donut = numpy.logical_and(circle < (6400 + 60), circle > (6400 - 60)) 
+0

tôi không bao giờ biết numpy có thể làm điều đó! –

+2

@MartinBeckett mgrid cho phép bạn đánh giá các hàm trên một loạt các giá trị. Lưu ý rằng bạn không bị giới hạn ở 2 thứ nguyên. – Simon

+2

Trên một mặt lưu ý, tôi tìm thấy 'donut = (vòng tròn <(6400 + 60)) và (vòng tròn> (6400 - 60))' có thể đọc được nhiều hơn một cách rõ ràng gọi 'logical_and'. Đó là một vấn đề sở thích cá nhân, mặc dù. Chúng chính xác tương đương. (Lưu ý rằng '&' sẽ gọi 'numpy.logical_and', trong khi' và' không thể bị ghi đè.) –

2

Một khả năng khác là sử dụng scikit-image. Bạn có thể sử dụng circle_perimeter cho hình tròn rỗng hoặc circle để có hình tròn đầy đủ.

Bạn có thể vẽ một vòng tròn đột quỵ duy nhất như vậy:

import matplotlib.pyplot as plt 
from skimage import draw 
arr = np.zeros((200, 200)) 
rr, cc = draw.circle_perimeter(100, 100, radius=80, shape=arr.shape) 
arr[rr, cc] = 1 
plt.imshow(arr) 
plt.show() 

Bạn cũng có thể bắt chước một cơn đột quỵ bằng cách sử dụng một loop. Trong trường hợp này bạn nên sử dụng phiên bản anti-aliased để tránh hiện vật:

import matplotlib.pyplot as plt 
from skimage import draw 
arr = np.zeros((200, 200)) 
stroke = 3 
# Create stroke-many circles centered at radius. 
for delta in range(-(stroke // 2) + (stroke % 2), (stroke + 1) // 2): 
    rr, cc, _ = draw.circle_perimeter_aa(100, 100, radius=80+delta, shape=arr.shape) 
    arr[rr, cc] = 1 
plt.imshow(arr) 
plt.show() 

Một cách có thể hiệu quả hơn là để tạo ra hai vòng tròn đầy đủ và "trừ" bên trong từ bên ngoài một:

import matplotlib.pyplot as plt 
from skimage import draw 
arr = np.zeros((200, 200)) 
stroke = 3 
# Create an outer and inner circle. Then subtract the inner from the outer. 
radius = 80 
inner_radius = radius - (stroke // 2) + (stroke % 2) - 1 
outer_radius = radius + ((stroke + 1) // 2) 
ri, ci = draw.circle(100, 100, radius=inner_radius, shape=arr.shape) 
ro, co = draw.circle(100, 100, radius=outer_radius, shape=arr.shape) 
arr[ro, co] = 1 
arr[ri, ci] = 0 
plt.imshow(arr) 
plt.show() 

Hai phương pháp mang lại kết quả hơi khác nhau.

Circle with <code>stroke=3</code>

Các vấn đề liên quan