Loading [MathJax]/extensions/TeX/AMSsymbols.js

18 de abril de 2013

Actividad 6: Relleno de Elipses y Círculos

Laboratorio de Visión Computacional
Actividad 6

A diferencia del código mostrado en la publicación de la clase, este código diferencia entre elipses y círculos, ya que el método de cuerda-tangente puede ser usado para la detección de ambas figuras.

En este código una vez detectado el centro de la figura, a partir de este punto se usa BFS para ir coloreando todos los pixeles dentro del contorno del elipse. A cada elipse y círculo se le asigna un número y se imprimen sus semidiámetros o radios, según corresponda, y por último se imprime para cada uno un porcentaje del tamaño con respecto al tamaño total de la imagen.



Código


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)
view raw ellipses.py hosted with ❤ by GitHub

Pruebas


Imagen después de binarizar y obtener bordes de las figuras.


Imagen obtenida.


Salida en el terminal.



Imagen después de haber encontrado los bordes y haber binarizado, antes de mandarse al método que buscará posibles elipses y círculos.


Resultado obtenido.


Y por último una captura de la ventana desplegada junto a la terminal donde se muestran las figuras detectadas, en este caso elipses y círculos, y se muestra en donde se encontró su centro, si es un elipse los semidiámetros o si es un círculo su radio, así como el porcentaje que ocupa la figura en relación a la totalidad de pixeles de la imagen.


1 comentario:

  1. Bien; 10 pts, pero casi te quito un punto por usar un constante arbitrario 20. Mejor que depende de la resolución de la imagen o algo así.

    ResponderEliminar

Nota: solo los miembros de este blog pueden publicar comentarios.