def bfs(self, image, start_pixel_pos, color):
        pixels = image.load()
        width, height = get_image_size(image)
        queue = []
        copy = []
        count = 0
        queue.append(start_pixel_pos)
        original = pixels[start_pixel_pos]

        while 0 < len(queue):
            (x, y) = queue.pop(0)
            current = pixels[x, y]
            if current == original or current == color:
                for pos_x in [-1, 0, 1]:
                    for pos_y in [-1, 0, 1]:
                        pixel_x = x + pos_x
                        pixel_y = y + pos_y
                        if pixel_x >= 0 and pixel_x < width and pixel_y >= 0 and pixel_y < height:
                            pixel_data = pixels[pixel_x, pixel_y]
                            if pixel_data == original:
                                pixels[pixel_x, pixel_y] = color
                                queue.append((pixel_x, pixel_y))
                                copy.append((pixel_x, pixel_y))
                                count += 1
        return image, count, copy

    def detect_forms(self, image):
        pixels = image.load()
        width, height = get_image_size(image)
        percentages = []
        all_colors = []
        can_be_ellipses = []

        for i in range(width):
            for j in range(height):
                if pixels[i, j] == (255, 255, 255):
                    r = random.randint(150, 255)
                    g = random.randint(150, 255)
                    b = random.randint(150, 255)
                    image, count, copy = self.bfs(image, (i, j), (r, g, b))
                    per = float(count)/float(width * height)
                    percentages.append(per)
                    all_colors.append((r, g, b))
                    pixels = image.load()
                    can_be_ellipses.append(copy)
        return can_be_ellipses, image

    def search_ellipse(self, can_be_ellipses, image, Gx, Gy):
        width, height = get_image_size(image)
        pixels_gx = Gx.load()
        pixels_gy = Gy.load()
        l = 80
        ellipses_found = []

        for ellipse in can_be_ellipses:
            pixels = image.load()
            votes = []

            for i in range(width):
                votes.append([0] * height)

            for i in range(100):
                P1 = random.choice(ellipse)
                P2 = random.choice(ellipse)
                px1 = P1[0]
                py1 = P1[1]
                px2 = P2[0]
                py2 = P2[1]

                Mx = (px1 + px2)/2
                My = (py1 + py2)/2

                gx1 = pixels_gx[px1, py1][0]
                gy1 = pixels_gy[px1, py1][0]
                gx2 = pixels_gx[px2, py2][0]
                gy2 = pixels_gy[px2, py2][0]

                if abs(gx1) + abs(gy1) <= 0:
                    theta = None
                else:
                    theta = math.atan2(gy1, gx1)
                    theta -= math.pi/2
                    x0 = px1 - l * math.cos(theta)
                    y0 = py1 - l * math.sin(theta)
                    x1 = px1 + l * math.cos(theta)
                    y1 = py1 + l * math.sin(theta)

                if abs(gx2) + abs(gy2) <= 0:
                    theta = None
                else:
                    theta = math.atan2(gy2, gx2)
                    theta -= math.pi/2
                    x2 = px2 - l * math.cos(theta)
                    y2 = py2 - l * math.sin(theta)
                    x3 = px2 + l * math.cos(theta)
                    y3 = py2 + l * math.sin(theta)

                try:
                    Tx = ((x0*y1-y0*x1)*(x2-x3)-(x0-x1)*(x2*y3-y2*x3))/((x0-x1)*(y2-y3)-(y0-y1)*(x2-x3))
                    Ty = ((x0*y1-y0*x1)*(y2-y3)-(y0-y1)*(x2*y3-y2*x3))/((x0-x1)*(y2-y3)-(y0-y1)*(x2-x3))
                    Kx = Tx - Mx
                    Ky = Ty - My
                    m = Ky/Kx
                    x0 = Mx
                    y0 = My
                    while True:
                        x = int(x0 + 1)
                        y = int(m*(x - x0) + y0)
                        if pixels[x, y] == (0, 0, 0):
                            votes[x][y] += 1
                            x0 = x
                            y0 = y
                        else:
                            break
                except:
                    pass

            morevotes = 0
            for x in range(width):
                for y in range(height):
                    v = votes[x][y]
                    if v > morevotes:
                        morevotes = v
                        center_x = x
                        center_y = y

            for coord in ellipse:
                x, y = coord
                if center_x == x:
                    ydiameter = abs(center_y - y)
                if center_y == y:
                    xdiameter = abs(center_x - x)

            ellipses_found.append((center_x, center_y, xdiameter, ydiameter))
        return ellipses_found

    def draw_ellipses_found(self, image, ellipses_found):
        draw = ImageDraw.Draw(image)
        max_w, max_h = get_image_size(image)
        counter_circle = 1
        counter_ellipse = 1

        for ellipse in ellipses_found:
            x, y, xd, yd = ellipse
            r = random.randint(100, 255)
            g = random.randint(100, 255)
            b = random.randint(100, 255)
            image, count, copy = self.bfs(image, (x, y), (r, g, b))
            percentage = (count * 100)/(SIZE**2)
            if abs(xd - yd) < 20:
                print '\nCircle %d detected at center (%d, %d)' % (counter_circle, x, y)
                print '> Radio', xd
                print '> %.1f%% of all the image' % percentage
                draw.ellipse((x-xd, y-xd, x+xd, y+xd), outline=(0, 150, 255), fill=None)
                draw.ellipse((x-1, y-1, x+1, y+1), fill=(255, 255, 0), outline=(255, 255, 0))
                draw.text((x-20, y-15), 'Circle '+str(counter_circle), fill=(255, 100, 0))
                counter_circle += 1
            else:
                print '\nEllipse %d detected at center (%d, %d)' % (counter_ellipse, x, y)
                print '> Semidiameters:', xd, yd
                print '> %.1f%% of all the image' % percentage
                draw.ellipse((x-xd, y-yd, x+xd, y+yd), outline=(0, 150, 255), fill=None)
                draw.ellipse((x-2, y-2, x+2, y+2), fill=(255, 255, 0), outline=(255, 255, 0))
                draw.text((x-20, y-15), 'Ellipse '+str(counter_ellipse), fill=(255, 100, 0))
                counter_ellipse += 1
        return image

    def action(self):
        original_image = Image.new('RGB', (SIZE, SIZE), (255, 255, 255))
        original_image = self.draw_some_ellipses([(100, 40, 120, 50), (70, 70, 220, 220), (30, 90, 50, 200)], original_image)
        original_image = grayscale(original_image)

        # detect all the edges
        h = [[0, 1, 0], [1, -4, 1], [0, 1, 0]]
        image = self.convolution(h, original_image)
        image.save('original.png', 'png')
        can_be_ellipses, image_bfs = self.detect_forms(image)

        # gradient
        sobely = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
        sobelx = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]
        Gx = self.convolution(sobelx, original_image)
        Gy = self.convolution(sobely, original_image)

        image_bfs = average_allneighbors(image_bfs)
        image_bfs.save('bfs.png', 'png')
        ellipses_found = self.search_ellipse(can_be_ellipses, image_bfs, Gx, Gy)
        image = self.draw_ellipses_found(original_image, ellipses_found)
        image.save('result.png', 'png')
        self.update_image(image)