import numpy as np
import cv2
import random
# =====================================================
# 1. Cargar imagen en escala de grises
# =====================================================
# imagen = "imagen1.png"
# imagen = "imagen2.jpeg"
imagen = "imagen3.png"
img = cv2.imread(imagen, 0)
if img is None:
raise FileNotFoundError("No se pudo cargar la imagen")
# La normalizamos a [0,1]
img = img / 255.0
# =====================================================
# 2. Funcion sigmoide g(x)
# =====================================================
# alpha controla la pendiente
# delta controla el desplazamiento
def sigmoide(img, alpha, delta):
g = 1.0 / (1.0 + np.exp(-alpha * (img - delta)))
# Normalizamos el resultado otra vez a [0,1]
g_min = g.min()
g_max = g.max()
if g_max - g_min == 0:
return np.zeros_like(g)
return (g - g_min) / (g_max - g_min)
# =====================================================
# 3. Medidas de calidad
# =====================================================
def entropia(img):
img_u8 = (img * 255).astype(np.uint8)
hist = cv2.calcHist([img_u8], [0], None, [256], [0, 256])
p = hist / hist.sum()
p = p[p > 0]
return float(-np.sum(p * np.log2(p)))
def desviacion(img):
return float(np.std(img))
# =====================================================
# 4. Funcion objetivo
# =====================================================
# Para mejorar contraste, aqui maximizamos:
# - entropia
# - desviacion estandar
def evaluar(ind, modelo):
alpha, delta = ind
img2 = sigmoide(img, alpha, delta)
if modelo == "entropia":
return entropia(img2)
elif modelo == "desviacion":
return desviacion(img2)
else:
raise ValueError("Modelo no valido")
# =====================================================
# 5. Crear individuo
# =====================================================
# Un individuo = [alpha, delta]
# alpha en [0,10]
# delta en [0,1]
def crear_individuo():
alpha = random.uniform(0, 10)
delta = random.uniform(0, 1)
return [alpha, delta]
# =====================================================
# 6. Seleccion por torneo determinista binario
# =====================================================
# Se eligen 2 individuos al azar y gana el mejor
def torneo_binario(poblacion, fitness):
i, j = random.sample(range(len(poblacion)), 2)
if fitness[i] > fitness[j]:
return poblacion[i][:]
else:
return poblacion[j][:]
# =====================================================
# 7. Cruzamiento SBX
# =====================================================
def sbx_variable(x1, x2, xmin, xmax, eta_c):
# Si los valores son casi iguales, no tiene sentido cruzar
if abs(x1 - x2) < 1e-14:
return x1, x2
# Aseguramos x1 < x2
if x1 > x2:
x1, x2 = x2, x1
u = random.random()
# Primer hijo
beta = 1.0 + (2.0 * (x1 - xmin) / (x2 - x1))
alpha = 2.0 - beta ** (-(eta_c + 1.0))
if u <= 1.0 / alpha:
beta_q = (u * alpha) ** (1.0 / (eta_c + 1.0))
else:
beta_q = (1.0 / (2.0 - u * alpha)) ** (1.0 / (eta_c + 1.0))
h1 = 0.5 * ((x1 + x2) - beta_q * (x2 - x1))
# Segundo hijo
beta = 1.0 + (2.0 * (xmax - x2) / (x2 - x1))
alpha = 2.0 - beta ** (-(eta_c + 1.0))
if u <= 1.0 / alpha:
beta_q = (u * alpha) ** (1.0 / (eta_c + 1.0))
else:
beta_q = (1.0 / (2.0 - u * alpha)) ** (1.0 / (eta_c + 1.0))
h2 = 0.5 * ((x1 + x2) + beta_q * (x2 - x1))
# Respetar limites
h1 = min(max(h1, xmin), xmax)
h2 = min(max(h2, xmin), xmax)
return h1, h2
def cruza_sbx(p1, p2, pc=0.9, eta_c=15):
# Con cierta probabilidad si hay cruce, si no se copian
if random.random() > pc:
return p1[:], p2[:]
h1 = [0, 0]
h2 = [0, 0]
# alpha en [0,10]
h1[0], h2[0] = sbx_variable(p1[0], p2[0], 0.0, 10.0, eta_c)
# delta en [0,1]
h1[1], h2[1] = sbx_variable(p1[1], p2[1], 0.0, 1.0, eta_c)
return h1, h2
# =====================================================
# 8. Mutacion polinomial
# =====================================================
def mutacion_variable(x, xmin, xmax, eta_m):
if xmin == xmax:
return x
delta1 = (x - xmin) / (xmax - xmin)
delta2 = (xmax - x) / (xmax - xmin)
u = random.random()
mut_pow = 1.0 / (eta_m + 1.0)
if u < 0.5:
xy = 1.0 - delta1
val = 2.0 * u + (1.0 - 2.0 * u) * (xy ** (eta_m + 1.0))
delta_q = val ** mut_pow - 1.0
else:
xy = 1.0 - delta2
val = 2.0 * (1.0 - u) + 2.0 * (u - 0.5) * (xy ** (eta_m + 1.0))
delta_q = 1.0 - val ** mut_pow
x_nuevo = x + delta_q * (xmax - xmin)
x_nuevo = min(max(x_nuevo, xmin), xmax)
return x_nuevo
def mutacion_polinomial(ind, pm=0.5, eta_m=20):
hijo = ind[:]
# Mutar alpha
if random.random() < pm:
hijo[0] = mutacion_variable(hijo[0], 0.0, 10.0, eta_m)
# Mutar delta
if random.random() < pm:
hijo[1] = mutacion_variable(hijo[1], 0.0, 1.0, eta_m)
return hijo
# =====================================================
# 9. Estadisticas de una poblacion
# =====================================================
def obtener_estadisticas(poblacion, fitness):
pos_mejor = int(np.argmax(fitness))
pos_peor = int(np.argmin(fitness))
mejor = poblacion[pos_mejor]
peor = poblacion[pos_peor]
promedio = float(np.mean(fitness))
return {
"mejor_ind": mejor,
"mejor_fit": float(fitness[pos_mejor]),
"promedio": promedio,
"peor_ind": peor,
"peor_fit": float(fitness[pos_peor])
}
# =====================================================
# 10. Algoritmo genetico
# =====================================================
# Sustitucion extintiva con elitismo:
# - se guarda el mejor de la poblacion actual
# - el resto desaparece
# - se reemplaza por hijos nuevos
def AG(modelo, pop_size=20, max_eval=100, elite=1, pc=0.9, pm=0.5, eta_c=15, eta_m=20):
# Poblacion inicial
poblacion = [crear_individuo() for _ in range(pop_size)]
fitness = [evaluar(ind, modelo) for ind in poblacion]
evaluaciones = pop_size
while evaluaciones < max_eval:
# 1. Guardar elite
indices_ordenados = np.argsort(fitness)[::-1]
elite_individuos = [poblacion[i][:] for i in indices_ordenados[:elite]]
# 2. Crear nueva descendencia
nueva_poblacion = []
while len(nueva_poblacion) < pop_size - elite:
# Seleccion de padres con torneo determinista binario
padre1 = torneo_binario(poblacion, fitness)
padre2 = torneo_binario(poblacion, fitness)
# Cruzamiento
hijo1, hijo2 = cruza_sbx(padre1, padre2, pc, eta_c)
# Mutacion
hijo1 = mutacion_polinomial(hijo1, pm, eta_m)
hijo2 = mutacion_polinomial(hijo2, pm, eta_m)
nueva_poblacion.append(hijo1)
if len(nueva_poblacion) < pop_size - elite:
nueva_poblacion.append(hijo2)
# 3. Sustitucion extintiva con elitismo
poblacion = elite_individuos + nueva_poblacion[:pop_size - elite]
fitness = [evaluar(ind, modelo) for ind in poblacion]
evaluaciones += (pop_size - elite)
return obtener_estadisticas(poblacion, fitness)
# =====================================================
# 11. Imprimir tabla final
# =====================================================
def imprimir_tabla(resultados):
print("\nResumen final")
print("-" * 110)
print(
f"{'Modelo':<15}"
f"{'Mejor alpha':>15}"
f"{'Mejor delta':>15}"
f"{'Mejor valor':>18}"
f"{'Promedio':>18}"
f"{'Peor alpha':>15}"
f"{'Peor delta':>15}"
f"{'Peor valor':>18}"
)
print("-" * 110)
for modelo in resultados:
r = resultados[modelo]
print(
f"{modelo:<15}"
f"{r['mejor_ind'][0]:>15.6f}"
f"{r['mejor_ind'][1]:>15.6f}"
f"{r['mejor_fit']:>18.6f}"
f"{r['promedio']:>18.6f}"
f"{r['peor_ind'][0]:>15.6f}"
f"{r['peor_ind'][1]:>15.6f}"
f"{r['peor_fit']:>18.6f}"
)
print("-" * 110)
# =====================================================
# 12. Programa principal
# =====================================================
random.seed(42)
np.random.seed(42)
resultados = {}
for modelo in ["entropia", "desviacion"]:
resumen = AG(
modelo=modelo,
pop_size=20,
max_eval=100,
elite=1,
pc=0.9,
pm=0.5,
eta_c=15,
eta_m=20
)
resultados[modelo] = resumen
# Guardar imagen mejorada usando la mejor solucion encontrada
mejor_alpha = resumen["mejor_ind"][0]
mejor_delta = resumen["mejor_ind"][1]
img_mejorada = sigmoide(img, mejor_alpha, mejor_delta)
cv2.imwrite(f"{modelo}_{imagen}", (img_mejorada * 255).astype(np.uint8))
print(f"\nModelo: {modelo}")
print(f"Mejor solucion: alpha={mejor_alpha:.6f}, delta={mejor_delta:.6f}")
print(f"Mejor valor: {resumen['mejor_fit']:.6f}")
print(f"Promedio: {resumen['promedio']:.6f}")
print(f"Peor solucion: alpha={resumen['peor_ind'][0]:.6f}, delta={resumen['peor_ind'][1]:.6f}")
print(f"Peor valor: {resumen['peor_fit']:.6f}")
imprimir_tabla(resultados)1 views