class_docstr: Implementation of a particular variation of the DPatch attack.
  It follows Lee & Kolter (2019) in using sign gradients with expectations over transformations.
  The particular transformations supported in this implementation are cropping, rotations by multiples of 90 degrees,
  and changes in the brightness of the image.
  
  | Paper link (original DPatch): https://arxiv.org/abs/1806.02299v4
  | Paper link (physical-world patch from Lee & Kolter): https://arxiv.org/abs/1906.11897
class_docstr_tok: ["Implementation","of","a","particular","variation","of","the","DPatch","attack",".","It","follows","Lee","&","Kolter","(","2019",")","in","using","sign","gradients","with","expectations","over","transformations",".","The","particular","transformations","supported","in","this","implementation","are","cropping",",","rotations","by","multiples","of","90","degrees",",","and","changes","in","the","brightness","of","the","image",".","|","Paper","link","(","original","DPatch",")",":","https",":","\/\/arxiv.org\/abs\/1806.02299v4","|","Paper","link","(","physical-world","patch","from","Lee","&","Kolter",")",":","https",":","\/\/arxiv.org\/abs\/1906.11897"]
docstr: Augment images with patch.
  
  :param x: Sample images.
  :param y: Target labels.
  :param patch: The patch to be applied.
  :param channels_first: Set channels first or last.
docstr_tok: ["Augment","images","with","patch",".",":","param","x",":","Sample","images",".",":","param","y",":","Target","labels",".",":","param","patch",":","The","patch","to","be","applied",".",":","param","channels_first",":","Set","channels","first","or","last","."]
code: def _augment_images_with_patch(
      self,
      x: np.ndarray,
      y: Optional[List[Dict[str, np.ndarray]]],
      patch: np.ndarray,
      channels_first: bool,
  ) -> Tuple[
      np.ndarray,
      List[Dict[str, np.ndarray]],
      Dict[str, Union[int, float]],
  ]:
      """
      Augment images with patch.
  
      :param x: Sample images.
      :param y: Target labels.
      :param patch: The patch to be applied.
      :param channels_first: Set channels first or last.
      """
  
      transformations: Dict[str, Union[float, int]] = {}
      x_copy = x.copy()
      patch_copy = patch.copy()
      x_patch = x.copy()
  
      if channels_first:
          x_copy = np.transpose(x_copy, (0, 2, 3, 1))
          x_patch = np.transpose(x_patch, (0, 2, 3, 1))
          patch_copy = np.transpose(patch_copy, (1, 2, 0))
  
      # Apply patch:
      x_1, y_1 = self.patch_location
      x_2, y_2 = x_1 + patch_copy.shape[0], y_1 + patch_copy.shape[1]
      x_patch[:, x_1:x_2, y_1:y_2, :] = patch_copy
  
      # 1) crop images:
      crop_x = random.randint(0, self.crop_range[0])
      crop_y = random.randint(0, self.crop_range[1])
      x_1, y_1 = crop_x, crop_y
      x_2, y_2 = (
          x_copy.shape[1] - crop_x + 1,
          x_copy.shape[2] - crop_y + 1,
      )
      x_copy = x_copy[:, x_1:x_2, y_1:y_2, :]
      x_patch = x_patch[:, x_1:x_2, y_1:y_2, :]
  
      transformations.update({"crop_x": crop_x, "crop_y": crop_y})
  
      # 2) rotate images:
      rot90 = random.choices(
          [0, 1, 2, 3], weights=self.rotation_weights
      )[0]
  
      x_copy = np.rot90(x_copy, rot90, (1, 2))
      x_patch = np.rot90(x_patch, rot90, (1, 2))
  
      transformations.update({"rot90": rot90})
  
      if y is not None:
          y_copy: List[Dict[str, np.ndarray]] = []
  
          for i_image in range(x_copy.shape[0]):
              y_b = y[i_image]["boxes"].copy()
              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 rot90 == 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
  
              if rot90 == 1:
                  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
  
              if rot90 == 2:
                  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
  
              if rot90 == 3:
                  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
  
              y_i = {}
              y_i["boxes"] = np.zeros_like(y[i_image]["boxes"])
              y_i["boxes"][:, 0] = x_1_new
              y_i["boxes"][:, 1] = y_1_new
              y_i["boxes"][:, 2] = x_2_new
              y_i["boxes"][:, 3] = y_2_new
  
              y_i["labels"] = y[i_image]["labels"]
              y_i["scores"] = y[i_image]["scores"]
  
              y_copy.append(y_i)
  
      # 3) adjust brightness:
      brightness = random.uniform(*self.brightness_range)
      x_copy = (
          np.round(brightness * x_copy / self.learning_rate)
          * self.learning_rate
      )
      x_patch = (
          np.round(brightness * x_patch / self.learning_rate)
          * self.learning_rate
      )
  
      transformations.update({"brightness": brightness})
  
      logger.debug("Transformations: %s", str(transformations))
  
      patch_target: List[Dict[str, np.ndarray]] = []
  
      if self.targeted:
          predictions = y_copy
      else:
          if channels_first:
              x_copy = np.transpose(x_copy, (0, 3, 1, 2))
          predictions = self.estimator.predict(
              x=x_copy, standardise_output=True
          )
  
      for i_image in range(x_copy.shape[0]):
          target_dict = {}
          target_dict["boxes"] = predictions[i_image]["boxes"]
          target_dict["labels"] = predictions[i_image]["labels"]
          target_dict["scores"] = predictions[i_image]["scores"]
  
          patch_target.append(target_dict)
  
      if channels_first:
          x_patch = np.transpose(x_patch, (0, 3, 1, 2))
  
      return x_patch, patch_target, transformations
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/dpatch_robust.py
imports: import logging
  import math
  import random
  from typing import Dict, List, Optional, Tuple, Union, TYPE_CHECKING
  import numpy
  from tqdm.auto import trange
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.object_detection.object_detector import ObjectDetectorMixin
  from art import config
  from art.summary_writer import SummaryWriter
label_desc: Use image node_id 3 for calling the RobustDPatch obj's underlying member method code with example usage: obj._augment_images_with_patch(x, y, patch, channels_first) and returns: x_patch,  patch_target,  transformations