How to write simple geometric shapes into numpy arrays How to write simple geometric shapes into numpy arrays python python

How to write simple geometric shapes into numpy arrays


The usual way is to define a coordinate mesh and apply your shape's equations. To do that the easiest way is to use 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 helperxx, yy = numpy.mgrid[:200, :200]# circles contains the squared distance to the (100, 100) point# we are just using the circle equation learnt at schoolcircle = (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 shapedonut = numpy.logical_and(circle < (6400 + 60), circle > (6400 - 60))


Cairo is a modern, flexible and fast 2D graphics library. It has Python bindings and allows creating "surfaces" based on NumPy arrays:

import numpyimport cairoimport mathdata = 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 whitecr.set_source_rgb(1.0, 1.0, 1.0)cr.paint()# draw red circlecr.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 outputprint data[38:48, 38:48, 0]surface.write_to_png("circle.png")

This code prints

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

showing some random fragment of the circle. It also creates this PNG:

Red circle


Another possibility is to use scikit-image. You can use circle_perimeter for a hollow or circle for a full circle.

You can draw a single stroke circle like so:

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

You can also emulate a stroke by using a loop. In this case you should use the anti-aliased version to avoid artifacts:

import matplotlib.pyplot as pltfrom skimage import drawarr = 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] = 1plt.imshow(arr)plt.show()

A probably more efficient way is to generate two full circles and "subtract" the inner from the outer one:

import matplotlib.pyplot as pltfrom skimage import drawarr = np.zeros((200, 200))stroke = 3# Create an outer and inner circle. Then subtract the inner from the outer.radius = 80inner_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] = 1arr[ri, ci] = 0plt.imshow(arr)plt.show()

The two methods yield in fact slightly different results.

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