Tarea 3: Clasificador de imágenes de ocho formas

Tarea 3: Clasificador de imágenes de ocho formas

Información de la Tarea

Descripción de la Tarea

Clasificador de imágenes de ocho formas. Realizar el software en OpenCV para probar el tiempo real los clasificadores realizados en el apunte del día 19.05.2026.


Introducción

El objetivo principal es detectar y clasificar ocho formas geométricas diferentes en cada fotograma del flujo de video.

Entrenamiento del Modelo en Scikit-Learn

Para el primer enfoque, el modelo utilizo un MLPClassifier de Scikit-Learn Tomado de los apuntes utilizando los momentos de Hu.

import numpy as np
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Obtiene las características y las clases
data = np.genfromtxt('Momentos_Hu.csv', delimiter=',')
clases = np.array(["Cruz", "Estrella", "I", "Línea", "Óvalo", "Pentágono", "Rectángulo", "Triángulo"])
# Elimina los momentos de Hu 4, 5 y 6 debido a que no proporcionan información
X = np.delete(data[:,:7], (4,5,6), axis=1)
y = data[:,7]
# Normalización: Media cero y desviación estándar uno
escala = StandardScaler()
X = escala.fit_transform(X)
# Genera los sets de entrenamiento
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=21)
# Genera el modelo y lo entrena
clasificador = MLPClassifier(hidden_layer_sizes=(4,), solver="lbfgs", random_state=1, max_iter=400)
clasificador.fit(X_train, y_train)
print("Score en entrenamiento:", clasificador.score(X_train, y_train))

Entrenamiento del Modelo en PyTorch

Usando PyTorch. La arquitectura consta de capas lineales con funciones de activación Sigmoide y Softmax. Se entrenó durante 118 épocas utilizando el optimizador SGD con momento Nesterov.

import torch
from torch import nn
# El modelo de la red neuronal
class RedNeuronal(nn.Module):
def __init__(self):
super().__init__()
self.arquitectura = nn.Sequential(
nn.Linear(4, 4),
nn.Sigmoid(),
nn.Linear(4, 8),
nn.Softmax(dim=1)
)
def forward(self, x):
return self.arquitectura(x)
# Instanciamos el modelo
modelo = RedNeuronal()
loss_fn = nn.CrossEntropyLoss()
optimizador = torch.optim.SGD(modelo.parameters(), lr=0.5, momentum=0.9, nesterov=True)
# Bucle de entrenamiento y prueba
epochs = 118
for t in range(epochs):
train_loop(X_entrena, y_entrena, modelo, loss_fn, optimizador)
test_loop(t, X_prueba, y_prueba, modelo, loss_fn)
# Guardamos el modelo entrenado
torch.save(modelo, 'mod1.pth')

Interfaz de Detección en Tiempo Real

La interfaz gráfica en Tkinter (detector_formas.py) se integra con OpenCV para capturar el video en vivo. Esta interfaz permite al usuario alternar entre el modelo cargado en PyTorch y el modelo de Scikit-Learn para comparar su desempeño en tiempo real al evaluar los momentos de Hu extraídos en cada fotograma.

import cv2
import numpy as np
import tkinter as tk
# El script carga tanto el modelo de PyTorch como el de Sklearn
# modelos_reg = { "PyTorch": ClasificadorPyTorch(...), "Scikit-Learn": ClasificadorSklearn(...) }
def actualizar_video(self):
if not self.pausado and (ret := self.cap.read()[0]):
self.f_actual = self.cap.read()[1]
frame = self.f_actual.copy()
# Preprocesamiento de la imagen para extraer contornos
blur = cv2.GaussianBlur(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), (5, 5), 0)
med = np.median(blur)
bordes = cv2.dilate(cv2.Canny(blur, int(max(0, 0.5*med)), int(min(255, 1.5*med))),
np.ones((3,3), np.uint8), iterations=2)
contornos, _ = cv2.findContours(bordes, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Obtiene el clasificador seleccionado actualmente en la UI
mod = self.modelos_reg.get(self.var_mod.get())
for c in contornos:
if no_es_valido(c): continue
# Extraemos los 4 momentos de Hu necesarios
hu = extraer_hu_desde_mascara(c)
if hu is None: continue
# Realizamos la predicción con el modelo en uso
clase, conf = mod.predecir(hu)
if conf < 0.4: continue
# Dibujamos los resultados (cajita y etiqueta) sobre el frame
x, y, w, h = cv2.boundingRect(c)
cv2.drawContours(frame, [c], -1, (0, 255, 0), 2)
cv2.putText(frame, f"{clase} {conf:.0%}", (x, y-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# Actualiza el frame en la interfaz Tkinter
mostrar_en_interfaz(frame)

Demostraciónes en Video

Resultados y Conclusiones

Durante las pruebas prácticas, se realizaron las siguientes observaciones: