def generate_perturbation(
        self,
        height: int,
        width: int,
        device: torch.device | None = None,
        anomaly_source_path: Path | str | None = None,
    ) -> tuple[torch.Tensor, torch.Tensor]:
        """Generate perturbed image and mask.

        Args:
            height: Height of the output image.
            width: Width of the output image.
            device: Device to generate the perturbation on.
            anomaly_source_path: Optional path to source image for anomaly.

        Returns:
            tuple[torch.Tensor, torch.Tensor]: Tuple containing:
                - Perturbation tensor of shape ``[H, W, C]``
                - Mask tensor of shape ``[H, W, 1]``
        """
        # Generate perlin noise
        perlin_noise = generate_perlin_noise(height, width, device=device)

        # Create rotated noise pattern
        perlin_noise = perlin_noise.unsqueeze(0)  # [1, H, W]
        perlin_noise = self.perlin_rotation_transform(perlin_noise).squeeze(0)  # [H, W]

        # Generate binary mask from perlin noise
        mask = torch.where(
            perlin_noise > 0.5,
            torch.ones_like(perlin_noise, device=device),
            torch.zeros_like(perlin_noise, device=device),
        ).unsqueeze(-1)  # [H, W, 1]

        # Generate anomaly source image
        if anomaly_source_path:
            anomaly_source_img = (
                io.read_image(str(anomaly_source_path), mode=io.ImageReadMode.RGB).float().to(device) / 255.0
            )
            if anomaly_source_img.shape[-2:] != (height, width):
                anomaly_source_img = v2.functional.resize(anomaly_source_img, [height, width], antialias=True)
            anomaly_source_img = anomaly_source_img.permute(1, 2, 0)  # [H, W, C]
        else:
            anomaly_source_img = perlin_noise.unsqueeze(-1).repeat(1, 1, 3)  # [H, W, C]
            anomaly_source_img = (anomaly_source_img * 0.5) + 0.25  # Adjust intensity range

        # Apply augmentations to source image
        anomaly_augmented = self.augmenters(anomaly_source_img.permute(2, 0, 1))  # [C, H, W]
        anomaly_augmented = anomaly_augmented.permute(1, 2, 0)  # [H, W, C]

        # Create final perturbation by applying mask
        perturbation = anomaly_augmented * mask

        return perturbation, mask
Generate perturbed image and mask.

        Args:
            height: Height of the output image.
            width: Width of the output image.
            device: Device to generate the perturbation on.
            anomaly_source_path: Optional path to source image for anomaly.

        Returns:
            tuple[torch.Tensor, torch.Tensor]: Tuple containing:
                - Perturbation tensor of shape ``[H, W, C]``
                - Mask tensor of shape ``[H, W, 1]``
        
src/anomalib/data/utils/generators/perlin.py