diff --git a/mmeval/metrics/__init__.py b/mmeval/metrics/__init__.py index e555298a..f0104a0c 100644 --- a/mmeval/metrics/__init__.py +++ b/mmeval/metrics/__init__.py @@ -3,6 +3,7 @@ from .accuracy import Accuracy from .ava_map import AVAMeanAP from .coco_detection import COCODetectionMetric +from .coco_pose import COCOPoseMetric from .end_point_error import EndPointError from .f_metric import F1Metric from .hmean_iou import HmeanIoU @@ -24,5 +25,5 @@ 'F1Metric', 'HmeanIoU', 'SingleLabelMetric', 'COCODetectionMetric', 'PCKAccuracy', 'MpiiPCKAccuracy', 'JhmdbPCKAccuracy', 'ProposalRecall', 'PSNR', 'MAE', 'MSE', 'SSIM', 'SNR', 'MultiLabelMetric', - 'AveragePrecision', 'AVAMeanAP' + 'AveragePrecision', 'AVAMeanAP', 'COCOPoseMetric' ] diff --git a/mmeval/metrics/coco_pose.py b/mmeval/metrics/coco_pose.py new file mode 100644 index 00000000..a1a8bd28 --- /dev/null +++ b/mmeval/metrics/coco_pose.py @@ -0,0 +1,627 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import datetime +import logging +import numpy as np +import os.path as osp +import tempfile +from collections import OrderedDict, defaultdict +from json import dump +from typing import Dict, Optional, Sequence + +from mmeval.core.base_metric import BaseMetric +from mmeval.fileio import load +from .utils import oks_nms, soft_oks_nms + +try: + from xtcocotools.coco import COCO + from xtcocotools.cocoeval import COCOeval + HAS_XTCOCOTOOLS = True +except ImportError: + HAS_XTCOCOTOOLS = False + +logger = logging.getLogger(__name__) + + +class COCOPoseMetric(BaseMetric): + """COCO pose estimation task evaluation metric. + + Evaluate AR, AP, and mAP for keypoint detection tasks. Support COCO + dataset and other datasets in COCO format. Please refer to + `COCO keypoint evaluation `__ + for more details. + + Args: + ann_file (str, optional): Path to the coco format annotation file. + If not specified, ground truth annotations from the dataset will + be converted to coco format. Defaults to None. + use_area (bool): Whether to use ``'area'`` message in the annotations. + If the ground truth annotations (e.g. CrowdPose, AIC) do not have + the field ``'area'``, please set ``use_area=False``. + Defaults to ``True``. + iou_type (str): The same parameter as `iouType` in + :class:`xtcocotools.COCOeval`, which can be ``'keypoints'``, or + ``'keypoints_crowd'`` (used in CrowdPose dataset). + Defaults to ``'keypoints'``. + score_mode (str): The mode to score the prediction results which + should be one of the following options: + + - ``'bbox'``: Take the score of bbox as the score of the + prediction results. + - ``'bbox_keypoint'``: Use keypoint score to rescore the + prediction results. + - ``'bbox_rle'``: Use rle_score to rescore the + prediction results. + + Defaults to ``'bbox_keypoint'` + keypoint_score_thr (float): The threshold of keypoint score. The + keypoints with score lower than it will not be included to + rescore the prediction results. Valid only when ``score_mode`` is + ``bbox_keypoint``. Defaults to ``0.2`` + nms_mode (str): The mode to perform Non-Maximum Suppression (NMS), + which should be one of the following options: + + - ``'oks_nms'``: Use Object Keypoint Similarity (OKS) to + perform NMS. + - ``'soft_oks_nms'``: Use Object Keypoint Similarity (OKS) + to perform soft NMS. + - ``'none'``: Do not perform NMS. Typically for bottomup mode + output. + + Defaults to ``'oks_nms'` + nms_thr (float): The Object Keypoint Similarity (OKS) threshold + used in NMS when ``nms_mode`` is ``'oks_nms'`` or + ``'soft_oks_nms'``. Will retain the prediction results with OKS + lower than ``nms_thr``. Defaults to ``0.9`` + format_only (bool): Whether only format the output results without + doing quantitative evaluation. This is designed for the need of + test submission when the ground truth annotations are absent. If + set to ``True``, ``outfile_prefix`` should specify the path to + store the output results. Defaults to ``False``. + outfile_prefix (str | None): The prefix of json files. It includes + the file path and the prefix of filename, e.g., ``'a/b/prefix'``. + If not specified, a temp file will be created. Defaults to ``None``. + **kwargs: Keyword parameters passed to :class:`mmeval.BaseMetric`. + + Examples: + >>> import numpy as np + >>> import copy + >>> from mmeval.fileio import load + >>> from mmeval import CocoPoseMetric + >>> try: + ... from xtcocotools.coco import COCO + ... from xtcocotools.cocoeval import COCOeval + ... HAS_XTCOCOTOOLS = True + ... except ImportError: + ... HAS_XTCOCOTOOLS = False + ... + >>> ann_file = 'tests/test_metrics/data/coco_pose_sample.json' + >>> coco = COCO(ann_file) + loading annotations into memory... + Done (t=0.00s) + creating index... + index created! + >>> classes = coco.loadCats(coco.getCatIds()) + >>> sigmas = np.array([ + ... 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, + ... 0.062, 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 + ... ]).astype(np.float32) + >>> coco_dataset_meta = { + ... 'CLASSES': classes, + ... 'num_keypoints': 17, + ... 'sigmas': sigmas, + ... } + >>> def _convert_ann_to_pred_and_gt(ann_file): + ... predictions = [] + ... groundtruths = [] + ... db = load(ann_file) + ... imgid2info = dict() + ... for img in db['images']: + ... imgid2info[img['id']] = img + ... for ann in db['annotations']: + ... bboxes = np.array(ann['bbox'], dtype=np.float32).reshape(-1, 4) + ... keypoints = np.array(ann['keypoints']).reshape((1, -1, 3)) + ... prediction = { + ... 'id': ann['id'], + ... 'img_id': ann['image_id'], + ... 'bboxes': bboxes, + ... 'keypoints': keypoints[..., :2], + ... 'keypoint_scores': keypoints[..., -1], + ... 'bbox_scores': np.ones((1, ), dtype=np.float32), + ... } + ... groundtruth = { + ... 'img_id': ann['image_id'], + ... 'width': 640, + ... 'height': 480, + ... 'num_keypoints': ann['num_keypoints'], + ... 'raw_ann_info': [copy.deepcopy(ann)], + ... } + ... if 'area' in ann: + ... groundtruth['area'] = ann['area'] + ... if 'crowdIndex' in imgid2info[ann['image_id']]: + ... groundtruth['crowd_index'] = imgid2info[ + ... ann['image_id']]['crowdIndex'] + ... predictions.append(prediction) + ... groundtruths.append(groundtruth) + ... return predictions, groundtruths + >>> predictions, groundtruths = _convert_ann_to_pred_and_gt(ann_file) + >>> coco_pose_metric = CocoPoseMetric( + ... ann_file=ann_file, + ... dataset_meta=coco_dataset_meta) + loading annotations into memory... + Done (t=0.00s) + creating index... + index created + >>> coco_pose_metric(predictions, groundtruths) + loading annotations into memory... + Done (t=0.00s) + creating index... + index created! + >>> coco_pose_metric(predictions, groundtruths) + Loading and preparing results... + DONE (t=0.00s) + creating index... + index created! + Running per image evaluation... + Evaluate annotation type *keypoints* + DONE (t=0.00s). + Accumulating evaluation results... + DONE (t=0.00s). + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets= 20 ] = 1.000 # noqa + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets= 20 ] = 1.000 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets= 20 ] = 1.000 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets= 20 ] = 1.000 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets= 20 ] = 1.000 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 20 ] = 1.000 + Average Recall (AR) @[ IoU=0.50 | area= all | maxDets= 20 ] = 1.000 + Average Recall (AR) @[ IoU=0.75 | area= all | maxDets= 20 ] = 1.000 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets= 20 ] = 1.000 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets= 20 ] = 1.000 + OrderedDict([('AP', 1.0), ('AP .5', 1.0), ('AP .75', 1.0), ('AP (M)', 1.0), + ('AP (L)', 1.0), ('AR', 1.0), ('AR .5', 1.0), ('AR .75', 1.0), + ('AR (M)', 1.0), ('AR (L)', 1.0)]) + """ + + def __init__(self, + ann_file: Optional[str] = None, + use_area: bool = True, + iou_type: str = 'keypoints', + score_mode: str = 'bbox_keypoint', + keypoint_score_thr: float = 0.2, + nms_mode: str = 'oks_nms', + nms_thr: float = 0.9, + format_only: bool = False, + outfile_prefix: Optional[str] = None, + **kwargs) -> None: + if not HAS_XTCOCOTOOLS: + raise RuntimeError( + 'Failed to import `COCO` and `COCOeval` from xtcocotools.' + 'Please try to install xtcocotools by ' + '`pip install xtcocotools`') + super().__init__(**kwargs) + self.dataset_meta: dict + self.ann_file = ann_file + # initialize coco helper with the annotation json file + # if ann_file is not specified, initialize with the converted dataset + if ann_file is not None: + self.coco = COCO(ann_file) + else: + self.coco = None + + self.use_area = use_area + self.iou_type = iou_type + + allowed_score_modes = ['bbox', 'bbox_keypoint', 'bbox_rle'] + if score_mode not in allowed_score_modes: + raise ValueError( + "`score_mode` should be one of 'bbox', 'bbox_keypoint', " + f"'bbox_rle', but got {score_mode}") + self.score_mode = score_mode + self.keypoint_score_thr = keypoint_score_thr + + allowed_nms_modes = ['oks_nms', 'soft_oks_nms', 'none'] + if nms_mode not in allowed_nms_modes: + raise ValueError( + "`nms_mode` should be one of 'oks_nms', 'soft_oks_nms', " + f"'none', but got {nms_mode}") + self.nms_mode = nms_mode + self.nms_thr = nms_thr + + if format_only: + assert outfile_prefix is not None, '`outfile_prefix` can not be '\ + 'None when `format_only` is True, otherwise the result file '\ + 'will be saved to a temp directory which will be cleaned up '\ + 'in the end.' + elif ann_file is not None: + # do evaluation only if the ground truth annotations exist + assert 'annotations' in load(ann_file), \ + 'Ground truth annotations are required for evaluation '\ + 'when `format_only` is False.' + + self.format_only = format_only + self.outfile_prefix = outfile_prefix + + def add(self, predictions: Sequence[Dict], groundtruths: Sequence[Dict]) -> None: # type: ignore # yapf: disable # noqa: E501 + """Add the intermediate results to `self._results`. + + Args: + predictions (Sequence[dict]): A sequence of dict. Each dict + representing a pose estimation result for an instance, with + the following keys: + - 'id'(int): The id of the instance + - 'img_id' (int): The image_id of the instance + - 'bboxes': The bounding bboxes of the instance + - 'keypoints' (np.ndarray): Shape (N, K, 2). + The predicted keypoints coordinates of the instance. + N: number of instances, K: number of keypoint. + For topdown-style output, N is usually 1, while + for bottomup-style output, N is the number of instances + in the image. + - 'keypoint_scores' (np.ndarray): Shape (N, K). + The scores for all keypoints of all instances. + - 'bbox_scores' (np.ndarray): Shape (N, ). + The predicted scores of the bounding boxes. + + groundtruths (Sequence[dict]): A sequence of dict. If load from + `ann_file`, the dict inside can be empty. Else, each dict + represents a groundtruths for an instance, with the following + keys: + - 'img_id' (int): The image_id of the instance + - 'width' (int): The width of the image. + - 'height' (int): The height of the image. + - 'crowd_index' (float, optional): Measure the crowding + level of an image, defined in CrowdPose dataset + - `raw_ann_info` (dict): The raw annotation information + of the instances. It is worth mentioning that, to + compute `COCOPoseMetric`, there are some required + keys in the `raw_ann_info`: + - `id`: the id to distinguish different annotations + - `image_id`: the image id of this annotation + - `category_id`: the category of the instance. + - `bbox`: the bounding box of the instance + - `keypoints`: the keypoints cooridinates with + their visibilities. It need to be aligned + with the official COCO format, e.g., a list + with length N * 3, in which N is the number of + keypoints. And each triplet represent the + [x, y, visible] of the keypoint. + - `iscrowd`: indicating whether the annotation is + a crowd. It is useful when matching the + detection results to the ground truth. + There are some optional keys as well: + - `area`: it is necessary when `self.use_area` is + `True` + - `num_keypoints`: it is necessary when + `self.iou_type` is set as `keypoints_crowd`. + """ + for prediction, groundtruth in zip(predictions, groundtruths): + assert isinstance(prediction, dict), 'The prediciton should be ' \ + f'a sequence of dict, but got a sequence of {type(prediction)}.' # noqa: E501 + assert isinstance(groundtruth, dict), 'The label should be ' \ + f'a sequence of dict, but got a sequence of {type(groundtruth)}.' # noqa: E501 + self._results.append((prediction, groundtruth)) + + def gt_to_coco_json(self, gt_dicts: Sequence[dict], + outfile_prefix: str) -> str: + """Convert ground truth to coco format json file. + + Args: + gt_dicts (Sequence[dict]): Ground truth of the dataset. Each dict + contains the ground truth information about the data sample. + Required keys of the each `gt_dict` in `gt_dicts`: + - `img_id`: image id of the data sample + - `width`: original image width + - `height`: original image height + - `raw_ann_info`: the raw annotation information + Optional keys: + - `crowd_index`: measure the crowding level of an image, + defined in CrowdPose dataset + It is worth mentioning that, in order to compute `CocoMetric`, + there are some required keys in the `raw_ann_info`: + - `id`: the id to distinguish different annotations + - `image_id`: the image id of this annotation + - `category_id`: the category of the instance. + - `bbox`: the object bounding box + - `keypoints`: the keypoints cooridinates along with their + visibilities. Note that it need to be aligned + with the official COCO format, e.g., a list with length + N * 3, in which N is the number of keypoints. And each + triplet represent the [x, y, visible] of the keypoint. + - `iscrowd`: indicating whether the annotation is a crowd. + It is useful when matching the detection results to + the ground truth. + There are some optional keys as well: + - `area`: it is necessary when `self.use_area` is `True` + - `num_keypoints`: it is necessary when `self.iou_type` + is set as `keypoints_crowd`. + outfile_prefix (str): The filename prefix of the json files. If the + prefix is "somepath/xxx", the json file will be named + "somepath/xxx.gt.json". + Returns: + str: The filename of the json file. + """ + image_infos = [] + annotations = [] + img_ids = [] + ann_ids = [] + + for gt_dict in gt_dicts: + # filter duplicate image_info + if gt_dict['img_id'] not in img_ids: + image_info = dict( + id=gt_dict['img_id'], + width=gt_dict['width'], + height=gt_dict['height'], + ) + if self.iou_type == 'keypoints_crowd': + image_info['crowdIndex'] = gt_dict['crowd_index'] + + image_infos.append(image_info) + img_ids.append(gt_dict['img_id']) + + # filter duplicate annotations + for ann in gt_dict['raw_ann_info']: + annotation = dict( + id=ann['id'], + image_id=ann['image_id'], + category_id=ann['category_id'], + bbox=ann['bbox'], + keypoints=ann['keypoints'], + iscrowd=ann['iscrowd'], + ) + if self.use_area: + assert 'area' in ann, \ + '`area` is required when `self.use_area` is `True`' + annotation['area'] = ann['area'] + + if self.iou_type == 'keypoints_crowd': + assert 'num_keypoints' in ann, \ + '`num_keypoints` is required when `self.iou_type` ' \ + 'is `keypoints_crowd`' + annotation['num_keypoints'] = ann['num_keypoints'] + + annotations.append(annotation) + ann_ids.append(ann['id']) + + info = dict( + date_created=str(datetime.datetime.now()), + description='Coco json file converted by mmpose CocoMetric.') + coco_json: dict = dict( + info=info, + images=image_infos, + categories=self.dataset_meta['CLASSES'], + licenses=None, + annotations=annotations, + ) + converted_json_path = f'{outfile_prefix}.gt.json' + with open(converted_json_path, 'w') as f: + dump(coco_json, f, sort_keys=True, indent=4) + return converted_json_path + + def compute_metric(self, results: list) -> Dict[str, float]: + """Compute the metrics from processed results. + + Args: + results (list): The processed results of each batch. + + Returns: + Dict[str, float]: The computed metrics. The keys are the names of + the metrics, and the values are corresponding results. + """ + # split prediction and gt list + preds, gts = zip(*results) + + tmp_dir = None + if self.outfile_prefix is None: + tmp_dir = tempfile.TemporaryDirectory() + outfile_prefix = osp.join(tmp_dir.name, 'results') + else: + outfile_prefix = self.outfile_prefix + + if self.coco is None: + # use converted gt json file to initialize coco helper + logger.info('Converting ground truth to coco format...') + coco_json_path = self.gt_to_coco_json( + gt_dicts=gts, outfile_prefix=outfile_prefix) + self.coco = COCO(coco_json_path) + + kpts = defaultdict(list) + + # group the preds by img_id + for pred in preds: + img_id = pred['img_id'] + for idx in range(len(pred['bbox_scores'])): + instance = { + 'id': pred['id'], + 'img_id': pred['img_id'], + 'category_id': pred['category_id'], + 'keypoints': pred['keypoints'][idx], + 'keypoint_scores': pred['keypoint_scores'][idx], + 'bbox_score': pred['bbox_scores'][idx], + } + + if 'areas' in pred: + instance['area'] = pred['areas'][idx] + else: + # use keypoint to calculate bbox and get area + keypoints = pred['keypoints'][idx] + area = ( + np.max(keypoints[:, 0]) - np.min(keypoints[:, 0])) * ( + np.max(keypoints[:, 1]) - np.min(keypoints[:, 1])) + instance['area'] = area + + kpts[img_id].append(instance) + + # sort keypoint results according to id and remove duplicate ones + kpts = self._sort_and_unique_bboxes(kpts, key='id') + + # score the prediction results according to `score_mode` + # and perform NMS according to `nms_mode` + valid_kpts: dict = defaultdict(list) + num_keypoints = self.dataset_meta['num_keypoints'] + for img_id, instances in kpts.items(): + for instance in instances: + # concatenate the keypoint coordinates and scores + instance['keypoints'] = np.concatenate([ + instance['keypoints'], instance['keypoint_scores'][:, None] + ], + axis=-1) + if self.score_mode == 'bbox': + instance['score'] = instance['bbox_score'] + else: + bbox_score = instance['bbox_score'] + if self.score_mode == 'bbox_rle': + keypoint_scores = instance['keypoint_scores'] + instance['score'] = float(bbox_score + + np.mean(keypoint_scores) + + np.max(keypoint_scores)) + + else: # self.score_mode == 'bbox_keypoint': + mean_kpt_score: float = 0.0 + valid_num = 0 + for kpt_idx in range(num_keypoints): + kpt_score = instance['keypoint_scores'][kpt_idx] + if kpt_score > self.keypoint_score_thr: + mean_kpt_score += kpt_score + valid_num += 1 + if valid_num != 0: + mean_kpt_score /= valid_num + instance['score'] = bbox_score * mean_kpt_score + # perform nms + if self.nms_mode == 'none': + valid_kpts[img_id] = instances + elif self.nms_mode == 'oks_nms': + keep = oks_nms( + instances, + self.nms_thr, + sigmas=self.dataset_meta['sigmas']) + valid_kpts[img_id] = [instances[_keep] for _keep in keep] + else: + keep = soft_oks_nms( + instances, + self.nms_thr, + sigmas=self.dataset_meta['sigmas']) + valid_kpts[img_id] = [instances[_keep] for _keep in keep] + + # convert results to coco style and dump into a json file + self.results2json(valid_kpts, outfile_prefix=outfile_prefix) + + # only format the results without doing quantitative evaluation + if self.format_only: + logger.info('results are saved in ' + f'{osp.dirname(outfile_prefix)}') + return {} + + # evaluation results + eval_results: OrderedDict = OrderedDict() + logger.info(f'Evaluating {self.__class__.__name__}...') + info_str = self._do_python_keypoint_eval(outfile_prefix) + name_value = OrderedDict(info_str) + eval_results.update(name_value) + + if tmp_dir is not None: + tmp_dir.cleanup() + return eval_results + + def results2json(self, keypoints: Dict[int, list], outfile_prefix: str): + """Dump the keypoint detection results to a COCO style json file. + + Args: + keypoints (Dict[int, list]): Keypoint detection results + of the dataset. + outfile_prefix (str): The filename prefix of the json files. If the + prefix is "somepath/xxx", the json files will be named + "somepath/xxx.keypoints.json", + + Returns: + str: The json file name of keypoint results. + """ + # the results with 'category_id' + cat_results = [] + + for _, img_kpts in keypoints.items(): + _keypoints = np.array( + [img_kpt['keypoints'] for img_kpt in img_kpts]) + num_keypoints = self.dataset_meta['num_keypoints'] + # collect all the person keypoints in current image + _keypoints = _keypoints.reshape(-1, num_keypoints * 3) + + result = [{ + 'image_id': img_kpt['img_id'], + 'category_id': img_kpt['category_id'], + 'keypoints': keypoint.tolist(), + 'score': float(img_kpt['score']), + } for img_kpt, keypoint in zip(img_kpts, _keypoints)] + + cat_results.extend(result) + + res_file = f'{outfile_prefix}.keypoints.json' + with open(res_file, 'w') as f: + dump(cat_results, f, sort_keys=True, indent=4) + + def _do_python_keypoint_eval(self, outfile_prefix: str) -> list: + """Do keypoint evaluation using COCOAPI. + + Args: + outfile_prefix (str): The filename prefix of the json files. If the + prefix is "somepath/xxx", the json files will be named + "somepath/xxx.keypoints.json", + + Returns: + list: a list of tuples. Each tuple contains the evaluation stats + name and corresponding stats value. + """ + res_file = f'{outfile_prefix}.keypoints.json' + coco_det = self.coco.loadRes(res_file) + sigmas = self.dataset_meta['sigmas'] + coco_eval = COCOeval(self.coco, coco_det, self.iou_type, sigmas, + self.use_area) + coco_eval.params.useSegm = None + coco_eval.evaluate() + coco_eval.accumulate() + coco_eval.summarize() + + if self.iou_type == 'keypoints_crowd': + stats_names = [ + 'AP', 'AP .5', 'AP .75', 'AR', 'AR .5', 'AR .75', 'AP(E)', + 'AP(M)', 'AP(H)' + ] + else: + stats_names = [ + 'AP', 'AP .5', 'AP .75', 'AP (M)', 'AP (L)', 'AR', 'AR .5', + 'AR .75', 'AR (M)', 'AR (L)' + ] + + info_str = list(zip(stats_names, coco_eval.stats)) + + return info_str + + def _sort_and_unique_bboxes(self, + kpts: Dict[int, list], + key: str = 'id') -> Dict[int, list]: + """Sort keypoint detection results in each image and remove the + duplicate ones. Usually performed in multi-batch testing. + + Args: + kpts (Dict[int, list]): keypoint prediction results. The keys are + '`img_id`' and the values are list that may contain + keypoints of multiple persons. Each element in the list is a + dict containing the ``'key'`` field. + See the argument ``key`` for details. + key (str): The key name in each person prediction results. The + corresponding value will be used for sorting the results. + Default: ``'id'``. + + Returns: + Dict[int, list]: The sorted keypoint detection results. + """ + for img_id, persons in kpts.items(): + # deal with bottomup-style output + if isinstance(kpts[img_id][0][key], Sequence): + return kpts + num = len(persons) + kpts[img_id] = sorted(kpts[img_id], key=lambda x: x[key]) + for i in range(num - 1, 0, -1): + if kpts[img_id][i][key] == kpts[img_id][i - 1][key]: + del kpts[img_id][i] + + return kpts diff --git a/mmeval/metrics/utils/__init__.py b/mmeval/metrics/utils/__init__.py index 409411c7..62a58ff6 100644 --- a/mmeval/metrics/utils/__init__.py +++ b/mmeval/metrics/utils/__init__.py @@ -3,11 +3,13 @@ from .hmean import compute_hmean from .image_transforms import reorder_and_crop from .keypoint_eval import keypoint_pck_accuracy +from .nms import nms, oks_nms, soft_oks_nms from .polygon import (poly2shapely, poly_intersection, poly_iou, poly_make_valid, poly_union, polys2shapely) __all__ = [ 'poly2shapely', 'polys2shapely', 'poly_union', 'poly_intersection', 'poly_make_valid', 'poly_iou', 'compute_hmean', 'keypoint_pck_accuracy', - 'calculate_overlaps', 'calculate_bboxes_area', 'reorder_and_crop' + 'calculate_overlaps', 'calculate_bboxes_area', 'reorder_and_crop', 'nms', + 'oks_nms', 'soft_oks_nms' ] diff --git a/mmeval/metrics/utils/nms.py b/mmeval/metrics/utils/nms.py new file mode 100644 index 00000000..21535e4f --- /dev/null +++ b/mmeval/metrics/utils/nms.py @@ -0,0 +1,250 @@ +# ------------------------------------------------------------------------------ +# Adapted from https://github.com/leoxiaobin/deep-high-resolution-net.pytorch +# Original licence: Copyright (c) Microsoft, under the MIT License. +# ------------------------------------------------------------------------------ + +import numpy as np +from typing import List, Optional + + +def nms(dets: np.ndarray, thr: float) -> List[int]: + """Greedily select boxes with high confidence and overlap <= thr. + + Args: + dets (np.ndarray): [[x1, y1, x2, y2, score]]. + thr (float): Retain overlap < thr. + + Returns: + list: Indexes to keep. + """ + if len(dets) == 0: + return [] + + x1 = dets[:, 0] + y1 = dets[:, 1] + x2 = dets[:, 2] + y2 = dets[:, 3] + scores = dets[:, 4] + + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = scores.argsort()[::-1] + + keep = [] + while len(order) > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + + inds = np.where(ovr <= thr)[0] + order = order[inds + 1] + + return keep + + +def oks_iou(g: np.ndarray, + d: np.ndarray, + a_g: float, + a_d: np.ndarray, + sigmas: Optional[np.ndarray] = None, + vis_thr: Optional[float] = None) -> np.ndarray: + """Calculate oks ious. + + Note: + + - number of keypoints: K + - number of instances: N + + Args: + g (np.ndarray): The instance to calculate OKS IOU with other + instances. Containing the keypoints coordinates. Shape: (K*3, ) + d (np.ndarray): The rest instances. Containing the keypoints + coordinates. Shape: (N, K*3) + a_g (float): Area of the ground truth object. + a_d (np.ndarray): Area of the detected object. Shape: (N, ) + sigmas (np.ndarray, optional): Keypoint labelling uncertainty. + Please refer to `COCO keypoint evaluation + `__ for more details. + If not given, use the sigmas on COCO dataset. + If specified, shape: (K, ). Defaults to ``None`` + vis_thr(float, optional): Threshold of the keypoint visibility. + If specified, will calculate OKS based on those keypoints whose + visibility higher than vis_thr. If not given, calculate the OKS + based on all keypoints. Defaults to ``None`` + + Returns: + np.ndarray: The oks ious. + """ + if sigmas is None: + sigmas = np.array([ + .26, .25, .25, .35, .35, .79, .79, .72, .72, .62, .62, 1.07, 1.07, + .87, .87, .89, .89 + ]) / 10.0 + vars = (sigmas * 2)**2 + xg = g[0::3] + yg = g[1::3] + vg = g[2::3] + ious = np.zeros(len(d), dtype=np.float32) + for n_d in range(0, len(d)): + xd = d[n_d, 0::3] + yd = d[n_d, 1::3] + vd = d[n_d, 2::3] + dx = xd - xg + dy = yd - yg + e = (dx**2 + dy**2) / vars / ((a_g + a_d[n_d]) / 2 + np.spacing(1)) / 2 + if vis_thr is not None: + ind = list(vg > vis_thr) and list(vd > vis_thr) + e = e[ind] + ious[n_d] = np.sum(np.exp(-e)) / len(e) if len(e) != 0 else 0.0 + return ious + + +def oks_nms(kpts_db: List[dict], + thr: float, + sigmas: Optional[np.ndarray] = None, + vis_thr: Optional[float] = None, + score_per_joint: bool = False) -> np.ndarray: + """OKS NMS implementations. + + Args: + kpts_db (List[dict]): The keypoints results of the same image. + thr (float): The threshold of NMS. Will retain oks overlap < thr. + sigmas (np.ndarray, optional): Keypoint labelling uncertainty. + Please refer to `COCO keypoint evaluation + `__ for more details. + If not given, use the sigmas on COCO dataset. Defaults to ``None`` + vis_thr(float, optional): Threshold of the keypoint visibility. + If specified, will calculate OKS based on those keypoints whose + visibility higher than vis_thr. If not given, calculate the OKS + based on all keypoints. Defaults to ``None`` + score_per_joint(bool): Whether the input scores (in kpts_db) are + per-joint scores. Defaults to ``False`` + + Returns: + np.ndarray: indexes to keep. + """ + if len(kpts_db) == 0: + return [] + + if score_per_joint: + scores = np.array([k['score'].mean() for k in kpts_db]) + else: + scores = np.array([k['score'] for k in kpts_db]) + + kpts = np.array([k['keypoints'].flatten() for k in kpts_db]) + areas = np.array([k['area'] for k in kpts_db]) + + order = scores.argsort()[::-1] + + keep = [] + while len(order) > 0: + i = order[0] + keep.append(i) + + oks_ovr = oks_iou(kpts[i], kpts[order[1:]], areas[i], areas[order[1:]], + sigmas, vis_thr) + + inds = np.where(oks_ovr <= thr)[0] + order = order[inds + 1] + + keep = np.array(keep) + + return keep + + +def _rescore(overlap: np.ndarray, + scores: np.ndarray, + thr: float, + type: str = 'gaussian') -> np.ndarray: + """Rescoring mechanism gaussian or linear. + + Args: + overlap (np.ndarray): The calculated oks ious. + scores (np.ndarray): target scores. + thr (float): retain oks overlap < thr. + type (str): The rescoring type. Could be 'gaussian' or 'linear'. + Defaults to ``'gaussian'`` + + Returns: + np.ndarray: indexes to keep + """ + assert len(overlap) == len(scores) + assert type in ['gaussian', 'linear'] + + if type == 'linear': + inds = np.where(overlap >= thr)[0] + scores[inds] = scores[inds] * (1 - overlap[inds]) + else: + scores = scores * np.exp(-overlap**2 / thr) + + return scores + + +def soft_oks_nms(kpts_db: List[dict], + thr: float, + max_dets: int = 20, + sigmas: Optional[np.ndarray] = None, + vis_thr: Optional[float] = None, + score_per_joint: bool = False) -> np.ndarray: + """Soft OKS NMS implementations. + + Args: + kpts_db (List[dict]): The keypoints results of the same image. + thr (float): The threshold of NMS. Will retain oks overlap < thr. + max_dets (int): Maximum number of detections to keep. Defaults to 20 + sigmas (np.ndarray, optional): Keypoint labelling uncertainty. + Please refer to `COCO keypoint evaluation + `__ for more details. + If not given, use the sigmas on COCO dataset. Defaults to ``None`` + vis_thr(float, optional): Threshold of the keypoint visibility. + If specified, will calculate OKS based on those keypoints whose + visibility higher than vis_thr. If not given, calculate the OKS + based on all keypoints. Defaults to ``None`` + score_per_joint(bool): Whether the input scores (in kpts_db) are + per-joint scores. Defaults to ``False`` + + Returns: + np.ndarray: indexes to keep. + """ + if len(kpts_db) == 0: + return [] + + if score_per_joint: + scores = np.array([k['score'].mean() for k in kpts_db]) + else: + scores = np.array([k['score'] for k in kpts_db]) + + kpts = np.array([k['keypoints'].flatten() for k in kpts_db]) + areas = np.array([k['area'] for k in kpts_db]) + + order = scores.argsort()[::-1] + scores = scores[order] + + keep = np.zeros(max_dets, dtype=np.intp) + keep_cnt = 0 + while len(order) > 0 and keep_cnt < max_dets: + i = order[0] + + oks_ovr = oks_iou(kpts[i], kpts[order[1:]], areas[i], areas[order[1:]], + sigmas, vis_thr) + + order = order[1:] + scores = _rescore(oks_ovr, scores[1:], thr) + + tmp = scores.argsort()[::-1] + order = order[tmp] + scores = scores[tmp] + + keep[keep_cnt] = i + keep_cnt += 1 + + keep = keep[:keep_cnt] + + return keep diff --git a/tests/test_metrics/data/ap10k_sample.json b/tests/test_metrics/data/ap10k_sample.json new file mode 100644 index 00000000..851dc1ad --- /dev/null +++ b/tests/test_metrics/data/ap10k_sample.json @@ -0,0 +1,5249 @@ +{ + "info":{ + "description":"AP-10k", + "url":"https://github.com/AlexTheBad/AP-10K", + "version":"1.0", + "year":2021, + "contributor":"AP-10k Team", + "date_created":"2021/07/01" + }, + "licenses":[ + { + "id":1, + "name":"The MIT License", + "url":"https://www.mit.edu/~amini/LICENSE.md" + } + ], + "images":[ + { + "license":1, + "id":37516, + "file_name":"000000037516.jpg", + "width":1200, + "height":867, + "background":5 + }, + { + "license":1, + "id":4, + "file_name":"000000000004.jpg", + "width":1024, + "height":683, + "background":1 + } + ], + "annotations":[ + { + "id":9284, + "image_id":37516, + "category_id":26, + "bbox":[ + 66, + 192, + 1092, + 512 + ], + "area":559104, + "iscrowd":0, + "num_keypoints":16, + "keypoints":[ + 134, + 415, + 2, + 0, + 0, + 0, + 94, + 475, + 2, + 302, + 330, + 2, + 890, + 287, + 2, + 414, + 470, + 2, + 414, + 554, + 2, + 396, + 624, + 2, + 302, + 466, + 2, + 230, + 515, + 2, + 214, + 623, + 2, + 838, + 422, + 2, + 946, + 511, + 2, + 936, + 628, + 2, + 708, + 442, + 2, + 698, + 555, + 2, + 636, + 602, + 2 + ] + }, + { + "id":6, + "image_id":4, + "category_id":1, + "bbox":[ + 408, + 197, + 429, + 341 + ], + "area":146289, + "iscrowd":0, + "num_keypoints":16, + "keypoints":[ + 488, + 443, + 2, + 0, + 0, + 0, + 466, + 499, + 2, + 600, + 307, + 2, + 787, + 255, + 2, + 643, + 369, + 2, + 660, + 438, + 2, + 684, + 514, + 2, + 592, + 380, + 2, + 594, + 443, + 2, + 591, + 520, + 2, + 757, + 350, + 2, + 778, + 408, + 2, + 772, + 513, + 2, + 729, + 352, + 2, + 778, + 400, + 2, + 765, + 497, + 2 + ] + } + ], + "categories":[ + { + "id":1, + "name":"antelope", + "supercategory":"Bovidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":2, + "name":"argali sheep", + "supercategory":"Bovidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":3, + "name":"bison", + "supercategory":"Bovidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":4, + "name":"buffalo", + "supercategory":"Bovidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":5, + "name":"cow", + "supercategory":"Bovidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":6, + "name":"sheep", + "supercategory":"Bovidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":7, + "name":"arctic fox", + "supercategory":"Canidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":8, + "name":"dog", + "supercategory":"Canidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":9, + "name":"fox", + "supercategory":"Canidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":10, + "name":"wolf", + "supercategory":"Canidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":11, + "name":"beaver", + "supercategory":"Castoridae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":12, + "name":"alouatta", + "supercategory":"Cercopithecidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":13, + "name":"monkey", + "supercategory":"Cercopithecidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":14, + "name":"noisy night monkey", + "supercategory":"Cercopithecidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":15, + "name":"spider monkey", + "supercategory":"Cercopithecidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":16, + "name":"uakari", + "supercategory":"Cercopithecidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":17, + "name":"deer", + "supercategory":"Cervidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":18, + "name":"moose", + "supercategory":"Cervidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":19, + "name":"hamster", + "supercategory":"Cricetidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":20, + "name":"elephant", + "supercategory":"Elephantidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":21, + "name":"horse", + "supercategory":"Equidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":22, + "name":"zebra", + "supercategory":"Equidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":23, + "name":"bobcat", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":24, + "name":"cat", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":25, + "name":"cheetah", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":26, + "name":"jaguar", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":27, + "name":"king cheetah", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":28, + "name":"leopard", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":29, + "name":"lion", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":30, + "name":"panther", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":31, + "name":"snow leopard", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":32, + "name":"tiger", + "supercategory":"Felidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":33, + "name":"giraffe", + "supercategory":"Giraffidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":34, + "name":"hippo", + "supercategory":"Hippopotamidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":35, + "name":"chimpanzee", + "supercategory":"Hominidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":36, + "name":"gorilla", + "supercategory":"Hominidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":37, + "name":"orangutan", + "supercategory":"Hominidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":38, + "name":"rabbit", + "supercategory":"Leporidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":39, + "name":"skunk", + "supercategory":"Mephitidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":40, + "name":"mouse", + "supercategory":"Muridae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":41, + "name":"rat", + "supercategory":"Muridae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":42, + "name":"otter", + "supercategory":"Mustelidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":43, + "name":"weasel", + "supercategory":"Mustelidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":44, + "name":"raccoon", + "supercategory":"Procyonidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":45, + "name":"rhino", + "supercategory":"Rhinocerotidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":46, + "name":"marmot", + "supercategory":"Sciuridae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":47, + "name":"squirrel", + "supercategory":"Sciuridae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":48, + "name":"pig", + "supercategory":"Suidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":49, + "name":"mole", + "supercategory":"Talpidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":50, + "name":"black bear", + "supercategory":"Ursidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":51, + "name":"brown bear", + "supercategory":"Ursidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":52, + "name":"panda", + "supercategory":"Ursidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":53, + "name":"polar bear", + "supercategory":"Ursidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + }, + { + "id":54, + "name":"bat", + "supercategory":"Vespertilionidae", + "keypoints":[ + "left_eye", + "right_eye", + "nose", + "neck", + "root_of_tail", + "left_shoulder", + "left_elbow", + "left_front_paw", + "right_shoulder", + "right_elbow", + "right_front_paw", + "left_hip", + "left_knee", + "left_back_paw", + "right_hip", + "right_knee", + "right_back_paw" + ], + "skeleton":[ + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 3, + 4 + ], + [ + 4, + 5 + ], + [ + 4, + 6 + ], + [ + 6, + 7 + ], + [ + 7, + 8 + ], + [ + 4, + 9 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 5, + 12 + ], + [ + 12, + 13 + ], + [ + 13, + 14 + ], + [ + 5, + 15 + ], + [ + 15, + 16 + ], + [ + 16, + 17 + ] + ] + } + ] +} diff --git a/tests/test_metrics/data/coco_pose_sample.json b/tests/test_metrics/data/coco_pose_sample.json new file mode 100644 index 00000000..75448df5 --- /dev/null +++ b/tests/test_metrics/data/coco_pose_sample.json @@ -0,0 +1,2465 @@ +{ + "info": { + "description": "For testing COCO dataset only.", + "year": 2020, + "date_created": "2020/06/20" + }, + "licenses": [ + { + "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/", + "id": 1, + "name": "Attribution-NonCommercial-ShareAlike License" + }, + { + "url": "http://creativecommons.org/licenses/by-nc/2.0/", + "id": 2, + "name": "Attribution-NonCommercial License" + }, + { + "url": "http://creativecommons.org/licenses/by-nc-nd/2.0/", + "id": 3, + "name": "Attribution-NonCommercial-NoDerivs License" + }, + { + "url": "http://creativecommons.org/licenses/by/2.0/", + "id": 4, + "name": "Attribution License" + }, + { + "url": "http://creativecommons.org/licenses/by-sa/2.0/", + "id": 5, + "name": "Attribution-ShareAlike License" + }, + { + "url": "http://creativecommons.org/licenses/by-nd/2.0/", + "id": 6, + "name": "Attribution-NoDerivs License" + }, + { + "url": "http://flickr.com/commons/usage/", + "id": 7, + "name": "No known copyright restrictions" + }, + { + "url": "http://www.usa.gov/copyright.shtml", + "id": 8, + "name": "United States Government Work" + } + ], + "categories": [ + { + "supercategory": "person", + "id": 1, + "name": "person", + "keypoints": [ + "nose", + "left_eye", + "right_eye", + "left_ear", + "right_ear", + "left_shoulder", + "right_shoulder", + "left_elbow", + "right_elbow", + "left_wrist", + "right_wrist", + "left_hip", + "right_hip", + "left_knee", + "right_knee", + "left_ankle", + "right_ankle" + ], + "skeleton": [ + [ + 16, + 14 + ], + [ + 14, + 12 + ], + [ + 17, + 15 + ], + [ + 15, + 13 + ], + [ + 12, + 13 + ], + [ + 6, + 12 + ], + [ + 7, + 13 + ], + [ + 6, + 7 + ], + [ + 6, + 8 + ], + [ + 7, + 9 + ], + [ + 8, + 10 + ], + [ + 9, + 11 + ], + [ + 2, + 3 + ], + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 4 + ], + [ + 3, + 5 + ], + [ + 4, + 6 + ], + [ + 5, + 7 + ] + ] + } + ], + "images": [ + { + "license": 4, + "file_name": "000000000785.jpg", + "coco_url": "http://images.cocodataset.org/val2017/000000000785.jpg", + "height": 425, + "width": 640, + "date_captured": "2013-11-19 21:22:42", + "flickr_url": "http://farm8.staticflickr.com/7015/6795644157_f019453ae7_z.jpg", + "id": 785 + }, + { + "license": 3, + "file_name": "000000040083.jpg", + "coco_url": "http://images.cocodataset.org/val2017/000000040083.jpg", + "height": 333, + "width": 500, + "date_captured": "2013-11-18 03:30:24", + "flickr_url": "http://farm1.staticflickr.com/116/254881838_e21c6d17b8_z.jpg", + "id": 40083 + }, + { + "license": 1, + "file_name": "000000196141.jpg", + "coco_url": "http://images.cocodataset.org/val2017/000000196141.jpg", + "height": 429, + "width": 640, + "date_captured": "2013-11-22 22:37:15", + "flickr_url": "http://farm4.staticflickr.com/3310/3611902235_57d4ae496d_z.jpg", + "id": 196141 + }, + { + "license": 3, + "file_name": "000000197388.jpg", + "coco_url": "http://images.cocodataset.org/val2017/000000197388.jpg", + "height": 392, + "width": 640, + "date_captured": "2013-11-19 20:10:37", + "flickr_url": "http://farm9.staticflickr.com/8375/8507321836_5b8b13188f_z.jpg", + "id": 197388 + } + ], + "annotations": [ + { + "segmentation": [ + [ + 353.37, + 67.65, + 358.15, + 52.37, + 362.92, + 47.59, + 374.38, + 44.73, + 389.66, + 52.37, + 389.66, + 67.65, + 389.66, + 76.25, + 393.48, + 83.89, + 396.35, + 88.66, + 397.3, + 91.53, + 406.85, + 99.17, + 413.54, + 104.9, + 451.74, + 148.83, + 458.43, + 153.6, + 462.25, + 166.02, + 467.02, + 173.66, + 463.2, + 181.3, + 449.83, + 183.21, + 448.88, + 191.81, + 455.56, + 226.19, + 448.88, + 254.84, + 453.65, + 286.36, + 475.62, + 323.6, + 491.85, + 361.81, + 494.72, + 382.82, + 494.72, + 382.82, + 499.49, + 391.41, + 416.4, + 391.41, + 424.04, + 383.77, + 439.33, + 374.22, + 445.06, + 360.85, + 436.46, + 334.11, + 421.18, + 303.55, + 416.4, + 289.22, + 409.72, + 268.21, + 396.35, + 280.63, + 405.9, + 298.77, + 417.36, + 324.56, + 425, + 349.39, + 425, + 357.99, + 419.27, + 360.85, + 394.44, + 367.54, + 362.92, + 370.4, + 346.69, + 367.54, + 360.06, + 362.76, + 369.61, + 360.85, + 382.98, + 340.8, + 355.28, + 271.08, + 360.06, + 266.3, + 386.8, + 219.5, + 368.65, + 162.2, + 348.6, + 175.57, + 309.44, + 187.03, + 301.8, + 192.76, + 288.43, + 193.72, + 282.7, + 193.72, + 280.79, + 187.03, + 280.79, + 174.62, + 287.47, + 171.75, + 291.29, + 171.75, + 295.11, + 171.75, + 306.57, + 166.98, + 312.3, + 165.07, + 345.73, + 142.14, + 350.51, + 117.31, + 350.51, + 102.03, + 350.51, + 90.57, + 353.37, + 65.74 + ] + ], + "num_keypoints": 17, + "area": 27789.11055, + "iscrowd": 0, + "keypoints": [ + 367, + 81, + 2, + 374, + 73, + 2, + 360, + 75, + 2, + 386, + 78, + 2, + 356, + 81, + 2, + 399, + 108, + 2, + 358, + 129, + 2, + 433, + 142, + 2, + 341, + 159, + 2, + 449, + 165, + 2, + 309, + 178, + 2, + 424, + 203, + 2, + 393, + 214, + 2, + 429, + 294, + 2, + 367, + 273, + 2, + 466, + 362, + 2, + 396, + 341, + 2 + ], + "image_id": 785, + "bbox": [ + 280.79, + 44.73, + 218.7, + 346.68 + ], + "category_id": 1, + "id": 442619 + }, + { + "segmentation": [ + [ + 98.56, + 273.72, + 132.9, + 267, + 140.37, + 281.93, + 165.75, + 285.66, + 156.79, + 264.01, + 170.23, + 261.02, + 177.7, + 272.97, + 182.18, + 279.69, + 200.85, + 268.49, + 212.79, + 255.05, + 188.9, + 256.54, + 164.26, + 240.12, + 139.62, + 212.49, + 109.01, + 221.45, + 103.04, + 220.71, + 122.45, + 202.04, + 113.49, + 196.07, + 96.32, + 168.44, + 97.06, + 162.47, + 110.5, + 136.34, + 112, + 124.39, + 91.09, + 110.95, + 80.64, + 114.68, + 71.68, + 131.86, + 62.72, + 147.54, + 57.49, + 156.5, + 48.53, + 168.44, + 41.07, + 180.39, + 38.08, + 193.08, + 40.32, + 205.03, + 47.04, + 213.24, + 54.5, + 216.23, + 82.13, + 252.06, + 91.09, + 271.48 + ] + ], + "num_keypoints": 14, + "area": 11025.219, + "iscrowd": 0, + "keypoints": [ + 99, + 144, + 2, + 104, + 141, + 2, + 96, + 137, + 2, + 0, + 0, + 0, + 78, + 133, + 2, + 56, + 161, + 2, + 81, + 162, + 2, + 0, + 0, + 0, + 103, + 208, + 2, + 116, + 204, + 2, + 0, + 0, + 0, + 57, + 246, + 1, + 82, + 259, + 1, + 137, + 219, + 2, + 138, + 247, + 2, + 177, + 256, + 2, + 158, + 296, + 1 + ], + "image_id": 40083, + "bbox": [ + 38.08, + 110.95, + 174.71, + 174.71 + ], + "category_id": 1, + "id": 198196 + }, + { + "segmentation": [ + [ + 257.76, + 288.05, + 273.4, + 258.26, + 325.55, + 253.79, + 335.23, + 232.93, + 326.3, + 186.74, + 333.74, + 177.05, + 327.79, + 153.21, + 333.74, + 142.04, + 344.17, + 139.06, + 353.11, + 139.06, + 359.07, + 145.02, + 360.56, + 148.74, + 362.05, + 168.86, + 388.87, + 197.17, + 397.81, + 276.88, + 372.48, + 293.27 + ] + ], + "num_keypoints": 15, + "area": 10171.9544, + "iscrowd": 0, + "keypoints": [ + 343, + 164, + 2, + 348, + 160, + 2, + 340, + 160, + 2, + 359, + 163, + 2, + 332, + 164, + 2, + 370, + 189, + 2, + 334, + 190, + 2, + 358, + 236, + 2, + 348, + 234, + 2, + 339, + 270, + 2, + 330, + 262, + 2, + 378, + 262, + 2, + 343, + 254, + 2, + 338, + 280, + 2, + 283, + 272, + 2, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "image_id": 40083, + "bbox": [ + 257.76, + 139.06, + 140.05, + 154.21 + ], + "category_id": 1, + "id": 230195 + }, + { + "segmentation": [ + [ + 285.37, + 126.5, + 281.97, + 127.72, + 280.76, + 132.33, + 280.76, + 136.46, + 275.17, + 143.26, + 275.9, + 158.08, + 277.6, + 164.4, + 278.33, + 173.87, + 278.33, + 183.83, + 279.79, + 191.11, + 281.97, + 194.76, + 284.89, + 192.09, + 284.89, + 186.99, + 284.89, + 181.16, + 284.64, + 177.51, + 285.86, + 173.87 + ] + ], + "num_keypoints": 0, + "area": 491.2669, + "iscrowd": 0, + "keypoints": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "image_id": 40083, + "bbox": [ + 275.17, + 126.5, + 10.69, + 68.26 + ], + "category_id": 1, + "id": 1202706 + }, + { + "segmentation": [ + [ + 339.34, + 107.97, + 338.38, + 102.19, + 339.34, + 91.58, + 335.49, + 84.84, + 326.81, + 74.23, + 312.35, + 74.23, + 301.75, + 74.23, + 295, + 86.76, + 295, + 93.51, + 292.11, + 99.3, + 287.29, + 102.19, + 291.14, + 107.01, + 295, + 107.01, + 295.96, + 112.79, + 301.75, + 115.69, + 305.6, + 119.54, + 307.53, + 123.4, + 317.17, + 123.4, + 311.39, + 129.18, + 286.32, + 139.79, + 274.75, + 139.79, + 264.15, + 138.82, + 262.22, + 144.61, + 261.26, + 147.5, + 253.54, + 147.5, + 247.76, + 150.39, + 249.69, + 159.07, + 256.44, + 161, + 262.22, + 161, + 268, + 161, + 276.68, + 161.96, + 284.39, + 168.71, + 293.07, + 174.49, + 301.75, + 174.49, + 308.49, + 169.67, + 308.49, + 188.95, + 311.39, + 194.74, + 312.35, + 208.23, + 307.53, + 221.73, + 297.89, + 229.44, + 281.5, + 250.65, + 269.93, + 262.22, + 278.61, + 320.06, + 281.5, + 331.63, + 276.68, + 338.38, + 270.9, + 349.95, + 262.22, + 356.7, + 253.54, + 359.59, + 253.54, + 365.37, + 274.75, + 365.37, + 291.14, + 365.37, + 306.57, + 359.59, + 303.67, + 352.84, + 297.89, + 340.31, + 293.07, + 318.13, + 295, + 294.03, + 293.07, + 278.61, + 294.03, + 270.9, + 305.6, + 259.33, + 313.31, + 299.82, + 319.1, + 309.46, + 341.27, + 317.17, + 384.65, + 330.67, + 387.55, + 335.49, + 383.69, + 341.27, + 397.19, + 350.91, + 398.15, + 363.44, + 398.15, + 375.01, + 405.86, + 374.05, + 409.72, + 357.66, + 411.65, + 342.24, + 416.47, + 328.74, + 417.43, + 321.03, + 410.68, + 319.1, + 401.04, + 318.13, + 392.37, + 318.13, + 382.73, + 314.28, + 348.98, + 300.78, + 339.34, + 293.07, + 334.52, + 285.36, + 340.31, + 259.33, + 340.31, + 246.8, + 340.31, + 242.94, + 350.91, + 228.48, + 358.62, + 214.98, + 355.22, + 204.32, + 357.05, + 196.11, + 361.61, + 188.82, + 361.61, + 181.97, + 365.26, + 165.63, + 367.54, + 139.18, + 366.17, + 123.68, + 361.15, + 112.73, + 353.86, + 107.72, + 351.58, + 105.89, + 344.74, + 105.89, + 340.18, + 109.08 + ] + ], + "num_keypoints": 15, + "area": 17123.92955, + "iscrowd": 0, + "keypoints": [ + 297, + 111, + 2, + 299, + 106, + 2, + 0, + 0, + 0, + 314, + 108, + 2, + 0, + 0, + 0, + 329, + 141, + 2, + 346, + 125, + 2, + 295, + 164, + 2, + 323, + 130, + 2, + 266, + 155, + 2, + 279, + 143, + 2, + 329, + 225, + 2, + 331, + 221, + 2, + 327, + 298, + 2, + 283, + 269, + 2, + 398, + 327, + 2, + 288, + 349, + 2 + ], + "image_id": 196141, + "bbox": [ + 247.76, + 74.23, + 169.67, + 300.78 + ], + "category_id": 1, + "id": 460541 + }, + { + "segmentation": [ + [ + 578.76, + 112.4, + 589.39, + 100.81, + 589.39, + 99.84, + 596.16, + 116.27, + 603.89, + 122.07, + 603.89, + 138.49, + 598.09, + 159.75, + 597.12, + 181, + 594.22, + 191.63, + 589.39, + 212.89, + 583.59, + 208.06, + 583.59, + 206.13, + 582.63, + 200.33, + 582.63, + 193.57, + 582.63, + 182.94, + 575.86, + 181, + 567.17, + 197.43, + 571.03, + 203.23, + 567.17, + 207.09, + 555.57, + 208.06, + 562.34, + 200.33, + 565.24, + 190.67, + 565.24, + 173.27, + 566.2, + 163.61, + 568.14, + 156.85, + 570.07, + 148.15, + 566.2, + 143.32, + 565.24, + 133.66, + 575.86, + 118.2 + ] + ], + "num_keypoints": 15, + "area": 2789.0208, + "iscrowd": 0, + "keypoints": [ + 589, + 113, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 595, + 112, + 1, + 584, + 110, + 2, + 598, + 123, + 2, + 579, + 119, + 2, + 594, + 141, + 2, + 570, + 137, + 2, + 576, + 135, + 2, + 585, + 139, + 2, + 590, + 157, + 2, + 574, + 156, + 2, + 589, + 192, + 2, + 565, + 189, + 1, + 587, + 222, + 1, + 557, + 219, + 1 + ], + "image_id": 196141, + "bbox": [ + 555.57, + 99.84, + 48.32, + 113.05 + ], + "category_id": 1, + "id": 488308 + }, + { + "segmentation": [ + [ + 446.96, + 73.13, + 445.81, + 77.71, + 443.33, + 78.29, + 441.61, + 81.72, + 441.23, + 84.58, + 440.85, + 90.5, + 442.19, + 94.32, + 443.52, + 97.18, + 443.52, + 102.33, + 442.57, + 105.58, + 446.58, + 105.19, + 447.15, + 99.85, + 447.53, + 94.89, + 446, + 93.55, + 446.38, + 92.03, + 453.64, + 92.41, + 454.02, + 94.51, + 457.64, + 94.51, + 455.74, + 88.4, + 455.35, + 82.29, + 453.64, + 78.48, + 451.92, + 77.71, + 452.87, + 74.47, + 450.58, + 73.13 + ] + ], + "num_keypoints": 0, + "area": 285.7906, + "iscrowd": 0, + "keypoints": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "image_id": 196141, + "bbox": [ + 440.85, + 73.13, + 16.79, + 32.45 + ], + "category_id": 1, + "id": 508900 + }, + { + "segmentation": [ + [ + 497.15, + 413.95, + 531.55, + 417.68, + 548.74, + 411.7, + 551.74, + 403.48, + 546.5, + 394.5, + 543.51, + 386.28, + 571.93, + 390.76, + 574.92, + 391.51, + 579.4, + 409.46, + 605.58, + 409.46, + 615.3, + 408.71, + 607.07, + 389.27, + 598.1, + 381.79, + 607.82, + 366.83, + 607.82, + 352.63, + 610.06, + 338.42, + 619.04, + 345.15, + 631, + 344.4, + 630.25, + 336.92, + 626.51, + 318.98, + 616.05, + 286.07, + 598.85, + 263.64, + 585.39, + 257.66, + 593.61, + 244.2, + 601.09, + 235.97, + 596.6, + 219.52, + 587.63, + 211.29, + 577.91, + 208.3, + 563.7, + 206.81, + 556.22, + 214.29, + 548, + 217.28, + 539.77, + 229.99, + 539.77, + 241.95, + 539.02, + 247.19, + 523.32, + 247.19, + 503.88, + 254.67, + 485.93, + 254.67, + 479.95, + 248.68, + 473.22, + 241.21, + 485.93, + 227, + 477.7, + 215.78, + 457.51, + 215.78, + 453.77, + 235.22, + 463.5, + 246.44, + 465.74, + 261.4, + 490.42, + 274.11, + 501.63, + 275.6, + 504.62, + 286.07, + 519.58, + 286.07, + 522.57, + 292.06, + 512.85, + 310, + 515.09, + 330.94, + 530.05, + 343.65, + 505.37, + 341.41, + 479.95, + 339.91, + 465.74, + 346.64, + 463.5, + 358.61, + 473.97, + 381.04, + 485.18, + 390.02, + 501.63, + 398.99, + 504.62, + 404.22, + 491.16, + 412.45, + 495.65, + 417.68 + ] + ], + "num_keypoints": 12, + "area": 21608.94075, + "iscrowd": 0, + "keypoints": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 552, + 234, + 2, + 0, + 0, + 0, + 531, + 262, + 2, + 600, + 283, + 2, + 480, + 260, + 2, + 622, + 336, + 2, + 466, + 242, + 2, + 0, + 0, + 0, + 546, + 365, + 2, + 592, + 371, + 2, + 470, + 351, + 2, + 551, + 330, + 2, + 519, + 394, + 2, + 589, + 391, + 2 + ], + "image_id": 196141, + "bbox": [ + 453.77, + 206.81, + 177.23, + 210.87 + ], + "category_id": 1, + "id": 1717641 + }, + { + "segmentation": [ + [ + 58.93, + 163.67, + 47.18, + 161.59, + 36.12, + 93.86, + 41.65, + 82.8, + 40.27, + 69.66, + 50.64, + 67.59, + 55.48, + 73.81, + 63.08, + 92.47, + 66.53, + 99.38, + 65.15, + 109.06, + 61, + 127.03, + 59.62, + 162.97 + ] + ], + "num_keypoints": 17, + "area": 1870.14015, + "iscrowd": 0, + "keypoints": [ + 48, + 79, + 2, + 50, + 77, + 2, + 46, + 77, + 2, + 54, + 78, + 2, + 45, + 78, + 2, + 57, + 90, + 2, + 42, + 90, + 2, + 63, + 103, + 2, + 42, + 105, + 2, + 56, + 113, + 2, + 49, + 112, + 2, + 55, + 117, + 2, + 44, + 117, + 2, + 55, + 140, + 2, + 47, + 140, + 2, + 56, + 160, + 2, + 49, + 159, + 2 + ], + "image_id": 196141, + "bbox": [ + 36.12, + 67.59, + 30.41, + 96.08 + ], + "category_id": 1, + "id": 1724673 + }, + { + "segmentation": [ + [ + 139.41, + 321.58, + 144.78, + 326.56, + 196.92, + 314.68, + 196.16, + 309.31, + 207.28, + 292.05, + 213.03, + 284, + 228.75, + 270.2, + 233.35, + 261.38, + 244.47, + 252.56, + 254.44, + 237.61, + 267.86, + 215.37, + 272.08, + 212.68, + 285.5, + 232.62, + 294.7, + 250.64, + 295.08, + 264.06, + 290.87, + 277.87, + 290.87, + 286.3, + 289.71, + 298.19, + 281.66, + 318.89, + 282.05, + 334.23, + 295.08, + 340.37, + 315.02, + 343.82, + 314.25, + 336.53, + 310.42, + 330.4, + 301.98, + 322.34, + 304.29, + 310.84, + 304.67, + 302.79, + 306.2, + 292.05, + 311.19, + 275.56, + 313.87, + 251.79, + 311.19, + 234.54, + 312.72, + 224.57, + 310.42, + 212.3, + 307.74, + 201.56, + 306.2, + 193.51, + 306.59, + 183.16, + 310.04, + 177.41, + 314.64, + 173.19, + 316.94, + 171.65, + 328.06, + 163.99, + 337.64, + 157.85, + 343.4, + 159.77, + 346.46, + 166.67, + 346.85, + 170.5, + 346.46, + 179.71, + 346.85, + 188.53, + 346.85, + 191.98, + 344.55, + 198.11, + 342.25, + 203.48, + 338.41, + 208.46, + 335.34, + 212.68, + 335.34, + 217.67, + 343.01, + 222.65, + 354.9, + 210.76, + 359.12, + 196.19, + 361.8, + 173.19, + 361.42, + 161.69, + 356.43, + 150.18, + 344.93, + 135.61, + 343.01, + 132.93, + 345.31, + 126.41, + 345.7, + 124.88, + 343.4, + 115.29, + 340.33, + 104.17, + 337.26, + 102.25, + 330.36, + 103.4, + 326.14, + 106.09, + 320.01, + 111.07, + 314.64, + 119.89, + 310.42, + 121.04, + 292.02, + 121.81, + 279.75, + 127.94, + 244.09, + 138.68, + 240.25, + 142.51, + 238.72, + 154.4, + 239.1, + 163.6, + 239.87, + 173.96, + 241.79, + 181.24, + 248.3, + 192.36, + 240.25, + 206.55, + 236.42, + 219.2, + 229.9, + 236.45, + 225.3, + 247.57, + 218.4, + 254.48, + 208.81, + 265.6, + 202.29, + 278.25, + 195.39, + 285.92, + 188.49, + 292.05, + 183.5, + 295.89, + 176.6, + 302.41, + 172, + 308.54, + 167.78, + 313.14, + 146.31, + 318.89 + ] + ], + "num_keypoints": 16, + "area": 14250.29385, + "iscrowd": 0, + "keypoints": [ + 334, + 135, + 2, + 340, + 129, + 2, + 331, + 129, + 2, + 0, + 0, + 0, + 319, + 123, + 2, + 340, + 146, + 2, + 292, + 133, + 2, + 353, + 164, + 2, + 246, + 144, + 2, + 354, + 197, + 2, + 250, + 185, + 2, + 293, + 197, + 2, + 265, + 187, + 2, + 305, + 252, + 2, + 231, + 254, + 2, + 293, + 321, + 2, + 193, + 297, + 2 + ], + "image_id": 197388, + "bbox": [ + 139.41, + 102.25, + 222.39, + 241.57 + ], + "category_id": 1, + "id": 437295 + }, + { + "segmentation": [ + [ + 287.17, + 121.42, + 294.22, + 106.44, + 302.15, + 116.13, + 303.03, + 121.42 + ], + [ + 297.74, + 99.39, + 310.08, + 76.49, + 326.81, + 76.49, + 329.46, + 67.68, + 337.38, + 61.52, + 346.19, + 62.4, + 353.24, + 65.92, + 353.24, + 76.49, + 355.88, + 84.42, + 359.41, + 87.94, + 362.05, + 96.75, + 354.12, + 139.04, + 349.72, + 142.56, + 345.31, + 139.92, + 349.72, + 117.89, + 348.84, + 108.2, + 345.31, + 113.49, + 336.5, + 101.16, + 325.93, + 110.85, + 311.84, + 123.18 + ], + [ + 324.17, + 176.91, + 332.1, + 191.89, + 328.58, + 198.94, + 327.69, + 205.98, + 333.86, + 213.03, + 337.38, + 227.13, + 332.98, + 227.13, + 319.77, + 219.2, + 313.6, + 211.27 + ], + [ + 332.98, + 165.46, + 341.79, + 161.06, + 336.5, + 174.27, + 333.86, + 186.6, + 326.81, + 176.03 + ] + ], + "num_keypoints": 16, + "area": 3404.869, + "iscrowd": 0, + "keypoints": [ + 345, + 92, + 2, + 350, + 87, + 2, + 341, + 87, + 2, + 0, + 0, + 0, + 330, + 83, + 2, + 357, + 94, + 2, + 316, + 92, + 2, + 357, + 104, + 2, + 291, + 123, + 1, + 351, + 133, + 2, + 281, + 136, + 1, + 326, + 131, + 1, + 305, + 128, + 1, + 336, + 152, + 1, + 303, + 171, + 1, + 318, + 206, + 2, + 294, + 211, + 1 + ], + "image_id": 197388, + "bbox": [ + 287.17, + 61.52, + 74.88, + 165.61 + ], + "category_id": 1, + "id": 467657 + }, + { + "segmentation": [ + [ + 547.95, + 201.57, + 546.73, + 190.62, + 547.95, + 181.49, + 547.95, + 169.31, + 547.95, + 156.53, + 546.73, + 144.36, + 544.3, + 139.49, + 540.04, + 132.19, + 540.04, + 121.84, + 542.47, + 107.24, + 544.3, + 99.33, + 548.56, + 88.98, + 561.95, + 78.03, + 572.29, + 71.33, + 572.29, + 71.33, + 572.29, + 65.25, + 574.12, + 51.86, + 583.86, + 48.81, + 592.99, + 48.81, + 597.86, + 57.33, + 599.07, + 64.64, + 608.2, + 76.81, + 614.9, + 82.89, + 620.98, + 89.59, + 628.89, + 93.24, + 636.81, + 101.76, + 640, + 109.67, + 640, + 115.76, + 640, + 127.93, + 620.37, + 111.5, + 619.16, + 111.5, + 618.55, + 112.11, + 608.2, + 105.41, + 600.9, + 119.41, + 592.99, + 131.58, + 596.03, + 148.01, + 605.16, + 162.01, + 612.46, + 190.01, + 614.9, + 204.61, + 606.98, + 216.78, + 603.94, + 226.52, + 606.38, + 239.91, + 605.16, + 256.95, + 604.55, + 264.26, + 602.12, + 271.56, + 586.29, + 272.17, + 584.47, + 255.13, + 588.73, + 237.48, + 592.99, + 221.65, + 596.64, + 207.05, + 596.64, + 197.31, + 594.2, + 186.96, + 584.47, + 172.36, + 577.77, + 166.27, + 570.47, + 170.53, + 558.91, + 179.66, + 555.86, + 192.44, + 548.56, + 198.53, + 547.95, + 198.53 + ] + ], + "num_keypoints": 15, + "area": 8913.98475, + "iscrowd": 0, + "keypoints": [ + 591, + 78, + 2, + 594, + 74, + 2, + 586, + 74, + 2, + 0, + 0, + 0, + 573, + 70, + 2, + 598, + 86, + 2, + 566, + 93, + 2, + 626, + 105, + 2, + 546, + 126, + 2, + 0, + 0, + 0, + 561, + 150, + 2, + 582, + 150, + 2, + 557, + 154, + 2, + 606, + 194, + 2, + 558, + 209, + 1, + 591, + 252, + 2, + 539, + 262, + 1 + ], + "image_id": 197388, + "bbox": [ + 540.04, + 48.81, + 99.96, + 223.36 + ], + "category_id": 1, + "id": 531914 + }, + { + "segmentation": [ + [ + 561.51, + 385.38, + 572.11, + 352.71, + 570.34, + 317.4, + 559.75, + 282.08, + 552.68, + 267.07, + 565.93, + 236.17, + 583.59, + 236.17, + 602.13, + 260.01, + 614.49, + 286.5, + 628.61, + 302.39, + 639.21, + 281.2, + 614.49, + 251.18, + 588, + 218.51, + 595.95, + 202.62, + 594.18, + 185.85, + 580.05, + 170.84, + 562.4, + 179.67, + 557.98, + 198.21, + 554.45, + 202.62, + 532.38, + 199.97, + 525.32, + 202.62, + 511.19, + 229.11, + 493.53, + 256.48, + 484.7, + 276.78, + 451.15, + 323.58, + 423.78, + 338.59, + 388.47, + 373.9, + 372.58, + 387.14, + 396.41, + 388.03, + 418.49, + 367.72, + 450.27, + 345.65, + 501.48, + 306.8, + 520.02, + 301.5, + 552.68, + 340.35, + 543.86, + 369.49 + ] + ], + "num_keypoints": 16, + "area": 14267.20475, + "iscrowd": 0, + "keypoints": [ + 580, + 211, + 2, + 586, + 206, + 2, + 574, + 204, + 2, + 0, + 0, + 0, + 562, + 198, + 2, + 584, + 220, + 2, + 529, + 215, + 2, + 599, + 242, + 2, + 512, + 260, + 2, + 619, + 274, + 2, + 538, + 285, + 2, + 537, + 288, + 2, + 506, + 277, + 2, + 562, + 332, + 2, + 452, + 332, + 2, + 550, + 387, + 1, + 402, + 371, + 2 + ], + "image_id": 197388, + "bbox": [ + 372.58, + 170.84, + 266.63, + 217.19 + ], + "category_id": 1, + "id": 533949 + }, + { + "segmentation": [ + [ + 2.03, + 75.18, + 10.85, + 70.58, + 16.99, + 65.59, + 17.75, + 55.24, + 20.05, + 50.25, + 29.64, + 43.74, + 37.31, + 47.57, + 41.52, + 53.7, + 43.83, + 64.82, + 53.03, + 70.19, + 61.85, + 77.09, + 72.58, + 87.06, + 74.88, + 79.01, + 78.72, + 73.64, + 86.39, + 77.86, + 90.6, + 90.13, + 86, + 93.2, + 82.17, + 102.4, + 75.27, + 106.24, + 68.75, + 104.7, + 50.34, + 90.9, + 43.06, + 112.37, + 40.76, + 123.11, + 42.29, + 130.78, + 48.04, + 161.83, + 52.26, + 190.59, + 50.73, + 210.15, + 44.21, + 245.04, + 50.34, + 256.16, + 53.03, + 261.53, + 47.28, + 263.83, + 40.37, + 263.83, + 31.56, + 260.76, + 28.1, + 256.16, + 26.95, + 244.65, + 29.25, + 233.54, + 32.71, + 223.95, + 33.09, + 213.98, + 32.32, + 206.31, + 32.71, + 194.81, + 33.09, + 185.61, + 24.65, + 177.17, + 16.99, + 161.45, + 13.53, + 176.02, + 10.85, + 206.31, + 1.65, + 231.62, + 1.65, + 235.84, + 0.5, + 146.88, + 0.88, + 122.34, + 1.65, + 75.56 + ] + ], + "num_keypoints": 13, + "area": 8260.75085, + "iscrowd": 0, + "keypoints": [ + 36, + 79, + 2, + 40, + 74, + 2, + 31, + 75, + 2, + 0, + 0, + 0, + 19, + 69, + 2, + 45, + 77, + 2, + 2, + 89, + 2, + 74, + 99, + 2, + 0, + 0, + 0, + 78, + 92, + 2, + 0, + 0, + 0, + 33, + 149, + 2, + 7, + 153, + 2, + 44, + 196, + 2, + 2, + 205, + 2, + 35, + 245, + 2, + 0, + 0, + 0 + ], + "image_id": 197388, + "bbox": [ + 0.5, + 43.74, + 90.1, + 220.09 + ], + "category_id": 1, + "id": 543117 + } + ] +} diff --git a/tests/test_metrics/data/crowdpose_sample.json b/tests/test_metrics/data/crowdpose_sample.json new file mode 100644 index 00000000..9e9d9b7a --- /dev/null +++ b/tests/test_metrics/data/crowdpose_sample.json @@ -0,0 +1,378 @@ +{ + "categories": [ + { + "supercategory": "person", + "id": 1, + "name": "person", + "keypoints": [ + "left_shoulder", + "right_shoulder", + "left_elbow", + "right_elbow", + "left_wrist", + "right_wrist", + "left_hip", + "right_hip", + "left_knee", + "right_knee", + "left_ankle", + "right_ankle", + "head", + "neck" + ], + "skeleton": [ + [ + 16, + 14 + ], + [ + 14, + 12 + ], + [ + 17, + 15 + ], + [ + 15, + 13 + ], + [ + 12, + 13 + ], + [ + 6, + 12 + ], + [ + 7, + 13 + ], + [ + 6, + 7 + ], + [ + 6, + 8 + ], + [ + 7, + 9 + ], + [ + 8, + 10 + ], + [ + 9, + 11 + ] + ] + } + ], + "images": [ + { + "file_name": "106848.jpg", + "id": 106848, + "height": 425, + "width": 640, + "crowdIndex": 0.33 + }, + { + "file_name": "103319.jpg", + "id": 103319, + "height": 480, + "width": 640, + "crowdIndex": 0.39 + } + ], + "annotations": [ + { + "num_keypoints": 5, + "iscrowd": 0, + "keypoints": [ + 0, + 0, + 0, + 208, + 108, + 2, + 0, + 0, + 0, + 278, + 158, + 2, + 262, + 206, + 2, + 348, + 98, + 2, + 0, + 0, + 0, + 173, + 299, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 256, + 27, + 1, + 220, + 89, + 1 + ], + "image_id": 106848, + "bbox": [ + 106.01, + 13.43, + 273.15, + 352.42 + ], + "category_id": 1, + "id": 123803 + }, + { + "num_keypoints": 0, + "iscrowd": 0, + "keypoints": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "image_id": 106848, + "bbox": [ + 108.5, + 96.78, + 35.46, + 30.23 + ], + "category_id": 1, + "id": 131039 + }, + { + "num_keypoints": 10, + "iscrowd": 0, + "keypoints": [ + 482, + 129, + 2, + 364, + 126, + 2, + 513, + 213, + 2, + 339, + 163, + 2, + 431, + 210, + 2, + 276, + 163, + 1, + 440, + 308, + 2, + 371, + 304, + 1, + 432, + 419, + 1, + 366, + 419, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 407, + 29, + 1, + 420, + 110, + 1 + ], + "image_id": 106848, + "bbox": [ + 281.51, + 21.92, + 244.5, + 349.72 + ], + "category_id": 1, + "id": 147481 + }, + { + "num_keypoints": 12, + "iscrowd": 0, + "keypoints": [ + 388, + 205, + 2, + 344, + 211, + 2, + 407, + 249, + 2, + 337, + 256, + 2, + 393, + 278, + 2, + 336, + 290, + 2, + 390, + 293, + 2, + 354, + 294, + 2, + 387, + 354, + 2, + 351, + 357, + 2, + 380, + 390, + 2, + 359, + 408, + 1, + 351, + 163, + 1, + 364, + 198, + 1 + ], + "image_id": 103319, + "bbox": [ + 316.76, + 157.3, + 100.54, + 247.56 + ], + "category_id": 1, + "id": 127068 + }, + { + "num_keypoints": 12, + "iscrowd": 0, + "keypoints": [ + 350, + 145, + 2, + 300, + 145, + 2, + 352, + 190, + 1, + 299, + 180, + 2, + 322, + 163, + 2, + 291, + 217, + 2, + 346, + 232, + 1, + 314, + 232, + 2, + 346, + 283, + 1, + 310, + 284, + 2, + 345, + 346, + 1, + 305, + 344, + 2, + 312, + 106, + 1, + 323, + 137, + 1 + ], + "image_id": 103319, + "bbox": [ + 279.68, + 102.17, + 81.13, + 255.49 + ], + "category_id": 1, + "id": 129014 + } + ] +} diff --git a/tests/test_metrics/test_coco_pose_metric.py b/tests/test_metrics/test_coco_pose_metric.py new file mode 100644 index 00000000..69acf887 --- /dev/null +++ b/tests/test_metrics/test_coco_pose_metric.py @@ -0,0 +1,337 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import numpy as np +import os.path as osp +import pytest +import tempfile +from json import dump +from unittest import TestCase + +from mmeval.fileio import load +from mmeval.metrics import COCOPoseMetric + +try: + from xtcocotools.coco import COCO + HAS_XTCOCOTOOLS = True +except ImportError: + HAS_XTCOCOTOOLS = False + + +@pytest.mark.skipif( + HAS_XTCOCOTOOLS is False, reason='xtcocotools is not available!') +class TestCOCOPoseMetric(TestCase): + + def setUp(self): + """Setup some variables which are used in every test method. + + TestCase calls functions in this order: setUp() -> testMethod() -> + tearDown() -> cleanUp() + """ + self.tmp_dir = tempfile.TemporaryDirectory() + self.ann_file = 'tests/test_metrics/data/coco_pose_sample.json' + self.coco = COCO(self.ann_file) + coco_sigmas = np.array([ + 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, + 0.062, 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 + ]).astype(np.float32) + + self.coco_dataset_meta = { + 'CLASSES': self.coco.loadCats(self.coco.getCatIds()), + 'num_keypoints': 17, + 'sigmas': coco_sigmas, + } + + self.predictions, self.groundtruths = self._convert_ann_to_pred_and_gt( + self.ann_file) + assert len(self.predictions) == len(self.groundtruths) == 14 + self.target = { + 'AP': 1.0, + 'AP .5': 1.0, + 'AP .75': 1.0, + 'AP (M)': 1.0, + 'AP (L)': 1.0, + 'AR': 1.0, + 'AR .5': 1.0, + 'AR .75': 1.0, + 'AR (M)': 1.0, + 'AR (L)': 1.0, + } + + self.ann_file_crowdpose = 'tests/test_metrics/data/' \ + 'crowdpose_sample.json' + self.coco_crowdpose = COCO(self.ann_file_crowdpose) + sigmas_crowdpose = np.array([ + 0.079, 0.079, 0.072, 0.072, 0.062, 0.062, 0.107, 0.107, 0.087, + 0.087, 0.089, 0.089, 0.079, 0.079 + ]).astype(np.float32) + self.dataset_meta_crowdpose = { + 'CLASSES': + self.coco_crowdpose.loadCats(self.coco_crowdpose.getCatIds()), + 'num_keypoints': + 14, + 'sigmas': + sigmas_crowdpose, + } + + self.preds_crowdpose, self.gts_crowdpose = \ + self._convert_ann_to_pred_and_gt(self.ann_file_crowdpose) + assert len(self.preds_crowdpose) == len(self.gts_crowdpose) == 5 + self.target_crowdpose = { + 'AP': 1.0, + 'AP .5': 1.0, + 'AP .75': 1.0, + 'AR': 1.0, + 'AR .5': 1.0, + 'AR .75': 1.0, + 'AP(E)': -1.0, + 'AP(M)': 1.0, + 'AP(H)': -1.0, + } + + self.ann_file_ap10k = 'tests/test_metrics/data/ap10k_sample.json' + self.coco_ap10k = COCO(self.ann_file_ap10k) + sigmas_ap10k = np.array([ + 0.025, 0.025, 0.026, 0.035, 0.035, 0.079, 0.072, 0.062, 0.079, + 0.072, 0.062, 0.107, 0.087, 0.089, 0.107, 0.087, 0.089 + ]).astype(np.float32) + self.dataset_meta_ap10k = { + 'CLASSES': self.coco_ap10k.loadCats(self.coco_ap10k.getCatIds()), + 'num_keypoints': 17, + 'sigmas': sigmas_ap10k, + } + + self.preds_ap10k, self.gts_ap10k = \ + self._convert_ann_to_pred_and_gt(self.ann_file_ap10k) + assert len(self.preds_ap10k) == len(self.gts_ap10k) == 2 + self.target_ap10k = { + 'AP': 1.0, + 'AP .5': 1.0, + 'AP .75': 1.0, + 'AP (M)': -1.0, + 'AP (L)': 1.0, + 'AR': 1.0, + 'AR .5': 1.0, + 'AR .75': 1.0, + 'AR (M)': -1.0, + 'AR (L)': 1.0, + } + + def _convert_ann_to_pred_and_gt(self, ann_file): + """Convert annotations to topdown-style batch data.""" + predictions = [] + groundtruths = [] + + db = load(ann_file) + imgid2info = dict() + + for img in db['images']: + imgid2info[img['id']] = img + + for ann in db['annotations']: + bboxes = np.array(ann['bbox'], dtype=np.float32).reshape(-1, 4) + keypoints = np.array(ann['keypoints']).reshape((1, -1, 3)) + + prediction = { + 'id': ann['id'], + 'img_id': ann['image_id'], + 'category_id': ann.get('category_id', 1), + 'bboxes': bboxes, + 'keypoints': keypoints[..., :2], + 'keypoint_scores': keypoints[..., -1], + 'bbox_scores': np.ones((1, ), dtype=np.float32), + } + + groundtruth = { + 'img_id': ann['image_id'], + # dummy image_shape for testing + 'width': 640, + 'height': 480, + 'num_keypoints': ann['num_keypoints'], + 'raw_ann_info': [copy.deepcopy(ann)], + } + if 'area' in ann: + groundtruth['area'] = ann['area'] + + # add crowdIndex to gt if it is present in the image_info + if 'crowdIndex' in imgid2info[ann['image_id']]: + groundtruth['crowd_index'] = imgid2info[ + ann['image_id']]['crowdIndex'] + + predictions.append(prediction) + groundtruths.append(groundtruth) + + return predictions, groundtruths + + def tearDown(self): + self.tmp_dir.cleanup() + + def test_init(self): + """test metric init method.""" + # test score_mode option + with self.assertRaisesRegex(ValueError, + '`score_mode` should be one of'): + _ = COCOPoseMetric(ann_file=self.ann_file, score_mode='keypoint') + + # test nms_mode option + with self.assertRaisesRegex(ValueError, '`nms_mode` should be one of'): + _ = COCOPoseMetric(ann_file=self.ann_file, nms_mode='invalid') + + # test format_only option + with self.assertRaisesRegex( + AssertionError, + '`outfile_prefix` can not be None when `format_only` is True'): + _ = COCOPoseMetric( + ann_file=self.ann_file, format_only=True, outfile_prefix=None) + + def test_other_methods(self): + """test other useful methods.""" + # test `_sort_and_unique_bboxes` method + coco_pose_metric = COCOPoseMetric( + ann_file=self.ann_file, + score_mode='bbox', + nms_mode='none', + dataset_meta=self.coco_dataset_meta) + # an extra sample + predictions = self.predictions + [self.predictions[0]] + groundtruths = self.groundtruths + [self.groundtruths[0]] + + eval_results = coco_pose_metric(predictions, groundtruths) + self.assertDictEqual(eval_results, self.target) + + def test_format_only(self): + """test `format_only` option.""" + coco_pose_metric = COCOPoseMetric( + ann_file=self.ann_file, + format_only=True, + outfile_prefix=f'{self.tmp_dir.name}/test', + score_mode='bbox_keypoint', + nms_mode='oks_nms', + dataset_meta=self.coco_dataset_meta) + # process one sample + eval_results = coco_pose_metric(self.predictions, self.groundtruths) + self.assertDictEqual(eval_results, {}) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test.keypoints.json'))) + + # test when gt annotations are absent + db_ = load(self.ann_file) + del db_['annotations'] + tmp_ann_file = osp.join(self.tmp_dir.name, 'temp_ann.json') + with open(tmp_ann_file, 'w') as f: + dump(db_, f, sort_keys=True, indent=4) + with self.assertRaisesRegex( + AssertionError, + 'Ground truth annotations are required for evaluation'): + _ = COCOPoseMetric(ann_file=tmp_ann_file, format_only=False) + + def test_evaluate(self): + """test COCO metric evaluation.""" + # case 1: score_mode='bbox', nms_mode='none' + coco_pose_metric = COCOPoseMetric( + ann_file=self.ann_file, + outfile_prefix=f'{self.tmp_dir.name}/test1', + score_mode='bbox', + nms_mode='none', + dataset_meta=self.coco_dataset_meta) + + eval_results = coco_pose_metric(self.predictions, self.groundtruths) + self.assertDictEqual(eval_results, self.target) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test1.keypoints.json'))) + + # case 2: score_mode='bbox_keypoint', nms_mode='oks_nms' + coco_pose_metric = COCOPoseMetric( + ann_file=self.ann_file, + outfile_prefix=f'{self.tmp_dir.name}/test2', + score_mode='bbox_keypoint', + nms_mode='oks_nms', + dataset_meta=self.coco_dataset_meta) + coco_pose_metric.dataset_meta = self.coco_dataset_meta + + eval_results = coco_pose_metric(self.predictions, self.groundtruths) + self.assertDictEqual(eval_results, self.target) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test2.keypoints.json'))) + + # case 3: score_mode='bbox_rle', nms_mode='soft_oks_nms' + coco_pose_metric = COCOPoseMetric( + ann_file=self.ann_file, + outfile_prefix=f'{self.tmp_dir.name}/test3', + score_mode='bbox_rle', + nms_mode='soft_oks_nms', + dataset_meta=self.coco_dataset_meta) + + eval_results = coco_pose_metric(self.predictions, self.groundtruths) + self.assertDictEqual(eval_results, self.target) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test3.keypoints.json'))) + + # case 4: test without providing ann_file + coco_pose_metric = COCOPoseMetric( + outfile_prefix=f'{self.tmp_dir.name}/test4', + dataset_meta=self.coco_dataset_meta) + eval_results = coco_pose_metric(self.predictions, self.groundtruths) + + self.assertDictEqual(eval_results, self.target) + # test whether convert the annotation to COCO format + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test4.gt.json'))) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test4.keypoints.json'))) + + # case 5: test Crowdpose dataset + metric_crowdpose = COCOPoseMetric( + ann_file=self.ann_file_crowdpose, + outfile_prefix=f'{self.tmp_dir.name}/test5', + use_area=False, + iou_type='keypoints_crowd', + dataset_meta=self.dataset_meta_crowdpose) + eval_results = metric_crowdpose(self.preds_crowdpose, + self.gts_crowdpose) + self.assertDictEqual(eval_results, self.target_crowdpose) + # test whether convert the annotation to COCO format + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test5.keypoints.json'))) + + # case 5: test Crowdpose dataset + without ann_file + metric_crowdpose = COCOPoseMetric( + outfile_prefix=f'{self.tmp_dir.name}/test6', + use_area=False, + iou_type='keypoints_crowd', + dataset_meta=self.dataset_meta_crowdpose) + eval_results = metric_crowdpose(self.preds_crowdpose, + self.gts_crowdpose) + self.assertDictEqual(eval_results, self.target_crowdpose) + # test whether convert the annotation to COCO format + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test6.gt.json'))) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test6.keypoints.json'))) + + # case 7: test AP10k dataset + metric_ap10k = COCOPoseMetric( + ann_file=self.ann_file_ap10k, + outfile_prefix=f'{self.tmp_dir.name}/test7', + use_area=False, + dataset_meta=self.dataset_meta_ap10k) + eval_results = metric_ap10k(self.preds_ap10k, self.gts_ap10k) + for key in self.target_ap10k: + self.assertTrue( + abs(eval_results[key] - self.target_ap10k[key]) < 1e-7) + # test whether convert the annotation to COCO format + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test7.keypoints.json'))) + + # case 8: test AP10k dataset + without ann_file + metric_ap10k = COCOPoseMetric( + outfile_prefix=f'{self.tmp_dir.name}/test8', + dataset_meta=self.dataset_meta_ap10k) + eval_results = metric_ap10k(self.preds_ap10k, self.gts_ap10k) + for key in self.target_ap10k: + self.assertTrue( + abs(eval_results[key] - self.target_ap10k[key]) < 1e-7) + # test whether convert the annotation to COCO format + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test8.gt.json'))) + self.assertTrue( + osp.isfile(osp.join(self.tmp_dir.name, 'test8.keypoints.json')))