Ir al contenido

← Configuración JSON y referencias golden para visión en Pi

Inspección visual (visión artificial)Raspberry Pi + cámara USBFicherosInfraestructura

Configuración JSON y referencias golden para visión en Pi — ejemplo completo

Persiste los parámetros de cámara y procesado en JSON y gestiona las referencias golden como PNG preprocesados en una estación de inspección con Raspberry Pi.

Programa completo y ejecutable para el Raspberry Pi + cámara USB (json-config-references.py): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

# -*- coding: utf-8 -*-
"""
COMPLETE EXAMPLE — Persistent JSON configuration + reference management

Hardware:  Raspberry Pi + USB camera
Based on:  visual inspection project in production (vision.py, config.json)

Requirements:
    pip install opencv-python numpy

What it does:
    1) Loads (or creates with default values) a config.json with the
       camera parameters (focus / brightness / contrast / saturation)
       and the processing parameters of the pipeline. This way the
       adjustments made on the shop floor survive a Raspberry Pi reboot.
    2) Applies the camera parameters to a cv2.VideoCapture via V4L2.
    3) Manages the references: saves each "good" pattern as an ALREADY
       PROCESSED PNG in references/ (processed once at capture time, not
       on every inspection cycle) and allows listing and loading them.

    The script runs without a camera: if there is no device, it skips
    step 2 and demonstrates the full cycle with a synthetic reference.

Integration with the catalog:
    - The processing parameters feed the OpenCV pipeline
      (ejemplos/inspeccion-visual/opencv-silkscreen-pipeline.py).
    - The PNG references are the template for the rotational matching
      (ejemplos/inspeccion-visual/rotational-template-matching.py).
    - The GUI edits these values with sliders and calls save_config()
      (ejemplos/inspeccion-visual/gui-pyside6-camera-thread.py).
"""

import json
import os
import cv2
import numpy as np

CONFIG_PATH = "config.json"
REFERENCES_DIR = "references"

# Factory defaults: written the first time the application starts
DEFAULT_CONFIG = {
    "camera": {
        "index": 0,          # /dev/video0
        "focus": 50,         # manual focus: autofocus "hunts" in production
        "brightness": 128,
        "contrast": 130,
        "saturation": 100,
    },
    "processing": {
        "bg_threshold": 60,
        "morph_kernel": 5,
        "clahe_clip": 2.0,
        "clahe_grid": 8,
        "block_size": 31,
        "C": 7,
    },
    "matching": {"angle_range": 15, "angle_step": 2, "ok_score": 0.85},
}


def load_config(path=CONFIG_PATH):
    """Loads config.json; if it does not exist, creates it with the defaults."""
    if os.path.exists(path):
        with open(path, "r", encoding="utf-8") as f:
            cfg = json.load(f)
        # Fills in new keys that did not exist in older versions
        for section, values in DEFAULT_CONFIG.items():
            cfg.setdefault(section, {})
            for k, v in values.items():
                cfg[section].setdefault(k, v)
        return cfg
    save_config(DEFAULT_CONFIG, path)
    return dict(DEFAULT_CONFIG)


def save_config(cfg, path=CONFIG_PATH):
    """Persists the configuration in a readable (diff-able) format."""
    with open(path, "w", encoding="utf-8") as f:
        json.dump(cfg, f, indent=2, ensure_ascii=False)
    print(f"Configuration saved to {path}")


def apply_camera_config(cap, cam_cfg):
    """Applies the V4L2 parameters to the USB camera."""
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)  # first disable autofocus
    cap.set(cv2.CAP_PROP_FOCUS, cam_cfg["focus"])
    cap.set(cv2.CAP_PROP_BRIGHTNESS, cam_cfg["brightness"])
    cap.set(cv2.CAP_PROP_CONTRAST, cam_cfg["contrast"])
    cap.set(cv2.CAP_PROP_SATURATION, cam_cfg["saturation"])


def save_reference(name, processed_img):
    """Saves an ALREADY PROCESSED reference as a PNG in references/."""
    os.makedirs(REFERENCES_DIR, exist_ok=True)
    path = os.path.join(REFERENCES_DIR, f"{name}.png")
    cv2.imwrite(path, processed_img)
    print(f"Reference saved: {path}")
    return path


def list_references():
    """Lists the available references (one per part model)."""
    if not os.path.isdir(REFERENCES_DIR):
        return []
    return sorted(f[:-4] for f in os.listdir(REFERENCES_DIR)
                  if f.endswith(".png"))


def load_reference(name):
    """Loads a reference in grayscale, ready for the matching."""
    path = os.path.join(REFERENCES_DIR, f"{name}.png")
    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        raise FileNotFoundError(f"Reference not found: {path}")
    return img


def main():
    # 1) Persistent configuration
    cfg = load_config()
    print("Processing parameters:", cfg["processing"])

    # 2) Camera (only if a device is connected)
    cap = cv2.VideoCapture(cfg["camera"]["index"])
    if cap.isOpened():
        apply_camera_config(cap, cfg["camera"])
        print("Camera configured via V4L2.")
        cap.release()
    else:
        print("No camera connected: skipping V4L2 configuration.")

    # 3) Reference cycle: save -> list -> reload
    demo = np.zeros((200, 300), np.uint8)
    cv2.putText(demo, "IS-42", (60, 120), cv2.FONT_HERSHEY_SIMPLEX, 1.5, 255, 4)
    save_reference("demo_part", demo)
    print("Available references:", list_references())
    ref = load_reference("demo_part")
    print(f"Reference reloaded: {ref.shape[1]}x{ref.shape[0]} px")

    # Simulates an adjustment made by the operator and persists it
    cfg["processing"]["bg_threshold"] = 65
    save_config(cfg)


if __name__ == "__main__":
    main()
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales