Skip to content

Stanford cars #5166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/datasets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ You can also create your own datasets using the provided :ref:`base classes <bas
SBU
SEMEION
Sintel
StanfordCars
STL10
SUN397
SVHN
Expand Down
56 changes: 56 additions & 0 deletions test/test_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2463,5 +2463,61 @@ def _meta_to_split_and_classification_ann(self, meta, idx):
return (image_id, class_id, species, breed_id)


class StanfordCarsTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.StanfordCars
REQUIRED_PACKAGES = ("scipy",)
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(train=(True, False))
FEATURE_TYPES = (PIL.Image.Image, int)

def _inject_fake_data(self, tmpdir, config):
import scipy.io as io
from numpy.core.records import fromarrays # to record arrays similar to matlab format

train = config["train"]
num_examples = 5
root_folder = os.path.join(tmpdir, "stanforddcars")
os.makedirs(root_folder, exist_ok=True)

# generate random data for labels
class_name = np.random.randint(0, 100, num_examples, dtype=np.uint8)
bbox_x1 = np.random.randint(0, 100, num_examples, dtype=np.uint8)
bbox_x2 = np.random.randint(0, 100, num_examples, dtype=np.uint8)

bbox_y1 = np.random.randint(0, 100, num_examples, dtype=np.uint8)
bb1ox_y2 = np.random.randint(0, 100, num_examples, dtype=np.uint8)
fname = [f"{i:5d}.jpg" for i in range(num_examples)]

rec_array = fromarrays(
[bbox_x1, bbox_y1, bbox_x2, bb1ox_y2, class_name, fname],
names=["bbox_x1", "bbox_y1", "bbox_x2", "bbox_y2", "class", "fname"],
)

if train:
# create training image folder
datasets_utils.create_image_folder(
root=root_folder,
name="cars_train",
file_name_fn=lambda image_index: f"{image_index:5d}.jpg",
num_examples=num_examples,
)
devkit = os.path.join(root_folder, "devkit")
io.savemat(
f"{devkit}/cars_train_annos.mat", {"annotations": rec_array}
) # save the recorded array as matlab file
else:
# create test image folder
datasets_utils.create_image_folder(
root=root_folder,
name="cars_test",
file_name_fn=lambda image_index: f"{image_index:5d}.jpg",
num_examples=num_examples,
)
io.savemat(
f"{root_folder}/cars_test_annos_withlabels.mat", {"annotations": rec_array}
) # save recorded array as matlab file

return num_examples


if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions torchvision/datasets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .sbd import SBDataset
from .sbu import SBU
from .semeion import SEMEION
from .standford_cars import StanfordCars
from .stl10 import STL10
from .sun397 import SUN397
from .svhn import SVHN
Expand All @@ -51,6 +52,7 @@
"QMNIST",
"MNIST",
"KMNIST",
"StanfordCars",
"STL10",
"SUN397",
"SVHN",
Expand Down
145 changes: 145 additions & 0 deletions torchvision/datasets/standford_cars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import os
import os.path
from typing import Callable, Optional

from PIL import Image

from .utils import download_and_extract_archive, download_url
from .vision import VisionDataset


class StanfordCars(VisionDataset):
"""`Stanford Cars <https://ai.stanford.edu/~jkrause/cars/car_dataset.html>`_ Dataset

.. warning::

This class needs `scipy <https://docs.scipy.org/doc/>`_ to load target files from `.mat` format.

Args:
root (string): Root directory of dataset
train (bool, optional):If True, creates dataset from training set, otherwise creates from test set
transform (callable, optional): A function/transform that takes in an PIL image
and returns a transformed version. E.g, ``transforms.RandomCrop``
target_transform (callable, optional): A function/transform that takes in the
target and transforms it.
download (bool, optional): If True, downloads the dataset from the internet and
puts it in root directory. If dataset is already downloaded, it is not
downloaded again."""

urls = (
"https://ai.stanford.edu/~jkrause/car196/cars_test.tgz",
"https://ai.stanford.edu/~jkrause/car196/cars_train.tgz",
) # test and train image urls

md5s = (
"4ce7ebf6a94d07f1952d94dd34c4d501",
"065e5b463ae28d29e77c1b4b166cfe61",
) # md5checksum for test and train data

annot_urls = (
"https://ai.stanford.edu/~jkrause/car196/cars_test_annos_withlabels.mat",
"https://ai.stanford.edu/~jkrause/cars/car_devkit.tgz",
) # annotations and labels for test and train

annot_md5s = (
"b0a2b23655a3edd16d84508592a98d10",
"c3b158d763b6e2245038c8ad08e45376",
) # md5 checksum for annotations

def __init__(
self,
root: str,
train: bool = True,
transform: Optional[Callable] = None,
target_transform: Optional[Callable] = None,
download: bool = False,
) -> None:

try:
from scipy.io import loadmat

self._loadmat = loadmat
except ImportError:
raise RuntimeError("Scipy is not found. This dataset needs to have scipy installed: pip install scipy")

super().__init__(root, transform=transform, target_transform=target_transform)

self.train = train

if download:
self.download()

if not self._check_exists():
raise RuntimeError("Dataset not found. You can use download=True to download it")

self._samples = self._make_dataset()
self.classes = self._get_classes_name() # class_id to class_name mapping

def _get_class_names(self) -> dict:
"""
Returns Mapping of class ids to class names in form of Dictionary
"""
meta_data = self._loadmat(os.path.join(self.root, "devkit/cars_meta.mat"))
class_names = meta_data["class_names"][0]
return {class_name[0].replace(" ", "_").replace("/", "_"): i for i, class_name in enumerate(class_names)}

def _make_dataset(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _make_dataset(self):
def _make_dataset(self) -> List[Tuple[str, int]]:

"""
Returns Annotations for training data and testing data
"""
annotations = None
if self.train:
annotations = self._loadmat(os.path.join(self.root, "devkit/cars_train_annos.mat"))
else:
annotations = self._loadmat(os.path.join(self.root, "cars_test_annos_withlabels.mat"))
samples = []
annotations = annotations["annotations"][0]
for index in range(len(annotations)):
target = annotations[index][4][0, 0]
image_file = annotations[index][5][0]
# Beware: Stanford cars targets starts at 1
target = target - 1
samples.append((image_file, target))
return samples

def __len__(self) -> int:
return len(self._samples)

def __getitem__(self, idx: int) -> (Image, int):
"""Returns pil_image and class_id for given index"""
image_file, target = self._samples[idx]
image_path = os.path.join(self.root, f"cars_{'train' if self.train else 'test'}", image_file)
pil_image = Image.open(image_path).convert("RGB")

if self.transform is not None:
pil_image = self.transform(pil_image)
if self.target_transform is not None:
target = self.target_transform(target)
return pil_image, target

def download(self) -> None:
if self._check_exists():
return
else:
download_and_extract_archive(
url=self.urls[self.train], download_root=self.root, extract_root=self.root, md5=self.md5s[self.train]
)
download_and_extract_archive(
url=self.annot_urls[1], download_root=self.root, extract_root=self.root, md5=self.annot_md5s[1]
)
if not self.train:
download_url(
url=self.annot_urls[0],
filename="cars_test_annos_withlabels.mat",
root=self.root,
md5=self.annot_md5s[0],
)

def _check_exists(self) -> bool:
return (
os.path.exists(os.path.join(self.root, f"cars_{'train' if self.train else 'test'}"))
and os.path.isdir(os.path.join(self.root, f"cars_{'train' if self.train else 'test'}"))
and os.path.exists(os.path.join(self.root, "devkit/cars_meta.mat"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is not created in the test and thus, all tests are failing.

if self.train
else os.path.exists(os.path.join(self.root, "cars_test_annos_withlabels.mat"))
)