Post-processing#
Base class for post-processing.
Post-processor for one-class anomaly detection.
MEBin (Main Element Binarization) post-processor from AnomalyNCD. Uses per-image adaptive thresholds based on connected-component stability analysis.
Base Post-processor#
Post-processing module for anomaly detection results.
This module provides post-processing functionality for one-class anomaly detection
outputs through the PostProcessor class.
- The post-processor handles:
Normalizing image and pixel-level anomaly scores
Computing adaptive thresholds for anomaly classification
Applying sensitivity adjustments to thresholds
Formatting results for downstream use
Example
>>> from anomalib.post_processing import PostProcessor
>>> post_processor = PostProcessor(image_sensitivity=0.5)
>>> predictions = post_processor(anomaly_maps=anomaly_maps)
- class anomalib.post_processing.post_processor.PostProcessor(enable_normalization=True, enable_thresholding=True, enable_threshold_matching=True, image_sensitivity=0.5, pixel_sensitivity=0.5, **kwargs)#
-
Post-processor for anomaly detection.
- This class handles post-processing of anomaly detection results by:
Normalizing image and pixel-level anomaly scores
Computing adaptive thresholds for anomaly classification
Applying sensitivity adjustments to thresholds
Formatting results for downstream use
- Parameters:
enable_normalization (
bool) – Enable normalization of anomaly scores. Defaults to True.enable_thresholding (
bool) – Enable thresholding of anomaly scores. Defaults to True.enable_threshold_matching (
bool) – Use image-level threshold for pixel-level predictions when pixel-level threshold is not available, and vice-versa. Defaults to True.image_sensitivity (
float) – Sensitivity value for image-level predictions. Higher values make the model more sensitive to anomalies. Defaults to None.pixel_sensitivity (
float) – Sensitivity value for pixel-level predictions. Higher values make the model more sensitive to anomalies. Defaults to None.**kwargs – Additional keyword arguments passed to parent class.
Example
>>> from anomalib.post_processing import PostProcessor >>> post_processor = PostProcessor(image_sensitivity=0.5) >>> predictions = post_processor(anomaly_maps=anomaly_maps)
- forward(predictions)#
Post-process model predictions.
- Parameters:
predictions (
InferenceBatch) – Batch containing model predictions.- Returns:
- Post-processed batch with normalized scores and
thresholded predictions.
- Return type:
- Raises:
ValueError – If neither pred_score nor anomaly_map is provided.
- property image_threshold: Tensor#
Get the image-level threshold.
- Returns:
Image-level threshold value.
- Return type:
- normalize_batch(batch)#
Normalize predicted scores and anomaly maps.
- property normalized_image_threshold: Tensor#
Get the normalized image-level threshold.
- Returns:
Normalized image-level threshold value, adjusted by sensitivity.
- Return type:
- property normalized_pixel_threshold: Tensor#
Get the normalized pixel-level threshold.
- Returns:
Normalized pixel-level threshold value, adjusted by sensitivity.
- Return type:
- on_predict_batch_end(trainer, pl_module, outputs, *args, **kwargs)#
Normalize predicted scores and anomaly maps.
- Parameters:
trainer (
Trainer) – PyTorch Lightning trainer instance.pl_module (
LightningModule) – PyTorch Lightning module instance.outputs (
Batch) – Batch containing model predictions.*args – Variable length argument list.
**kwargs – Arbitrary keyword arguments.
- Return type:
- on_test_batch_end(trainer, pl_module, outputs, *args, **kwargs)#
Apply post-processing steps to current batch of predictions.
- Parameters:
trainer (
Trainer) – PyTorch Lightning trainer instance.pl_module (
LightningModule) – PyTorch Lightning module instance.outputs (
Batch) – Batch containing model predictions.*args – Variable length argument list.
**kwargs – Arbitrary keyword arguments.
- Return type:
- on_validation_batch_end(trainer, pl_module, outputs, *args, **kwargs)#
Update normalization and thresholding metrics using batch output.
- Parameters:
trainer (
Trainer) – PyTorch Lightning trainer instance.pl_module (
LightningModule) – PyTorch Lightning module instance.outputs (
Batch) – Batch containing model predictions and ground truth.*args – Variable length argument list.
**kwargs – Arbitrary keyword arguments.
- Return type:
- on_validation_epoch_end(trainer, pl_module)#
Compute final threshold and normalization values.
- Parameters:
trainer (
Trainer) – PyTorch Lightning trainer instance.pl_module (
LightningModule) – PyTorch Lightning module instance.
- Return type:
- property pixel_threshold: Tensor#
Get the pixel-level threshold.
If the pixel-level threshold is not set, the image-level threshold is used.
- Returns:
Pixel-level threshold value.
- Return type:
- post_process_batch(batch)#
Post-process a batch of predictions.
Applies normalization and thresholding to the batch predictions.
One-class Post-processor#
MEBin Post-processor#
MEBin (Main Element Binarization) is an adaptive binarization method introduced in the AnomalyNCD paper. It determines per-image thresholds by sweeping thresholds across the anomaly map, counting connected components at each level, and selecting the threshold at the endpoint of the longest stable interval.
MEBin is precision-oriented: it favours high-confidence anomaly regions over exhaustive coverage. Pixel-level F1 may be lower than the default post-processor, but the resulting masks are well-suited for downstream tasks such as anomaly classification.
MEBin post-processor for anomaly detection.
This module provides a post-processor that uses the MEBin (Main Element
Binarization) algorithm to adaptively determine per-image thresholds for anomaly
map binarization. Unlike the default PostProcessor which uses a single
global F1-adaptive threshold, MEBinPostProcessor computes a per-image
threshold based on connected-component stability analysis.
- Reference:
“AnomalyNCD: Towards Novel Anomaly Class Discovery in Industrial Scenarios”, CVPR 2025. https://arxiv.org/abs/2410.14379 HUST-SLOW/AnomalyNCD
Example
>>> from anomalib.models import Padim
>>> from anomalib.post_processing import MEBinPostProcessor
>>> post_processor = MEBinPostProcessor()
>>> model = Padim(post_processor=post_processor)
- class anomalib.post_processing.mebin_post_processor.MEBinPostProcessor(sample_rate=4, min_interval_len=4, erode=True, kernel_size=6, **kwargs)#
Bases:
PostProcessorPost-processor using MEBin adaptive binarization.
MEBin determines per-image thresholds by sweeping thresholds across the anomaly map, counting connected components at each level, and selecting the threshold at the endpoint of the longest stable interval (a contiguous range where the component count stays constant).
This post-processor inherits all normalization and metric-tracking functionality from
PostProcessor. The key difference is that pred_mask is computed using the MEBin per-image threshold instead of the global F1-adaptive threshold.Note
MEBin is precision-oriented — it suppresses false positives at the cost of recall. Pixel-level F1 might be lower than the default post-processor, but the resulting masks are better suited for downstream tasks like anomaly class discovery.
- Parameters:
sample_rate (
int) – Step size for the threshold sweep in the normalised [0, 255] space. Smaller values give finer granularity but are slower. Defaults to 4.min_interval_len (
int) – Minimum length (in sweep steps) of a stable interval to be considered valid. Defaults to 4.erode (
bool) – Whether to apply morphological erosion to the binarized map before counting connected components. Helps suppress noise. Defaults to True.kernel_size (
int) – Size of the square erosion kernel (only used when erode=True). Defaults to 6.**kwargs – Additional keyword arguments passed to
PostProcessor.
Example
>>> from anomalib.post_processing import MEBinPostProcessor >>> processor = MEBinPostProcessor(sample_rate=4, min_interval_len=4) >>> # Use with a model >>> from anomalib.models import Patchcore >>> model = Patchcore(post_processor=processor)
- forward(predictions)#
Post-process model predictions using MEBin adaptive thresholding.
When normalization statistics (
pixel_min/pixel_max) are available (i.e. after a validation pass), the anomaly maps are first normalised using the standardPostProcessorlogic, and then MEBin is applied to compute per-image masks.When normalization statistics are not available (e.g. during standalone inference), MEBin is applied directly to the raw anomaly maps.
- Parameters:
predictions (
InferenceBatch) – Batch of model predictions containing at least one of pred_score or anomaly_map.- Returns:
- Post-processed predictions with:
pred_score – normalised image-level anomaly score
anomaly_map – normalised anomaly map
pred_label – binary image-level label (from global threshold)
pred_mask – binary pixel-level mask (from MEBin)
- Return type:
- Raises:
ValueError – If neither pred_score nor anomaly_map is provided.
- post_process_batch(batch)#
Post-process a batch during on_test_batch_end / on_predict_batch_end.
Applies the inherited normalization (image + pixel level) and then computes the pixel-level mask using MEBin instead of the global threshold.
MEBin (Main Element Binarization) algorithm for anomaly map thresholding.
MEBin is an adaptive binarization method introduced in AnomalyNCD that determines per-image thresholds by finding “stable intervals” in the connected-component count as the threshold is swept from high to low.
The search range is determined by per-image peak anomaly scores: s_max is the maximum peak across images and s_min is the minimum peak. Values below s_min are clipped to 0, and the range [s_min, s_max] is mapped to [0, 255] . This ensures the threshold sweep focuses on the region where anomalies actually appear, matching the reference implementation.
- Reference:
“AnomalyNCD: Towards Novel Anomaly Class Discovery in Industrial Scenarios”, CVPR 2025. https://arxiv.org/abs/2410.14379 HUST-SLOW/AnomalyNCD
The implementation uses kornia (instead of CV2) for connected-component analysis and morphological erosion to be compatible with ONNX/OpenVINO export.
Example
>>> import torch
>>> from anomalib.post_processing.mebin import mebin_binarize
>>> anomaly_maps = torch.rand(4, 1, 256, 256)
>>> masks, thresholds = mebin_binarize(anomaly_maps)
- anomalib.post_processing.mebin.mebin_binarize(anomaly_maps, sample_rate=4, min_interval_len=4, erode=True, kernel_size=6)#
Apply MEBin adaptive binarization to a batch of anomaly maps.
The algorithm follows the reference implementation in AnomalyNCD:
Compute the search range [s_min, s_max] from per-image peak scores (i.e. s_max = max(per-image max) and s_min = min(per-image max) ). This clips background pixels below the noise floor and focuses the threshold sweep on the region where anomalies actually appear.
- Per-image: clip pixels below s_min to 0 and linearly map
[s_min, s_max] → [0, 255] .
Sweep thresholds from 255 → 0 (step sample_rate ). At each threshold, binarize → optionally erode → count connected components.
Find the stable interval in the component-count sequence.
Select the threshold at the endpoint of the longest stable interval.
Map the threshold back to the original score space, binarize, and return binary masks and per-image thresholds.
- Parameters:
anomaly_maps (
Tensor) – Anomaly score maps of shape (B, 1, H, W) .sample_rate (
int) – Step size for the threshold sweep. Defaults to 4 .min_interval_len (
int) – Minimum length of a stable interval. Defaults to 4 .erode (
bool) – Whether to apply morphological erosion before counting connected components. Defaults to True.kernel_size (
int) – Size of the erosion kernel (only used when erode=True). Defaults to 6.
- Returns:
masks : Binary masks of shape (B, 1, H, W) (float, 0/1).
thresholds : Per-image thresholds of shape (B,) in the original anomaly-score space.
- Return type:
Example
>>> import torch >>> maps = torch.rand(4, 1, 256, 256) >>> masks, thresholds = mebin_binarize(maps) >>> masks.shape torch.Size([4, 1, 256, 256]) >>> thresholds.shape torch.Size([4])