← JSON Config and Golden References for Pi Vision
Visual inspection (machine vision)Raspberry Pi + USB cameraFicherosInfrastructure
JSON Config and Golden References for Pi Vision — full example
Persist camera and processing parameters in JSON and manage golden reference images as preprocessed PNGs on a Raspberry Pi visual inspection station.
Complete, runnable program for the Raspberry Pi + USB camera (json-config-references.py): wiring header, requirements and integration notes included.
Download the full project pack — freeThis example + the related ones + bill of materials
Read-only preview.
# -*- 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()
Download the full project pack — freeThis example + the related ones + bill of materials