jueves, 21 de febrero de 2013

Lab 3: Convex hull

Para el laboratorio numero 3 de la materia de Visión Computacional se nos pide realizar un algoritmo de convex hull, para esto, seleccione el gift wrapping, también conocido marcha de Jarvis en versión 2 dimensional.

Hice un preprocesamiento para empezar a utilizar el gift wrapping, primero, utilicé el mismo código que  había utilizando para detectar formas, pero ahora en los bordes que están de color blanco, estos los cambio de color y guardo todos los pixeles para ponerlos en el algoritmo de convex hull.

Luego de preprocesar la información, entra al algoritmo, el cual va verificando las direcciones izquierdas mas próximas para ir formando el polígono, el cual lo pongo con unas lineas rojas utilizando PIL de python.

Estas son algunas capturas de mis pruebas




Este es el código.

from Tkinter import *
from PIL import Image, ImageTk, ImageDraw
from math import floor
import numpy
import random
def ventana():
root = Tk()
root.title('Lab 3')
global frame
frame = Frame()
frame.pack(padx=5,pady=5)
poner_imagen(obtener_original(path_imagen_original))
b1 = Button(text='Original', command = boton_original).pack(in_=frame, side=LEFT)
b4 = Button(text='Identificar', command = boton_bordes).pack(in_=frame, side=LEFT)
root.mainloop()
def poner_imagen(image):
photo = ImageTk.PhotoImage(image)
global label
label = Label(image=photo)
label.imagen = photo
label.pack()
def BFS(imagen, inicio, color):
pixeles = imagen.load()
altura, ancho = imagen.size
fila, columna = inicio
original = pixeles[fila, columna]
cola = []
cola.append((fila, columna))
masa = []
pixeles_BFS = []
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]))
pixeles_BFS.append((candidato[0], candidato[1]))
return imagen, masa, pixeles_BFS
def cambiar_agrises(path_original):
imagen = Image.open(path_imagen_original).convert("RGB")
pixeles = imagen.load()
x, y = imagen.size
imagen_nueva = Image.new("RGB", (x, y))
colores = []
for a in range(x):
for b in range(y):
pixel_color = pixeles[a, b]
promedio = sum(pixel_color)/3
tupla_promedio = (promedio, promedio, promedio)
colores.append(tupla_promedio)
imagen_nueva.putpixel((a, b), tupla_promedio)
return imagen_nueva
def cambiar_promedio(imagen):
pixeles = imagen.load()
x, y = imagen.size
imagen_nueva_prom = Image.new("RGB", (x, y))
colores = []
for a in range(x):
for b in range(y):
pixel_color = pixeles[a, b]
veces = 5
suma = 0
promedio = 0
try:
pixel_norte = pixeles[a-1,b]
except IndexError:
pixel_norte = (0, 0, 0)
veces = veces - 1
try:
pixel_sur = pixeles[a+1, b]
except IndexError:
pixel_sur = (0, 0, 0)
veces = veces - 1
try:
pixel_este = pixeles[a, b+1]
except IndexError:
pixel_este = (0, 0, 0)
veces = veces - 1
try:
pixel_oeste = pixeles[a, b-1]
except IndexError:
pixel_oeste = (0, 0, 0)
veces = veces - 1
Rojos_suma = pixel_norte[0] + pixel_sur[0] + pixel_este[0] + pixel_oeste[0] + pixel_color[0]
Verdes_suma = pixel_norte[1]+ pixel_sur[1] + pixel_este[1] + pixel_oeste[1] + pixel_color[1]
Azul_suma = pixel_norte[2]+ pixel_sur[2] + pixel_este[2] + pixel_oeste[2] + pixel_color[2]
Rojo_prom = Rojos_suma/veces
Verdes_prom = Verdes_suma/veces
Azul_prom = Azul_suma/veces
tupla_promedio = (Rojo_prom, Verdes_prom, Azul_prom)
colores.append(tupla_promedio)
imagen_nueva_prom.putpixel((a, b), tupla_promedio)
return imagen_nueva_prom
def diferencia(imagen):
pixeles = imagen.load()
x, y = imagen.size
imagen_nueva_prom = Image.new("RGB", (x, y))
colores = []
for a in range(x):
for b in range(y):
pixel_color = pixeles[a, b]
veces = 5
suma = 0
promedio = 0
try:
pixel_norte = pixeles[a-1,b]
except IndexError:
pixel_norte = (0, 0, 0)
veces = veces - 1
try:
pixel_sur = pixeles[a+1, b]
except IndexError:
pixel_sur = (0, 0, 0)
veces =veces - 1
try:
pixel_este = pixeles[a, b+1]
except IndexError:
pixel_este = (0, 0, 0)
veces =veces - 1
try:
pixel_oeste = pixeles[a, b-1]
except IndexError:
pixel_oeste = (0, 0, 0)
veces =veces - 1
Rojos_suma = pixel_norte[0] + pixel_sur[0] + pixel_este[0] + pixel_oeste[0] + pixel_color[0]
Verdes_suma = pixel_norte[1]+ pixel_sur[1] + pixel_este[1] + pixel_oeste[1] + pixel_color[1]
Azul_suma = pixel_norte[2]+ pixel_sur[2] + pixel_este[2] + pixel_oeste[2] + pixel_color[2]
Rojo_prom = Rojos_suma/veces
Verde_prom = Verdes_suma/veces
Azul_prom = Azul_suma/veces
Rojo_dif = pixel_color[0] - Rojo_prom
Verde_dif = pixel_color[1] - Verde_prom
Azul_dif = pixel_color[2] - Azul_prom
tupla_promedio = (Rojo_dif, Verde_dif, Azul_dif)
colores.append(tupla_promedio)
imagen_nueva_prom.putpixel((a, b), tupla_promedio)
return imagen_nueva_prom
def normalizacion(imagen):
pixeles = imagen.load()
x, y = imagen.size
min = 0
max = 0
imagen_nueva = Image.new("RGB", (x, y))
for a in range(x):
for b in range(y):
pixel_color = pixeles[a, b]
max_ant = max
max_new = pixel_color[0]
min_ant = min
min_new = pixel_color[0]
if (max_new >= max_ant):
max = max_new
elif (min_new <= min_ant):
min = min_new
elif (min == 0 and max == 255):
break
for a in range(x):
for b in range(y):
pixel_color = pixeles[a, b]
try:
nuevo_pixel = ( float(pixel_color[0]) - float(min) )*( float(255) / (float(max) - float(min)) )
nuevo_pixel = int(floor(nuevo_pixel))
except:
nuevo_pixel = 255
tupla_promedio = (nuevo_pixel, nuevo_pixel, nuevo_pixel)
imagen_nueva.putpixel((a, b), tupla_promedio)
return imagen_nueva
def cambiar_umbral(imagen, umbral_valor):
pixeles = imagen.load()
x, y = imagen.size
imagen_nueva = Image.new("RGB", (x, y))
for a in range(x):
for b in range(y):
pixel_color = pixeles[a, b]
valor_canal = float(pixel_color[0])
color_nor = valor_canal/255.0
if(color_nor > umbral_valor):
poner_pixel = 255
else:
poner_pixel = 0
tupla_pixel = (poner_pixel, poner_pixel, poner_pixel)
imagen_nueva.putpixel((a, b), tupla_pixel)
return imagen_nueva
def mediana(arreglo):
if len(arreglo) % 2 == 1:
return arreglo[(len(arreglo)+1)/2-1]
else:
izq = arreglo[len(arreglo)/2-1]
der = arreglo[len(arreglo)/2]
return (float(izq + izq)) / 2.0
def obtener_original(path_imagen_original):
imagen = Image.open(path_imagen_original)
return imagen
def boton_bordes():
label.destroy()
#Pongo a grises
imagen_grises = cambiar_agrises(path_imagen_original)
imagen_grises.save("paso_1.jpg")
#Agrego diferencia
imagen_prom = diferencia(imagen_grises.convert("RGB"))
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.001
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.001
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.001
imagen_BFS = cambiar_umbral(imagen_prom.convert("RGB"), umbral_valor)
imagen_BFS.save("paso_9.jpg")
aplicar_BFS(imagen_bin2)
def aplicar_gift(coordenadas):
y = []
x = []
for i in range(len(coordenadas)):
x.append(coordenadas[i][0])
y.append(coordenadas[i][1])
p0 = min(coordenadas)
hull = [p0]
cont = 0
while 1:
fin = coordenadas[0]
for k in range(len(coordenadas) - 1):
direccion = cmp(0, (hull[cont][0] - coordenadas[k][0])*(fin[1] - coordenadas[k][1]) - (fin[0] - coordenadas[k][0])*(hull[cont][1] - coordenadas[k][1]))
if fin == hull[cont] or direccion == -1:
fin = coordenadas[k]
cont += 1
hull.append(fin)
if fin == hull[0]:
break
return hull
def aplicar_BFS(imagen_BFS):
bordes = []
pixeles = imagen_BFS.load()
x, y = imagen_BFS.size
colores = []
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, pixeles_BFS = BFS(imagen_BFS.convert("RGB"), (a, b), color)
bordes.append(pixeles_BFS)
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 = []
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
suma = 0
for i in range(len(colores)):
suma = suma + colores[i][1]
global frame
y = frame.winfo_height()
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]
print "Fondo fig: " + str(fig)
imagen_BFS = pinta_fondo(imagen_BFS, color_max)
#poner_imagen(imagen_BFS)
imagen_BFS.save("paso_10.jpg")
for i in range(len(colores)):
promedio = float(colores[i][1])/float(suma)*100.0
if promedio > 1.5:
print "Identifico . . ."
label_fig = Label(text = str(i))
label_fig.place(x = colores[i][2][0], y = colores[i][2][1] + y)
todos_hull = []
for i in range(len(bordes)):
hull = aplicar_gift(bordes[i])
todos_hull.append(hull)
draw = ImageDraw.Draw(imagen_BFS)
for i in range(len(todos_hull)):
for j in range(len(todos_hull[i])):
try:
linea = (todos_hull[i][j][0],todos_hull[i][j][1], todos_hull[i][j+1][0],todos_hull[i][j+1][1])
except:
break
draw.line(linea, fill=128)
imagen_BFS.save("paso_11.jpg")
poner_imagen(imagen_BFS)
print todos_hull
def pinta_fondo(imagen_BFS, color_max):
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, bordes = BFS(imagen_BFS.convert("RGB"), (a, b), color)
return imagen_BFS
def boton_original():
label.destroy()
global imagen_original
imagen_original = obtener_original(path_imagen_original)
poner_imagen(imagen_original)
path_imagen_original = "elefante.jpg"
imagen_original = obtener_original(path_imagen_original)
ventana()
view raw convex.py hosted with ❤ by GitHub

Las partes importantes se encientan en BFS y en aplicar_gift

1 comentario:

  1. Del código podrías poner aquí solamente lo nuevo/relevante y el resto tenerlo accessible con una liga al Git. 8 pts lo obligatorio (detecta multiples objetos y les calcula los convex hull a cada uno).

    ResponderEliminar