Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Added

- πŸš€ Add 3D-ADAM dataset by @PaulMcHard in https://github.com/open-edge-platform/anomalib/pull/2986
- πŸš€ Add BMAD dataset by @code-dev05 in https://github.com/open-edge-platform/anomalib/pull/2900

### Removed
Expand Down
10 changes: 10 additions & 0 deletions examples/configs/data/adam_3d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class_path: anomalib.data.ADAM3D
init_args:
root: ./datasets/ADAM3D
category: "1m1"
train_batch_size: 32
eval_batch_size: 32
num_workers: 8
test_split_mode: from_dir
val_split_mode: from_dir
seed: null
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies = [
"opencv-python>=4.5.3.56",
"scikit-image",
"tifffile",
"imagecodecs",
"kornia>=0.6.6",
# Data science and analysis
"pandas>=1.1.0",
Expand Down
6 changes: 4 additions & 2 deletions src/anomalib/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

# Datamodules
from .datamodules.base import AnomalibDataModule
from .datamodules.depth import DepthDataFormat, Folder3D, MVTec3D
from .datamodules.depth import ADAM3D, DepthDataFormat, Folder3D, MVTec3D
from .datamodules.image import (
BMAD,
MPDD,
Expand All @@ -70,7 +70,7 @@

# Datasets
from .datasets import AnomalibDataset
from .datasets.depth import Folder3DDataset, MVTec3DDataset
from .datasets.depth import ADAM3DDataset, Folder3DDataset, MVTec3DDataset
from .datasets.image import (
BMADDataset,
BTechDataset,
Expand Down Expand Up @@ -177,6 +177,7 @@ def get_datamodule(config: DictConfig | ListConfig | dict) -> AnomalibDataModule
# Depth Data Modules
"Folder3D",
"MVTec3D",
"ADAM3D",
# Image Data Modules
"BMAD",
"BTech",
Expand Down Expand Up @@ -204,6 +205,7 @@ def get_datamodule(config: DictConfig | ListConfig | dict) -> AnomalibDataModule
"FolderDataset",
"KolektorDataset",
"MPDDDataset",
"ADAM3DDataset",
"MVTecADDataset",
"MVTecLOCODataset",
"TabularDataset",
Expand Down
4 changes: 3 additions & 1 deletion src/anomalib/data/datamodules/depth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from enum import Enum

from .adam_3d import ADAM3D
from .folder_3d import Folder3D
from .mvtec_3d import MVTec3D

Expand All @@ -14,6 +15,7 @@ class DepthDataFormat(str, Enum):

MVTEC_3D = "mvtec_3d"
FOLDER_3D = "folder_3d"
ADAM_3D = "adam_3d"


__all__ = ["Folder3D", "MVTec3D"]
__all__ = ["Folder3D", "MVTec3D", "ADAM3D"]
146 changes: 146 additions & 0 deletions src/anomalib/data/datamodules/depth/adam_3d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Copyright (C) 2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

"""3D-ADAM Datamodule.

This module provides a PyTorch Lightning DataModule for the 3D-ADAM dataset.
The dataset contains RGB and depth image pairs for anomaly detection tasks.

Example:
Create a ADAM3D datamodule::

>>> from anomalib.data import ADAM3D
>>> datamodule = ADAM3D(
... root="./datasets/ADAM3D",
... category="1m1"
... )

License:
3D-ADAM dataset is released under the Creative Commons
Attribution-NonCommercial-ShareAlike 4.0 International License
(CC BY-NC-SA 4.0).
https://creativecommons.org/licenses/by-nc-sa/4.0/

Reference: https://arxiv.org/abs/2507.07838

"""

import logging
from pathlib import Path
from shutil import move

from torchvision.transforms.v2 import Transform

from anomalib.data.datamodules.base.image import AnomalibDataModule
from anomalib.data.datasets.depth.adam_3d import ADAM3DDataset
from anomalib.data.utils import DownloadInfo, Split, TestSplitMode, ValSplitMode, download_and_extract

logger = logging.getLogger(__name__)


DOWNLOAD_INFO = DownloadInfo(
name="adam_3d",
url="https://huggingface.co/datasets/pmchard/3D-ADAM_anomalib/resolve/main/adam3d_cropped.zip",
hashsum="ffc4c52afa1566a4165c42300c21758ec8292ff04305c65e81e830abb8200c36",
)


class ADAM3D(AnomalibDataModule):
"""3D-ADAM Datamodule.

Args:
root (Path | str): Path to the root of the dataset.
Defaults to ``"./datasets/ADAM3D"``.
category (str): Category of the 3D-ADAM dataset (e.g. ``"1m1"`` or
``"spiral_gear"``). Defaults to ``"1m1"``.
train_batch_size (int, optional): Training batch size.
Defaults to ``32``.
eval_batch_size (int, optional): Test batch size.
Defaults to ``32``.
num_workers (int, optional): Number of workers for data loading.
Defaults to ``8``.
train_augmentations (Transform | None): Augmentations to apply dto the training images
Defaults to ``None``.
val_augmentations (Transform | None): Augmentations to apply to the validation images.
Defaults to ``None``.
test_augmentations (Transform | None): Augmentations to apply to the test images.
Defaults to ``None``.
augmentations (Transform | None): General augmentations to apply if stage-specific
augmentations are not provided.
test_split_mode (TestSplitMode | str): Method to create test set.
Defaults to ``TestSplitMode.FROM_DIR``.
test_split_ratio (float): Fraction of data to use for testing.
Defaults to ``0.2``.
val_split_mode (ValSplitMode | str): Method to create validation set.
Defaults to ``ValSplitMode.SAME_AS_TEST``.
val_split_ratio (float): Fraction of data to use for validation.
Defaults to ``0.5``.
seed (int | None, optional): Random seed for reproducibility.
Defaults to ``None``.
"""

def __init__(
self,
root: Path | str = "./datasets/ADAM3D",
category: str = "1m1",
train_batch_size: int = 32,
eval_batch_size: int = 32,
num_workers: int = 8,
train_augmentations: Transform | None = None,
val_augmentations: Transform | None = None,
test_augmentations: Transform | None = None,
augmentations: Transform | None = None,
test_split_mode: TestSplitMode | str = TestSplitMode.FROM_DIR,
test_split_ratio: float = 0.2,
val_split_mode: ValSplitMode | str = ValSplitMode.SAME_AS_TEST,
val_split_ratio: float = 0.5,
seed: int | None = None,
) -> None:
super().__init__(
train_batch_size=train_batch_size,
eval_batch_size=eval_batch_size,
num_workers=num_workers,
train_augmentations=train_augmentations,
val_augmentations=val_augmentations,
test_augmentations=test_augmentations,
augmentations=augmentations,
test_split_mode=test_split_mode,
test_split_ratio=test_split_ratio,
val_split_mode=val_split_mode,
val_split_ratio=val_split_ratio,
seed=seed,
)

self.root = Path(root)
self.category = category

def _setup(self, _stage: str | None = None) -> None:
"""Set up the datasets.

Args:
_stage (str | None, optional): Stage of setup. Not used.
Defaults to ``None``.
"""
self.train_data = ADAM3DDataset(
split=Split.TRAIN,
root=self.root,
category=self.category,
)
self.test_data = ADAM3DDataset(
split=Split.TEST,
root=self.root,
category=self.category,
)

def prepare_data(self) -> None:
"""Download the dataset if not available."""
if (self.root / self.category).is_dir():
logger.info("Found the dataset.")
else:
download_and_extract(self.root, DOWNLOAD_INFO)
# The Huggingface dataset is stored in adam3d_cropped
# Move the contents to the root
extracted_folder = self.root / "adam3d_cropped"
for filename in extracted_folder.glob("*"):
move(str(filename), str(self.root / filename.name))
extracted_folder.rmdir()
2 changes: 2 additions & 0 deletions src/anomalib/data/datamodules/image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class ImageDataFormat(str, Enum):
- ``VISA``: Visual Anomaly Dataset
"""

ADAM_3D = "adam_3d"
BMAD = "bmad"
BTECH = "btech"
DATUMARO = "datumaro"
Expand All @@ -86,6 +87,7 @@ class ImageDataFormat(str, Enum):


__all__ = [
"ADAM_3D",
"BMAD",
"BTech",
"Datumaro",
Expand Down
4 changes: 3 additions & 1 deletion src/anomalib/data/datasets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Depth Datasets:
- ``Folder3DDataset``: Custom RGB-D dataset from folder structure
- ``MVTec3DDataset``: MVTec 3D AD dataset with industrial objects
- ``ADAM3DDataset``: 3D ADAM dataset with additive manufactured objects

Image Datasets:
- ``BTechDataset``: BTech dataset containing industrial objects
Expand Down Expand Up @@ -40,7 +41,7 @@
"""

from .base import AnomalibDataset, AnomalibDepthDataset, AnomalibVideoDataset
from .depth import Folder3DDataset, MVTec3DDataset
from .depth import ADAM3DDataset, Folder3DDataset, MVTec3DDataset
from .image import (
BMADDataset,
BTechDataset,
Expand All @@ -63,6 +64,7 @@
# Depth
"Folder3DDataset",
"MVTec3DDataset",
"ADAM3DDataset",
# Image
"BMADDataset",
"BTechDataset",
Expand Down
4 changes: 3 additions & 1 deletion src/anomalib/data/datasets/depth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

- ``Folder3DDataset``: Custom dataset for loading RGB-D data from a folder structure
- ``MVTec3DDataset``: Implementation of the MVTec 3D-AD dataset
- ``ADAM3DDataset``: Implementation of the 3D-ADAM dataset

Example:
>>> from anomalib.data.datasets import Folder3DDataset
Expand All @@ -25,7 +26,8 @@
... )
"""

from .adam_3d import ADAM3DDataset
from .folder_3d import Folder3DDataset
from .mvtec_3d import MVTec3DDataset

__all__ = ["Folder3DDataset", "MVTec3DDataset"]
__all__ = ["Folder3DDataset", "MVTec3DDataset", "ADAM3DDataset"]
Loading
Loading