torchsight.datasets.coco
module
Coco dataset
Source code
"""Coco dataset"""
import os
import time
import matplotlib
import numpy as np
import skimage
import skimage.io
import torch
from pycocotools.coco import COCO
from pycocotools.cocoeval import COCOeval
from torch.utils.data import Dataset
class CocoDataset(Dataset):
"""Coco dataset class.
Heavily inspired by the code at:
https://github.com/SetaSouto/pytorch-retinanet/blob/master/dataloader.py
"""
def __init__(self, root, dataset, classes_names=(), transform=None, stats=True):
"""Initialize the dataset.
Initialize the coco api under the 'coco' attribute.
Also, loads the classes and labels.
It sets the 'classes' attribute of the class that contains a dict with four dicts:
- 'ids': Keep track of the classes' ids given its label (label: int -> id: int).
- 'labels': Keep track of the label given the id of the class (id: int -> label: int).
- 'names': Keep track of the name of the class given its label (label: int -> name: string).
- 'length': Keep track of how many images are for the given label (label: int -> length: int).
Why labels and ids? Because ids are given by the coco api, are static, but if we filter the classes
we want to reorder the labels from 0 to N if we load N classes.
For example, the 2017 dataset contains classes with ids from 1 to 90, but we like to keep labels
starting from 0 (zero indexed). If we want only to load the classes 'person' (id: 1), 'bus' (id: 6)
and 'stop sign' (id: 13) we don't want to work with labels 1, 6 and 13, we want to work with labels
0, 1, 2, because we loaded only 3 classes.
You can filter the images and classes to be loaded by using classes_names argument.
Why we load the bounding boxes already? Because the COCO api already does that, so instead of keeping
the coco api instance we format the bounding boxes in the initialization and keep track of the path
of each image. The images are loaded in running time.
This way we use the api in the initialization only and free some memory.
Args:
root (str): COCO root directory.
Inside this directory we must find the 'annotations' and 'images' folder for example.
dataset (str): The name of the set to be loaded. Is the name of the directory that contains
the images and is in the name of the file that contains the annotations.
Example: 'train2017' will trigger the loading of the images at coco/images/train2017
and the annotations from the file 'instances_train2017.json'.
classes_names (tuple): Tuple of strings with the name of the classes to load. Only load images with those
classes' names.
transform (torchvision.transforms.Compose, optional): A list with transforms to apply to each image.
stats (Boolean): Print the stats of the classes. Indicates how many images are per category.
Keep in mind that the sum of all the images per category may not be the same to the total number
of images, this is because some images could contain more than one object type (very common).
"""
self.transform = transform
# Initialize the COCO api
print('--- COCO API ---')
self.annotations_path = os.path.join(root, 'annotations', 'instances_{}.json'.format(dataset))
coco = COCO(self.annotations_path)
print('----------------')
# Load classes and set classes dict
print('Loading classes and setting labels, names and lengths ...')
self.classes = {'ids': {}, 'names': {}, 'labels': {}, 'length': {}}
for label, category in enumerate(coco.loadCats(coco.getCatIds(catNms=classes_names))):
self.classes['ids'][label] = category['id']
self.classes['labels'][category['id']] = label
self.classes['names'][label] = category['name']
# Get filtered images ids
print('Loading images info ...')
images_ids = set()
for category_id in self.classes['ids'].values():
category_images = set(coco.catToImgs[category_id])
category_label = self.classes['labels'][category_id]
self.classes['length'][category_label] = len(category_images)
images_ids |= category_images
# Init images array that contains tuples with the path to the images and the annotations
print('Setting bounding boxes ...')
self.images = []
for image_info in coco.loadImgs(images_ids):
bounding_boxes = np.zeros((0, 5))
for annotation in coco.imgToAnns[image_info['id']]:
try:
label = self.classes['labels'][annotation['category_id']]
bounding_boxes = np.append(bounding_boxes, np.array([[*annotation['bbox'], label]]), axis=0)
except KeyError:
# The image has a bounding box from a class that does not exists in classes_names sequence
continue
self.images.append((
os.path.join(root, 'images', dataset, image_info['file_name']), # Image's path
bounding_boxes, # Bounding boxes with shape (N, 5)
image_info
))
# Print stats
if stats:
print('Images per class:')
stats = [(label,
self.classes['names'][label],
self.classes['length'][label])
for label in self.classes['labels'].values()]
stats = sorted(stats, key=lambda x: x[2], reverse=True)
for label, name, length in stats:
print('{}: {}{}'.format(str(label).ljust(2), name.ljust(15), length))
def __len__(self):
"""Get the length of the dataset.
Returns:
int: The length of the dataset.
"""
return len(self.images)
def __getitem__(self, index):
"""Get an item from the dataset given its index.
Load the image and bounding boxes for that image and return a tuple with
image, bounding boxes. Both are ndarrays.
The bounding boxes is a numpy array with shape (N, 5) where N is the number
of bounding boxes in the image. Why 5? Because they are x1, y1 for the top
left corner of the bounding box, x2, y2 for the bottom right corner of the
bounding box and the last one is the label of the class.
Args:
index (int): Index of the image in the dataset.
Returns:
ndarray: The transformed image if there is any transformation or the original image.
ndarray: The bounding boxes of the image.
"""
path, bounding_boxes, info, *_ = self.images[index]
image = skimage.io.imread(path)
if len(image.shape) == 2:
image = skimage.color.gray2rgb(image)
image = image.astype(np.float32) / 255.0
# Transform from [x,y,w,h] to [x1,y1,x2,y2]
bounding_boxes[:, 2] = bounding_boxes[:, 0] + bounding_boxes[:, 2]
bounding_boxes[:, 3] = bounding_boxes[:, 1] + bounding_boxes[:, 3]
if self.transform:
image, bounding_boxes, info = self.transform((image, bounding_boxes, info))
return image, bounding_boxes, info
def visualize(self, image, boxes=None, initial_time=None, n_colors=20):
"""Visualize an image and its bounding boxes.
Arguments:
image (torch.Tensor or ndarray): The image to visualize.
boxes (torch.Tensor or ndarray): The bounding boxes to visualize in the image.
It must contains the x1, y1, x2, y2 points and the label in the 4th index.
You could provide the probability of the label too optionally in the 5th index.
Shape:
(number of annotations, 5 or 6)
"""
initial_time = initial_time if initial_time is not None else time.time()
if torch.is_tensor(image):
image = image.numpy().transpose(1, 2, 0)
# Matplotlib colormaps, for more information please visit:
# https://matplotlib.org/examples/color/colormaps_reference.html
# Is a continuous map of colors, you can get a color by calling it on a number between
# 0 and 1
colormap = matplotlib.pyplot.get_cmap('tab20')
# Select n_colors colors from 0 to 1
colors = [colormap(i) for i in np.linspace(0, 1, n_colors)]
# Generate figure and axes
_, axes = matplotlib.pyplot.subplots(1)
# Generate rectangles
if boxes is not None:
for i in range(boxes.shape[0]):
# We need the top left corner of the rectangle and its width and height
if boxes[i].shape[0] == 6:
x, y, x2, y2, label, prob = boxes[i]
prob = ' {:.2f}'.format(prob)
else:
x, y, x2, y2, label = boxes[i]
prob = ''
w, h = x2 - x, y2 - y
color = colors[int(label) % n_colors]
# Generate and add rectangle to plot
axes.add_patch(matplotlib.patches.Rectangle((x, y), w, h, linewidth=2,
edgecolor=color, facecolor='none'))
# Generate text if there are any classes
tag = '{}{}'.format(self.classes['names'][int(label)], prob)
matplotlib.pyplot.text(x, y, s=tag, color='white',
verticalalignment='top', bbox={'color': color, 'pad': 0})
# Print stats
print('-----\nProcessing time: {}\nBounding boxes:\n{}'.format(time.time() - initial_time, boxes))
# Show image and plot
axes.imshow(image)
matplotlib.pyplot.show()
def visualize_annotations(self, index, *args, **kwargs):
"""Visualize an image with its bounding boxes.
Args:
index (int): The index of the image in the dataset to be loaded.
n_colors (int, optional): The number of colors to use. Optional. Already in the max value.
"""
image, boxes, *_ = self.__getitem__(index)
self.visualize(image, boxes, *args, **kwargs)
def compute_map(self, predictions_file):
"""Compute the mAP using the pycocotools over the given categories ids.
Arguments:
predictions_file (str): The path to the file that contains the JSON with the predictions
in the correct format as indicated in: http://cocodataset.org/#detection-eval
cat_ids (list, optional): The ids of the categories over it must compute the mAP.
If None is provided it will compute the mAP for all the classes.
"""
coco_gt = COCO(self.annotations_path)
coco_dt = coco_gt.loadRes(predictions_file)
coco_eval = COCOeval(coco_gt, coco_dt, 'bbox')
coco_eval.params.imgIds = [info['id'] for _, _, info in self.images]
coco_eval.params.catIds = list(self.classes['ids'].values())
coco_eval.evaluate()
coco_eval.accumulate()
coco_eval.summarize()
Classes
class CocoDataset (ancestors: torch.utils.data.dataset.Dataset)
-
Coco dataset class.
Heavily inspired by the code at: https://github.com/SetaSouto/pytorch-retinanet/blob/master/dataloader.py
Source code
class CocoDataset(Dataset): """Coco dataset class. Heavily inspired by the code at: https://github.com/SetaSouto/pytorch-retinanet/blob/master/dataloader.py """ def __init__(self, root, dataset, classes_names=(), transform=None, stats=True): """Initialize the dataset. Initialize the coco api under the 'coco' attribute. Also, loads the classes and labels. It sets the 'classes' attribute of the class that contains a dict with four dicts: - 'ids': Keep track of the classes' ids given its label (label: int -> id: int). - 'labels': Keep track of the label given the id of the class (id: int -> label: int). - 'names': Keep track of the name of the class given its label (label: int -> name: string). - 'length': Keep track of how many images are for the given label (label: int -> length: int). Why labels and ids? Because ids are given by the coco api, are static, but if we filter the classes we want to reorder the labels from 0 to N if we load N classes. For example, the 2017 dataset contains classes with ids from 1 to 90, but we like to keep labels starting from 0 (zero indexed). If we want only to load the classes 'person' (id: 1), 'bus' (id: 6) and 'stop sign' (id: 13) we don't want to work with labels 1, 6 and 13, we want to work with labels 0, 1, 2, because we loaded only 3 classes. You can filter the images and classes to be loaded by using classes_names argument. Why we load the bounding boxes already? Because the COCO api already does that, so instead of keeping the coco api instance we format the bounding boxes in the initialization and keep track of the path of each image. The images are loaded in running time. This way we use the api in the initialization only and free some memory. Args: root (str): COCO root directory. Inside this directory we must find the 'annotations' and 'images' folder for example. dataset (str): The name of the set to be loaded. Is the name of the directory that contains the images and is in the name of the file that contains the annotations. Example: 'train2017' will trigger the loading of the images at coco/images/train2017 and the annotations from the file 'instances_train2017.json'. classes_names (tuple): Tuple of strings with the name of the classes to load. Only load images with those classes' names. transform (torchvision.transforms.Compose, optional): A list with transforms to apply to each image. stats (Boolean): Print the stats of the classes. Indicates how many images are per category. Keep in mind that the sum of all the images per category may not be the same to the total number of images, this is because some images could contain more than one object type (very common). """ self.transform = transform # Initialize the COCO api print('--- COCO API ---') self.annotations_path = os.path.join(root, 'annotations', 'instances_{}.json'.format(dataset)) coco = COCO(self.annotations_path) print('----------------') # Load classes and set classes dict print('Loading classes and setting labels, names and lengths ...') self.classes = {'ids': {}, 'names': {}, 'labels': {}, 'length': {}} for label, category in enumerate(coco.loadCats(coco.getCatIds(catNms=classes_names))): self.classes['ids'][label] = category['id'] self.classes['labels'][category['id']] = label self.classes['names'][label] = category['name'] # Get filtered images ids print('Loading images info ...') images_ids = set() for category_id in self.classes['ids'].values(): category_images = set(coco.catToImgs[category_id]) category_label = self.classes['labels'][category_id] self.classes['length'][category_label] = len(category_images) images_ids |= category_images # Init images array that contains tuples with the path to the images and the annotations print('Setting bounding boxes ...') self.images = [] for image_info in coco.loadImgs(images_ids): bounding_boxes = np.zeros((0, 5)) for annotation in coco.imgToAnns[image_info['id']]: try: label = self.classes['labels'][annotation['category_id']] bounding_boxes = np.append(bounding_boxes, np.array([[*annotation['bbox'], label]]), axis=0) except KeyError: # The image has a bounding box from a class that does not exists in classes_names sequence continue self.images.append(( os.path.join(root, 'images', dataset, image_info['file_name']), # Image's path bounding_boxes, # Bounding boxes with shape (N, 5) image_info )) # Print stats if stats: print('Images per class:') stats = [(label, self.classes['names'][label], self.classes['length'][label]) for label in self.classes['labels'].values()] stats = sorted(stats, key=lambda x: x[2], reverse=True) for label, name, length in stats: print('{}: {}{}'.format(str(label).ljust(2), name.ljust(15), length)) def __len__(self): """Get the length of the dataset. Returns: int: The length of the dataset. """ return len(self.images) def __getitem__(self, index): """Get an item from the dataset given its index. Load the image and bounding boxes for that image and return a tuple with image, bounding boxes. Both are ndarrays. The bounding boxes is a numpy array with shape (N, 5) where N is the number of bounding boxes in the image. Why 5? Because they are x1, y1 for the top left corner of the bounding box, x2, y2 for the bottom right corner of the bounding box and the last one is the label of the class. Args: index (int): Index of the image in the dataset. Returns: ndarray: The transformed image if there is any transformation or the original image. ndarray: The bounding boxes of the image. """ path, bounding_boxes, info, *_ = self.images[index] image = skimage.io.imread(path) if len(image.shape) == 2: image = skimage.color.gray2rgb(image) image = image.astype(np.float32) / 255.0 # Transform from [x,y,w,h] to [x1,y1,x2,y2] bounding_boxes[:, 2] = bounding_boxes[:, 0] + bounding_boxes[:, 2] bounding_boxes[:, 3] = bounding_boxes[:, 1] + bounding_boxes[:, 3] if self.transform: image, bounding_boxes, info = self.transform((image, bounding_boxes, info)) return image, bounding_boxes, info def visualize(self, image, boxes=None, initial_time=None, n_colors=20): """Visualize an image and its bounding boxes. Arguments: image (torch.Tensor or ndarray): The image to visualize. boxes (torch.Tensor or ndarray): The bounding boxes to visualize in the image. It must contains the x1, y1, x2, y2 points and the label in the 4th index. You could provide the probability of the label too optionally in the 5th index. Shape: (number of annotations, 5 or 6) """ initial_time = initial_time if initial_time is not None else time.time() if torch.is_tensor(image): image = image.numpy().transpose(1, 2, 0) # Matplotlib colormaps, for more information please visit: # https://matplotlib.org/examples/color/colormaps_reference.html # Is a continuous map of colors, you can get a color by calling it on a number between # 0 and 1 colormap = matplotlib.pyplot.get_cmap('tab20') # Select n_colors colors from 0 to 1 colors = [colormap(i) for i in np.linspace(0, 1, n_colors)] # Generate figure and axes _, axes = matplotlib.pyplot.subplots(1) # Generate rectangles if boxes is not None: for i in range(boxes.shape[0]): # We need the top left corner of the rectangle and its width and height if boxes[i].shape[0] == 6: x, y, x2, y2, label, prob = boxes[i] prob = ' {:.2f}'.format(prob) else: x, y, x2, y2, label = boxes[i] prob = '' w, h = x2 - x, y2 - y color = colors[int(label) % n_colors] # Generate and add rectangle to plot axes.add_patch(matplotlib.patches.Rectangle((x, y), w, h, linewidth=2, edgecolor=color, facecolor='none')) # Generate text if there are any classes tag = '{}{}'.format(self.classes['names'][int(label)], prob) matplotlib.pyplot.text(x, y, s=tag, color='white', verticalalignment='top', bbox={'color': color, 'pad': 0}) # Print stats print('-----\nProcessing time: {}\nBounding boxes:\n{}'.format(time.time() - initial_time, boxes)) # Show image and plot axes.imshow(image) matplotlib.pyplot.show() def visualize_annotations(self, index, *args, **kwargs): """Visualize an image with its bounding boxes. Args: index (int): The index of the image in the dataset to be loaded. n_colors (int, optional): The number of colors to use. Optional. Already in the max value. """ image, boxes, *_ = self.__getitem__(index) self.visualize(image, boxes, *args, **kwargs) def compute_map(self, predictions_file): """Compute the mAP using the pycocotools over the given categories ids. Arguments: predictions_file (str): The path to the file that contains the JSON with the predictions in the correct format as indicated in: http://cocodataset.org/#detection-eval cat_ids (list, optional): The ids of the categories over it must compute the mAP. If None is provided it will compute the mAP for all the classes. """ coco_gt = COCO(self.annotations_path) coco_dt = coco_gt.loadRes(predictions_file) coco_eval = COCOeval(coco_gt, coco_dt, 'bbox') coco_eval.params.imgIds = [info['id'] for _, _, info in self.images] coco_eval.params.catIds = list(self.classes['ids'].values()) coco_eval.evaluate() coco_eval.accumulate() coco_eval.summarize()
Methods
def __init__(self, root, dataset, classes_names=(), transform=None, stats=True)
-
Initialize the dataset.
Initialize the coco api under the 'coco' attribute.
Also, loads the classes and labels.
It sets the 'classes' attribute of the class that contains a dict with four dicts: - 'ids': Keep track of the classes' ids given its label (label: int -> id: int). - 'labels': Keep track of the label given the id of the class (id: int -> label: int). - 'names': Keep track of the name of the class given its label (label: int -> name: string). - 'length': Keep track of how many images are for the given label (label: int -> length: int).
Why labels and ids? Because ids are given by the coco api, are static, but if we filter the classes we want to reorder the labels from 0 to N if we load N classes. For example, the 2017 dataset contains classes with ids from 1 to 90, but we like to keep labels starting from 0 (zero indexed). If we want only to load the classes 'person' (id: 1), 'bus' (id: 6) and 'stop sign' (id: 13) we don't want to work with labels 1, 6 and 13, we want to work with labels 0, 1, 2, because we loaded only 3 classes.
You can filter the images and classes to be loaded by using classes_names argument.
Why we load the bounding boxes already? Because the COCO api already does that, so instead of keeping the coco api instance we format the bounding boxes in the initialization and keep track of the path of each image. The images are loaded in running time. This way we use the api in the initialization only and free some memory.
Args
root
:str
- COCO root directory. Inside this directory we must find the 'annotations' and 'images' folder for example.
dataset
:str
- The name of the set to be loaded. Is the name of the directory that contains the images and is in the name of the file that contains the annotations. Example: 'train2017' will trigger the loading of the images at coco/images/train2017 and the annotations from the file 'instances_train2017.json'.
classes_names
:tuple
- Tuple of strings with the name of the classes to load. Only load images with those classes' names.
transform
:torchvision.transforms.Compose
, optional- A list with transforms to apply to each image.
stats
:Boolean
- Print the stats of the classes. Indicates how many images are per category. Keep in mind that the sum of all the images per category may not be the same to the total number of images, this is because some images could contain more than one object type (very common).
Source code
def __init__(self, root, dataset, classes_names=(), transform=None, stats=True): """Initialize the dataset. Initialize the coco api under the 'coco' attribute. Also, loads the classes and labels. It sets the 'classes' attribute of the class that contains a dict with four dicts: - 'ids': Keep track of the classes' ids given its label (label: int -> id: int). - 'labels': Keep track of the label given the id of the class (id: int -> label: int). - 'names': Keep track of the name of the class given its label (label: int -> name: string). - 'length': Keep track of how many images are for the given label (label: int -> length: int). Why labels and ids? Because ids are given by the coco api, are static, but if we filter the classes we want to reorder the labels from 0 to N if we load N classes. For example, the 2017 dataset contains classes with ids from 1 to 90, but we like to keep labels starting from 0 (zero indexed). If we want only to load the classes 'person' (id: 1), 'bus' (id: 6) and 'stop sign' (id: 13) we don't want to work with labels 1, 6 and 13, we want to work with labels 0, 1, 2, because we loaded only 3 classes. You can filter the images and classes to be loaded by using classes_names argument. Why we load the bounding boxes already? Because the COCO api already does that, so instead of keeping the coco api instance we format the bounding boxes in the initialization and keep track of the path of each image. The images are loaded in running time. This way we use the api in the initialization only and free some memory. Args: root (str): COCO root directory. Inside this directory we must find the 'annotations' and 'images' folder for example. dataset (str): The name of the set to be loaded. Is the name of the directory that contains the images and is in the name of the file that contains the annotations. Example: 'train2017' will trigger the loading of the images at coco/images/train2017 and the annotations from the file 'instances_train2017.json'. classes_names (tuple): Tuple of strings with the name of the classes to load. Only load images with those classes' names. transform (torchvision.transforms.Compose, optional): A list with transforms to apply to each image. stats (Boolean): Print the stats of the classes. Indicates how many images are per category. Keep in mind that the sum of all the images per category may not be the same to the total number of images, this is because some images could contain more than one object type (very common). """ self.transform = transform # Initialize the COCO api print('--- COCO API ---') self.annotations_path = os.path.join(root, 'annotations', 'instances_{}.json'.format(dataset)) coco = COCO(self.annotations_path) print('----------------') # Load classes and set classes dict print('Loading classes and setting labels, names and lengths ...') self.classes = {'ids': {}, 'names': {}, 'labels': {}, 'length': {}} for label, category in enumerate(coco.loadCats(coco.getCatIds(catNms=classes_names))): self.classes['ids'][label] = category['id'] self.classes['labels'][category['id']] = label self.classes['names'][label] = category['name'] # Get filtered images ids print('Loading images info ...') images_ids = set() for category_id in self.classes['ids'].values(): category_images = set(coco.catToImgs[category_id]) category_label = self.classes['labels'][category_id] self.classes['length'][category_label] = len(category_images) images_ids |= category_images # Init images array that contains tuples with the path to the images and the annotations print('Setting bounding boxes ...') self.images = [] for image_info in coco.loadImgs(images_ids): bounding_boxes = np.zeros((0, 5)) for annotation in coco.imgToAnns[image_info['id']]: try: label = self.classes['labels'][annotation['category_id']] bounding_boxes = np.append(bounding_boxes, np.array([[*annotation['bbox'], label]]), axis=0) except KeyError: # The image has a bounding box from a class that does not exists in classes_names sequence continue self.images.append(( os.path.join(root, 'images', dataset, image_info['file_name']), # Image's path bounding_boxes, # Bounding boxes with shape (N, 5) image_info )) # Print stats if stats: print('Images per class:') stats = [(label, self.classes['names'][label], self.classes['length'][label]) for label in self.classes['labels'].values()] stats = sorted(stats, key=lambda x: x[2], reverse=True) for label, name, length in stats: print('{}: {}{}'.format(str(label).ljust(2), name.ljust(15), length))
def compute_map(self, predictions_file)
-
Compute the mAP using the pycocotools over the given categories ids.
Arguments
predictions_file
:str
- The path to the file that contains the JSON with the predictions in the correct format as indicated in: http://cocodataset.org/#detection-eval
cat_ids
:list
, optional- The ids of the categories over it must compute the mAP. If None is provided it will compute the mAP for all the classes.
Source code
def compute_map(self, predictions_file): """Compute the mAP using the pycocotools over the given categories ids. Arguments: predictions_file (str): The path to the file that contains the JSON with the predictions in the correct format as indicated in: http://cocodataset.org/#detection-eval cat_ids (list, optional): The ids of the categories over it must compute the mAP. If None is provided it will compute the mAP for all the classes. """ coco_gt = COCO(self.annotations_path) coco_dt = coco_gt.loadRes(predictions_file) coco_eval = COCOeval(coco_gt, coco_dt, 'bbox') coco_eval.params.imgIds = [info['id'] for _, _, info in self.images] coco_eval.params.catIds = list(self.classes['ids'].values()) coco_eval.evaluate() coco_eval.accumulate() coco_eval.summarize()
def visualize(self, image, boxes=None, initial_time=None, n_colors=20)
-
Visualize an image and its bounding boxes.
Arguments
image
:torch.Tensor
orndarray
- The image to visualize.
boxes
:torch.Tensor
orndarray
- The bounding boxes to visualize in the image. It must contains the x1, y1, x2, y2 points and the label in the 4th index. You could provide the probability of the label too optionally in the 5th index. Shape: (number of annotations, 5 or 6)
Source code
def visualize(self, image, boxes=None, initial_time=None, n_colors=20): """Visualize an image and its bounding boxes. Arguments: image (torch.Tensor or ndarray): The image to visualize. boxes (torch.Tensor or ndarray): The bounding boxes to visualize in the image. It must contains the x1, y1, x2, y2 points and the label in the 4th index. You could provide the probability of the label too optionally in the 5th index. Shape: (number of annotations, 5 or 6) """ initial_time = initial_time if initial_time is not None else time.time() if torch.is_tensor(image): image = image.numpy().transpose(1, 2, 0) # Matplotlib colormaps, for more information please visit: # https://matplotlib.org/examples/color/colormaps_reference.html # Is a continuous map of colors, you can get a color by calling it on a number between # 0 and 1 colormap = matplotlib.pyplot.get_cmap('tab20') # Select n_colors colors from 0 to 1 colors = [colormap(i) for i in np.linspace(0, 1, n_colors)] # Generate figure and axes _, axes = matplotlib.pyplot.subplots(1) # Generate rectangles if boxes is not None: for i in range(boxes.shape[0]): # We need the top left corner of the rectangle and its width and height if boxes[i].shape[0] == 6: x, y, x2, y2, label, prob = boxes[i] prob = ' {:.2f}'.format(prob) else: x, y, x2, y2, label = boxes[i] prob = '' w, h = x2 - x, y2 - y color = colors[int(label) % n_colors] # Generate and add rectangle to plot axes.add_patch(matplotlib.patches.Rectangle((x, y), w, h, linewidth=2, edgecolor=color, facecolor='none')) # Generate text if there are any classes tag = '{}{}'.format(self.classes['names'][int(label)], prob) matplotlib.pyplot.text(x, y, s=tag, color='white', verticalalignment='top', bbox={'color': color, 'pad': 0}) # Print stats print('-----\nProcessing time: {}\nBounding boxes:\n{}'.format(time.time() - initial_time, boxes)) # Show image and plot axes.imshow(image) matplotlib.pyplot.show()
def visualize_annotations(self, index, *args, **kwargs)
-
Visualize an image with its bounding boxes.
Args
index
:int
- The index of the image in the dataset to be loaded.
n_colors
:int
, optional- The number of colors to use. Optional. Already in the max value.
Source code
def visualize_annotations(self, index, *args, **kwargs): """Visualize an image with its bounding boxes. Args: index (int): The index of the image in the dataset to be loaded. n_colors (int, optional): The number of colors to use. Optional. Already in the max value. """ image, boxes, *_ = self.__getitem__(index) self.visualize(image, boxes, *args, **kwargs)