code: def from_voc(
      root: str,
      splits: Optional[Union[str, tuple]] = None,
      exts: Optional[Union[str, tuple]] = (".jpg", ".jpeg", ".png"),
  ):
      """
      Construct dataframe from pascal VOC format. Modified from gluon cv.
      Normally you will see a structure like:
      ├── VOC2007
      │   ├── Annotations
      │   ├── ImageSets
      |   |   ├── Main
      |   |   |   ├── train.txt
      |   |   |   ├── test.txt
      │   ├── JPEGImages
  
      Parameters
      ----------
      root
          The root directory for VOC, e.g., the `VOC2007`. If an url is provided, it will be downloaded and extracted.
      splits
          If given, will search for this name in `ImageSets/Main/`, e.g., ('train', 'test')
      exts
          The supported image formats.
  
      Returns
      -------
      A dataframe with columns "image", "rois", and "image_attr".
      """
      if is_url(root):
          root = download(root)
      rpath = Path(root).expanduser()
      img_list = []
  
      class_names = get_detection_classes(root)
  
      NAME_TO_IDX = dict(zip(class_names, range(len(class_names))))
      name_to_index = lambda name: NAME_TO_IDX[name]
  
      if splits:
          logger.debug("Use splits: %s for root: %s", str(splits), root)
          if isinstance(splits, str):
              splits = [splits]
          for split in splits:
              split_file = rpath / "ImageSets" / "Main" / split
              if not split_file.resolve().exists():
                  split_file = (
                      rpath / "ImageSets" / "Main" / (split + ".txt")
                  )
              if not split_file.resolve().exists():
                  raise FileNotFoundError(split_file)
              with split_file.open(mode="r") as fi:
                  img_list += [
                      line.split()[0].strip() for line in fi.readlines()
                  ]
      else:
          logger.debug(
              "No split provided, use full image list in %s, with extension %s",
              str(rpath / "JPEGImages"),
              str(exts),
          )
          if not isinstance(exts, (list, tuple)):
              exts = [exts]
          for ext in exts:
              img_list.extend(
                  [rp.stem for rp in rpath.glob("JPEGImages/*" + ext)]
              )
      d = {"image": [], "rois": []}
      logger.info(f"Number of Images: {len(img_list)}")
      for stem in img_list:
          basename = stem + ".xml"
          anno_file = (rpath / "Annotations" / basename).resolve()
          tree = ET.parse(anno_file)
          xml_root = tree.getroot()
          size = xml_root.find("size")
          im_path = xml_root.find("filename").text
          if "." not in im_path:
              im_path += ".jpg"
          width = float(size.find("width").text)
          height = float(size.find("height").text)
          rois = []
          for obj in xml_root.iter("object"):
              class_label = name_to_index(
                  obj.find("name").text.strip().lower()
              )
              xml_box = obj.find("bndbox")
              xmin = max(0, float(xml_box.find("xmin").text) - 1)
              ymin = max(0, float(xml_box.find("ymin").text) - 1)
              xmax = min(width, float(xml_box.find("xmax").text) - 1)
              ymax = min(height, float(xml_box.find("ymax").text) - 1)
              if xmin >= xmax or ymin >= ymax:
                  logger.warning(
                      "Invalid bbox: {%s} for {%s}",
                      str(xml_box),
                      anno_file.name,
                  )
              else:
                  rois.append(
                      [
                          xmin,
                          ymin,
                          xmax,
                          ymax,
                          class_label,
                      ]
                  )
          if rois:
              d["image"].append(str(rpath / "JPEGImages" / im_path))
              d["rois"].append(rois)
      df = pd.DataFrame(d)
      df["label"] = df.loc[
          :, "rois"
      ].copy()  # TODO: remove duplicate column
  
      return df.sort_values("image").reset_index(drop=True)
  
imports: import json
  import logging
  import os
  import warnings
  from pathlib import Path
  from typing import Dict, Iterable, List, Optional, Union
  import defusedxml.ElementTree
  import numpy
  import pandas
  import PIL
  from torchmetrics.detection.mean_ap import MeanAveragePrecision
  from ..constants import BBOX, LABEL, MAP, MAP_50, MAP_75, MAP_LARGE, MAP_MEDIUM, MAP_SMALL, MAR_1, MAR_10, MAR_100, MAR_LARGE, MAR_MEDIUM, MAR_SMALL, MEAN_AVERAGE_PRECISION
  from .download import download, is_url
label_desc: Use image node_id 9 for calling a global function with example usage: from_voc(root, splits, exts) and returns: df