4

Given the center (x,y) and radius r, how one can draw a circle C((x,y),r) in pixel grid using python? It is fine to assume that pixel grid is large enough.

  • Do you want to output a image file, or create an interactive application? If it's interactive, is it for data visualization, or a game? – loopbackbee Jul 20 '15 at 14:39
  • 1
    @goncalopp I want a 2D array containing `0` and `1` such that `1` denote the location of circle. –  Jul 20 '15 at 14:41
  • Have a look into the [Midpoint circle algorithm](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm). Let us know if you struggle with an implementation detail. – Falko Jul 20 '15 at 14:44
  • @Falko Thanks a lot. –  Jul 20 '15 at 14:46
  • If you want to get fancy & draw a smooth circle, take a look at [Fast, Antialiased Circles and Ellipses from Xiaolin Wu’s concepts](https://yellowsplash.wordpress.com/2009/10/23/fast-antialiased-circles-and-ellipses-from-xiaolin-wus-concepts/). The code on that site is in Pascal, but it doesn't look _too_ hard to translate to Python. FWIW, Wu's line algorithm is the standard for drawing antialiased lines; his circle algorithm is less well-known. – PM 2Ring Jul 20 '15 at 14:57

2 Answers2

5

Here's the RosettaCode Midpoint circle algorithm in Python

def circle(self, x0, y0, radius, colour=black):
    f = 1 - radius
    ddf_x = 1
    ddf_y = -2 * radius
    x = 0
    y = radius
    self.set(x0, y0 + radius, colour)
    self.set(x0, y0 - radius, colour)
    self.set(x0 + radius, y0, colour)
    self.set(x0 - radius, y0, colour)

    while x < y:
      if f >= 0: 
        y -= 1
        ddf_y += 2
        f += ddf_y
        x += 1
        ddf_x += 2
        f += ddf_x    
        self.set(x0 + x, y0 + y, colour)
        self.set(x0 - x, y0 + y, colour)
        self.set(x0 + x, y0 - y, colour)
        self.set(x0 - x, y0 - y, colour)
        self.set(x0 + y, y0 + x, colour)
        self.set(x0 - y, y0 + x, colour)
        self.set(x0 + y, y0 - x, colour)
        self.set(x0 - y, y0 - x, colour)
        Bitmap.circle = circle

        bitmap = Bitmap(25,25)
        bitmap.circle(x0=12, y0=12, radius=12)
        bitmap.chardisplay()
A.M.
  • 1,757
  • 5
  • 22
  • 41
  • It's better to make the link text a little more meaningful to guard against link rot. Eg "Here's the RosettaCode [Midpoint circle algorithm](http://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#Python) in Python". True, rosettacode is a rather stable site, but you never know... and it's a good habit to get into on Stack Exchange sites. – PM 2Ring Jul 20 '15 at 15:08
  • @PM2Ring Thanks for the comment. I will fix it. – A.M. Jul 20 '15 at 15:10
  • What if I would like to implement this on matplotlib? – FaCoffee Feb 21 '16 at 17:22
4

Assuming you want to get things done (as opposed to learning raster graphics algorithms), simply use Pillow:

from PIL import Image, ImageDraw
image = Image.new('1', (10, 10)) #create new image, 10x10 pixels, 1 bit per pixel
draw = ImageDraw.Draw(image)
draw.ellipse((2, 2, 8, 8), outline ='white')
print list(image.getdata())

output:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 0, 255, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 255, 0, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

The range is 0..255 because Pillow stores a byte-per-pixel even for a 1-bit-per-pixel image (as its more efficient).

If you want the range on 0..1, you can then divide by 255:

[x/255 for x in image.getdata()]
loopbackbee
  • 21,962
  • 10
  • 62
  • 97