---
pretty_name: XMR Demo — Industrial Foreign-Object Detection (Lentils) — trained pipelines
license: apache-2.0
library_name: cuvis-ai
pipeline_tag: image-segmentation
tags:
- hyperspectral
- hyperspectral-imaging
- anomaly-detection
- foreign-object-detection
- food-safety
- industrial-inspection
- dinomaly
- dinov2
- cuvis-ai
- cu3s
- cubert
- xmr
---
# Trained Dinomaly anomaly-detection pipelines for industrial lentils
Three pre-trained [Cuvis.AI](https://docs.cuvis.ai) pipelines for hyperspectral foreign-object detection on a sliding lentil conveyor. All three use the same architecture (a frozen DINOv2 backbone with a Dinomaly anomaly head and a two-stage gate-then-quantile binary decider); they differ only in **which three bands the channel-selector node feeds the detector**.
The companion [dataset repo](https://huggingface.co/datasets/cubert-gmbh/XMR_Demo_Industrial_Foreign_Object_Detection_Lentils) contains the CU3S session and annotations used by the notebook. This page is the model-side reference: pipeline folders, hparams, weights, and the minimum code to run inference.
## Pipelines
| Subfolder | Selector node | Wavelengths (nm) | Image threshold | Quantile | Weight (.pt) |
|---|---|---|---|---|---|
| `dinomaly_rgb_full_pipeline/` | `FixedWavelengthSelector` | (650, 550, 450) | 0.140 | 0.995 | `dinomaly_multifile_rgb_two_stage.pt` |
| `dinomaly_cir_full_pipeline/` | `CIRSelector` | NIR=860, R=670, G=560 | 0.140 | 0.995 | `dinomaly_multifile_cir.pt` |
| `dinomaly_custom_selector_full_pipeline/` | `FixedWavelengthSelector` | (542, 902, 886) | 0.151 | 0.995 | `dinomaly_multifile_custom_two_stage.pt` |
The `image_threshold` is the gate on the mean of the top-0.1 % per-pixel anomaly scores; only frames above it are pixel-thresholded against the per-frame `quantile` (0.995). Both knobs are persisted in each pipeline YAML and loaded automatically by `restore-pipeline`.
## Pipeline diagram

1. **LentilsAnomalyDataNode** — reads the `.cu3s` cube, casts to float32, and maps the multi-class GT mask to a binary anomaly mask (used at training/eval; inference reads the cube directly from the dataloader's batch).
2. **MinMaxNormalizer** — running per-cube min-max so the selector sees data in a consistent dynamic range.
3. **rgb_selector / cir_selector** — picks three target wavelengths and emits a 3-channel image. This is the only node that differs between the three methods.
4. **DinomalyDetector** — pre-trained DINOv2 backbone + Dinomaly anomaly head; produces a per-pixel anomaly score map.
5. **TwoStageBinaryDecider** — gates the frame on the mean of the top-k per-pixel scores (image-level threshold), then quantile-thresholds the score map per pixel.
## How to use
The pipelines load with the standard Cuvis.AI restore helpers. Minimal end-to-end snippet:
```python
import torch
from huggingface_hub import hf_hub_download
from cuvis_ai_core.utils.node_registry import NodeRegistry
from cuvis_ai_core.pipeline.pipeline import CuvisPipeline
REPO = "cubert-gmbh/XMR_Demo_Industrial_Foreign_Object_Detection_Lentils"
yaml_path = hf_hub_download(
repo_id=REPO,
subfolder="dinomaly_custom_selector_full_pipeline",
filename="dinomaly_multifile_custom_two_stage.yaml",
)
pt_path = hf_hub_download(
repo_id=REPO,
subfolder="dinomaly_custom_selector_full_pipeline",
filename="dinomaly_multifile_custom_two_stage.pt",
)
# The dinomaly plugin (cuvis-ai-dinomaly v0.1.3) auto-fetches its dependencies
# and the DINOv2 backbone on first use.
registry = NodeRegistry()
registry.load_plugins("configs/plugins/dinomaly.yaml") # ships with cuvis-ai
device = "cuda" if torch.cuda.is_available() else "cpu"
pipeline = CuvisPipeline.load_pipeline(
yaml_path,
weights_path=str(pt_path),
device=device,
strict_weight_loading=False,
node_registry=registry,
)
pipeline.torch_layers.eval()
# ... feed a CU3S batch into pipeline.forward(...)
```
For the full notebook walk-through (preview frames, video export, side-by-side comparison) see `notebooks/use_cases/lentils_dinomaly.ipynb` in the [cuvis-ai repo](https://github.com/cubert-hyperspectral/cuvis-ai).
## Dataset
Recorded on the same product line and conveyor rig described on the companion dataset card:
[**cubert-gmbh/XMR_Demo_Industrial_Foreign_Object_Detection_Lentils**](https://huggingface.co/datasets/cubert-gmbh/XMR_Demo_Industrial_Foreign_Object_Detection_Lentils) (dataset)
Acquisition: Ultris XMR · 50 mm · video mode · 15 ms integration · 4 fps · white & dark references recorded.
## Training details
- **Framework:** [Cuvis.AI](https://github.com/cubert-hyperspectral/cuvis-ai) + [cuvis-ai-dinomaly](https://github.com/cubert-hyperspectral/cuvis-ai-dinomaly) v0.1.3.
- **Backbone:** DINOv2 ViT-B/14 with 4 register tokens (`dinov2reg_vit_base_14`), frozen.
- **Head:** Dinomaly anomaly head from anomalib v2.1.0, image size 448, decoder depth 8, bottleneck dropout 0.2.
- **Loss / optimizer:** Standard Dinomaly training schedule; 50 epochs, weight 1.0 on the train-loss bridge.
- **Decider:** TwoStageBinaryDecider tuned on a held-out NPZ split (pixel F1) — see each yaml's `decider.hparams` for the exact threshold values.
- **Data:** Multi-file conveyor lentil sequences under controlled industrial belt lighting. The published CU3S in the companion dataset is one held-out evaluation session.
## Contact
Trained and packaged by the [AI Team @ Cubert](mailto:cuvis.ai@cubert-gmbh.de). For pilot enquiries on your own product line, reach out via email or the contact details on .