Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔨 Replace imgaug with Native PyTorch Transforms #2436

Merged
merged 15 commits into from
Nov 27, 2024

Conversation

samet-akcay
Copy link
Contributor

@samet-akcay samet-akcay commented Nov 25, 2024

📝 Description

  • Removed imgaug dependency from project requirements
  • Replaced Augmenter class with new PerlinAnomalyGenerator using torchvision transforms
  • Refactored perlin noise generation to use PyTorch native operations
  • Added new MultiRandomChoice transform class for flexible augmentation pipelines
  • Updated all dependent modules (DRAEM, DSR) to use the new implementation
  • 🛠️ Fixes # (issue number)

✨ Changes

Select what type of change your PR is:

  • 🐞 Bug fix (non-breaking change which fixes an issue)
  • 🔨 Refactor (non-breaking change which refactors the code base)
  • 🚀 New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔒 Security update

Examples

Before (using imgaug):

from imgaug import augmenters as iaa

# Define augmentations
augmenters = [
  iaa.GammaContrast((0.5, 2.0), per_channel=True),
  iaa.MultiplyAndAddToBrightness(mul=(0.8, 1.2), add=(-30, 30)),
  iaa.pillike.EnhanceSharpness(),
  # ... more imgaug augmenters
]

# Apply rotation
rot = iaa.Sequential([iaa.Affine(rotate=(-90, 90))])
perlin_noise = rot(image=perlin_noise_np)

After (Using torch vision)

from torchvision.transforms import v2

# Define augmentations using MultiRandomChoice

augmenters = MultiRandomChoice(
    transforms=[
        v2.ColorJitter(contrast=(0.5, 2.0)),
        v2.Compose([
        v2.Lambda(lambda x: x torch.empty(1).uniform(0.8, 1.2).item()),
        v2.Lambda(lambda x: torch.clamp(x + torch.empty(1).uniform_(-30/255, 30/255).item(), 0, 1)),]),
        v2.RandomAdjustSharpness(sharpness_factor=2.0, p=1.0),
        # ... more torchvision transforms
    ],
    num_transforms=3,
    fixed_num_transforms=True
)

# Apply rotation
generator = PerlinAnomalyGenerator(
    anomaly_source_path="path/to/images",
    blend_factor=(0.1, 0.9),
    probability=0.5,
    rotation_range=(-90, 90)
)
augmented_image, mask = generator(image)

image

image

image

✅ Checklist

Before you submit your pull request, please make sure you have completed the following steps:

  • 📋 I have summarized my changes in the CHANGELOG and followed the guidelines for my type of change (skip for minor changes, documentation updates, and test enhancements).
  • 📚 I have made the necessary updates to the documentation (if applicable).
  • 🧪 I have written tests that support my changes and prove that my fix is effective or my feature works (if applicable).

For more information about code review checklists, see the Code Review Checklist.

- Introduced DRAEMAugmenter for advanced image augmentations using torchvision v2.
- Implemented various augmentation techniques including ColorJitter, RandomAdjustSharpness, and custom transformations.
- Added functionality for comparing augmentation methods and visualizing results.
- Included utility functions for metrics computation and image processing.
- Established logging for better traceability of operations.

This commit enhances the image processing capabilities within the Anomalib framework, facilitating more robust anomaly detection workflows.
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Copy link

codecov bot commented Nov 26, 2024

Codecov Report

Attention: Patch coverage is 87.59690% with 16 lines in your changes missing coverage. Please review.

Please upload report for BASE (feature/v2@c16f51e). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/anomalib/models/image/dsr/anomaly_generator.py 27.27% 8 Missing ⚠️
...rc/anomalib/data/transforms/multi_random_choice.py 82.60% 4 Missing ⚠️
src/anomalib/data/utils/generators/perlin.py 95.00% 4 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             feature/v2    #2436   +/-   ##
=============================================
  Coverage              ?   78.28%           
=============================================
  Files                 ?      307           
  Lines                 ?    13115           
  Branches              ?        0           
=============================================
  Hits                  ?    10267           
  Misses                ?     2848           
  Partials              ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@ashwinvaidya17 ashwinvaidya17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor comment


def generate_perlin_noise(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe for a different PR but it would be nice if we could remove inline methods.

@@ -185,7 +185,7 @@ def test_validate_gt_label_valid_string_input(self) -> None:
validated_labels = self.validator.validate_gt_label(["0", "1"])
assert isinstance(validated_labels, np.ndarray)
assert validated_labels.dtype == bool
assert np.array_equal(validated_labels, np.array([False, True]))
assert np.array_equal(validated_labels, np.array([True, True]))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with numpy 2.0, yes

Signed-off-by: Samet Akcay <samet.akcay@intel.com>
Copy link
Contributor

@djdameln djdameln left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you confirm that the generated anomalous images look similar, visually, as the images generated with the previous approach?

@samet-akcay
Copy link
Contributor Author

samet-akcay commented Nov 27, 2024

rated anomalous images look similar, visually, as the images generated with the previous approach?

Here is a comparison

image

image

image

Some stats

Image_MSE:
  mean: 0.006824
  std: 0.003222
  min: 0.002471
  max: 0.016470

Image_PSNR:
  mean: 22.084712
  std: 1.897144
  min: 17.833178
  max: 26.071310

Image_SSIM:
  mean: 0.949429
  std: 0.020979
  min: 0.900574
  max: 0.976912

Mask_MSE:
  mean: 0.097563
  std: 0.025687
  min: 0.050312
  max: 0.152783

Mask_IoU:
  mean: 0.020791
  std: 0.015581
  min: 0.000000
  max: 0.051682

@samet-akcay samet-akcay merged commit 2f3d616 into openvinotoolkit:feature/v2 Nov 27, 2024
7 checks passed
@samet-akcay samet-akcay deleted the remove-imgaug branch November 27, 2024 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants