OpenCV
Tutorial OpenCV: Clasificación de imágenes con ML
Aprende a clasificar imágenes integrando OpenCV y técnicas de ML con Scikit Learn y TensorFlow. Guía paso a paso para optimizar modelos de aprendizaje automático con Python y OpenCV.
Aprende OpenCV GRATIS y certifícateClasificación de imágenes con scikit-learn
La clasificación de imágenes es una tarea fundamental en visión por computadora que consiste en asignar una etiqueta o categoría a una imagen dada. En esta sección, exploraremos cómo utilizar scikit-learn para construir modelos de clasificación de imágenes, integrando OpenCV para el procesamiento y preprocesamiento de las imágenes.
Para comenzar, es necesario convertir las imágenes en formatos que puedan ser interpretados por los algoritmos de scikit-learn. Esto implica transformar las imágenes en vectores de características que representen adecuadamente el contenido visual. Una técnica común es aplanar las imágenes, convirtiendo las matrices multidimensionales en vectores unidimensionales.
A continuación, importamos las bibliotecas necesarias y cargamos el conjunto de datos de imágenes. Suponiendo que tenemos un conjunto de imágenes organizadas en directorios según sus clases, podemos utilizar OpenCV para leer las imágenes y NumPy para manipularlas:
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import svm
import os
Es fundamental mantener un equilibrio entre la dimensionalidad de los datos y la capacidad del modelo para generalizar. Imágenes de alta resolución pueden generar vectores de características muy grandes, lo que podría llevar a un sobreajuste. Por ello, es recomendable redimensionar las imágenes a una escala más manejable:
IMAGE_SIZE = (64, 64) # Tamaño al que redimensionaremos las imágenes
data = []
labels = []
classes = ['perros', 'gatos']
for idx, class_name in enumerate(classes):
class_dir = os.path.join('ruta_a_las_imagenes', class_name)
for img_name in os.listdir(class_dir):
img_path = os.path.join(class_dir, img_name)
img = cv2.imread(img_path)
img = cv2.resize(img, IMAGE_SIZE)
data.append(img.flatten())
labels.append(idx)
En este ejemplo, las imágenes se redimensionan a 64x64 píxeles y se aplanan, convirtiéndolas en vectores de tamaño 12,288 (64x64x3). Las etiquetas se almacenan en la lista labels
como enteros que representan cada clase.
Tras preparar los datos, dividimos el conjunto en entrenamiento y prueba utilizando train_test_split()
de scikit-learn:
X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=42)
Elegimos un algoritmo de clasificación adecuado para nuestro problema. Las Máquinas de Vectores de Soporte (SVM) son una opción popular para tareas de clasificación. Entrenamos el modelo con los datos de entrenamiento:
clf = svm.SVC(kernel='linear')
clf.fit(X_train, y_train)
Una vez entrenado, evaluamos el rendimiento del modelo en los datos de prueba:
accuracy = clf.score(X_test, y_test)
print(f'Precisión del modelo: {accuracy * 100:.2f}%')
La precisión obtenida nos indica la eficacia del modelo en la clasificación correcta de nuevas imágenes. Para mejorar el rendimiento, podríamos considerar técnicas como la extracción de características más avanzadas en lugar de simplemente aplanar las imágenes.
Una alternativa es utilizar histogramas de colores como características. Los histogramas capturan la distribución de colores en una imagen, ofreciendo una representación más robusta:
def extract_color_histogram(image, bins=(8, 8, 8)):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1, 2], None, bins,
[0, 180, 0, 256, 0, 256])
cv2.normalize(hist, hist)
return hist.flatten()
data = []
labels = []
for idx, class_name in enumerate(classes):
class_dir = os.path.join('ruta_a_las_imagenes', class_name)
for img_name in os.listdir(class_dir):
img_path = os.path.join(class_dir, img_name)
img = cv2.imread(img_path)
img = cv2.resize(img, IMAGE_SIZE)
features = extract_color_histogram(img)
data.append(features)
labels.append(idx)
Con los histogramas de colores como vectores de características, repetimos el proceso de entrenamiento y evaluación:
X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=42)
clf = svm.SVC(kernel='linear')
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
print(f'Precisión del modelo con histogramas de color: {accuracy * 100:.2f}%')
El uso de características basadas en histogramas puede ofrecer una mejor discriminación entre clases, mejorando la performance del modelo. Además, ajustar parámetros como el tipo de kernel en el SVM o utilizar otros algoritmos de clasificación como árboles de decisión o k-NN puede afectar significativamente los resultados.
Es importante también realizar una validación cruzada para asegurar que el modelo generaliza bien y no está sobreajustado a los datos de entrenamiento:
from sklearn.model_selection import cross_val_score
scores = cross_val_score(clf, data, labels, cv=5)
print(f'Precisión media en validación cruzada: {np.mean(scores) * 100:.2f}%')
La validación cruzada proporciona una estimación más fiable de la precisión del modelo al utilizar diferentes particiones de los datos para entrenamiento y prueba.
Es esencial preprocesar adecuadamente las imágenes y considerar técnicas de normalización y estandarización de las características para mejorar el rendimiento del modelo. La biblioteca scikit-learn ofrece herramientas como StandardScaler y MinMaxScaler para este propósito.
Redes neuronales convolucionales con TensorFlow
Las Redes Neuronales Convolucionales (CNNs) son una arquitectura de redes neuronales especialmente eficaz para tareas de clasificación y reconocimiento en imágenes. En esta sección, aprenderemos a implementar una CNN utilizando TensorFlow, combinando el preprocesamiento de imágenes con OpenCV.
Comenzamos importando las bibliotecas necesarias:
import cv2
import numpy as np
import tensorflow as tf
import os
Definimos las clases y preparamos listas para almacenar los datos y las etiquetas:
IMAGE_SIZE = (64, 64) # Tamaño al que redimensionaremos las imágenes
data = []
labels = []
classes = ['perros', 'gatos']
Cargamos y preprocesamos las imágenes utilizando OpenCV:
for idx, class_name in enumerate(classes):
class_dir = os.path.join('ruta_a_las_imagenes', class_name)
for img_name in os.listdir(class_dir):
img_path = os.path.join(class_dir, img_name)
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, IMAGE_SIZE)
data.append(img)
labels.append(idx)
Convertimos las listas a arrays de NumPy y normalizamos las imágenes:
data = np.array(data, dtype='float32') / 255.0 # Normalización de píxeles
labels = np.array(labels)
Dividimos los datos en conjuntos de entrenamiento y validación utilizando train_test_split:
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(data, labels, test_size=0.2, random_state=42)
Codificamos las etiquetas en formato categórico para la clasificación multiclase:
y_train = tf.keras.utils.to_categorical(y_train, num_classes=len(classes))
y_val = tf.keras.utils.to_categorical(y_val, num_classes=len(classes))
Diseñamos el modelo de CNN utilizando la API Keras de TensorFlow:
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=IMAGE_SIZE + (3,)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(len(classes), activation='softmax')
])
Compilamos el modelo definiendo el optimizador, la función de pérdida y las métricas:
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
Entrenamos el modelo con los datos de entrenamiento y validamos su rendimiento:
history = model.fit(X_train, y_train,
epochs=10,
batch_size=32,
validation_data=(X_val, y_val))
El historial de entrenamiento almacena información útil sobre la pérdida y la precisión en cada época, lo que permite analizar el desempeño del modelo.
Para evaluar el modelo en el conjunto de validación, utilizamos:
val_loss, val_accuracy = model.evaluate(X_val, y_val)
print(f'Precisión en validación: {val_accuracy * 100:.2f}%')
La precisión obtenida refleja la capacidad de generalización del modelo a nuevos datos.
Implementamos Data Augmentation para aumentar la variabilidad del conjunto de entrenamiento y mejorar la robustez del modelo:
from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=20,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True
)
datagen.fit(X_train)
Reentrenamos el modelo utilizando el generador de datos:
history = model.fit(datagen.flow(X_train, y_train, batch_size=32),
epochs=10,
validation_data=(X_val, y_val))
El aumento de datos permite al modelo aprender de imágenes modificadas, reduciendo el riesgo de sobreajuste.
Podemos guardar el modelo entrenado para futuras predicciones:
model.save('modelo_cnn.h5')
Para realizar predicciones con nuevas imágenes, preprocesamos la imagen y utilizamos el modelo cargado:
from tensorflow.keras.models import load_model
model = load_model('modelo_cnn.h5')
def prepare_image(img_path):
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, IMAGE_SIZE)
img = img.astype('float32') / 255.0
img = np.expand_dims(img, axis=0)
return img
img = prepare_image('ruta_a_la_nueva_imagen.jpg')
prediction = model.predict(img)
clase_predicha = classes[np.argmax(prediction)]
print(f'La imagen se ha clasificado como: {clase_predicha}')
La función prepare_image se encarga de cargar y preprocesar la imagen para que sea compatible con el modelo.
Visualizamos la curva de aprendizaje para analizar el rendimiento durante el entrenamiento:
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'], label='Precisión de entrenamiento')
plt.plot(history.history['val_accuracy'], label='Precisión de validación')
plt.xlabel('Épocas')
plt.ylabel('Precisión')
plt.legend()
plt.show()
Las gráficas permiten identificar tendencias y posibles problemas, como el sobreajuste si la precisión en entrenamiento aumenta mientras que la de validación se estanca o disminuye.
Es posible mejorar el modelo ajustando hiperparámetros, añadiendo capas de regularización como Dropout, o utilizando arquitecturas más complejas. La integración de OpenCV y TensorFlow proporciona una poderosa combinación para abordar desafíos en visión por computadora y aprendizaje profundo.
Uso de modelos pre-entrenados
Los modelos pre-entrenados son redes neuronales que han sido entrenadas previamente en grandes conjuntos de datos y pueden reutilizarse para resolver tareas similares. Este enfoque aprovecha los conocimientos adquiridos por el modelo, reduciendo el tiempo de entrenamiento y mejorando el rendimiento en problemas con datos limitados.
Una de las ventajas de utilizar modelos pre-entrenados es la capacidad de transferir aprendizaje. En lugar de entrenar una red desde cero, podemos importar un modelo existente y adaptarlo a nuestra tarea específica. Frameworks como TensorFlow y Keras facilitan la carga y modificación de estos modelos.
Empezamos importando las librerías necesarias:
import tensorflow as tf
import cv2
import numpy as np
import os
Seleccionamos un modelo pre-entrenado, como MobileNetV2, optimizado para dispositivos con recursos limitados y adecuado para clasificación de imágenes. Cargamos el modelo sin incluir las capas superiores (top layers), ya que añadiremos nuestras propias capas para la clasificación personalizada:
base_model = tf.keras.applications.MobileNetV2(input_shape=(128, 128, 3),
include_top=False,
weights='imagenet')
base_model.trainable = False # Congelamos las capas del modelo base
Preparamos nuestro conjunto de datos. Supongamos que tenemos imágenes organizadas en carpetas según sus categorías:
IMAGE_SIZE = (128, 128)
BATCH_SIZE = 32
data_dir = 'ruta_a_las_imagenes'
datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255,
validation_split=0.2)
train_generator = datagen.flow_from_directory(data_dir,
target_size=IMAGE_SIZE,
batch_size=BATCH_SIZE,
subset='training',
class_mode='categorical')
val_generator = datagen.flow_from_directory(data_dir,
target_size=IMAGE_SIZE,
batch_size=BATCH_SIZE,
subset='validation',
class_mode='categorical')
Utilizamos ImageDataGenerator para generar lotes de imágenes y aplicar una normalización a los píxeles. Es importante resaltar la división en entrenamiento y validación mediante el parámetro validation_split
.
Construimos el modelo añadiendo capas superiores sobre el modelo base:
inputs = tf.keras.Input(shape=(128, 128, 3))
x = base_model(inputs, training=False)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dense(128, activation='relu')(x)
outputs = tf.keras.layers.Dense(train_generator.num_classes, activation='softmax')(x)
model = tf.keras.Model(inputs, outputs)
En este modelo, utilizamos una capa de GlobalAveragePooling2D para reducir las dimensiones, seguida de una capa densa intermedia y la capa de salida con activación softmax para la clasificación multiclase.
Compilamos el modelo especificando el optimizador, la función de pérdida y las métricas:
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss='categorical_crossentropy',
metrics=['accuracy'])
Entrenamos el modelo utilizando los generadores de datos:
history = model.fit(train_generator,
epochs=10,
validation_data=val_generator)
Tras entrenar las capas superiores, podemos descongelar algunas capas del modelo base para ajustar finamente el modelo a nuestro conjunto de datos:
base_model.trainable = True
fine_tune_at = 100 # Descongelamos desde la capa número 100
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
model.compile(optimizer=tf.keras.optimizers.Adam(1e-5),
loss='categorical_crossentropy',
metrics=['accuracy'])
history_fine = model.fit(train_generator,
epochs=5,
validation_data=val_generator)
Al ajustar finamente el modelo, utilizamos una tasa de aprendizaje baja para no sobrescribir los pesos pre-entrenados de forma abrupta. Este proceso puede mejorar significativamente la precisión del modelo en tareas específicas.
Evaluamos el modelo en el conjunto de validación:
val_loss, val_accuracy = model.evaluate(val_generator)
print(f'Precisión de validación: {val_accuracy * 100:.2f}%')
Para predecir nuevas imágenes, preprocesamos la imagen y utilizamos el modelo entrenado:
def prepare_image(img_path):
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, IMAGE_SIZE)
img = img.astype('float32') / 255.0
img = np.expand_dims(img, axis=0)
return img
img = prepare_image('ruta_a_la_nueva_imagen.jpg')
prediction = model.predict(img)
clase_predicha = train_generator.class_indices
clase_predicha = {v: k for k, v in clase_predicha.items()}
print(f'La imagen se ha clasificado como: {clase_predicha[np.argmax(prediction)]}')
Es fundamental entender que los modelos pre-entrenados fueron entrenados en grandes conjuntos de datos como ImageNet, que contiene millones de imágenes y mil clases. Esto permite que los modelos aprendan características ricas y generales, que son útiles para numerosas tareas de visión por computadora.
Además de MobileNetV2, existen otros modelos pre-entrenados disponibles en TensorFlow, como VGG16, ResNet50, InceptionV3, entre otros. La elección del modelo depende de las necesidades, considerando factores como la precisión y el rendimiento.
Podemos explorar los modelos disponibles en tensorflow.keras.applications:
from tensorflow.keras.applications import VGG16, ResNet50, InceptionV3
# Ejemplo de carga de VGG16
vgg_base = VGG16(input_shape=(224, 224, 3),
include_top=False,
weights='imagenet')
vgg_base.trainable = False
Es posible utilizar los modelos pre-entrenados como extractores de características. En este enfoque, extraemos las características de las imágenes utilizando el modelo base y luego entrenamos un clasificador tradicional como una máquina de vectores de soporte (SVM) con scikit-learn:
def extract_features(directory, sample_count):
features = np.zeros(shape=(sample_count, 7, 7, 512)) # Ajustar según el modelo
labels = np.zeros(shape=(sample_count))
generator = datagen.flow_from_directory(directory,
target_size=(224, 224),
batch_size=BATCH_SIZE,
class_mode='binary',
shuffle=False)
i = 0
for inputs_batch, labels_batch in generator:
features_batch = vgg_base.predict(inputs_batch)
features[i * BATCH_SIZE: (i + 1) * BATCH_SIZE] = features_batch
labels[i * BATCH_SIZE: (i + 1) * BATCH_SIZE] = labels_batch
i += 1
if i * BATCH_SIZE >= sample_count:
break
return features, labels
train_features, train_labels = extract_features('ruta_a_las_imagenes_entrenamiento', 2000)
val_features, val_labels = extract_features('ruta_a_las_imagenes_validacion', 1000)
# Aplanamos las características
train_features = np.reshape(train_features, (2000, 7 * 7 * 512))
val_features = np.reshape(val_features, (1000, 7 * 7 * 512))
Con las características extraídas, entrenamos un clasificador con scikit-learn:
from sklearn.svm import SVC
classifier = SVC(kernel='linear')
classifier.fit(train_features, train_labels)
accuracy = classifier.score(val_features, val_labels)
print(f'Precisión del clasificador SVM: {accuracy * 100:.2f}%')
De esta manera combinamos la potencia de los modelos pre-entrenados para extracción de características con la flexibilidad de los algoritmos de scikit-learn.
Todas las lecciones de OpenCV
Accede a todas las lecciones de OpenCV y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción E Instalación De Opencv
Introducción Y Entorno
Carga Y Visualización De Imágenes
Manipulación Imágenes
Operaciones Básicas En Imágenes
Manipulación Imágenes
Detección De Bordes Y Contornos
Procesamiento Y Análisis
Histograma Y Ecualización
Procesamiento Y Análisis
Preprocesamiento Para Machine Learning
Aprendizaje Automático
Clasificación De Imágenes Con Ml
Aprendizaje Automático
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender la clasificación de imágenes con scikit-learn.
- Aprender a convertir imágenes en vectores de características.
- Saber cómo redimensionar y procesar imágenes con OpenCV.
- Emplear máquinas de vectores de soporte para clasificación.
- Evaluar modelos con técnicas de validación cruzada.