Tutorial Práctico: Etiquetado de Datos con LabelMe para Entrenar un Modelo Mask-RCNN Personalizado (Incluye Script de Organización de Datos)

En proyectos de visión por computadora, la segmentación por instancias juega un papel crucial al conectar la “reconocimiento” con la “comprensión”. No solo identifica qué objetos están en una imagen, sino que también delinea con precisión el contorno de cada uno. Este nivel de precisión a nivel de píxeles es fundamental en aplicaciones como la inspección industrial, el análisis de imágenes médicas y el percepción autonómica. Mask R-CNN es un marco clásico en este campo, conocido por su rendimiento sólido y diseño arquitectónico claro, lo que lo convierte en la eleción preferida de muchos ingenieros y investigadores para tareas de segmentación personalizadas. Sin embargo, pasar del código de un repositorio de papers a un modelo que funcione estables en datos propios implica superar una barrera llamada “ingeniería”. Este proceso va más allá de ejecutar un script de entrenamiento; implica diseñar un flujo de trabajo de etiquetado de datos, limpiar y convertir los datos de anotación, normalizar la estructura de directorios y optimizar los parámetros para escenarios de muestras pequeñas. En este artículo, te guiaré paso a paso a través de este proceso desde la perspectiva de un profesional, ayudándote a construir una canalización de entrenamiento de Mask R-CNN personalizada robusta y reproducible.

  1. Punto de Partida Ingenieril: Construyendo un Marco de Gestión de Datos Claro

Antes de escribir una sola línea de código de entrenamiento, un plan de gestión de datos bien pensado puede ahorrarte mucho tiempo de depuración posterior. Una organización desordenada de datos es a menudo el origen de muchos problemas en proyectos.

1.1 Diseño de una Estructura de Directorios Escalable

Una estructura de directorios excelente debe separar responsabilidades, mantener rutas claras y facilitar la gestión de versiones e inclusión incremental de datos. Recomiendo la siguiente estructura, que ha sido probada en múltiples proyectos reales:

proyecto_custom_mask_rcnn/
├── datos/
│   ├── imagenes_brutas/         # Almacena todas las imágenes originales
│   ├── anotaciones/             # Archivos de anotación originales (como .json de Labelme)
│   ├── procesados/              # Conjunto de datos estándar procesados
│   │   ├── entrenamiento/
│   │   │   ├── imagenes/      # Imágenes de entrenamiento
│   │   │   └── mascaras/      # Máscaras de entrenamiento (PNG monocanal)
│   │   └── validacion/
│   │       ├── imagenes/      # Imágenes de validación
│   │       └── mascaras/      # Máscaras de validación
│   └── json_labelme/          # Carpeta intermedia generada por Labelme (opcional, para depuración)
├── scripts/                     # Todos los scripts de procesamiento de datos y entrenamiento
├── configuraciones/             # Archivos de configuración del modelo
├── registros/                   # Registros de entrenamiento y archivos de TensorBoard
├── modelos/                     # Pesos de modelos entrenados guardados
└── src/                         # Código central del modelo (como Mask R-CNN modificado)


¿Por qué esta estructura?

  • imagenes\_brutas y anotaciones separados: Mantén los datos originales intactos, cualquier procesamiento genera nuevos archivos, evitando sobrescribir.
  • Directorio procesados estándarizado: Este es el formato directamente alimentado al modelo. Usar imagenes/mascaras es la expectativa de muchos marcos, reduciendo costos de adaptación.
  • Directorio scripts independiente: Gestiona todos los scripts de preprocesamiento, conversión y visualización, formando una cadena de herramientas reutilizables.

1.2 Conversión Automatizada desde Anotaciones de Labelme a Máscaras Estándar

Usar Labelme para anotaciones poligonales es muy intuitivo, pero los archivos JSON generados deben convertirse en imágenes de máscaras que el modelo pueda leer directamente. El núcleo de este proceso es analizar las coordenadas poligonales en JSON y llenarlas en máscaras a nivel de píxel. A continuación, se presenta un script de conversión mejorado que incluye manejo de errores y capacidad de operaciones por lotes.

# scripts/conversor_labelme_a_mascara.py
import json
import os
import numpy as np
import cv2
from PIL import Image
import argparse
from tqdm import tqdm

def convertir_json_individual(ruta_json, directorio_salida_mascara, directorio_salida_vis=None):
    """
    Convierte un archivo JSON individual de Labelme en una imagen de máscara y una imagen visualizada.
    
    Parámetros:
        ruta_json: Ruta del archivo JSON de Labelme.
        directorio_salida_mascara: Directorio de salida para las imágenes de máscara.
        directorio_salida_vis: Directorio de salida para las imágenes visualizadas (opcional).
    """
    try:
        with open(ruta_json, 'r') as archivo:
            datos = json.load(archivo)
        
        altura_imagen = datos['imageHeight']
        anchura_imagen = datos['imageWidth']
        # Crear una máscara cero completa
        mascara = np.zeros((altura_imagen, anchura_imagen), dtype=np.uint8)
        
        # Asignar un ID entero único a cada objeto (comenzando desde 1, 0 para fondo)
        for idx, forma in enumerate(datos['shapes'], start=1):
            etiqueta = forma['label']
            puntos = np.array(forma['points'], dtype=np.int32)
            
            # Llenar el polígono usando OpenCV
            cv2.fillPoly(mascara, [puntos], color=idx)
            
            # Si es necesario, registrar la correspondencia entre nombre de etiqueta e ID aquí
        
        # Generar el nombre del archivo de máscara (generalmente con el mismo nombre que la imagen original)
        nombre_base = os.path.splitext(os.path.basename(datos['imagePath']))[0]
        nombre_archivo_mascara = f"{nombre_base}.png"
        ruta_mascara = os.path.join(directorio_salida_mascara, nombre_archivo_mascara)
        
        # Guardar la imagen de máscara monocanal
        Image.fromarray(mascara).save(ruta_mascara)
        
        # Opcional: Guardar resultados visualizados para revisión
        if directorio_salida_vis:
            # ... código de visualización ...
            pass
            

Etiquetas: Labelme mask-rcnn Segmentación por Instancias Visión por Computadora

Publicado el 9-10 21:50