Post-processing#

Base Post-processor

Base class for post-processing.

Base Post-processor
One-class Post-processor

Post-processor for one-class anomaly detection.

One-class Post-processor
MEBin Post-processor

MEBin (Main Element Binarization) post-processor from AnomalyNCD. Uses per-image adaptive thresholds based on connected-component stability analysis.

MEBin Post-processor

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)#

Bases: Module, Callback

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:

InferenceBatch

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:

float

normalize_batch(batch)#

Normalize predicted scores and anomaly maps.

Parameters:

batch (Batch) – Batch containing model predictions.

Return type:

None

property normalized_image_threshold: Tensor#

Get the normalized image-level threshold.

Returns:

Normalized image-level threshold value, adjusted by sensitivity.

Return type:

float

property normalized_pixel_threshold: Tensor#

Get the normalized pixel-level threshold.

Returns:

Normalized pixel-level threshold value, adjusted by sensitivity.

Return type:

float

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:

None

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:

None

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:

None

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:

None

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:

float

post_process_batch(batch)#

Post-process a batch of predictions.

Applies normalization and thresholding to the batch predictions.

Parameters:

batch (Batch) – Batch containing model predictions.

Return type:

None

threshold_batch(batch)#

Apply thresholding to batch predictions.

Parameters:

batch (Batch) – Batch containing model predictions.

Return type:

None

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: PostProcessor

Post-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 standard PostProcessor logic, 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:

InferenceBatch

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.

Parameters:

batch (Batch) – Batch containing model predictions (modified in-place).

Return type:

None

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:

  1. 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.

  2. Per-image: clip pixels below s_min to 0 and linearly map

    [s_min, s_max] → [0, 255] .

  3. Sweep thresholds from 255 → 0 (step sample_rate ). At each threshold, binarize → optionally erode → count connected components.

  4. Find the stable interval in the component-count sequence.

  5. Select the threshold at the endpoint of the longest stable interval.

  6. 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:

tuple[Tensor, Tensor]

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])