Grey Aycock
Grey Aycock

Reputation: 15

How to create a filled in circle within an array of pixels

I am having trouble creating a method that can create a FILLED IN circle within a 2d array of pixels. So far, the Image class I have created can create a 2d array of pixels, change individual pixel values, etc. What I have been able to complete so far is use Bresenham's circle algorithm to create a hollow circle of any radius around any given point in the array. I cannot, however, figure out how to make this circle filled in.

I am open to any solution! I have tried creating a "flood fill" method, only to be greeted by various recursion errors. I have also tried just calling the circleBres method several times with decrementing radii, but this does not work either. For the sake of space, just assume that the writePixel method works.

class Image:

    def drawCircle(self, centerX, centerY, x, y):
    self.writePixel(centerX + x, centerY + y, 50.0)
    self.writePixel(centerX - x, centerY + y, 50.0)
    self.writePixel(centerX + x, centerY - y, 50.0)
    self.writePixel(centerX - x, centerY - y, 50.0)
    self.writePixel(centerX + y, centerY + x, 50.0)
    self.writePixel(centerX - y, centerY + x, 50.0)
    self.writePixel(centerX + y, centerY - x, 50.0)
    self.writePixel(centerX - y, centerY - x, 50.0)

    def circleBres(self, xc, yc, r):
        x = 0
        y = r
        d = 3 - (2*r)
        self.drawCircle(xc, yc, x, y)
        while(y>=x):
            x+=1
            if(d>0):
                y-=1
                d = d+4*(x-y)+10
            else:
                d = d + 4 * x + 6
            self.drawCircle(xc, yc, x, y)
            time.sleep(.06)

obj = Image(50, 50, 51.0)
obj.circleBres(35, 35, 10)

The Image constructor's third parameter is the value that all pixels are assigned upon creation (51.0), and the third parameter of the writePixel method is the value that the pixel is being changed to (50.0).

Any help is greatly appreciated. Thanks!

Upvotes: 0

Views: 1008

Answers (2)

MBo
MBo

Reputation: 80187

When you write

self.writePixel(centerX + x, centerY + y, 50.0)
self.writePixel(centerX - x, centerY + y, 50.0)

you draw the leftmost and the rightmost pixels of some scanline.

To fill it, just make for loops instead of these 8 lines:

for xx in range(centerX - x, centerX + x + 1):
    self.writePixel(xx, centerY + y, 50.0)
    self.writePixel(xx, centerY - y, 50.0)
for xx in range(centerX - y, centerX + y):
    self.writePixel(centerX + y, centerY + x, 50.0)
    self.writePixel(centerX - y, centerY - x, 50.0)

Upvotes: 1

Stephen C
Stephen C

Reputation: 2036

Here's an example of how I would handle a problem like this:

Assuming you have a correct outline of circle, just iterate through the rows and fill all pixels between edges of the circle.

grid = [
    [0,0,0,1,1,1,0,0,0],
    [0,0,1,0,0,0,1,0,0],
    [0,1,0,0,0,0,0,1,0],
    [0,1,0,0,0,0,0,1,0], 
    [0,0,1,0,0,0,1,0,0],
    [0,0,0,1,1,1,0,0,0],  
]

def fill_circle(grid):
    for r in grid:  # For each row
        j1 = None  # left endpoint
        j2 = None  # right endpoint
        for j, v in enumerate(r):
            if v == 1 and j1 is None:
                j1 = j
                continue
            if v == 1 and j2 is None:
                j2 = j
                break
        else:  # Did not find j1 AND j2
            continue
        for j in range(j1, j2):  # Fill all points between
            r[j] = 1

fill_circle(grid)
grid

[[0,0,0,1,1,1,0,0,0],
 [0,0,1,1,1,1,1,0,0],
 [0,1,1,1,1,1,1,1,0],
 [0,1,1,1,1,1,1,1,0], 
 [0,0,1,1,1,1,1,0,0],
 [0,0,0,1,1,1,0,0,0]]

Upvotes: 0

Related Questions