• Identificar cada elipse/círculo individual
• Rellénalo de un color aleatorio
• Sigue marcando su centro con bolita & ID con etiqueta
• Imprime un listado de los áreas de los círculos/elipses
• En porcentaje de la imagen completa
Por lo que para realizar esto, utilicé las mismas funciones que he estado reutilizando durante el curso, para identificar el elipse o círculo lo que se hace es verificar sus radios y comparar que si el radio calculado obtenido es igual para ambos lados (o sea, vertical y horizontal) quiere decir que tenemos un círculo, por el contrario tenemos un elipse.
Estos se rellenan con mi subrutina BFS con un color aleatorio, se marca una bolita en el centro y se identifican para proceder a obtener un listado de los que son círculos y elipses, al igual que su porcentaje en base a la figura completa.
Estas son las capturas del programa.
En donde podemos ver que el programa sabe satisfactoriamente si es un circulo o un elipse al igual que información en base a la imagen en general
A continuación expongo el código modificado.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def BFS(imagen, inicio, color): | |
#Busqueda de anchura para determinar una figura | |
pixeles = imagen.load() | |
altura, ancho = imagen.size | |
fila, columna = inicio | |
original = pixeles[fila, columna] | |
cola = [] | |
cola.append((fila, columna)) | |
masa = [] | |
c = [] | |
while len(cola) > 0: | |
(fila, columna) = cola.pop(0) | |
actual = pixeles[fila, columna] | |
if actual == original or actual == color: | |
for dx in [-1, 0, 1]: | |
for dy in [-1, 0, 1]: | |
candidato = (fila + dy, columna + dx) | |
if candidato[0] >= 0 and candidato[0] < altura and candidato[1] >= 0 and candidato[1] < ancho: | |
contenido = pixeles[candidato[0], candidato[1]] | |
if contenido == original: | |
pixeles[candidato[0], candidato[1]] = color | |
imagen.putpixel((candidato[0], candidato[1]), color) | |
cola.append(candidato) | |
masa.append((candidato[0], candidato[1])) | |
c.append((candidato[0], candidato[1])) | |
return imagen, masa, c | |
def aplicar_BFS(imagen_BFS): | |
#aplica busqueda de anchura a todas las figuras encontradas con color aleatorio | |
pixeles = imagen_BFS.load() | |
x, y = imagen_BFS.size | |
colores = [] | |
elipses = [] | |
for a in range(x): | |
for b in range(y): | |
if pixeles[a, b] == (255, 255, 255): | |
color = (random.randint(0,255), random.randint(0,255), random.randint(0, 255)) | |
imagen_BFS, masa, c = BFS(imagen_BFS.convert("RGB"), (a, b), color) | |
elipses.append(c) | |
x_suma = 0 | |
y_suma = 0 | |
for i in range(len(masa)): | |
x_suma = x_suma + masa[i][0] | |
y_suma = y_suma + masa[i][1] | |
x_centro = x_suma/len(masa) | |
y_centro = y_suma/len(masa) | |
colores.append([color, 0, (x_centro, y_centro)]) | |
pixeles = imagen_BFS.load() | |
masa = [] | |
#suma la cantidad de colores diferentes en la imagen | |
pixeles = imagen_BFS.load() | |
for a in range(x): | |
for b in range(y): | |
for n in range(len(colores)): | |
if colores[n][0] == pixeles[a,b]: | |
colores[n][1] = colores[n][1] + 1 | |
print colores | |
suma = 0 | |
for i in range(len(colores)): | |
suma = suma + colores[i][1] | |
global frame | |
y = frame.winfo_height() | |
#Obtenemos porcentajes | |
prom = [] | |
for i in range(len(colores)): | |
promedio = float(colores[i][1])/float(suma)*100.0 | |
if promedio > 3.0: | |
print "Porcentajes: " | |
print "Figura " + str(i) + ": " + str(promedio) | |
prom.append((i, promedio, colores[i][0])) | |
maxim = 0.0 | |
for i in range(len(prom)): | |
if maxim < prom[i][1]: | |
maxim = prom[i][1] | |
fig = prom[i][0] | |
color_max = prom[i][2] | |
#Itentificamos fondo y lo pintamos a gris | |
print "Fondo fig: " + str(fig) | |
imagen_BFS = pinta_fondo(imagen_BFS, color_max) | |
#poner_imagen(imagen_BFS) | |
return imagen_BFS, colores, elipses | |
def pinta_fondo(imagen_BFS, color_max): | |
#pintamos fondo de manera que obtenemos el color que predomina en la imagen | |
pixeles = imagen_BFS.load() | |
x, y = imagen_BFS.size | |
for a in range(x): | |
for b in range(y): | |
if pixeles[a, b] == color_max: | |
color = (100,100,100) | |
imagen_BFS, masa, c = BFS(imagen_BFS.convert("RGB"), (a, b), color) | |
return imagen_BFS | |
def boton_elipse(): | |
inicio = time.time() | |
label.destroy() | |
max = 0 | |
suma = 0.0 | |
#A grises | |
imagen = cambiar_agrises(path_imagen_original) | |
imagen.save("paso_1.jpg") | |
votos = list() | |
#A grises | |
imagen = cambiar_agrises(path_imagen_original) | |
imagen.save("paso_1.jpg") | |
#Agrego Laplaciana | |
h_lap = numpy.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]]) | |
imagen_prom, puntos = convolucion(imagen, numpy.multiply(1.0/1.0,h_lap)) | |
imagen_prom = cambiar_umbral(imagen_prom, 0.5) | |
imagen_prom.save("paso_2.jpg") | |
#Agrego normalizacion | |
imagen_nor = normalizacion(imagen_prom) | |
imagen_nor.save("paso_3.jpg") | |
#Agrego umbral para binarizar | |
umbral_valor = 0.1 | |
imagen_bin = cambiar_umbral(imagen_nor.convert("RGB"), umbral_valor) | |
imagen_bin.save("paso_4.jpg") | |
#Pongo promedio | |
imagen_prom = cambiar_promedio(imagen_bin.convert("RGB")) | |
imagen_prom.save("paso_5.jpg") | |
#Agrego umbral para binarizar | |
umbral_valor = 0.08 | |
imagen_bin2 = cambiar_umbral(imagen_prom.convert("RGB"), umbral_valor) | |
imagen_bin2.save("paso_6.jpg") | |
#Pongo promedio | |
imagen_prom = cambiar_promedio(imagen_bin2.convert("RGB")) | |
imagen_prom.save("paso_7.jpg") | |
#Pongo promedio | |
imagen_prom = cambiar_promedio(imagen_prom.convert("RGB")) | |
imagen_prom.save("paso_8.jpg") | |
#Agrego umbral para binarizar | |
umbral_valor = 0.5 | |
imagen_BFS = cambiar_umbral(imagen_prom.convert("RGB"), umbral_valor) | |
imagen_BFS.save("paso_9.jpg") | |
#Se aplica BFS | |
imagen_BFS, colores, elipses = aplicar_BFS(imagen_BFS) | |
imagen_BFS.save("paso_10.jpg") | |
x, y = imagen_BFS.size | |
pixeles = imagen_BFS.load() | |
bordes_detectados = [] | |
#Se aplican mascaras de sobel | |
h_Y = numpy.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]) | |
h_X = numpy.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]]) | |
imagen_hori, puntos_GX = convolucion(imagen, numpy.multiply(1.0/1.0,h_X)) | |
imagen_hori.save("paso_sobelX.jpg") | |
pixeles_GX = imagen_hori.load() | |
imagen_verti, puntos_GY = convolucion(imagen, numpy.multiply(1.0/1.0,h_Y)) | |
imagen_verti.save("paso_sobelY.jpg") | |
pixeles_GY = imagen_verti.load() | |
#Empezamos a detectar elipses y circulos | |
dibuja = ImageDraw.Draw(imagen_BFS) | |
x, y = imagen_BFS.size | |
puntos = numpy.zeros(x*y).reshape((x, y)) | |
centros = [] | |
for elipse in elipses: | |
x, y = imagen_BFS.size | |
puntos = numpy.zeros(x*y).reshape((x, y)) | |
#Sacamos 2000 puntos aleatorios para calcular el centro mas preciso | |
for i in range(2000): | |
tam = len(elipse) | |
punto_1 = elipse[randint(0,tam-1)] | |
punto_2 = elipse[randint(0,tam-1)] | |
x_1 = punto_1[0] | |
y_1 = punto_1[1] | |
x_2 = punto_2[0] | |
y_2 = punto_2[1] | |
gx_1 = puntos_GX[x_1, y_1] | |
gy_1 = puntos_GY[x_1, y_1] | |
gx_2 = puntos_GX[x_2, y_2] | |
gy_2 = puntos_GY[x_2, y_2] | |
gx_1 = - float(gx_1) | |
gx_2 = - float(gx_2) | |
x_22 = x_2 | |
y_22 = y_2 | |
x_11 = x_1 | |
y_11 = y_1 | |
if abs(gx_1) + abs(gy_1) <= 0: | |
theta = None | |
else: | |
theta = atan2(gy_1, gx_1) | |
l = 50 | |
if theta is not None: | |
theta = theta-(pi/2) | |
x_1 = x_11 - l * cos(theta) | |
y_1 = y_11 - l * sin(theta) | |
x_2 = x_11 + l * cos(theta) | |
y_2 = y_11 + l * sin(theta) | |
if abs(gx_2) + abs(gy_2) <= 0: | |
theta = None | |
else: | |
theta = atan2(gy_2, gx_2) | |
if theta is not None: | |
theta = theta-(pi/2) | |
x_3 = x_22 - l * cos(theta) | |
y_3 = y_22 - l * sin(theta) | |
x_4 = x_22 + l * cos(theta) | |
y_4 = y_22 + l * sin(theta) | |
y_medio = (y_11+y_22) / 2 | |
x_medio = (x_11+x_22) / 2 | |
pixeles = imagen_BFS.load() | |
try: | |
Px = ((x_1*y_2-y_1*x_2)*(x_3-x_4)-(x_1-x_2)*(x_3*y_4-y_3*x_4))/((x_1-x_2)*(y_3-y_4)-(y_1-y_2)*(x_3-x_4)) | |
Py = ((x_1*y_2-y_1*x_2)*(y_3-y_4)-(y_1-y_2)*(x_3*y_4-y_3*x_4))/((x_1-x_2)*(y_3-y_4)-(y_1-y_2)*(x_3-x_4)) | |
Dx = Px - x_medio | |
Dy = Py - y_medio | |
m = Dy/Dx | |
x0 = x_medio | |
y0 = y_medio | |
#Obtenemos votos | |
while True: | |
x = x0+1 | |
y = m*(x-x0)+y0 | |
if pixeles[x,y] == (0, 0, 0): | |
puntos[x, y] = puntos[x, y] + 1 | |
x0 = x | |
y0 = y | |
else: | |
break | |
except: | |
pass | |
max = numpy.max(puntos) | |
index = numpy.where(puntos==max) | |
try: | |
mayor_x = sum(index[0])/len(index[0]) | |
mayor_y = sum(index[1])/len(index[0]) | |
#dibuja.ellipse((mayor_x-2, mayor_y-2, mayor_x+2, mayor_y+2), fill="blue") | |
centros.append((mayor_x, mayor_y)) | |
except: | |
mayor_x = index[0] | |
mayor_y = index[1] | |
#dibuja.ellipse((mayor_x-2, mayor_y-2, mayor_x+2, mayor_y+2), fill="blue") | |
centros.append((mayor_x, mayor_y)) | |
#de los mayores detectados, los utilizamos como centros | |
r_x = [] | |
r_y = [] | |
pixeles_imagen = imagen_BFS.load() | |
for i in range(len(centros)): | |
x0 = int(centros[i][0]) | |
y0 = int(centros[i][1]) | |
while True: | |
y0 = y0 + 1 | |
if pixeles_imagen[x0, y0] != (0, 0, 0): | |
r_y.append((x0, y0)) | |
break | |
for i in range(len(centros)): | |
x0 = int(centros[i][0]) | |
y0 = int(centros[i][1]) | |
while True: | |
x0 = x0 + 1 | |
if pixeles_imagen[x0, y0] != (0, 0, 0): | |
r_x.append((x0, y0)) | |
break | |
Radios = [] | |
x, y = imagen_BFS.size | |
print "Semidiametros perpendiculares del elipse" | |
for i in range(len(centros)): | |
x0 = int(centros[i][0]) | |
y0 = int(centros[i][1]) | |
x1 = int(r_x[i][0]) | |
y1 = int(r_x[i][1]) | |
x2 = int(r_y[i][0]) | |
y2 = int(r_y[i][1]) | |
Rx = sqrt((x1-x0)**2+(y1-y0)**2) | |
Ry = sqrt((x2-x0)**2+(y2-y0)**2) | |
#si los radios son iguales, es un circulo | |
if Rx == Ry: | |
cad = "Es circulo" | |
else: | |
cad = "Es elipse" | |
porcentaje = float(Rx * 100)/float(x) | |
print "ID: %s SemiDiametro: %s Porcentaje: %s %s" % (i, Rx, porcentaje, cad) | |
#Radios.append((Rx, Ry)) | |
color = (255, 255, 255) | |
a = 0 | |
#Pintamos en los 360 grados | |
while a < 2*pi: | |
x4, y4 = x0 + Rx * sin(a), y0 + Ry * cos(a) | |
a = a + 0.01 | |
dibuja.ellipse((x4-2, y4-2, x4+2, y4+2), fill=color) | |
for i in range(len(centros)): | |
#Agregamos BFS empezando por el centro del circulo o elipse capturado | |
color = (random.randint(0,255), random.randint(0,255), random.randint(0, 255)) | |
imagen_BFS, masa, c = BFS(imagen_BFS.convert("RGB"), (int(centros[i][0]), int(centros[i][1])), color) | |
dibuja.ellipse((centros[i][0]-2, centros[i][1]-2, centros[i][0]+2, centros[i][1]+2), fill="blue") | |
poner_imagen(imagen_BFS) | |
global frame | |
y = frame.winfo_height() | |
for i in range(len(centros)): | |
label_fig = Label(text = str(i)) | |
label_fig.place(x = centros[i][0], y = centros[i][1] + y) | |
imagen_BFS.save("paso_lineas.jpg") | |
#Tiempo | |
fin = time.time() | |
tiempo = fin - inicio | |
print "Tiempo que trascurrio -> " + str(tiempo) | |
return tiempo |
Bien; 10 pts.
ResponderEliminar