flowers102.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. from pathlib import Path
  2. from typing import Any, Callable, Optional, Tuple
  3. import PIL.Image
  4. from .utils import check_integrity, download_and_extract_archive, download_url, verify_str_arg
  5. from .vision import VisionDataset
  6. class Flowers102(VisionDataset):
  7. """`Oxford 102 Flower <https://www.robots.ox.ac.uk/~vgg/data/flowers/102/>`_ Dataset.
  8. .. warning::
  9. This class needs `scipy <https://docs.scipy.org/doc/>`_ to load target files from `.mat` format.
  10. Oxford 102 Flower is an image classification dataset consisting of 102 flower categories. The
  11. flowers were chosen to be flowers commonly occurring in the United Kingdom. Each class consists of
  12. between 40 and 258 images.
  13. The images have large scale, pose and light variations. In addition, there are categories that
  14. have large variations within the category, and several very similar categories.
  15. Args:
  16. root (string): Root directory of the dataset.
  17. split (string, optional): The dataset split, supports ``"train"`` (default), ``"val"``, or ``"test"``.
  18. transform (callable, optional): A function/transform that takes in an PIL image and returns a
  19. transformed version. E.g, ``transforms.RandomCrop``.
  20. target_transform (callable, optional): A function/transform that takes in the target and transforms it.
  21. download (bool, optional): If true, downloads the dataset from the internet and
  22. puts it in root directory. If dataset is already downloaded, it is not
  23. downloaded again.
  24. """
  25. _download_url_prefix = "https://www.robots.ox.ac.uk/~vgg/data/flowers/102/"
  26. _file_dict = { # filename, md5
  27. "image": ("102flowers.tgz", "52808999861908f626f3c1f4e79d11fa"),
  28. "label": ("imagelabels.mat", "e0620be6f572b9609742df49c70aed4d"),
  29. "setid": ("setid.mat", "a5357ecc9cb78c4bef273ce3793fc85c"),
  30. }
  31. _splits_map = {"train": "trnid", "val": "valid", "test": "tstid"}
  32. def __init__(
  33. self,
  34. root: str,
  35. split: str = "train",
  36. transform: Optional[Callable] = None,
  37. target_transform: Optional[Callable] = None,
  38. download: bool = False,
  39. ) -> None:
  40. super().__init__(root, transform=transform, target_transform=target_transform)
  41. self._split = verify_str_arg(split, "split", ("train", "val", "test"))
  42. self._base_folder = Path(self.root) / "flowers-102"
  43. self._images_folder = self._base_folder / "jpg"
  44. if download:
  45. self.download()
  46. if not self._check_integrity():
  47. raise RuntimeError("Dataset not found or corrupted. You can use download=True to download it")
  48. from scipy.io import loadmat
  49. set_ids = loadmat(self._base_folder / self._file_dict["setid"][0], squeeze_me=True)
  50. image_ids = set_ids[self._splits_map[self._split]].tolist()
  51. labels = loadmat(self._base_folder / self._file_dict["label"][0], squeeze_me=True)
  52. image_id_to_label = dict(enumerate((labels["labels"] - 1).tolist(), 1))
  53. self._labels = []
  54. self._image_files = []
  55. for image_id in image_ids:
  56. self._labels.append(image_id_to_label[image_id])
  57. self._image_files.append(self._images_folder / f"image_{image_id:05d}.jpg")
  58. def __len__(self) -> int:
  59. return len(self._image_files)
  60. def __getitem__(self, idx: int) -> Tuple[Any, Any]:
  61. image_file, label = self._image_files[idx], self._labels[idx]
  62. image = PIL.Image.open(image_file).convert("RGB")
  63. if self.transform:
  64. image = self.transform(image)
  65. if self.target_transform:
  66. label = self.target_transform(label)
  67. return image, label
  68. def extra_repr(self) -> str:
  69. return f"split={self._split}"
  70. def _check_integrity(self):
  71. if not (self._images_folder.exists() and self._images_folder.is_dir()):
  72. return False
  73. for id in ["label", "setid"]:
  74. filename, md5 = self._file_dict[id]
  75. if not check_integrity(str(self._base_folder / filename), md5):
  76. return False
  77. return True
  78. def download(self):
  79. if self._check_integrity():
  80. return
  81. download_and_extract_archive(
  82. f"{self._download_url_prefix}{self._file_dict['image'][0]}",
  83. str(self._base_folder),
  84. md5=self._file_dict["image"][1],
  85. )
  86. for id in ["label", "setid"]:
  87. filename, md5 = self._file_dict[id]
  88. download_url(self._download_url_prefix + filename, str(self._base_folder), md5=md5)