- Detectar elipses marcados con tonos naranja.
- Marcar el centro con un punto azul
- Poner una etiqueta ID
- Imprimir un listado de los semidiametros perpendiculares y su porcentaje con la diagonal máxima de la imagen
Para realizar esto, se nos pide utilizar el método de la cuerda tangente, es por eso que se hacen los siguientes pasos:
- Cambiar a grises
- Sacar convolución Laplaciana para sacar bordes
- Normalizo la imagen
- Binarizo los datos
- Sacamos el promedio
- Se agrega un umbral
- Agregamos BFS para detectar todos los bordes
- Los pintamos de diferentes colores
- Sacamos mascara de sobel en X
- Sacamos mascara de sobel en Y
- Generamos puntos aleatorios para cada borde detectado
- Calculamos su theta
- Creamos dos lineas tangenciales a los bordes
- Se calcula su punto medio
- Realizamos los votos a partir de esa linea hasta al final del borde siguiente
- Repetimos varias veces para obtener mejor precisión en el centro
- Se calcula los radios en X y en Y
- dibujamos un punto entre 0 a 360 grados a partir de los datos obtenidos
- Vemos el elipse detectado en un tono anaranjado
Les muestro unas capturas de pantalla del procedimiento
Otros ejemplos:
Este es el código de la función principal, si quieren ver mi repositorio, ahí se encuentra completo.
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 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") | |
#Aplica BFS a los bordes detectados | |
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 aplica mascara sobel en X y Y | |
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 los elipses | |
dibuja = ImageDraw.Draw(imagen_BFS) | |
x, y = imagen_BFS.size | |
puntos = numpy.zeros(x*y).reshape((x, y)) | |
centros = [] | |
#Para cada borde detectado sacamos puntos aleatorios para hacer votos en la linea donde posiblemente tenemos un centro | |
for elipse in elipses: | |
x, y = imagen_BFS.size | |
puntos = numpy.zeros(x*y).reshape((x, y)) | |
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 | |
#Calculamos theta segun mascara de sobel | |
if abs(gx_1) + abs(gy_1) <= 0: | |
theta = None | |
else: | |
theta = atan2(gy_1, gx_1) | |
l = 50 | |
#Creamos las lineas tangentes | |
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) | |
#Misma operacion con otro punto | |
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: | |
#Detectamos la interseccion y pendiente | |
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 | |
#Empezamos a hacer votos hasta encontrar un borde | |
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 | |
#De los resultados sacamos los mas voteados | |
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)) | |
#Sacamos los radios | |
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 | |
#Dibujamos elipse | |
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) | |
porcentaje = float(Rx * 100)/float(x) | |
print "ID: %s SemiDiametro: %s Porcentaje: %s" % (i, Rx, porcentaje) | |
color = (randint(175,255), randint(134, 196), 0) #rango anaranjado | |
a = 0 | |
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) | |
#Ponemos imagen en ventana | |
poner_imagen(imagen_BFS) | |
#Etiquetamos | |
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) | |
dibuja.ellipse((centros[i][0]-2, centros[i][1]-2, centros[i][0]+2, centros[i][1]+2), fill="blue") | |
#Guardamos | |
imagen_BFS.save("paso_lineas.jpg") | |
#Tiempo | |
fin = time.time() | |
tiempo = fin - inicio | |
print "Tiempo que trascurrio -> " + str(tiempo) | |
return tiempo |
OK, 5 pts.
ResponderEliminar