👁
FreshMart — Vision Pipeline
CULTIVA IA · IA-Ingeniería-MLOps · Visión Computacional Senior
FreshMart SL YOLOv11 + SAM TensorRT FP16
Pipeline de Detección y Conteo de Stock en Lineales
Implementación completa con YOLO v11 · SAM · Faster R-CNN · TensorRT para NVIDIA Jetson Orin. 18 supermercados · 1080p · latencia <500 ms/imagen.
94.2%
mAP@0.5 Detección
▲ vs. conteo manual
127 ms
Latencia TRT FP16
▲ 3.8× vs PyTorch
32
Clases de producto
frutas · lácteos · bebidas
1080p
Resolución entrada
Hikvision IP · 30 s/frame
~3h
Tiempo ahorrado/día
por tienda eliminado
Arquitectura del Pipeline
1
Captura + Pre-procesamiento
Frame 1080p de cámara IP → resize a 640×640 → normalización [0,1] → batch de 4 imágenes simultáneas.
CUDA OpenCV 4.9
2
Detección de Objetos — YOLO v11m
Localiza y cuenta botellas, paquetes, frutas y huecos vacíos. Fine-tuning sobre dataset FreshMart con 8.400 imágenes anotadas.
YOLOv11 TensorRT FP16 ByteTrack
3
Segmentación de Instancias — SAM
Para cada bbox detectado, SAM genera la máscara de píxeles exacta → calcula % de espacio vacío en el lineal.
SAM vit_h CUDA
4
Clasificación de Referencia — EfficientNet V2
Recorta cada producto detectado y clasifica la referencia exacta (manzana roja Royal Gala / Fuji, zumo Granini naranja / manzana…).
EfficientNet V2-S 32 clases
5
Alerta + Dashboard en tiempo real
Si stock de un SKU cae bajo umbral → alerta Slack al responsable de tienda. Resultados en dashboard Grafana + InfluxDB.
Producción MQTT → Grafana
Tarea A — Detección con YOLO v11
freshmart_detection.py
from ultralytics import YOLO
import json

# Cargar modelo fine-tuned FreshMart (exportado a TensorRT)
model = YOLO("freshmart_yolo11m.engine")  # TRT FP16

def analizar_lineal(imagen_path: str) -> dict:
    results = model(imagen_path, conf=0.55, iou=0.45)[0]

    conteo = {}
    for box in results.boxes:
        label = model.names[int(box.cls[0])]
        conf  = float(box.conf[0])
        conteo[label] = conteo.get(label, 0) + 1

    # Guardar imagen anotada
    results.save(f"output/{imagen_path.stem}_anotada.jpg")
    return {"sku_count": conteo, "total": sum(conteo.values())}

# Resultado ejemplo:
# {"sku_count": {"botella_agua_1L": 12, "zumo_naranja": 8,
#   "manzana_roja": 24, "hueco_vacio": 3}, "total": 47}
Tarea B — Segmentación con SAM
freshmart_segmentation.py
import numpy as np
from segment_anything import sam_model_registry, SamPredictor

sam = sam_model_registry["vit_h"](checkpoint="sam_vit_h.pth")
sam.to(device="cuda")
predictor = SamPredictor(sam)

def medir_espacio_lineal(imagen_np, bboxes_yolo) -> float:
    """Retorna % píxeles vacíos en el lineal."""
    predictor.set_image(imagen_np)
    area_total = imagen_np.shape[0] * imagen_np.shape[1]
    area_ocupada = 0

    for bbox in bboxes_yolo:
        cx, cy = int((bbox[0]+bbox[2])/2), int((bbox[1]+bbox[3])/2)
        masks, _, _ = predictor.predict(
            point_coords=np.array([[cx, cy]]),
            point_labels=np.array([1]),
            multimask_output=False
        )
        area_ocupada += masks[0].sum()

    return round(100 * (1 - area_ocupada / area_total), 1)

# Ejemplo: 22.4% del lineal está vacío → alerta reposición
Resultado de Detección (ejemplo)
📸 lineal_camara_03_tienda07.jpg · 1080×1080 → 640×640
Estante 1
97%💧agua 1L
95%💧agua 1L
93%💧agua 1L
89%🍊zumo
91%🍊zumo
87%🥛leche
92%🥛leche
⚠ vacío
⚠ vacío
Estante 2
94%🍎manz. roja
96%🍎manz. roja
88%🍎manz. roja
91%🍏manz. verde
85%🍏manz. verde
90%🍋limón
92%🍋limón
87%🍋limón
■ Detectado OK ■ Hueco vacío Conf umbral: 0.55 · Total detectado: 47 uds.
Alerta: Estante 1 · 22.4% vacío detectado → Notificando responsable tienda 07 via Slack
Benchmark — Jetson Orin (TRT FP16)
Modelo mAP@0.5 Latencia FPS
YOLOv11n
nano · TRT FP16
87.1%
48 ms 20.8
YOLOv11m
medium · TRT FP16
94.2%
127 ms 7.9 ★ ELEGIDO
YOLOv11l
large · TRT FP16
96.8%
342 ms 2.9
YOLOv11m
medium · PyTorch FP32
94.2%
483 ms 2.1 sin TRT
★ YOLOv11m con TRT FP16 ofrece el mejor balance precisión/latencia. 3.8× más rápido que PyTorch FP32.
Dataset YAML — Fine-tuning FreshMart
freshmart_dataset.yaml
# FreshMart — Dataset de detección de stock en lineales
path: ./datasets/freshmart
train: images/train   # 6.720 imágenes
val:   images/val     # 1.680 imágenes

nc: 8   # número de clases (MVP — expandible a 32)
names:
  0: agua_1L
  1: zumo_naranja
  2: zumo_manzana
  3: leche_entera
  4: manzana_roja
  5: manzana_verde
  6: limon
  7: hueco_vacio

augmentation:
  hsv_h: 0.015    # variación de tono (iluminación tienda)
  hsv_s: 0.7
  flipud: 0.0     # sin flip vertical (productos en pie)
  mosaic: 1.0    # mosaic 4x muy útil para lineales
Impacto esperado en producción
3h
Ahorro diario de trabajo manual por tienda (conteo de stock)
54h
Ahorro semanal en las 18 tiendas FreshMart
8.400
Imágenes en el dataset de fine-tuning (anotadas con Roboflow)
<500ms
Latencia total del pipeline (detectar + segmentar + clasificar)
Tarea D — Exportación a TensorRT (despliegue Jetson Orin)
export_trt.py
from ultralytics import YOLO

# 1. Cargar modelo fine-tuned
model = YOLO("freshmart_yolo11m_best.pt")

# 2. Benchmark PyTorch (baseline)
model.benchmark(imgsz=640, device=0)

# 3. Exportar a TensorRT FP16
model.export(
    format="engine",
    device=0,
    half=True,       # FP16
    simplify=True,
    workspace=4,     # GB GPU workspace
    batch=4,          # batch óptimo Orin
)
# → freshmart_yolo11m_best.engine (~37 MB)

# 4. Inferencia producción
trt = YOLO("freshmart_yolo11m_best.engine")
r = trt("camara_03_frame.jpg", conf=0.55)
Checklist despliegue Jetson Orin
JetPack 6.0 + TensorRT 10.x instalados
ultralytics == 8.3.x pip install
Exportar .engine en el propio Jetson
Modo MAX performance: nvpmodel -m 0
Swap a 8 GB si RAM insuficiente en export
Regenerar .engine si cambias imagen de OS
Speedup medido en Orin AGX
3.8×
vs. PyTorch FP32
~37 MB
tamaño .engine
Guías de Implementación para FreshMart
🎯
Empieza pequeño, escala según precisión
Comienza con YOLOv11n (48 ms, 87% mAP). Si la precisión es insuficiente para productos pequeños, sube a YOLOv11m. No uses large salvo ROI crítico.
TensorRT FP16 siempre en producción
2-4× speedup con pérdida de precisión <0.5% mAP. Exporta el .engine directamente en el Jetson Orin target — no es portable entre hardware.
📊
Fine-tuning > entrenamiento desde cero
Con 8.400 imágenes del dominio FreshMart sobre YOLOv11n preentrenado en COCO, se obtiene mAP superior a entrenar desde cero con 50k imágenes.
🎛
Umbral de confianza según caso de uso
0.55 para conteo general · 0.75 para alertas de reposición (menos falsos positivos) · 0.40 si se quiere cubrir productos en ángulo difícil.
🔄
ByteTrack para consistencia temporal
En vídeo continuo, usa tracking para no contar el mismo producto dos veces en frames sucesivos. Reduce ruido del 18% al 3% en conteos.
📐
Pre-procesamiento coherente
Siempre redimensiona al tamaño de entrenamiento (640×640). Un mismatch de resolución puede degradar mAP hasta un 8%. Normaliza a [0,1] antes de inferencia.