2012-04-05 48 views
22

我想生成一个大小为200x200的元素的numpy数组,并放入一个以100,100坐标,半径80和笔划宽度为3像素为中心的圆。如何在不涉及文件操作的情况下在python 2.7中执行此操作?可能使用几何或图像库来推广到其他形状。如何将简单的几何形状写入numpy数组

回答

17

Cairo是一个现代化的,灵活和快速的2D图形库。它有Python bindings和允许创建基于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") 

此代码打印

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

示出的圆的一些随机片段。它还会创建这个PNG:

Red circle

+0

由于我使用灰度(8位)数据I使用以下内容:\ data = numpy.zeros((200,200),dtype = numpy.uint8)\ surface = cairo.ImageSurface.create_for_data(data,cairo.FORMAT_A8,200,200)\ #绘制50%灰色表面(使用alpha值)\ cr.set_source_rgba(0,0,0,0.5) – a1an 2012-04-10 08:51:53

+0

如果有人试图将此示例与cairocffi库一起使用,它将无法工作。下面是关于cairocffi repo的一个问题,详细介绍如下:https:// github。com/Kozea/cairocffi/issues/51 – neelshiv 2016-09-28 01:03:17

6

OpenCV的新的python绑定import cv2创建numpy的数组作为默认的图像格式

它们包括drawing functions

+0

输出数组有什么格式?只是坐标列表或二进制网格? – 2012-06-22 14:43:26

+0

这是一个图像=即通常是一个2D的numpy数组,你可以对它们进行所有正常的numpy操作并以任何图像格式保存 – 2012-06-22 14:46:56

+0

非常感谢您的更新@Martin – 2012-06-22 14:56:35

31

的常用方法是定义一个坐标网格并应用形状的方程。要做到这一点最简单的方法是使用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

我从来不知道numpy能做到这一点! – 2012-04-06 14:47:57

+2

@MartinBeckett mgrid允许您评估一系列值的函数。请注意,您不限于2个维度。 – Simon 2012-04-06 15:11:40

+2

在附注中,我发现'donut =(circle <(6400 + 60))&(circle(6400 - 60))'比明确调用'logical_and'更可读。不过,这是个人喜好的问题。他们完全相同。 (注意,'&'会调用'numpy.logical_and',尽管'and'不能被覆盖。) – 2012-04-06 17:13:16

2

另一种可能性是使用scikit-image。您可以将circle_perimeter用于镂空或circle整圈。

您可以绘制一个冲程,像这样:

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

您也可以通过使用loop模拟中风。在这种情况下,你应该使用反走样版本,以避免工件:

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

一个可能更有效的方法是产生两个完整的圆,并且从外一个“减”内:

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

这两种方法实际上产生的结果稍有不同。

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