class_docstr: Implementation of the ObjectSeeker certifiable robust defense applied to object detection models.
  The original implementation is https://github.com/inspire-group/ObjectSeeker
  
  | Paper link: https://arxiv.org/abs/2202.01811
class_docstr_tok: ["Implementation","of","the","ObjectSeeker","certifiable","robust","defense","applied","to","object","detection","models",".","The","original","implementation","is","https",":","\/\/github.com\/inspire-group\/ObjectSeeker","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/2202.01811"]
docstr: Cluster the bounding boxes for the pruned masked predictions.
  
  :param masked_preds: The merged masked predictions of a single image already pruned.
  :return: The clustered masked predictions with overlapping boxes merged.
docstr_tok: ["Cluster","the","bounding","boxes","for","the","pruned","masked","predictions",".",":","param","masked_preds",":","The","merged","masked","predictions","of","a","single","image","already","pruned",".",":","return",":","The","clustered","masked","predictions","with","overlapping","boxes","merged","."]
code: def _unionize_clusters(
      self, masked_preds: Dict[str, np.ndarray]
  ) -> Dict[str, np.ndarray]:
      """
      Cluster the bounding boxes for the pruned masked predictions.
  
      :param masked_preds: The merged masked predictions of a single image already pruned.
      :return: The clustered masked predictions with overlapping boxes merged.
      """
      boxes = masked_preds["boxes"]
      labels = masked_preds["labels"]
      scores = masked_preds["scores"]
  
      # Skip clustering if not enough bounding boxes
      if len(boxes) <= 1:
          return masked_preds
  
      unionized_boxes = []
      unionized_labels = []
      unionized_scores = []
  
      unique_labels = np.unique(labels)
      for label in unique_labels:
          # Select bounding boxes of same class
          mask = labels == label
          selected_boxes = boxes[mask]
          selected_scores = scores[mask]
  
          # Calculate pairwise distances between bounding boxes
          areas = (selected_boxes[:, 2] - selected_boxes[:, 0]) * (
              selected_boxes[:, 3] - selected_boxes[:, 1]
          )
          top_left = np.maximum(
              selected_boxes[:, None, :2], selected_boxes[:, :2]
          )
          bottom_right = np.minimum(
              selected_boxes[:, None, 2:], selected_boxes[:, 2:]
          )
          pairwise_intersection = np.prod(
              np.clip(bottom_right - top_left, 0, None), axis=2
          )
          pairwise_ioa = pairwise_intersection / (areas[:, None])
          distances = 1 - np.maximum(pairwise_ioa, pairwise_ioa.T)
  
          # Cluster bounding boxes
          dbscan = DBSCAN(
              eps=self.epsilon, min_samples=1, metric="precomputed"
          )
          clusters = dbscan.fit_predict(distances)
          num_clusters = np.max(clusters) + 1
  
          for cluster in range(num_clusters):
              # Merge all boxes in the cluster
              clustered_boxes = selected_boxes[clusters == cluster]
  
              clustered_box = [
                  np.min(clustered_boxes[:, 0]),
                  np.min(clustered_boxes[:, 1]),
                  np.max(clustered_boxes[:, 2]),
                  np.max(clustered_boxes[:, 3]),
              ]
              clustered_score = np.max(selected_scores)
  
              unionized_boxes.append(clustered_box)
              unionized_labels.append(label)
              unionized_scores.append(clustered_score)
  
      unionized_predictions = {
          "boxes": np.asarray(unionized_boxes),
          "labels": np.asarray(unionized_labels),
          "scores": np.asarray(unionized_scores),
      }
      return unionized_predictions
  
file_path: adversarial-robustness-toolbox/art/estimators/certification/object_seeker/object_seeker.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import abc
  import logging
  from typing import Dict, List, Tuple
  import numpy
  from sklearn.cluster import DBSCAN
  from tqdm.auto import tqdm
  from art.utils import intersection_over_area, non_maximum_suppression
label_desc: Use image node_id 8 for calling the ObjectSeekerMixin obj's underlying member method code with example usage: obj._unionize_clusters(masked_preds) and returns: unionized_predictions, masked_preds