class_docstr: This module implements Expectation over Transformation preprocessing for image rotation in PyTorch.
docstr: Transformation of an input image and its label by randomly sampled rotation.
  
  :param x: Input samples.
  :param y: Label of the samples `x`.
  :return: Transformed samples and labels.
code: def _transform(
      self,
      x: "torch.Tensor",
      y: Optional[
          Union["torch.Tensor", List[Dict[str, "torch.Tensor"]]]
      ],
      **kwargs,
  ) -> Tuple[
      "torch.Tensor",
      Optional[Union["torch.Tensor", List[Dict[str, "torch.Tensor"]]]],
  ]:
      """
      Transformation of an input image and its label by randomly sampled rotation.
  
      :param x: Input samples.
      :param y: Label of the samples `x`.
      :return: Transformed samples and labels.
      """
      import torch
      import torchvision
  
      if isinstance(self.angles, list):
          angles = np.random.choice(self.angles).item()
      else:
          angles = np.random.uniform(
              low=self.angles_range[0], high=self.angles_range[1]
          )
  
      # Ensure channels-first
      channels_first = True
      if x.shape[-1] in [1, 3]:
          x = torch.permute(x, (0, 3, 1, 2))
          channels_first = False
  
      expand = self.label_type == "object_detection"
  
      x_preprocess = torchvision.transforms.functional.rotate(
          img=x,
          angle=angles,
          interpolation=torchvision.transforms.functional.InterpolationMode.NEAREST,
          expand=expand,
      )
  
      x_preprocess = torch.clamp(
          input=x_preprocess,
          min=-self.clip_values[0],
          max=self.clip_values[1],
      )
  
      y_preprocess: Optional[
          Union["torch.Tensor", List[Dict[str, "torch.Tensor"]]]
      ]
  
      if self.label_type == "object_detection" and y is not None:
          y_od: List[Dict[str, "torch.Tensor"]] = [{}]
  
          if isinstance(y, list):
              if isinstance(y[0], dict):
                  y_od[0]["boxes"] = torch.clone(y[0]["boxes"])
                  y_od[0]["labels"] = torch.clone(y[0]["labels"])
              else:
                  raise TypeError(
                      "Wrong type for `y` and label_type=object_detection."
                  )
          else:
              raise TypeError(
                  "Wrong type for `y` and label_type=object_detection."
              )
  
          y_b = y[0]["boxes"]
          image_width = x.shape[2]
          image_height = x.shape[1]
          x_1_arr = y_b[:, 0]
          y_1_arr = y_b[:, 1]
          x_2_arr = y_b[:, 2]
          y_2_arr = y_b[:, 3]
          box_width = x_2_arr - x_1_arr
          box_height = y_2_arr - y_1_arr
  
          if angles == 0:
              x_1_new = x_1_arr
              y_1_new = y_1_arr
              x_2_new = x_2_arr
              y_2_new = y_2_arr
  
          elif angles == 90:
              x_1_new = y_1_arr
              y_1_new = image_width - x_1_arr - box_width
              x_2_new = y_1_arr + box_height
              y_2_new = image_width - x_1_arr
  
          elif angles == 180:
              x_1_new = image_width - x_2_arr
              y_1_new = image_height - y_2_arr
              x_2_new = x_1_new + box_width
              y_2_new = y_1_new + box_height
  
          elif angles == 270:
              x_1_new = image_height - y_1_arr - box_height
              y_1_new = x_1_arr
              x_2_new = image_height - y_1_arr
              y_2_new = x_1_arr + box_width
  
          else:
              raise ValueError(
                  "The angle is not supported for object detection."
              )
  
          y_od[0]["boxes"][:, 0] = x_1_new
          y_od[0]["boxes"][:, 1] = y_1_new
          y_od[0]["boxes"][:, 2] = x_2_new
          y_od[0]["boxes"][:, 3] = y_2_new
  
          y_preprocess = y_od
  
      else:
          y_preprocess = y
  
      if not channels_first:
          x_preprocess = torch.permute(x_preprocess, (0, 2, 3, 1))
  
      return x_preprocess, y_preprocess
  
file_path: adversarial-robustness-toolbox/art/preprocessing/expectation_over_transformation/image_rotation/pytorch.py
imports: import logging
  from typing import Dict, List, Optional, TYPE_CHECKING, Tuple, Union
  import numpy
  from art.preprocessing.expectation_over_transformation.pytorch import EoTPyTorch
label_desc: Use image node_id 2 for calling the EoTImageRotationPyTorch obj's underlying member method code with example usage: obj._transform(x, y) and returns: x_preprocess,  y_preprocess