Skip to content

Izanvz/VisuCheck

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VisuCheck

Pipeline modular de análisis visual para imágenes de retail. Le metes una foto de una estantería o de un producto y te devuelve texto extraído, precios detectados, marcas identificadas y una imagen anotada con los resultados.

No entrena modelos. Integra, orquesta y extrae información estructurada usando YOLOv8 + PaddleOCR sobre imágenes reales.


¿Qué hace exactamente?

  1. Preprocesa la imagen — Sharpen, CLAHE, corrección gamma y escalado inteligente para maximizar la calidad del OCR.
  2. Detecta bandas de estantería — Canny edges + HoughLines para segmentar filas y procesar cada zona por separado.
  3. Extrae texto con PaddleOCR — OCR multi-escala (1.0x + 1.5x) con fallback automático GPU → CPU si el entorno no tiene CUDA disponible.
  4. Fusiona y limpia tokens — Agrupa palabras de la misma línea por proximidad, elimina duplicados y aplica fuzzy matching para corregir marcas.
  5. Extrae precios — Regex + heurísticas para normalizar formatos como $12,95, 1295, €2.99 a valores float validados.
  6. Genera resultados estructurados — JSON con todos los tokens, precios detectados, metadatos de tiempo y una imagen anotada.

Stack

Componente Herramienta
API REST FastAPI ≥ 0.115
Detección de objetos YOLOv8 ≥ 8.3 (modelo sku110k.pt)
OCR PaddleOCR ≥ 2.9
Procesado de imagen OpenCV ≥ 4.10 + Pillow ≥ 10.4
Interfaz web Streamlit ≥ 1.39
Fuzzy matching RapidFuzz (corrección de marcas)

Estructura del proyecto

VisuCheck/
├── src/
│   ├── app/                  # Servidor FastAPI (main.py, schemas.py)
│   ├── core/
│   │   ├── detectors/        # Wrapper YoloDetector
│   │   ├── ocr/              # PaddleOCR + Tesseract + preprocesado
│   │   ├── rules/            # Parsers de precios, pesos, variantes
│   │   └── utils/            # Carga de configuración YAML
│   ├── services/
│   │   ├── pipeline.py       # Pipeline principal (analyze_image) ← núcleo del sistema
│   │   └── annotate.py       # Anotación visual de resultados
│   ├── lang/                 # LLM/reasoning (estructura preparada, no activo)
│   └── ui/app.py             # Frontend Streamlit
│
├── scripts/
│   ├── analyze_samples.py    # Procesa imágenes en batch
│   ├── analyze_shelf.py      # Análisis con segmentación por estanterías
│   ├── export_results.py     # Exporta JSONs a JSONL
│   ├── import_to_sqlite.py   # Importa resultados a SQLite
│   └── visualize_results.py  # Visualiza anotaciones
│
├── dashboard/app.py          # Dashboard para revisar resultados generados
│
├── configs/
│   ├── datasets.yaml         # Paths de datos y modelos
│   ├── detector.yaml         # Configuración YOLO
│   ├── ocr.yaml              # Configuración PaddleOCR
│   └── rules/                # Reglas por dominio (precios, pesos, variantes)
│
├── data/
│   ├── samples/              # Imágenes de ejemplo (versionadas)
│   └── results/              # Salida generada (ignorada por git)
│
└── pyproject.toml

Instalación

# 1. Clona el repo
git clone https://github.com/Izanvz/VisuCheck.git
cd VisuCheck

# 2. Crea el entorno virtual (Python 3.10+)
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate

# 3. Instala dependencias
pip install -e .

Si tienes GPU NVIDIA y quieres acelerar el OCR, asegúrate de tener CUDA instalado. PaddleOCR intenta usar GPU automáticamente y hace fallback a CPU si no puede.

Requisito del sistema: FFmpeg no es necesario aquí, pero sí tener los drivers de GPU correctos si quieres aprovechar CUDA.


Uso

Procesar imágenes en batch (CLI)

python -m scripts.analyze_samples --glob "data/samples/*.*" --warmup --lang en --outdir data/results --txt

Parámetros:

Flag Descripción Default
--glob Patrón de imágenes a procesar data/samples/*.*
--lang Idioma para PaddleOCR en
--outdir Carpeta de salida data/results
--txt Guardar también .txt además del .json false
--warmup Precarga el modelo OCR antes del primer análisis false

Salida por cada imagen: {nombre}.json + {nombre}_viz.jpg (anotada)

Análisis con segmentación de estanterías

python -m scripts.analyze_shelf \
  --glob "data/samples/*.jpg,data/samples/*.png" \
  --lang en \
  --outdir data/results \
  --font "C:\Windows\Fonts\arial.ttf"

Detecta las bandas horizontales de la estantería y procesa cada fila por separado. Mejora los resultados en imágenes con mucho texto a distintas alturas.

API REST

uvicorn src.app.main:app --reload --port 8000

Dashboard de resultados

streamlit run dashboard/app.py

Visualiza los JSONs generados en data/results/. Muestra la imagen original junto a la imagen anotada y el JSON completo.

Frontend (envía imágenes a la API)

streamlit run src/ui/app.py

Interfaz para subir imágenes directamente al servidor FastAPI y ver la respuesta.


API

POST /analyze

Analiza una imagen y devuelve los resultados estructurados.

Request: multipart/form-data

Campo Tipo Descripción
image File Imagen JPG o PNG
ruleset string Conjunto de reglas a aplicar (ej: producto_simple_v1)

Response:

{
  "status": "valid",
  "failures": [],
  "evidence": {
    "objects": [
      { "label": "producto", "conf": 0.87, "bbox": { "x": 100, "y": 50, "w": 200, "h": 150 } }
    ],
    "ocr": [
      { "text": "FOLGERS", "bbox": { "x": 110, "y": 60, "w": 80, "h": 20 }, "conf": 0.95 }
    ],
    "scores": {}
  },
  "explanation": "",
  "artifacts": {}
}

status puede ser valid, invalid o uncertain.


Formato de salida interno (JSON por imagen)

{
  "meta": {
    "image": "test.jpg",
    "init_ms": 234,
    "ocr_ms": 456,
    "total_ms": 690,
    "device": "GPU",
    "lang": "en",
    "raw_boxes": 45,
    "merged_lines": 28,
    "shelf_bands": [[0, 150], [150, 300]],
    "scale": 1.5
  },
  "items": [
    { "text": "FOLGERS", "conf": 0.95, "boxes": [[[x1,y1],[x2,y2],[x3,y3],[x4,y4]]] }
  ],
  "texts": ["FOLGERS", "COFFEE", "12,95"],
  "prices": [["$12,95", 12.95], ["€1,99", 1.99]]
}

Configuración

Todo el comportamiento del sistema está parametrizado en configs/. Cambias el YAML y cambias el comportamiento sin tocar el código.

configs/detector.yaml — YOLO

model: "artifacts/yolo/sku110k.pt"
fallback_model: "yolov8n.pt"
confidence_threshold: 0.25
iou_threshold: 0.45
device: "cuda"

configs/ocr.yaml — PaddleOCR

lang: "en"
use_gpu: true
use_angle_cls: true

configs/rules/price.yaml — Patrones de precios

price_patterns:
  - '(?:\$|€|£)\s?([0-9]+[\.,][0-9]{2})'
  - '([0-9]+[\.,][0-9]{2})\s?(USD|EUR|GBP)'
currency_symbols: ['$', '€', '£']

Scripts auxiliares

# Exportar resultados a JSONL (un token por línea, listo para ML)
python -m scripts.export_results --glob "data/results/*.json" --out data/exports/tokens.jsonl

# Importar a SQLite
python -m scripts.import_to_sqlite --glob "data/results/*.json" --db data/visucheck.db

# Limpiar y normalizar precios detectados
python -m scripts.clean_prices --glob "data/results/*.json"

# Visualizar anotaciones
python -m scripts.visualize_results --glob "data/results/*.json"

Cómo funciona el preprocesado

El pipeline en services/pipeline.py aplica este stack antes de lanzar el OCR:

  1. Escalado — Si el lado largo es menor de 2600px, escala la imagen proporcionalmente
  2. Sharpenimg * 1.4 - blur * 0.4 para aumentar nitidez de bordes
  3. CLAHE — Equalización de histograma adaptativa en canal L del espacio LAB (clipLimit=3.0)
  4. Gamma correction — γ=1.20 para recuperar detalle en zonas oscuras
  5. OCR multi-escala — Corre PaddleOCR a 1.0x y 1.5x, combina resultados y remapea coordenadas

Después del OCR, fusiona tokens de la misma fila (mismo eje Y ± 60% de la altura del token, distancia horizontal < 260px) y aplica fuzzy matching para corregir marcas conocidas.


Modelo YOLO (descarga manual)

El repo incluye fallback a yolov8n.pt (descarga automática con ultralytics), pero para retail el modelo recomendado es SKU110K:

  1. Descarga sku110k.pt desde Hugging Face / repositorios de la comunidad
  2. Ponlo en artifacts/yolo/sku110k.pt

Si no existe ese archivo, el sistema carga yolov8n.pt automáticamente.


Estado del proyecto

Pausado — La arquitectura está completa y el pipeline funciona sobre las imágenes de muestra. No está orientado a producción. Lo pausé cuando alcancé el objetivo principal: diseñar un sistema modular donde cambiar el OCR, el detector o las reglas no rompe el resto.

Lo que queda pendiente si se retoma:

  • Activar diarización real con pyannote (separar fuentes en imágenes con texto superpuesto)
  • Conectar la capa lang/ (LangGraph + LangChain) para razonamiento sobre los resultados
  • Añadir base de datos real (SQLAlchemy + aiosqlite ya están como dependencia)
  • Soporte multiidioma configurable por imagen
  • Entrenamiento fine-tuning sobre dataset propio de retail español

Autor

Izan Villarejo Adames — Backend Developer & AI Engineer


"La IA no es el producto. El sistema que la integra correctamente, sí."

About

VisuCheck es un sistema de análisis visual automatizado que combina visión por computador y OCR para detectar objetos, extraer texto y estructurar información a partir de imágenes. Está diseñado como un pipeline modular, escalable y orientado a automatizar procesos de verificación y análisis documental.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages