Skip to content
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

Skip crowd images #361

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
54 changes: 42 additions & 12 deletions alodataset/coco_base_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from typing import Dict, Union



class CocoBaseDataset(BaseDataset):
"""
Attributes
Expand Down Expand Up @@ -73,22 +72,29 @@ def __init__(
classes: list = None,
fix_classes_len: int = None,
return_multiple_labels: list = None,
ignore_classes: list = None,
skip_crowd: bool = True,
**kwargs,
):
super(CocoBaseDataset, self).__init__(name=name, **kwargs)
if self.sample:
return
else:
assert img_folder is not None, "When sample = False, img_folder must be given."
assert ann_file is not None or "test" in img_folder, "When sample = False and the test split is not used, ann_file must be given."

assert (
ann_file is not None or "test" in img_folder
), "When sample = False and the test split is not used, ann_file must be given."

# Create properties
self.img_folder = os.path.join(self.dataset_dir, img_folder)

if "test" in img_folder:
#get a list of indices that don't rely on the annotation file
self.items = [int(Path(os.path.join(self.img_folder, f)).stem) for f in os.listdir(self.img_folder) if os.path.isfile(os.path.join(self.img_folder, f))]
# get a list of indices that don't rely on the annotation file
self.items = [
int(Path(os.path.join(self.img_folder, f)).stem)
for f in os.listdir(self.img_folder)
if os.path.isfile(os.path.join(self.img_folder, f))
]
return

self.coco = COCO(os.path.join(self.dataset_dir, ann_file))
Expand All @@ -103,6 +109,12 @@ def __init__(

self._ids_renamed = classes
self.label_names = label_names

if classes is not None and ignore_classes is not None:
raise Exception("Can't considere both classes & ignore_classes at the same time.")
if ignore_classes is not None:
classes = [l for l in self.label_names if l not in set(ignore_classes + ["N/A"])]

if classes is not None:
notclass = [label for label in classes if label not in self.label_names]
if len(notclass) > 0: # Ignore all labels not in classes
Expand All @@ -122,6 +134,13 @@ def __init__(
ids.append(i)
self.items = ids # Remove images without bboxes with classes in classes list

if skip_crowd:
# Check each annotation and remove crowded ones.
for i in range(len(self.items) - 1, -1, -1):
anns = self.coco.loadAnns(self.coco.getAnnIds(self.items[i]))
if any([ann["iscrowd"] for ann in anns]):
del self.items[i]

# Fix lenght of label_names to a desired `fix_classes_len`
if fix_classes_len is not None:
self._fix_classes(fix_classes_len)
Expand Down Expand Up @@ -172,7 +191,12 @@ def _fix_classes(self, new_label_size):

def _append_labels(self, element: Union[BoundingBoxes2D, Mask], target):
def append_new_labels(element, ltensor, lnames, name):
label_2d = Labels(ltensor.to(torch.float32), labels_names=lnames, names=("N"), encoding="id")
label_2d = Labels(
ltensor.to(torch.float32),
labels_names=lnames,
names=("N"),
encoding="id",
)
element.append_labels(label_2d, name=name)

labels = target["labels"]
Expand All @@ -186,7 +210,10 @@ def append_new_labels(element, ltensor, lnames, name):
# Append supercategory labels
for ktype in self.label_types:
append_new_labels(
element, torch.as_tensor(self.label_types[ktype])[labels], self.label_types_names[ktype], ktype
element,
torch.as_tensor(self.label_types[ktype])[labels],
self.label_types_names[ktype],
ktype,
)

# Append specific labels
Expand All @@ -211,7 +238,11 @@ def _target2aloscene(self, target, frame):

# Create and append labels to boxes
boxes = BoundingBoxes2D(
target["boxes"], boxes_format="xyxy", absolute=True, frame_size=frame.HW, names=("N", None)
target["boxes"],
boxes_format="xyxy",
absolute=True,
frame_size=frame.HW,
names=("N", None),
)
self._append_labels(boxes, target)

Expand Down Expand Up @@ -241,7 +272,7 @@ def getitem(self, idx):

image_id = self.items[idx]
if "test" in self.img_folder:
#get the filename from image_id without relying on annotation file
# get the filename from image_id without relying on annotation file
return Frame(os.path.join(self.img_folder, f"{str(image_id).zfill(12)}.jpg"))

frame = Frame(os.path.join(self.img_folder, self.coco.loadImgs(image_id)[0]["file_name"]))
Expand Down Expand Up @@ -293,7 +324,6 @@ def convert_coco_poly_to_mask(self, segmentations, height, width):
return masks

def __call__(self, image, target):

w, h = image.shape[-1], image.shape[-2]

image_id = target["image_id"]
Expand Down Expand Up @@ -356,11 +386,11 @@ def __call__(self, image, target):

if __name__ == "__main__":
coco_dataset = CocoBaseDataset(sample=False, img_folder="test2017")
#checking if regular getitem works
# checking if regular getitem works
frame = coco_dataset[0]
frame.get_view().render()

#check if dataloader works
# check if dataloader works
for f, frames in enumerate(coco_dataset.train_loader(batch_size=2)):
frames = Frame.batch_list(frames)
frames.get_view().render()
Expand Down
11 changes: 11 additions & 0 deletions alodataset/coco_detection_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class CocoDetectionDataset(CocoBaseDataset, SplitMixin):
Return Labels as a dictionary, with all posible categories found in annotations file, by default False
ann_file : str
Start from a fixe given annotation file where the path is relative to the `dataset_dir`
skip_crowd : bool, optional
Filter out images with `iscrowd` attribute, by default False
Images with crowd are often mislabeled with missing boxes for some persons.
**kwargs : dict
:mod:`BaseDataset <base_dataset>` optional parameters

Expand Down Expand Up @@ -80,6 +83,7 @@ def __init__(
fix_classes_len: int = None,
split=Split.TRAIN,
ann_file=None,
skip_crowd: bool = False,
**kwargs,
):
SplitMixin.__init__(self, split)
Expand Down Expand Up @@ -144,6 +148,13 @@ def __init__(
if fix_classes_len is not None:
self._fix_classes(fix_classes_len)

if skip_crowd:
# Check each annotation and remove crowded ones.
for i in range(len(self.items) - 1, -1, -1):
target = self.items[i][2]["segments_info"]
if any([seg["iscrowd"] for seg in target]):
del self.items[i]

# Re-calcule encoding label types (+stuff)
if self.label_types is not None:
dict_cats = dict()
Expand Down
57 changes: 38 additions & 19 deletions alodataset/coco_panoptic_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class CocoPanopticDataset(BaseDataset, SplitMixin):
fix_classes_len : int, optional
Fix to a specific number the number of classes, filling the rest with "N/A" value.
Use when the number of model outputs does not match with the number of classes in the dataset, by default 250
skip_crowd : bool, optional
Filter out images with `iscrowd` attribute, by default False
Images with crowd are often mislabeled for person boxes and instance segmentation.
**kwargs : dict
:mod:`BaseDataset <base_dataset>` optional parameters

Expand All @@ -61,7 +64,10 @@ class CocoPanopticDataset(BaseDataset, SplitMixin):
"""

SPLIT_FOLDERS = {Split.VAL: "val2017", Split.TRAIN: "train2017"}
SPLIT_ANN_FOLDERS = {Split.VAL: "annotations/panoptic_val2017", Split.TRAIN: "annotations/panoptic_train2017"}
SPLIT_ANN_FOLDERS = {
Split.VAL: "annotations/panoptic_val2017",
Split.TRAIN: "annotations/panoptic_train2017",
}
SPLIT_ANN_FILES = {
Split.VAL: "annotations/panoptic_val2017.json",
Split.TRAIN: "annotations/panoptic_train2017.json",
Expand All @@ -73,9 +79,10 @@ def __init__(
split=Split.TRAIN,
return_masks: bool = True,
classes: list = None,
ignore_classes: list=None,
fix_classes_len: int = None, # Match with pre-trained weights
**kwargs,
ignore_classes: list = None,
fix_classes_len: int = None,
skip_crowd: bool = False,
**kwargs, # Match with pre-trained weights
):
super(CocoPanopticDataset, self).__init__(name=name, split=split, **kwargs)
if self.sample:
Expand All @@ -99,7 +106,7 @@ def __init__(
if classes is not None:
if self.label_names is None:
raise Exception(
"'classes' attribute not support in datasets without 'categories' as attribute in annotation file"
"'classes' attribute not supported in datasets without 'categories' as attribute in annotation file"
)
notclass = [label for label in classes if label not in self.label_names]
if len(notclass) > 0: # Ignore all labels not in classes
Expand All @@ -111,7 +118,7 @@ def __init__(
self._ids_renamed = np.array(self._ids_renamed)
self.label_names = classes

# Check each annotation and keep only that have at least 1 element in classes list
# Check each annotation and keep only that have at least 1 element in classes
items = []
for i, (_, _, ann_info) in enumerate(self.items):
target = ann_info["segments_info"]
Expand All @@ -137,6 +144,13 @@ def __init__(
self.label_types[ltype] = [x for _, x in sorted(zip(idx_sort, self.label_types[ltype]))]
self._ids_renamed = torch.from_numpy(self._ids_renamed)

if skip_crowd:
# Check each annotation and remove crowded ones.
for i in range(len(self.items) - 1, -1, -1):
target = self.items[i][2]["segments_info"]
if any([seg["iscrowd"] for seg in target]):
del self.items[i]

# Fix number of label names if desired
if fix_classes_len is not None:
if fix_classes_len > len(self.label_names):
Expand Down Expand Up @@ -269,7 +283,12 @@ def getitem(self, idx):

# Make aloscene.frame
frame = Frame(img_path)
labels_2d = Labels(labels.to(torch.float32), labels_names=self.label_names, names=("N"), encoding="id")
labels_2d = Labels(
labels.to(torch.float32),
labels_names=self.label_names,
names=("N"),
encoding="id",
)
boxes_2d = BoundingBoxes2D(
masks_to_boxes(masks),
boxes_format="xyxy",
Expand All @@ -291,15 +310,15 @@ def getitem(self, idx):

if __name__ == "__main__":
# coco_seg = CocoPanopticDataset(sample=True)
coco_seg = CocoPanopticDataset() # test
for f, frames in enumerate(coco_seg.train_loader(batch_size=2)):
frames = Frame.batch_list(frames)
labels_set = "category" if isinstance(frames.boxes2d[0].labels, dict) else None
views = [fr.boxes2d.get_view(fr, labels_set=labels_set) for fr in frames]
if frames.segmentation is not None:
views += [fr.segmentation.get_view(fr, labels_set=labels_set) for fr in frames]
frames.get_view(views).render()
# frames.get_view(labels_set=labels_set).render()

if f > 1:
break
coco_seg = CocoPanopticDataset(classes=["person"], skip_crowd=False) # test
for f, frames in enumerate(
coco_seg.train_loader(batch_size=1, num_workers=0, sampler=torch.utils.data.SequentialSampler(coco_seg))
):
if f > 10:
frames = Frame.batch_list(frames)
labels_set = "category" if isinstance(frames.boxes2d[0].labels, dict) else None
views = [fr.boxes2d.get_view(fr, labels_set=labels_set) for fr in frames]
if frames.segmentation is not None:
views += [fr.segmentation.get_view(fr, labels_set=labels_set) for fr in frames]
frames.get_view(views).render()
# frames.get_view(labels_set=labels_set).render()
Loading