Initial snapshot: hand motion pipeline (Dyn-HaMR + dex-retargeting + SPIDER)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 14:13:49 +08:00
commit 7e4ef6f98b
7002 changed files with 1452249 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 UC Regents, Georgios Pavlakos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+130
View File
@@ -0,0 +1,130 @@
# HaMeR: Hand Mesh Recovery
Code repository for the paper:
**Reconstructing Hands in 3D with Transformers**
[Georgios Pavlakos](https://geopavlakos.github.io/), [Dandan Shan](https://ddshan.github.io/), [Ilija Radosavovic](https://people.eecs.berkeley.edu/~ilija/), [Angjoo Kanazawa](https://people.eecs.berkeley.edu/~kanazawa/), [David Fouhey](https://cs.nyu.edu/~fouhey/), [Jitendra Malik](http://people.eecs.berkeley.edu/~malik/)
[![arXiv](https://img.shields.io/badge/arXiv-2312.05251-00ff00.svg)](https://arxiv.org/pdf/2312.05251.pdf) [![Website shields.io](https://img.shields.io/website-up-down-green-red/http/shields.io.svg)](https://geopavlakos.github.io/hamer/) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1rQbQzegFWGVOm1n1d-S6koOWDo7F2ucu?usp=sharing) [![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/geopavlakos/HaMeR)
![teaser](assets/teaser.jpg)
## News
- [2026/02] Check out our [new work](https://gkarv.github.io/hand-texture-module/) using learned texture priors to improve HaMeR.
- [2024/06] HaMeR received the 2nd place award in the Ego-Pose Hands task of the Ego-Exo4D Challenge! Please check the [validation report](https://www.cs.utexas.edu/~pavlakos/hamer/resources/egoexo4d_challenge.pdf).
- [2024/05] We have released the evaluation pipeline!
- [2024/05] We have released the HInt dataset annotations! Please check [here](https://github.com/ddshan/hint).
- [2023/12] Original release!
## Installation
First you need to clone the repo:
```
git clone --recursive https://github.com/geopavlakos/hamer.git
cd hamer
```
We recommend creating a virtual environment for HaMeR. You can use venv:
```bash
python3.10 -m venv .hamer
source .hamer/bin/activate
```
or alternatively conda:
```bash
conda create --name hamer python=3.10
conda activate hamer
```
Then, you can install the rest of the dependencies. This is for CUDA 11.7, but you can adapt accordingly:
```bash
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu117
pip install -e .[all]
pip install -v -e third-party/ViTPose
```
You also need to download the trained models:
```bash
bash fetch_demo_data.sh
```
Besides these files, you also need to download the MANO model. Please visit the [MANO website](https://mano.is.tue.mpg.de) and register to get access to the downloads section. We only require the right hand model. You need to put `MANO_RIGHT.pkl` under the `_DATA/data/mano` folder.
### Docker Compose
If you wish to use HaMeR with Docker, you can use the following command:
```
docker compose -f ./docker/docker-compose.yml up -d
```
After the image is built successfully, enter the container and run the steps as above:
```
docker compose -f ./docker/docker-compose.yml exec hamer-dev /bin/bash
```
Continue with the installation steps:
```bash
bash fetch_demo_data.sh
```
## Demo
```bash
python demo.py \
--img_folder example_data --out_folder demo_out \
--batch_size=48 --side_view --save_mesh --full_frame
```
## HInt Dataset
We have released the annotations for the HInt dataset. Please follow the instructions [here](https://github.com/ddshan/hint)
## Training
First, download the training data to `./hamer_training_data/` by running:
```
bash fetch_training_data.sh
```
Then you can start training using the following command:
```
python train.py exp_name=hamer data=mix_all experiment=hamer_vit_transformer trainer=gpu launcher=local
```
Checkpoints and logs will be saved to `./logs/`.
## Evaluation
Download the [evaluation metadata](https://www.dropbox.com/scl/fi/7ip2vnnu355e2kqbyn1bc/hamer_evaluation_data.tar.gz?rlkey=nb4x10uc8mj2qlfq934t5mdlh) to `./hamer_evaluation_data/`. Additionally, download the FreiHAND, HO-3D, and HInt dataset images and update the corresponding paths in `hamer/configs/datasets_eval.yaml`.
Run evaluation on multiple datasets as follows, results are stored in `results/eval_regression.csv`.
```bash
python eval.py --dataset 'FREIHAND-VAL,HO3D-VAL,NEWDAYS-TEST-ALL,NEWDAYS-TEST-VIS,NEWDAYS-TEST-OCC,EPICK-TEST-ALL,EPICK-TEST-VIS,EPICK-TEST-OCC,EGO4D-TEST-ALL,EGO4D-TEST-VIS,EGO4D-TEST-OCC'
```
Results for HInt are stored in `results/eval_regression.csv`. For [FreiHAND](https://github.com/lmb-freiburg/freihand) and [HO-3D](https://codalab.lisn.upsaclay.fr/competitions/4318) you get as output a `.json` file that can be used for evaluation using their corresponding evaluation processes.
## Acknowledgements
Parts of the code are taken or adapted from the following repos:
- [4DHumans](https://github.com/shubham-goel/4D-Humans)
- [SLAHMR](https://github.com/vye16/slahmr)
- [ProHMR](https://github.com/nkolot/ProHMR)
- [SPIN](https://github.com/nkolot/SPIN)
- [SMPLify-X](https://github.com/vchoutas/smplify-x)
- [HMR](https://github.com/akanazawa/hmr)
- [ViTPose](https://github.com/ViTAE-Transformer/ViTPose)
- [Detectron2](https://github.com/facebookresearch/detectron2)
Additionally, we thank [StabilityAI](https://stability.ai/) for a generous compute grant that enabled this work.
## Open-Source Contributions
- [Wentao Hu](https://vincenthu19.github.io/) integrated the hand parameters predicted by HaMeR into SMPL-X - [Mano2Smpl-X](https://github.com/VincentHu19/Mano2Smpl-X)
## Citing
If you find this code useful for your research, please consider citing the following paper:
```bibtex
@inproceedings{pavlakos2024reconstructing,
title={Reconstructing Hands in 3{D} with Transformers},
author={Pavlakos, Georgios and Shan, Dandan and Radosavovic, Ilija and Kanazawa, Angjoo and Fouhey, David and Malik, Jitendra},
booktitle={CVPR},
year={2024}
}
```
+208
View File
@@ -0,0 +1,208 @@
from pathlib import Path
import torch
import argparse
import os
import cv2
import numpy as np
from hamer.configs import CACHE_DIR_HAMER
from hamer.models import HAMER, download_models, load_hamer, DEFAULT_CHECKPOINT
from hamer.utils import recursive_to
from hamer.datasets.vitdet_dataset import ViTDetDataset, DEFAULT_MEAN, DEFAULT_STD
from hamer.utils.renderer import Renderer, cam_crop_to_full
LIGHT_BLUE=(0.65098039, 0.74117647, 0.85882353)
from vitpose_model import ViTPoseModel
import json
from typing import Dict, Optional
def main():
parser = argparse.ArgumentParser(description='HaMeR demo code')
parser.add_argument('--checkpoint', type=str, default=DEFAULT_CHECKPOINT, help='Path to pretrained model checkpoint')
parser.add_argument('--img_folder', type=str, default='images', help='Folder with input images')
parser.add_argument('--out_folder', type=str, default='out_demo', help='Output folder to save rendered results')
parser.add_argument('--side_view', dest='side_view', action='store_true', default=False, help='If set, render side view also')
parser.add_argument('--full_frame', dest='full_frame', action='store_true', default=True, help='If set, render all people together also')
parser.add_argument('--save_mesh', dest='save_mesh', action='store_true', default=False, help='If set, save meshes to disk also')
parser.add_argument('--batch_size', type=int, default=1, help='Batch size for inference/fitting')
parser.add_argument('--rescale_factor', type=float, default=2.0, help='Factor for padding the bbox')
parser.add_argument('--body_detector', type=str, default='vitdet', choices=['vitdet', 'regnety'], help='Using regnety improves runtime and reduces memory')
parser.add_argument('--file_type', nargs='+', default=['*.jpg', '*.png'], help='List of file extensions to consider')
args = parser.parse_args()
# Download and load checkpoints
download_models(CACHE_DIR_HAMER)
model, model_cfg = load_hamer(args.checkpoint)
# Setup HaMeR model
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
model = model.to(device)
model.eval()
# Load detector
from hamer.utils.utils_detectron2 import DefaultPredictor_Lazy
if args.body_detector == 'vitdet':
from detectron2.config import LazyConfig
import hamer
cfg_path = Path(hamer.__file__).parent/'configs'/'cascade_mask_rcnn_vitdet_h_75ep.py'
detectron2_cfg = LazyConfig.load(str(cfg_path))
detectron2_cfg.train.init_checkpoint = "https://dl.fbaipublicfiles.com/detectron2/ViTDet/COCO/cascade_mask_rcnn_vitdet_h/f328730692/model_final_f05665.pkl"
for i in range(3):
detectron2_cfg.model.roi_heads.box_predictors[i].test_score_thresh = 0.25
detector = DefaultPredictor_Lazy(detectron2_cfg)
elif args.body_detector == 'regnety':
from detectron2 import model_zoo
from detectron2.config import get_cfg
detectron2_cfg = model_zoo.get_config('new_baselines/mask_rcnn_regnety_4gf_dds_FPN_400ep_LSJ.py', trained=True)
detectron2_cfg.model.roi_heads.box_predictor.test_score_thresh = 0.5
detectron2_cfg.model.roi_heads.box_predictor.test_nms_thresh = 0.4
detector = DefaultPredictor_Lazy(detectron2_cfg)
# keypoint detector
cpm = ViTPoseModel(device)
# Setup the renderer
renderer = Renderer(model_cfg, faces=model.mano.faces)
# Make output directory if it does not exist
os.makedirs(args.out_folder, exist_ok=True)
# Get all demo images ends with .jpg or .png
img_paths = [img for end in args.file_type for img in Path(args.img_folder).glob(end)]
# Iterate over all images in folder
for img_path in img_paths:
img_cv2 = cv2.imread(str(img_path))
# Detect humans in image
det_out = detector(img_cv2)
img = img_cv2.copy()[:, :, ::-1]
det_instances = det_out['instances']
valid_idx = (det_instances.pred_classes==0) & (det_instances.scores > 0.5)
pred_bboxes=det_instances.pred_boxes.tensor[valid_idx].cpu().numpy()
pred_scores=det_instances.scores[valid_idx].cpu().numpy()
# Detect human keypoints for each person
vitposes_out = cpm.predict_pose(
img,
[np.concatenate([pred_bboxes, pred_scores[:, None]], axis=1)],
)
bboxes = []
is_right = []
# Use hands based on hand keypoint detections
for vitposes in vitposes_out:
left_hand_keyp = vitposes['keypoints'][-42:-21]
right_hand_keyp = vitposes['keypoints'][-21:]
# Rejecting not confident detections
keyp = left_hand_keyp
valid = keyp[:,2] > 0.5
if sum(valid) > 3:
bbox = [keyp[valid,0].min(), keyp[valid,1].min(), keyp[valid,0].max(), keyp[valid,1].max()]
bboxes.append(bbox)
is_right.append(0)
keyp = right_hand_keyp
valid = keyp[:,2] > 0.5
if sum(valid) > 3:
bbox = [keyp[valid,0].min(), keyp[valid,1].min(), keyp[valid,0].max(), keyp[valid,1].max()]
bboxes.append(bbox)
is_right.append(1)
if len(bboxes) == 0:
continue
boxes = np.stack(bboxes)
right = np.stack(is_right)
# Run reconstruction on all detected hands
dataset = ViTDetDataset(model_cfg, img_cv2, boxes, right, rescale_factor=args.rescale_factor)
dataloader = torch.utils.data.DataLoader(dataset, batch_size=8, shuffle=False, num_workers=0)
all_verts = []
all_cam_t = []
all_right = []
for batch in dataloader:
batch = recursive_to(batch, device)
with torch.no_grad():
out = model(batch)
multiplier = (2*batch['right']-1)
pred_cam = out['pred_cam']
pred_cam[:,1] = multiplier*pred_cam[:,1]
box_center = batch["box_center"].float()
box_size = batch["box_size"].float()
img_size = batch["img_size"].float()
multiplier = (2*batch['right']-1)
scaled_focal_length = model_cfg.EXTRA.FOCAL_LENGTH / model_cfg.MODEL.IMAGE_SIZE * img_size.max()
pred_cam_t_full = cam_crop_to_full(pred_cam, box_center, box_size, img_size, scaled_focal_length).detach().cpu().numpy()
# Render the result
batch_size = batch['img'].shape[0]
for n in range(batch_size):
# Get filename from path img_path
img_fn, _ = os.path.splitext(os.path.basename(img_path))
person_id = int(batch['personid'][n])
white_img = (torch.ones_like(batch['img'][n]).cpu() - DEFAULT_MEAN[:,None,None]/255) / (DEFAULT_STD[:,None,None]/255)
input_patch = batch['img'][n].cpu() * (DEFAULT_STD[:,None,None]/255) + (DEFAULT_MEAN[:,None,None]/255)
input_patch = input_patch.permute(1,2,0).numpy()
regression_img = renderer(out['pred_vertices'][n].detach().cpu().numpy(),
out['pred_cam_t'][n].detach().cpu().numpy(),
batch['img'][n],
mesh_base_color=LIGHT_BLUE,
scene_bg_color=(1, 1, 1),
)
if args.side_view:
side_img = renderer(out['pred_vertices'][n].detach().cpu().numpy(),
out['pred_cam_t'][n].detach().cpu().numpy(),
white_img,
mesh_base_color=LIGHT_BLUE,
scene_bg_color=(1, 1, 1),
side_view=True)
final_img = np.concatenate([input_patch, regression_img, side_img], axis=1)
else:
final_img = np.concatenate([input_patch, regression_img], axis=1)
cv2.imwrite(os.path.join(args.out_folder, f'{img_fn}_{person_id}.png'), 255*final_img[:, :, ::-1])
# Add all verts and cams to list
verts = out['pred_vertices'][n].detach().cpu().numpy()
is_right = batch['right'][n].cpu().numpy()
verts[:,0] = (2*is_right-1)*verts[:,0]
cam_t = pred_cam_t_full[n]
all_verts.append(verts)
all_cam_t.append(cam_t)
all_right.append(is_right)
# Save all meshes to disk
if args.save_mesh:
camera_translation = cam_t.copy()
tmesh = renderer.vertices_to_trimesh(verts, camera_translation, LIGHT_BLUE, is_right=is_right)
tmesh.export(os.path.join(args.out_folder, f'{img_fn}_{person_id}.obj'))
# Render front view
if args.full_frame and len(all_verts) > 0:
misc_args = dict(
mesh_base_color=LIGHT_BLUE,
scene_bg_color=(1, 1, 1),
focal_length=scaled_focal_length,
)
cam_view = renderer.render_rgba_multiple(all_verts, cam_t=all_cam_t, render_res=img_size[n], is_right=all_right, **misc_args)
# Overlay image
input_img = img_cv2.astype(np.float32)[:,:,::-1]/255.0
input_img = np.concatenate([input_img, np.ones_like(input_img[:,:,:1])], axis=2) # Add alpha channel
input_img_overlay = input_img[:,:,:3] * (1-cam_view[:,:,3:]) + cam_view[:,:,:3] * cam_view[:,:,3:]
cv2.imwrite(os.path.join(args.out_folder, f'{img_fn}_all.jpg'), 255*input_img_overlay[:, :, ::-1])
if __name__ == '__main__':
main()
+16
View File
@@ -0,0 +1,16 @@
services:
hamer-dev:
build:
context: ../
dockerfile: ./docker/hamer-dev.Dockerfile
volumes:
- ../:/app
tty: true
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1 # alternatively, use `count: all` for all GPUs
capabilities: [gpu]
+166
View File
@@ -0,0 +1,166 @@
import argparse
import os
import json
from pathlib import Path
import traceback
from typing import List, Optional
import pandas as pd
import torch
from filelock import FileLock
from hamer.configs import dataset_eval_config
from hamer.datasets import create_dataset
from hamer.utils import Evaluator, recursive_to
from tqdm import tqdm
from hamer.configs import CACHE_DIR_HAMER
from hamer.models import HAMER, download_models, load_hamer, DEFAULT_CHECKPOINT
def main():
parser = argparse.ArgumentParser(description='Evaluate trained models')
parser.add_argument('--checkpoint', type=str, default=DEFAULT_CHECKPOINT, help='Path to pretrained model checkpoint')
parser.add_argument('--results_folder', type=str, default='results', help='Path to results folder.')
parser.add_argument('--dataset', type=str, default='FREIHAND-VAL,HO3D-VAL,NEWDAYS-TEST-ALL,NEWDAYS-TEST-VIS,NEWDAYS-TEST-OCC,EPICK-TEST-ALL,EPICK-TEST-VIS,EPICK-TEST-OCC,EGO4D-TEST-ALL,EGO4D-TEST-VIS,EGO4D-TEST-OCC', help='Dataset to evaluate')
parser.add_argument('--batch_size', type=int, default=16, help='Batch size for inference')
parser.add_argument('--num_samples', type=int, default=1, help='Number of test samples to draw')
parser.add_argument('--num_workers', type=int, default=8, help='Number of workers used for data loading')
parser.add_argument('--log_freq', type=int, default=10, help='How often to log results')
parser.add_argument('--shuffle', dest='shuffle', action='store_true', default=False, help='Shuffle the dataset during evaluation')
parser.add_argument('--exp_name', type=str, default=None, help='Experiment name')
args = parser.parse_args()
# Download and load checkpoints
download_models(CACHE_DIR_HAMER)
model, model_cfg = load_hamer(args.checkpoint)
# Setup HMR2.0 model
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
model = model.to(device)
model.eval()
# Load config and run eval, one dataset at a time
print('Evaluating on datasets: {}'.format(args.dataset), flush=True)
for dataset in args.dataset.split(','):
dataset_cfg = dataset_eval_config()[dataset]
args.dataset = dataset
run_eval(model, model_cfg, dataset_cfg, device, args)
def run_eval(model, model_cfg, dataset_cfg, device, args):
# List of metrics to log
if args.dataset in ['FREIHAND-VAL', 'HO3D-VAL']:
metrics = None
preds = ['vertices', 'keypoints_3d']
pck_thresholds = None
rescale_factor = -1
elif args.dataset in ['NEWDAYS-TEST-ALL', 'NEWDAYS-TEST-VIS', 'NEWDAYS-TEST-OCC',
'EPICK-TEST-ALL', 'EPICK-TEST-VIS', 'EPICK-TEST-OCC',
'EGO4D-TEST-ALL', 'EGO4D-TEST-VIS', 'EGO4D-TEST-OCC']:
metrics = ['mode_kpl2']
preds = None
pck_thresholds = [0.05, 0.1, 0.15]
rescale_factor = 2
# Create dataset and data loader
dataset = create_dataset(model_cfg, dataset_cfg, train=False, rescale_factor=rescale_factor)
dataloader = torch.utils.data.DataLoader(dataset, args.batch_size, shuffle=args.shuffle, num_workers=args.num_workers)
# Setup evaluator object
evaluator = Evaluator(
dataset_length=dataset.__len__(),
dataset=args.dataset,
keypoint_list=dataset_cfg.KEYPOINT_LIST,
pelvis_ind=model_cfg.EXTRA.PELVIS_IND,
metrics=metrics,
preds=preds,
pck_thresholds=pck_thresholds,
)
# Go over the images in the dataset.
try:
for i, batch in enumerate(tqdm(dataloader)):
batch = recursive_to(batch, device)
with torch.no_grad():
out = model(batch)
evaluator(out, batch)
if i % args.log_freq == args.log_freq - 1:
evaluator.log()
evaluator.log()
error = None
except (Exception, KeyboardInterrupt) as e:
traceback.print_exc()
error = repr(e)
i = 0
# Append results to file
if metrics is not None:
metrics_dict = evaluator.get_metrics_dict()
results_csv = os.path.join(args.results_folder, 'eval_regression.csv')
save_eval_result(results_csv, metrics_dict, args.checkpoint, args.dataset, error=error, iters_done=i, exp_name=args.exp_name)
if preds is not None:
results_json = os.path.join(args.results_folder, '%s.json' % args.dataset.lower())
preds_dict = evaluator.get_preds_dict()
save_preds_result(results_json, preds_dict)
def save_eval_result(
csv_path: str,
metric_dict: float,
checkpoint_path: str,
dataset_name: str,
# start_time: pd.Timestamp,
error: Optional[str] = None,
iters_done=None,
exp_name=None,
) -> None:
"""Save evaluation results for a single scene file to a common CSV file."""
timestamp = pd.Timestamp.now()
exists: bool = os.path.exists(csv_path)
exp_name = exp_name or Path(checkpoint_path).parent.parent.name
# save each metric as different row to the csv path
metric_names = list(metric_dict.keys())
metric_values = list(metric_dict.values())
N = len(metric_names)
df = pd.DataFrame(
dict(
timestamp=[timestamp] * N,
checkpoint_path=[checkpoint_path] * N,
exp_name=[exp_name] * N,
dataset=[dataset_name] * N,
metric_name=metric_names,
metric_value=metric_values,
error=[error] * N,
iters_done=[iters_done] * N,
),
index=list(range(N)),
)
# Lock the file to prevent multiple processes from writing to it at the same time.
lock = FileLock(f"{csv_path}.lock", timeout=10)
with lock:
df.to_csv(csv_path, mode="a", header=not exists, index=False)
def save_preds_result(
pred_out_path: str,
preds_dict: float,
) -> None:
""" Save predictions into a json file. """
xyz_pred_list = preds_dict['keypoints_3d']
verts_pred_list = preds_dict['vertices']
# make sure its only lists
xyz_pred_list = [x.tolist() for x in xyz_pred_list]
verts_pred_list = [x.tolist() for x in verts_pred_list]
# save to a json
with open(pred_out_path, 'w') as fo:
json.dump(
[
xyz_pred_list,
verts_pred_list
], fo)
print('Dumped %d joints and %d verts predictions to %s' % (len(xyz_pred_list), len(verts_pred_list), pred_out_path))
if __name__ == '__main__':
main()
+7
View File
@@ -0,0 +1,7 @@
# Google drive link to download the model
gdown https://drive.google.com/uc?id=1mv7CUAnm73oKsEEG1xE3xH2C_oqcFSzT
# Alternatively, you can use wget
#wget https://www.cs.utexas.edu/~pavlakos/hamer/data/hamer_demo_data.tar.gz
tar --warning=no-unknown-keyword --exclude=".*" -xvf hamer_demo_data.tar.gz
+19
View File
@@ -0,0 +1,19 @@
# Google drive links to download the training data
gdown https://drive.google.com/uc?id=1BuKEc9qoBVgF8ApTTgAKRFVvDagWHPt7 # hamer_training_data_part1.tar.gz
gdown https://drive.google.com/uc?id=1lNqBsifaxMP3NHIV_KKJVCT1zDvUn2T_ # hamer_training_data_part2.tar.gz
gdown https://drive.google.com/uc?id=16xfV_ALY_M3VZeXKpjlB3MhnCNiS5XSq # hamer_training_data_part3.tar.gz
gdown https://drive.google.com/uc?id=1SqzFHH2-UI6PlGTMd0Ds2FJKALBBOaEO # hamer_training_data_part4a.tar.gz
gdown https://drive.google.com/uc?id=1xQxEjpaa3WqJt60UMtX_wpnOZ3bpj-u9 # hamer_training_data_part4b.tar.gz
gdown https://drive.google.com/uc?id=1ozejeAue1M-p4boIfpnpX0E8RFIeHUZH # hamer_training_data_part4c.tar.gz
# Alternatively, consider using the dropbox links:
#wget -O hamer_training_data_part1.tar.gz https://www.dropbox.com/scl/fi/bqq0jheev3626q1wiijs1/hamer_training_data_part1.tar.gz?rlkey=8fv4ktvk7r3txofd90q0trgxr
#wget -O hamer_training_data_part2.tar.gz https://www.dropbox.com/scl/fi/l9l5udalchu0mh4qxnw2t/hamer_training_data_part2.tar.gz?rlkey=i0n2lzix4q6jxmhm4sr5rtmkt
#wget -O hamer_training_data_part3.tar.gz https://www.dropbox.com/scl/fi/6lamcbwt79ri0oj4knwm3/hamer_training_data_part3.tar.gz?rlkey=j5y7ea7xrlu440ud12otaj2ne
#wget -O hamer_training_data_part4a.tar.gz https://www.dropbox.com/scl/fi/vp6cw7he8t0eigjf6001l/hamer_training_data_part4a.tar.gz?rlkey=wylmufft4a5nq3yxep2olifrk
#wget -O hamer_training_data_part4b.tar.gz https://www.dropbox.com/scl/fi/vyjasngr67ru14fb8s108/hamer_training_data_part4b.tar.gz?rlkey=qgotg1v9lkgo5eu78gh8b007t
#wget -O hamer_training_data_part4c.tar.gz https://www.dropbox.com/scl/fi/nfvz5zpcmhz8hkwzc6ji4/hamer_training_data_part4c.tar.gz?rlkey=ygh0wvse04twhh1ri3xiw2sag
for f in hamer_training_data_part*.tar.gz; do
tar --warning=no-unknown-keyword --exclude=".*" -xvf $f
done
View File
+114
View File
@@ -0,0 +1,114 @@
import os
from typing import Dict
from yacs.config import CfgNode as CN
CACHE_DIR_HAMER = "./_DATA"
def to_lower(x: Dict) -> Dict:
"""
Convert all dictionary keys to lowercase
Args:
x (dict): Input dictionary
Returns:
dict: Output dictionary with all keys converted to lowercase
"""
return {k.lower(): v for k, v in x.items()}
_C = CN(new_allowed=True)
_C.GENERAL = CN(new_allowed=True)
_C.GENERAL.RESUME = True
_C.GENERAL.TIME_TO_RUN = 3300
_C.GENERAL.VAL_STEPS = 100
_C.GENERAL.LOG_STEPS = 100
_C.GENERAL.CHECKPOINT_STEPS = 20000
_C.GENERAL.CHECKPOINT_DIR = "checkpoints"
_C.GENERAL.SUMMARY_DIR = "tensorboard"
_C.GENERAL.NUM_GPUS = 1
_C.GENERAL.NUM_WORKERS = 4
_C.GENERAL.MIXED_PRECISION = True
_C.GENERAL.ALLOW_CUDA = True
_C.GENERAL.PIN_MEMORY = False
_C.GENERAL.DISTRIBUTED = False
_C.GENERAL.LOCAL_RANK = 0
_C.GENERAL.USE_SYNCBN = False
_C.GENERAL.WORLD_SIZE = 1
_C.TRAIN = CN(new_allowed=True)
_C.TRAIN.NUM_EPOCHS = 100
_C.TRAIN.BATCH_SIZE = 32
_C.TRAIN.SHUFFLE = True
_C.TRAIN.WARMUP = False
_C.TRAIN.NORMALIZE_PER_IMAGE = False
_C.TRAIN.CLIP_GRAD = False
_C.TRAIN.CLIP_GRAD_VALUE = 1.0
_C.LOSS_WEIGHTS = CN(new_allowed=True)
_C.DATASETS = CN(new_allowed=True)
_C.MODEL = CN(new_allowed=True)
_C.MODEL.IMAGE_SIZE = 224
_C.EXTRA = CN(new_allowed=True)
_C.EXTRA.FOCAL_LENGTH = 5000
_C.DATASETS.CONFIG = CN(new_allowed=True)
_C.DATASETS.CONFIG.SCALE_FACTOR = 0.3
_C.DATASETS.CONFIG.ROT_FACTOR = 30
_C.DATASETS.CONFIG.TRANS_FACTOR = 0.02
_C.DATASETS.CONFIG.COLOR_SCALE = 0.2
_C.DATASETS.CONFIG.ROT_AUG_RATE = 0.6
_C.DATASETS.CONFIG.TRANS_AUG_RATE = 0.5
_C.DATASETS.CONFIG.DO_FLIP = False
_C.DATASETS.CONFIG.FLIP_AUG_RATE = 0.5
_C.DATASETS.CONFIG.EXTREME_CROP_AUG_RATE = 0.10
def default_config() -> CN:
"""
Get a yacs CfgNode object with the default config values.
"""
# Return a clone so that the defaults will not be altered
# This is for the "local variable" use pattern
return _C.clone()
def dataset_config(name='datasets_tar.yaml') -> CN:
"""
Get dataset config file
Returns:
CfgNode: Dataset config as a yacs CfgNode object.
"""
cfg = CN(new_allowed=True)
config_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), name)
cfg.merge_from_file(config_file)
cfg.freeze()
return cfg
def dataset_eval_config() -> CN:
return dataset_config('datasets_eval.yaml')
def get_config(config_file: str, merge: bool = True, update_cachedir: bool = False) -> CN:
"""
Read a config file and optionally merge it with the default config file.
Args:
config_file (str): Path to config file.
merge (bool): Whether to merge with the default config or not.
Returns:
CfgNode: Config as a yacs CfgNode object.
"""
if merge:
cfg = default_config()
else:
cfg = CN(new_allowed=True)
cfg.merge_from_file(config_file)
if update_cachedir:
def update_path(path: str) -> str:
if os.path.isabs(path):
return path
return os.path.join(CACHE_DIR_HAMER, path)
cfg.MANO.MODEL_PATH = update_path(cfg.MANO.MODEL_PATH)
cfg.MANO.MEAN_PARAMS = update_path(cfg.MANO.MEAN_PARAMS)
cfg.freeze()
return cfg
@@ -0,0 +1,129 @@
## coco_loader_lsj.py
import detectron2.data.transforms as T
from detectron2 import model_zoo
from detectron2.config import LazyCall as L
# Data using LSJ
image_size = 1024
dataloader = model_zoo.get_config("common/data/coco.py").dataloader
dataloader.train.mapper.augmentations = [
L(T.RandomFlip)(horizontal=True), # flip first
L(T.ResizeScale)(
min_scale=0.1, max_scale=2.0, target_height=image_size, target_width=image_size
),
L(T.FixedSizeCrop)(crop_size=(image_size, image_size), pad=False),
]
dataloader.train.mapper.image_format = "RGB"
dataloader.train.total_batch_size = 64
# recompute boxes due to cropping
dataloader.train.mapper.recompute_boxes = True
dataloader.test.mapper.augmentations = [
L(T.ResizeShortestEdge)(short_edge_length=image_size, max_size=image_size),
]
from functools import partial
from fvcore.common.param_scheduler import MultiStepParamScheduler
from detectron2 import model_zoo
from detectron2.config import LazyCall as L
from detectron2.solver import WarmupParamScheduler
from detectron2.modeling.backbone.vit import get_vit_lr_decay_rate
# mask_rcnn_vitdet_b_100ep.py
model = model_zoo.get_config("common/models/mask_rcnn_vitdet.py").model
# Initialization and trainer settings
train = model_zoo.get_config("common/train.py").train
train.amp.enabled = True
train.ddp.fp16_compression = True
train.init_checkpoint = "detectron2://ImageNetPretrained/MAE/mae_pretrain_vit_base.pth"
# Schedule
# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep
train.max_iter = 184375
lr_multiplier = L(WarmupParamScheduler)(
scheduler=L(MultiStepParamScheduler)(
values=[1.0, 0.1, 0.01],
milestones=[163889, 177546],
num_updates=train.max_iter,
),
warmup_length=250 / train.max_iter,
warmup_factor=0.001,
)
# Optimizer
optimizer = model_zoo.get_config("common/optim.py").AdamW
optimizer.params.lr_factor_func = partial(get_vit_lr_decay_rate, num_layers=12, lr_decay_rate=0.7)
optimizer.params.overrides = {"pos_embed": {"weight_decay": 0.0}}
# cascade_mask_rcnn_vitdet_b_100ep.py
from detectron2.config import LazyCall as L
from detectron2.layers import ShapeSpec
from detectron2.modeling.box_regression import Box2BoxTransform
from detectron2.modeling.matcher import Matcher
from detectron2.modeling.roi_heads import (
FastRCNNOutputLayers,
FastRCNNConvFCHead,
CascadeROIHeads,
)
# arguments that don't exist for Cascade R-CNN
[model.roi_heads.pop(k) for k in ["box_head", "box_predictor", "proposal_matcher"]]
model.roi_heads.update(
_target_=CascadeROIHeads,
box_heads=[
L(FastRCNNConvFCHead)(
input_shape=ShapeSpec(channels=256, height=7, width=7),
conv_dims=[256, 256, 256, 256],
fc_dims=[1024],
conv_norm="LN",
)
for _ in range(3)
],
box_predictors=[
L(FastRCNNOutputLayers)(
input_shape=ShapeSpec(channels=1024),
test_score_thresh=0.05,
box2box_transform=L(Box2BoxTransform)(weights=(w1, w1, w2, w2)),
cls_agnostic_bbox_reg=True,
num_classes="${...num_classes}",
)
for (w1, w2) in [(10, 5), (20, 10), (30, 15)]
],
proposal_matchers=[
L(Matcher)(thresholds=[th], labels=[0, 1], allow_low_quality_matches=False)
for th in [0.5, 0.6, 0.7]
],
)
# cascade_mask_rcnn_vitdet_h_75ep.py
from functools import partial
train.init_checkpoint = "detectron2://ImageNetPretrained/MAE/mae_pretrain_vit_huge_p14to16.pth"
model.backbone.net.embed_dim = 1280
model.backbone.net.depth = 32
model.backbone.net.num_heads = 16
model.backbone.net.drop_path_rate = 0.5
# 7, 15, 23, 31 for global attention
model.backbone.net.window_block_indexes = (
list(range(0, 7)) + list(range(8, 15)) + list(range(16, 23)) + list(range(24, 31))
)
optimizer.params.lr_factor_func = partial(get_vit_lr_decay_rate, lr_decay_rate=0.9, num_layers=32)
optimizer.params.overrides = {}
optimizer.params.weight_decay_norm = None
train.max_iter = train.max_iter * 3 // 4 # 100ep -> 75ep
lr_multiplier.scheduler.milestones = [
milestone * 3 // 4 for milestone in lr_multiplier.scheduler.milestones
]
lr_multiplier.scheduler.num_updates = train.max_iter
+65
View File
@@ -0,0 +1,65 @@
FREIHAND-VAL:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/freihand_val.npz
IMG_DIR: /home/user/datasets/FreiHAND_pub_v2_eval/evaluation/rgb/
KEYPOINT_LIST: [0] # Dummy
HO3D-VAL:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/ho3d_val.npz
IMG_DIR: /home/user/datasets/HO3D_v2/evaluation/
KEYPOINT_LIST: [0] # Dummy
EGO4D-TEST-ALL:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_ego4d_img_all.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_ego4d_img/
KEYPOINT_LIST: [0] # Dummy
EGO4D-TEST-VIS:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_ego4d_img_vis.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_ego4d_img/
KEYPOINT_LIST: [0] # Dummy
EGO4D-TEST-OCC:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_ego4d_img_occ.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_ego4d_img/
KEYPOINT_LIST: [0] # Dummy
EPICK-TEST-ALL:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_epick_img_all.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_epick_img/
KEYPOINT_LIST: [0] # Dummy
EPICK-TEST-VIS:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_epick_img_vis.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_epick_img/
KEYPOINT_LIST: [0] # Dummy
EPICK-TEST-OCC:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_epick_img_occ.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_epick_img/
KEYPOINT_LIST: [0] # Dummy
NEWDAYS-TEST-ALL:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_newdays_img_all.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_newdays_img/
KEYPOINT_LIST: [0] # Dummy
NEWDAYS-TEST-VIS:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_newdays_img_vis.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_newdays_img/
KEYPOINT_LIST: [0] # Dummy
NEWDAYS-TEST-OCC:
TYPE: ImageDataset
DATASET_FILE: hamer_evaluation_data/TEST_newdays_img_occ.npz
IMG_DIR: /home/user/datasets/HInt_annotation_partial/TEST_newdays_img/
KEYPOINT_LIST: [0] # Dummy
+42
View File
@@ -0,0 +1,42 @@
FREIHAND-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/freihand-train/{000000..000130}.tar
epoch_size: 130_240
INTERHAND26M-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/interhand26m-train/{000000..001056}.tar
epoch_size: 1_424_632
HALPE-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/halpe-train/{000000..000022}.tar
epoch_size: 34_289
COCOW-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/cocow-train/{000000..000036}.tar
epoch_size: 78_666
MTC-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/mtc-train/{000000..000306}.tar
epoch_size: 363_947
RHD-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/rhd-train/{000000..000041}.tar
epoch_size: 61_705
MPIINZSL-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/mpiinzsl-train/{000000..000015}.tar
epoch_size: 15_184
HO3D-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/ho3d-train/{000000..000083}.tar
epoch_size: 83_325
H2O3D-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/h2o3d-train/{000000..000060}.tar
epoch_size: 121_996
DEX-TRAIN:
TYPE: ImageDataset
URLS: hamer_training_data/dataset_tars/dex-train/{000000..000406}.tar
epoch_size: 406_888
FREIHAND-MOCAP:
DATASET_FILE: hamer_training_data/freihand_mocap.npz
+31
View File
@@ -0,0 +1,31 @@
# @package _global_
defaults:
- /data_filtering: low1
DATASETS:
TRAIN:
FREIHAND-TRAIN:
WEIGHT: 0.25
INTERHAND26M-TRAIN:
WEIGHT: 0.25
MTC-TRAIN:
WEIGHT: 0.1
RHD-TRAIN:
WEIGHT: 0.05
COCOW-TRAIN:
WEIGHT: 0.1
HALPE-TRAIN:
WEIGHT: 0.05
MPIINZSL-TRAIN:
WEIGHT: 0.05
HO3D-TRAIN:
WEIGHT: 0.05
H2O3D-TRAIN:
WEIGHT: 0.05
DEX-TRAIN:
WEIGHT: 0.05
VAL:
FREIHAND-TRAIN:
WEIGHT: 1.0
MOCAP: FREIHAND-MOCAP
@@ -0,0 +1,13 @@
# @package _global_
DATASETS:
# Data filtering during training
SUPPRESS_KP_CONF_THRESH: 0.3
FILTER_NUM_KP: 4
FILTER_NUM_KP_THRESH: 0.0
FILTER_REPROJ_THRESH: 31000
SUPPRESS_BETAS_THRESH: 3.0
SUPPRESS_BAD_POSES: False
POSES_BETAS_SIMULTANEOUS: True
FILTER_NO_POSES: False # If True, filters images that don't have poses
@@ -0,0 +1,29 @@
# @package _global_
MANO:
DATA_DIR: _DATA/data/
MODEL_PATH: ${MANO.DATA_DIR}/mano
GENDER: neutral
NUM_HAND_JOINTS: 15
MEAN_PARAMS: ${MANO.DATA_DIR}/mano_mean_params.npz
CREATE_BODY_POSE: FALSE
EXTRA:
FOCAL_LENGTH: 5000
NUM_LOG_IMAGES: 4
NUM_LOG_SAMPLES_PER_IMAGE: 8
PELVIS_IND: 0
DATASETS:
BETAS_REG: True
CONFIG:
SCALE_FACTOR: 0.3
ROT_FACTOR: 30
TRANS_FACTOR: 0.02
COLOR_SCALE: 0.2
ROT_AUG_RATE: 0.6
TRANS_AUG_RATE: 0.5
DO_FLIP: False
FLIP_AUG_RATE: 0.0
EXTREME_CROP_AUG_RATE: 0.0
EXTREME_CROP_AUG_LEVEL: 1
@@ -0,0 +1,51 @@
# @package _global_
defaults:
- default.yaml
GENERAL:
TOTAL_STEPS: 1_000_000
LOG_STEPS: 1000
VAL_STEPS: 1000
CHECKPOINT_STEPS: 1000
CHECKPOINT_SAVE_TOP_K: 1
NUM_WORKERS: 4
PREFETCH_FACTOR: 2
TRAIN:
LR: 1e-5
WEIGHT_DECAY: 1e-4
BATCH_SIZE: 8
LOSS_REDUCTION: mean
NUM_TRAIN_SAMPLES: 2
NUM_TEST_SAMPLES: 64
POSE_2D_NOISE_RATIO: 0.01
SMPL_PARAM_NOISE_RATIO: 0.005
MODEL:
IMAGE_SIZE: 256
IMAGE_MEAN: [0.485, 0.456, 0.406]
IMAGE_STD: [0.229, 0.224, 0.225]
BACKBONE:
TYPE: vit
PRETRAINED_WEIGHTS: hamer_training_data/vitpose_backbone.pth
MANO_HEAD:
TYPE: transformer_decoder
IN_CHANNELS: 2048
TRANSFORMER_DECODER:
depth: 6
heads: 8
mlp_dim: 1024
dim_head: 64
dropout: 0.0
emb_dropout: 0.0
norm: layer
context_dim: 1280 # from vitpose-H
LOSS_WEIGHTS:
KEYPOINTS_3D: 0.05
KEYPOINTS_2D: 0.01
GLOBAL_ORIENT: 0.001
HAND_POSE: 0.001
BETAS: 0.0005
ADVERSARIAL: 0.0005
@@ -0,0 +1,8 @@
# disable python warnings if they annoy you
ignore_warnings: False
# ask user for tags if none are provided in the config
enforce_tags: True
# pretty print config tree at the start of the run using Rich library
print_config: True
@@ -0,0 +1,26 @@
# @package _global_
# https://hydra.cc/docs/configure_hydra/intro/
# enable color logging
defaults:
- override /hydra/hydra_logging: colorlog
- override /hydra/job_logging: colorlog
# exp_name: ovrd_${hydra:job.override_dirname}
exp_name: ${now:%Y-%m-%d}_${now:%H-%M-%S}
hydra:
run:
dir: ${paths.log_dir}/${task_name}/runs/${exp_name}
sweep:
dir: ${paths.log_dir}/${task_name}/multiruns/${exp_name}
subdir: ${hydra.job.num}
job:
config:
override_dirname:
exclude_keys:
- trainer
- trainer.devices
- trainer.num_nodes
- callbacks
- debug
@@ -0,0 +1,13 @@
# @package _global_
defaults:
- override /hydra/launcher: submitit_local
hydra:
launcher:
timeout_min: 10_080 # 7 days
nodes: 1
tasks_per_node: ${trainer.devices}
cpus_per_task: 6
gpus_per_node: ${trainer.devices}
name: hamer
@@ -0,0 +1,22 @@
# @package _global_
defaults:
- override /hydra/launcher: submitit_slurm
hydra:
launcher:
timeout_min: 10_080 # 7 days
max_num_timeout: 3
partition: g40
qos: idle
nodes: 1
tasks_per_node: ${trainer.devices}
gpus_per_task: null
cpus_per_task: 12
gpus_per_node: ${trainer.devices}
cpus_per_gpu: null
comment: laion
name: hamer
setup:
- module load cuda openmpi libfabric-aws
- export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
@@ -0,0 +1,18 @@
# path to root directory
# this requires PROJECT_ROOT environment variable to exist
# PROJECT_ROOT is inferred and set by pyrootutils package in `train.py` and `eval.py`
root_dir: ${oc.env:PROJECT_ROOT}
# path to data directory
data_dir: ${paths.root_dir}/data/
# path to logging directory
log_dir: logs/
# path to output directory, created dynamically by hydra
# path generation pattern is specified in `configs/hydra/default.yaml`
# use it to store all files generated during the run, like ckpts and metrics
output_dir: ${hydra:runtime.output_dir}
# path to working directory
work_dir: ${hydra:runtime.cwd}
+47
View File
@@ -0,0 +1,47 @@
# @package _global_
# specify here default configuration
# order of defaults determines the order in which configs override each other
defaults:
- _self_
- data: mix_all.yaml
- trainer: ddp.yaml
- paths: default.yaml
- extras: default.yaml
- hydra: default.yaml
# experiment configs allow for version control of specific hyperparameters
# e.g. best hyperparameters for given model and datamodule
- experiment: null
- texture_exp: null
# optional local config for machine/user specific settings
# it's optional since it doesn't need to exist and is excluded from version control
- optional launcher: local.yaml
# - optional launcher: slurm.yaml
# debugging config (enable through command line, e.g. `python train.py debug=default)
- debug: null
# task name, determines output directory path
task_name: "train"
# tags to help you identify your experiments
# you can overwrite this in experiment configs
# overwrite from command line with `python train.py tags="[first_tag, second_tag]"`
# appending lists from command line is currently not supported :(
# https://github.com/facebookresearch/hydra/issues/1547
tags: ["dev"]
# set False to skip model training
train: True
# evaluate on test set, using best model weights achieved during training
# lightning chooses best weights based on the metric specified in checkpoint callback
test: False
# simply provide checkpoint path to resume training
ckpt_path: null
# seed for random number generators in pytorch, numpy and python.random
seed: null
@@ -0,0 +1,6 @@
defaults:
- default.yaml
- default_hamer.yaml
accelerator: cpu
devices: 1
+14
View File
@@ -0,0 +1,14 @@
defaults:
- default.yaml
- default_hamer.yaml
# use "ddp_spawn" instead of "ddp",
# it's slower but normal "ddp" currently doesn't work ideally with hydra
# https://github.com/facebookresearch/hydra/issues/2070
# https://pytorch-lightning.readthedocs.io/en/latest/accelerators/gpu_intermediate.html#distributed-data-parallel-spawn
strategy: ddp
accelerator: gpu
devices: 8
num_nodes: 1
sync_batchnorm: True
@@ -0,0 +1,10 @@
_target_: pytorch_lightning.Trainer
default_root_dir: ${paths.output_dir}
accelerator: cpu
devices: 1
# set True to to ensure deterministic results
# makes training slower but gives more reproducibility than just setting seeds
deterministic: False
@@ -0,0 +1,8 @@
num_sanity_val_steps: 0
log_every_n_steps: ${GENERAL.LOG_STEPS}
val_check_interval: ${GENERAL.VAL_STEPS}
precision: 16
max_steps: ${GENERAL.TOTAL_STEPS}
# move_metrics_to_cpu: True
limit_val_batches: 1
# track_grad_norm: -1
@@ -0,0 +1,6 @@
defaults:
- default.yaml
- default_hamer.yaml
accelerator: gpu
devices: 1
@@ -0,0 +1,6 @@
defaults:
- default.yaml
- default_hamer.yaml
accelerator: mps
devices: 1
+88
View File
@@ -0,0 +1,88 @@
from typing import Dict, Optional
import torch
import numpy as np
import pytorch_lightning as pl
from yacs.config import CfgNode
import webdataset as wds
from ..configs import to_lower
from .dataset import Dataset
from .image_dataset import ImageDataset
from .mocap_dataset import MoCapDataset
def create_dataset(cfg: CfgNode, dataset_cfg: CfgNode, train: bool = True, **kwargs) -> Dataset:
"""
Instantiate a dataset from a config file.
Args:
cfg (CfgNode): Model configuration file.
dataset_cfg (CfgNode): Dataset configuration info.
train (bool): Variable to select between train and val datasets.
"""
dataset_type = Dataset.registry[dataset_cfg.TYPE]
return dataset_type(cfg, **to_lower(dataset_cfg), train=train, **kwargs)
def create_webdataset(cfg: CfgNode, dataset_cfg: CfgNode, train: bool = True) -> Dataset:
"""
Like `create_dataset` but load data from tars.
"""
dataset_type = Dataset.registry[dataset_cfg.TYPE]
return dataset_type.load_tars_as_webdataset(cfg, **to_lower(dataset_cfg), train=train)
class MixedWebDataset(wds.WebDataset):
def __init__(self, cfg: CfgNode, dataset_cfg: CfgNode, train: bool = True) -> None:
super(wds.WebDataset, self).__init__()
dataset_list = cfg.DATASETS.TRAIN if train else cfg.DATASETS.VAL
datasets = [create_webdataset(cfg, dataset_cfg[dataset], train=train) for dataset, v in dataset_list.items()]
weights = np.array([v.WEIGHT for dataset, v in dataset_list.items()])
weights = weights / weights.sum() # normalize
self.append(wds.RandomMix(datasets, weights))
class HAMERDataModule(pl.LightningDataModule):
def __init__(self, cfg: CfgNode, dataset_cfg: CfgNode) -> None:
"""
Initialize LightningDataModule for HAMER training
Args:
cfg (CfgNode): Config file as a yacs CfgNode containing necessary dataset info.
dataset_cfg (CfgNode): Dataset configuration file
"""
super().__init__()
self.cfg = cfg
self.dataset_cfg = dataset_cfg
self.train_dataset = None
self.val_dataset = None
self.test_dataset = None
self.mocap_dataset = None
def setup(self, stage: Optional[str] = None) -> None:
"""
Load datasets necessary for training
Args:
cfg (CfgNode): Config file as a yacs CfgNode containing necessary dataset info.
"""
if self.train_dataset == None:
self.train_dataset = MixedWebDataset(self.cfg, self.dataset_cfg, train=True).with_epoch(100_000).shuffle(4000)
self.val_dataset = MixedWebDataset(self.cfg, self.dataset_cfg, train=False).shuffle(4000)
self.mocap_dataset = MoCapDataset(**to_lower(self.dataset_cfg[self.cfg.DATASETS.MOCAP]))
def train_dataloader(self) -> Dict:
"""
Setup training data loader.
Returns:
Dict: Dictionary containing image and mocap data dataloaders
"""
train_dataloader = torch.utils.data.DataLoader(self.train_dataset, self.cfg.TRAIN.BATCH_SIZE, drop_last=True, num_workers=self.cfg.GENERAL.NUM_WORKERS, prefetch_factor=self.cfg.GENERAL.PREFETCH_FACTOR)
mocap_dataloader = torch.utils.data.DataLoader(self.mocap_dataset, self.cfg.TRAIN.NUM_TRAIN_SAMPLES * self.cfg.TRAIN.BATCH_SIZE, shuffle=True, drop_last=True, num_workers=1)
return {'img': train_dataloader, 'mocap': mocap_dataloader}
def val_dataloader(self) -> torch.utils.data.DataLoader:
"""
Setup val data loader.
Returns:
torch.utils.data.DataLoader: Validation dataloader
"""
val_dataloader = torch.utils.data.DataLoader(self.val_dataset, self.cfg.TRAIN.BATCH_SIZE, drop_last=True, num_workers=self.cfg.GENERAL.NUM_WORKERS)
return val_dataloader
+27
View File
@@ -0,0 +1,27 @@
"""
This file contains the defition of the base Dataset class.
"""
class DatasetRegistration(type):
"""
Metaclass for registering different datasets
"""
def __init__(cls, name, bases, nmspc):
super().__init__(name, bases, nmspc)
if not hasattr(cls, 'registry'):
cls.registry = dict()
cls.registry[name] = cls
# Metamethods, called on class objects:
def __iter__(cls):
return iter(cls.registry)
def __str__(cls):
return str(cls.registry)
class Dataset(metaclass=DatasetRegistration):
"""
Base Dataset class
"""
def __init__(self, *args, **kwargs):
pass
+434
View File
@@ -0,0 +1,434 @@
import copy
import os
import numpy as np
import torch
from typing import Any, Dict, List
from yacs.config import CfgNode
import braceexpand
import cv2
from .dataset import Dataset
from .utils import get_example, expand_to_aspect_ratio
def expand(s):
return os.path.expanduser(os.path.expandvars(s))
def expand_urls(urls: str|List[str]):
if isinstance(urls, str):
urls = [urls]
urls = [u for url in urls for u in braceexpand.braceexpand(expand(url))]
return urls
FLIP_KEYPOINT_PERMUTATION = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
DEFAULT_MEAN = 255. * np.array([0.485, 0.456, 0.406])
DEFAULT_STD = 255. * np.array([0.229, 0.224, 0.225])
DEFAULT_IMG_SIZE = 256
class ImageDataset(Dataset):
def __init__(self,
cfg: CfgNode,
dataset_file: str,
img_dir: str,
train: bool = True,
rescale_factor = 2,
prune: Dict[str, Any] = {},
**kwargs):
"""
Dataset class used for loading images and corresponding annotations.
Args:
cfg (CfgNode): Model config file.
dataset_file (str): Path to npz file containing dataset info.
img_dir (str): Path to image folder.
train (bool): Whether it is for training or not (enables data augmentation).
"""
super(ImageDataset, self).__init__()
self.train = train
self.cfg = cfg
self.img_size = cfg.MODEL.IMAGE_SIZE
self.mean = 255. * np.array(self.cfg.MODEL.IMAGE_MEAN)
self.std = 255. * np.array(self.cfg.MODEL.IMAGE_STD)
self.rescale_factor = rescale_factor
self.img_dir = img_dir
self.data = np.load(dataset_file, allow_pickle=True)
self.imgname = self.data['imgname']
self.personid = np.zeros(len(self.imgname), dtype=np.int32)
self.extra_info = self.data.get('extra_info', [{} for _ in range(len(self.imgname))])
self.flip_keypoint_permutation = copy.copy(FLIP_KEYPOINT_PERMUTATION)
num_pose = 3 * (self.cfg.MANO.NUM_HAND_JOINTS + 1)
# Bounding boxes are assumed to be in the center and scale format
self.center = self.data['center']
self.scale = self.data['scale'].reshape(len(self.center), -1) / 200.0
if self.scale.shape[1] == 1:
self.scale = np.tile(self.scale, (1, 2))
assert self.scale.shape == (len(self.center), 2)
try:
self.right = self.data['right']
except KeyError:
self.right = np.ones(len(self.imgname), dtype=np.float32)
# Get gt MANO parameters, if available
try:
self.hand_pose = self.data['hand_pose'].astype(np.float32)
self.has_hand_pose = self.data['has_hand_pose'].astype(np.float32)
except KeyError:
self.hand_pose = np.zeros((len(self.imgname), num_pose), dtype=np.float32)
self.has_hand_pose = np.zeros(len(self.imgname), dtype=np.float32)
try:
self.betas = self.data['betas'].astype(np.float32)
self.has_betas = self.data['has_betas'].astype(np.float32)
except KeyError:
self.betas = np.zeros((len(self.imgname), 10), dtype=np.float32)
self.has_betas = np.zeros(len(self.imgname), dtype=np.float32)
# Try to get 2d keypoints, if available
try:
hand_keypoints_2d = self.data['hand_keypoints_2d']
except KeyError:
hand_keypoints_2d = np.zeros((len(self.center), 21, 3))
self.keypoints_2d = hand_keypoints_2d
# Try to get 3d keypoints, if available
try:
hand_keypoints_3d = self.data['hand_keypoints_3d'].astype(np.float32)
except KeyError:
hand_keypoints_3d = np.zeros((len(self.center), 21, 4), dtype=np.float32)
self.keypoints_3d = hand_keypoints_3d
def __len__(self) -> int:
return len(self.scale)
def __getitem__(self, idx: int) -> Dict:
"""
Returns an example from the dataset.
"""
try:
image_file_rel = self.imgname[idx].decode('utf-8')
except AttributeError:
image_file_rel = self.imgname[idx]
image_file = os.path.join(self.img_dir, image_file_rel)
keypoints_2d = self.keypoints_2d[idx].copy()
keypoints_3d = self.keypoints_3d[idx].copy()
center = self.center[idx].copy()
center_x = center[0]
center_y = center[1]
scale = self.scale[idx]
right = self.right[idx].copy()
if self.rescale_factor == -1:
BBOX_SHAPE = self.cfg.MODEL.get('BBOX_SHAPE', None)
bbox_size = expand_to_aspect_ratio(scale*200, target_aspect_ratio=BBOX_SHAPE).max()
bbox_expand_factor = bbox_size / ((scale*200).max())
else:
bbox_expand_factor = self.rescale_factor
bbox_size = bbox_expand_factor*scale.max()*200
hand_pose = self.hand_pose[idx].copy().astype(np.float32)
betas = self.betas[idx].copy().astype(np.float32)
has_hand_pose = self.has_hand_pose[idx].copy()
has_betas = self.has_betas[idx].copy()
mano_params = {'global_orient': hand_pose[:3],
'hand_pose': hand_pose[3:],
'betas': betas
}
has_mano_params = {'global_orient': has_hand_pose,
'hand_pose': has_hand_pose,
'betas': has_betas
}
mano_params_is_axis_angle = {'global_orient': True,
'hand_pose': True,
'betas': False
}
augm_config = self.cfg.DATASETS.CONFIG
# Crop image and (possibly) perform data augmentation
img_patch, keypoints_2d, keypoints_3d, mano_params, has_mano_params, img_size = get_example(image_file,
center_x, center_y,
bbox_size, bbox_size,
keypoints_2d, keypoints_3d,
mano_params, has_mano_params,
self.flip_keypoint_permutation,
self.img_size, self.img_size,
self.mean, self.std, self.train, right, augm_config)
item = {}
# These are the keypoints in the original image coordinates (before cropping)
orig_keypoints_2d = self.keypoints_2d[idx].copy()
item['img'] = img_patch
item['keypoints_2d'] = keypoints_2d.astype(np.float32)
item['keypoints_3d'] = keypoints_3d.astype(np.float32)
item['orig_keypoints_2d'] = orig_keypoints_2d
item['box_center'] = self.center[idx].copy()
item['box_size'] = bbox_size
item['bbox_expand_factor'] = bbox_expand_factor
item['img_size'] = 1.0 * img_size[::-1].copy()
item['mano_params'] = mano_params
item['has_mano_params'] = has_mano_params
item['mano_params_is_axis_angle'] = mano_params_is_axis_angle
item['imgname'] = image_file
item['imgname_rel'] = image_file_rel
item['personid'] = int(self.personid[idx])
item['extra_info'] = copy.deepcopy(self.extra_info[idx])
item['idx'] = idx
item['_scale'] = scale
item['right'] = self.right[idx].copy()
return item
@staticmethod
def load_tars_as_webdataset(cfg: CfgNode, urls: str|List[str], train: bool,
resampled=False,
epoch_size=None,
cache_dir=None,
**kwargs) -> Dataset:
"""
Loads the dataset from a webdataset tar file.
"""
IMG_SIZE = cfg.MODEL.IMAGE_SIZE
BBOX_SHAPE = cfg.MODEL.get('BBOX_SHAPE', None)
MEAN = 255. * np.array(cfg.MODEL.IMAGE_MEAN)
STD = 255. * np.array(cfg.MODEL.IMAGE_STD)
def split_data(source):
for item in source:
datas = item['data.pyd']
for data in datas:
if 'detection.npz' in item:
det_idx = data['extra_info']['detection_npz_idx']
mask = item['detection.npz']['masks'][det_idx]
else:
mask = np.ones_like(item['jpg'][:,:,0], dtype=bool)
yield {
'__key__': item['__key__'],
'jpg': item['jpg'],
'data.pyd': data,
'mask': mask,
}
def suppress_bad_kps(item, thresh=0.0):
if thresh > 0:
kp2d = item['data.pyd']['keypoints_2d']
kp2d_conf = np.where(kp2d[:, 2] < thresh, 0.0, kp2d[:, 2])
item['data.pyd']['keypoints_2d'] = np.concatenate([kp2d[:,:2], kp2d_conf[:,None]], axis=1)
return item
def filter_numkp(item, numkp=4, thresh=0.0):
kp_conf = item['data.pyd']['keypoints_2d'][:, 2]
return (kp_conf > thresh).sum() > numkp
def filter_reproj_error(item, thresh=10**4.5):
losses = item['data.pyd'].get('extra_info', {}).get('fitting_loss', np.array({})).item()
reproj_loss = losses.get('reprojection_loss', None)
return reproj_loss is None or reproj_loss < thresh
def filter_bbox_size(item, thresh=1):
bbox_size_min = item['data.pyd']['scale'].min().item() * 200.
return bbox_size_min > thresh
def filter_no_poses(item):
return (item['data.pyd']['has_hand_pose'] > 0)
def supress_bad_betas(item, thresh=3):
has_betas = item['data.pyd']['has_betas']
if thresh > 0 and has_betas:
betas_abs = np.abs(item['data.pyd']['betas'])
if (betas_abs > thresh).any():
item['data.pyd']['has_betas'] = False
return item
def supress_bad_poses(item):
has_hand_pose = item['data.pyd']['has_hand_pose']
if has_hand_pose:
hand_pose = item['data.pyd']['hand_pose']
pose_is_probable = poses_check_probable(torch.from_numpy(hand_pose)[None, 3:], amass_poses_hist100_smooth).item()
if not pose_is_probable:
item['data.pyd']['has_hand_pose'] = False
return item
def poses_betas_simultaneous(item):
# We either have both hand_pose and betas, or neither
has_betas = item['data.pyd']['has_betas']
has_hand_pose = item['data.pyd']['has_hand_pose']
item['data.pyd']['has_betas'] = item['data.pyd']['has_hand_pose'] = np.array(float((has_hand_pose>0) and (has_betas>0)))
return item
def set_betas_for_reg(item):
# Always have betas set to true
has_betas = item['data.pyd']['has_betas']
betas = item['data.pyd']['betas']
if not (has_betas>0):
item['data.pyd']['has_betas'] = np.array(float((True)))
item['data.pyd']['betas'] = betas * 0
return item
# Load the dataset
if epoch_size is not None:
resampled = True
#corrupt_filter = lambda sample: (sample['__key__'] not in CORRUPT_KEYS)
import webdataset as wds
dataset = wds.WebDataset(expand_urls(urls),
nodesplitter=wds.split_by_node,
shardshuffle=True,
resampled=resampled,
cache_dir=cache_dir,
) #.select(corrupt_filter)
if train:
dataset = dataset.shuffle(100)
dataset = dataset.decode('rgb8').rename(jpg='jpg;jpeg;png')
# Process the dataset
dataset = dataset.compose(split_data)
# Filter/clean the dataset
SUPPRESS_KP_CONF_THRESH = cfg.DATASETS.get('SUPPRESS_KP_CONF_THRESH', 0.0)
SUPPRESS_BETAS_THRESH = cfg.DATASETS.get('SUPPRESS_BETAS_THRESH', 0.0)
SUPPRESS_BAD_POSES = cfg.DATASETS.get('SUPPRESS_BAD_POSES', False)
POSES_BETAS_SIMULTANEOUS = cfg.DATASETS.get('POSES_BETAS_SIMULTANEOUS', False)
BETAS_REG = cfg.DATASETS.get('BETAS_REG', False)
FILTER_NO_POSES = cfg.DATASETS.get('FILTER_NO_POSES', False)
FILTER_NUM_KP = cfg.DATASETS.get('FILTER_NUM_KP', 4)
FILTER_NUM_KP_THRESH = cfg.DATASETS.get('FILTER_NUM_KP_THRESH', 0.0)
FILTER_REPROJ_THRESH = cfg.DATASETS.get('FILTER_REPROJ_THRESH', 0.0)
FILTER_MIN_BBOX_SIZE = cfg.DATASETS.get('FILTER_MIN_BBOX_SIZE', 0.0)
if SUPPRESS_KP_CONF_THRESH > 0:
dataset = dataset.map(lambda x: suppress_bad_kps(x, thresh=SUPPRESS_KP_CONF_THRESH))
if SUPPRESS_BETAS_THRESH > 0:
dataset = dataset.map(lambda x: supress_bad_betas(x, thresh=SUPPRESS_BETAS_THRESH))
if SUPPRESS_BAD_POSES:
dataset = dataset.map(lambda x: supress_bad_poses(x))
if POSES_BETAS_SIMULTANEOUS:
dataset = dataset.map(lambda x: poses_betas_simultaneous(x))
if FILTER_NO_POSES:
dataset = dataset.select(lambda x: filter_no_poses(x))
if FILTER_NUM_KP > 0:
dataset = dataset.select(lambda x: filter_numkp(x, numkp=FILTER_NUM_KP, thresh=FILTER_NUM_KP_THRESH))
if FILTER_REPROJ_THRESH > 0:
dataset = dataset.select(lambda x: filter_reproj_error(x, thresh=FILTER_REPROJ_THRESH))
if FILTER_MIN_BBOX_SIZE > 0:
dataset = dataset.select(lambda x: filter_bbox_size(x, thresh=FILTER_MIN_BBOX_SIZE))
if BETAS_REG:
dataset = dataset.map(lambda x: set_betas_for_reg(x)) # NOTE: Must be at the end
use_skimage_antialias = cfg.DATASETS.get('USE_SKIMAGE_ANTIALIAS', False)
border_mode = {
'constant': cv2.BORDER_CONSTANT,
'replicate': cv2.BORDER_REPLICATE,
}[cfg.DATASETS.get('BORDER_MODE', 'constant')]
# Process the dataset further
dataset = dataset.map(lambda x: ImageDataset.process_webdataset_tar_item(x, train,
augm_config=cfg.DATASETS.CONFIG,
MEAN=MEAN, STD=STD, IMG_SIZE=IMG_SIZE,
BBOX_SHAPE=BBOX_SHAPE,
use_skimage_antialias=use_skimage_antialias,
border_mode=border_mode,
))
if epoch_size is not None:
dataset = dataset.with_epoch(epoch_size)
return dataset
@staticmethod
def process_webdataset_tar_item(item, train,
augm_config=None,
MEAN=DEFAULT_MEAN,
STD=DEFAULT_STD,
IMG_SIZE=DEFAULT_IMG_SIZE,
BBOX_SHAPE=None,
use_skimage_antialias=False,
border_mode=cv2.BORDER_CONSTANT,
):
# Read data from item
key = item['__key__']
image = item['jpg']
data = item['data.pyd']
mask = item['mask']
keypoints_2d = data['keypoints_2d']
keypoints_3d = data['keypoints_3d']
center = data['center']
scale = data['scale']
hand_pose = data['hand_pose']
betas = data['betas']
right = data['right']
has_hand_pose = data['has_hand_pose']
has_betas = data['has_betas']
# image_file = data['image_file']
# Process data
orig_keypoints_2d = keypoints_2d.copy()
center_x = center[0]
center_y = center[1]
bbox_size = expand_to_aspect_ratio(scale*200, target_aspect_ratio=BBOX_SHAPE).max()
if bbox_size < 1:
breakpoint()
mano_params = {'global_orient': hand_pose[:3],
'hand_pose': hand_pose[3:],
'betas': betas
}
has_mano_params = {'global_orient': has_hand_pose,
'hand_pose': has_hand_pose,
'betas': has_betas
}
mano_params_is_axis_angle = {'global_orient': True,
'hand_pose': True,
'betas': False
}
augm_config = copy.deepcopy(augm_config)
# Crop image and (possibly) perform data augmentation
img_rgba = np.concatenate([image, mask.astype(np.uint8)[:,:,None]*255], axis=2)
img_patch_rgba, keypoints_2d, keypoints_3d, mano_params, has_mano_params, img_size, trans = get_example(img_rgba,
center_x, center_y,
bbox_size, bbox_size,
keypoints_2d, keypoints_3d,
mano_params, has_mano_params,
FLIP_KEYPOINT_PERMUTATION,
IMG_SIZE, IMG_SIZE,
MEAN, STD, train, right, augm_config,
is_bgr=False, return_trans=True,
use_skimage_antialias=use_skimage_antialias,
border_mode=border_mode,
)
img_patch = img_patch_rgba[:3,:,:]
mask_patch = (img_patch_rgba[3,:,:] / 255.0).clip(0,1)
if (mask_patch < 0.5).all():
mask_patch = np.ones_like(mask_patch)
item = {}
item['img'] = img_patch
item['mask'] = mask_patch
# item['img_og'] = image
# item['mask_og'] = mask
item['keypoints_2d'] = keypoints_2d.astype(np.float32)
item['keypoints_3d'] = keypoints_3d.astype(np.float32)
item['orig_keypoints_2d'] = orig_keypoints_2d
item['box_center'] = center.copy()
item['box_size'] = bbox_size
item['img_size'] = 1.0 * img_size[::-1].copy()
item['mano_params'] = mano_params
item['has_mano_params'] = has_mano_params
item['mano_params_is_axis_angle'] = mano_params_is_axis_angle
item['_scale'] = scale
item['_trans'] = trans
item['imgname'] = key
# item['idx'] = idx
return item
+213
View File
@@ -0,0 +1,213 @@
import copy
import os
import json
import glob
import numpy as np
import torch
from typing import Any, Dict, List
from yacs.config import CfgNode
import braceexpand
import cv2
from .dataset import Dataset
from .utils import get_example, expand_to_aspect_ratio
from .smplh_prob_filter import poses_check_probable, load_amass_hist_smooth
def expand(s):
return os.path.expanduser(os.path.expandvars(s))
def expand_urls(urls: str|List[str]):
if isinstance(urls, str):
urls = [urls]
urls = [u for url in urls for u in braceexpand.braceexpand(expand(url))]
return urls
AIC_TRAIN_CORRUPT_KEYS = {
'0a047f0124ae48f8eee15a9506ce1449ee1ba669',
'1a703aa174450c02fbc9cfbf578a5435ef403689',
'0394e6dc4df78042929b891dbc24f0fd7ffb6b6d',
'5c032b9626e410441544c7669123ecc4ae077058',
'ca018a7b4c5f53494006ebeeff9b4c0917a55f07',
'4a77adb695bef75a5d34c04d589baf646fe2ba35',
'a0689017b1065c664daef4ae2d14ea03d543217e',
'39596a45cbd21bed4a5f9c2342505532f8ec5cbb',
'3d33283b40610d87db660b62982f797d50a7366b',
}
CORRUPT_KEYS = {
*{f'aic-train/{k}' for k in AIC_TRAIN_CORRUPT_KEYS},
*{f'aic-train-vitpose/{k}' for k in AIC_TRAIN_CORRUPT_KEYS},
}
FLIP_KEYPOINT_PERMUTATION = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
DEFAULT_MEAN = 255. * np.array([0.485, 0.456, 0.406])
DEFAULT_STD = 255. * np.array([0.229, 0.224, 0.225])
DEFAULT_IMG_SIZE = 256
class JsonDataset(Dataset):
def __init__(self,
cfg: CfgNode,
dataset_file: str,
img_dir: str,
right: bool,
train: bool = False,
prune: Dict[str, Any] = {},
**kwargs):
"""
Dataset class used for loading images and corresponding annotations.
Args:
cfg (CfgNode): Model config file.
dataset_file (str): Path to npz file containing dataset info.
img_dir (str): Path to image folder.
train (bool): Whether it is for training or not (enables data augmentation).
"""
super(JsonDataset, self).__init__()
self.train = train
self.cfg = cfg
self.img_size = cfg.MODEL.IMAGE_SIZE
self.mean = 255. * np.array(self.cfg.MODEL.IMAGE_MEAN)
self.std = 255. * np.array(self.cfg.MODEL.IMAGE_STD)
self.img_dir = img_dir
boxes = np.array(json.load(open(dataset_file, 'rb')))
self.imgname = glob.glob(os.path.join(self.img_dir,'*.jpg'))
self.imgname.sort()
self.flip_keypoint_permutation = copy.copy(FLIP_KEYPOINT_PERMUTATION)
num_pose = 3 * (self.cfg.MANO.NUM_HAND_JOINTS + 1)
# Bounding boxes are assumed to be in the center and scale format
boxes = boxes.astype(np.float32)
self.center = (boxes[:, 2:4] + boxes[:, 0:2]) / 2.0
self.scale = 2 * (boxes[:, 2:4] - boxes[:, 0:2]) / 200.0
self.personid = np.arange(len(boxes), dtype=np.int32)
if right:
self.right = np.ones(len(self.imgname), dtype=np.float32)
else:
self.right = np.zeros(len(self.imgname), dtype=np.float32)
assert self.scale.shape == (len(self.center), 2)
# Get gt SMPLX parameters, if available
try:
self.hand_pose = self.data['hand_pose'].astype(np.float32)
self.has_hand_pose = self.data['has_hand_pose'].astype(np.float32)
except:
self.hand_pose = np.zeros((len(self.imgname), num_pose), dtype=np.float32)
self.has_hand_pose = np.zeros(len(self.imgname), dtype=np.float32)
try:
self.betas = self.data['betas'].astype(np.float32)
self.has_betas = self.data['has_betas'].astype(np.float32)
except:
self.betas = np.zeros((len(self.imgname), 10), dtype=np.float32)
self.has_betas = np.zeros(len(self.imgname), dtype=np.float32)
# Try to get 2d keypoints, if available
try:
hand_keypoints_2d = self.data['hand_keypoints_2d']
except:
hand_keypoints_2d = np.zeros((len(self.center), 21, 3))
## Try to get extra 2d keypoints, if available
#try:
# extra_keypoints_2d = self.data['extra_keypoints_2d']
#except KeyError:
# extra_keypoints_2d = np.zeros((len(self.center), 19, 3))
#self.keypoints_2d = np.concatenate((hand_keypoints_2d, extra_keypoints_2d), axis=1).astype(np.float32)
self.keypoints_2d = hand_keypoints_2d
# Try to get 3d keypoints, if available
try:
hand_keypoints_3d = self.data['hand_keypoints_3d'].astype(np.float32)
except:
hand_keypoints_3d = np.zeros((len(self.center), 21, 4), dtype=np.float32)
## Try to get extra 3d keypoints, if available
#try:
# extra_keypoints_3d = self.data['extra_keypoints_3d'].astype(np.float32)
#except KeyError:
# extra_keypoints_3d = np.zeros((len(self.center), 19, 4), dtype=np.float32)
self.keypoints_3d = hand_keypoints_3d
#body_keypoints_3d[:, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], -1] = 0
#self.keypoints_3d = np.concatenate((body_keypoints_3d, extra_keypoints_3d), axis=1).astype(np.float32)
def __len__(self) -> int:
return len(self.scale)
def __getitem__(self, idx: int) -> Dict:
"""
Returns an example from the dataset.
"""
try:
image_file = self.imgname[idx].decode('utf-8')
except AttributeError:
image_file = self.imgname[idx]
keypoints_2d = self.keypoints_2d[idx].copy()
keypoints_3d = self.keypoints_3d[idx].copy()
center = self.center[idx].copy()
center_x = center[0]
center_y = center[1]
scale = self.scale[idx]
right = self.right[idx].copy()
BBOX_SHAPE = self.cfg.MODEL.get('BBOX_SHAPE', None)
#bbox_size = expand_to_aspect_ratio(scale*200, target_aspect_ratio=BBOX_SHAPE).max()
bbox_size = ((scale*200).max())
bbox_expand_factor = bbox_size / ((scale*200).max())
hand_pose = self.hand_pose[idx].copy().astype(np.float32)
betas = self.betas[idx].copy().astype(np.float32)
has_hand_pose = self.has_hand_pose[idx].copy()
has_betas = self.has_betas[idx].copy()
mano_params = {'global_orient': hand_pose[:3],
'hand_pose': hand_pose[3:],
'betas': betas
}
has_mano_params = {'global_orient': has_hand_pose,
'hand_pose': has_hand_pose,
'betas': has_betas
}
mano_params_is_axis_angle = {'global_orient': True,
'hand_pose': True,
'betas': False
}
augm_config = self.cfg.DATASETS.CONFIG
# Crop image and (possibly) perform data augmentation
img_patch, keypoints_2d, keypoints_3d, mano_params, has_mano_params, img_size = get_example(image_file,
center_x, center_y,
bbox_size, bbox_size,
keypoints_2d, keypoints_3d,
mano_params, has_mano_params,
self.flip_keypoint_permutation,
self.img_size, self.img_size,
self.mean, self.std, self.train, right, augm_config)
item = {}
# These are the keypoints in the original image coordinates (before cropping)
orig_keypoints_2d = self.keypoints_2d[idx].copy()
item['img'] = img_patch
item['keypoints_2d'] = keypoints_2d.astype(np.float32)
item['keypoints_3d'] = keypoints_3d.astype(np.float32)
item['orig_keypoints_2d'] = orig_keypoints_2d
item['box_center'] = self.center[idx].copy()
item['box_size'] = bbox_size
item['bbox_expand_factor'] = bbox_expand_factor
item['img_size'] = 1.0 * img_size[::-1].copy()
item['mano_params'] = mano_params
item['has_mano_params'] = has_mano_params
item['mano_params_is_axis_angle'] = mano_params_is_axis_angle
item['imgname'] = image_file
item['personid'] = int(self.personid[idx])
item['idx'] = idx
item['_scale'] = scale
item['right'] = self.right[idx].copy()
return item
+25
View File
@@ -0,0 +1,25 @@
import numpy as np
from typing import Dict
class MoCapDataset:
def __init__(self, dataset_file: str):
"""
Dataset class used for loading a dataset of unpaired MANO parameter annotations
Args:
cfg (CfgNode): Model config file.
dataset_file (str): Path to npz file containing dataset info.
"""
data = np.load(dataset_file)
self.pose = data['hand_pose'].astype(np.float32)[:, 3:]
self.betas = data['betas'].astype(np.float32)
self.length = len(self.pose)
def __getitem__(self, idx: int) -> Dict:
pose = self.pose[idx].copy()
betas = self.betas[idx].copy()
item = {'hand_pose': pose, 'betas': betas}
return item
def __len__(self) -> int:
return self.length
+993
View File
@@ -0,0 +1,993 @@
"""
Parts of the code are taken or adapted from
https://github.com/mkocabas/EpipolarPose/blob/master/lib/utils/img_utils.py
"""
import torch
import numpy as np
from skimage.transform import rotate, resize
from skimage.filters import gaussian
import random
import cv2
from typing import List, Dict, Tuple
from yacs.config import CfgNode
def expand_to_aspect_ratio(input_shape, target_aspect_ratio=None):
"""Increase the size of the bounding box to match the target shape."""
if target_aspect_ratio is None:
return input_shape
try:
w , h = input_shape
except (ValueError, TypeError):
return input_shape
w_t, h_t = target_aspect_ratio
if h / w < h_t / w_t:
h_new = max(w * h_t / w_t, h)
w_new = w
else:
h_new = h
w_new = max(h * w_t / h_t, w)
if h_new < h or w_new < w:
breakpoint()
return np.array([w_new, h_new])
def do_augmentation(aug_config: CfgNode) -> Tuple:
"""
Compute random augmentation parameters.
Args:
aug_config (CfgNode): Config containing augmentation parameters.
Returns:
scale (float): Box rescaling factor.
rot (float): Random image rotation.
do_flip (bool): Whether to flip image or not.
do_extreme_crop (bool): Whether to apply extreme cropping (as proposed in EFT).
color_scale (List): Color rescaling factor
tx (float): Random translation along the x axis.
ty (float): Random translation along the y axis.
"""
tx = np.clip(np.random.randn(), -1.0, 1.0) * aug_config.TRANS_FACTOR
ty = np.clip(np.random.randn(), -1.0, 1.0) * aug_config.TRANS_FACTOR
scale = np.clip(np.random.randn(), -1.0, 1.0) * aug_config.SCALE_FACTOR + 1.0
rot = np.clip(np.random.randn(), -2.0,
2.0) * aug_config.ROT_FACTOR if random.random() <= aug_config.ROT_AUG_RATE else 0
do_flip = aug_config.DO_FLIP and random.random() <= aug_config.FLIP_AUG_RATE
do_extreme_crop = random.random() <= aug_config.EXTREME_CROP_AUG_RATE
extreme_crop_lvl = aug_config.get('EXTREME_CROP_AUG_LEVEL', 0)
# extreme_crop_lvl = 0
c_up = 1.0 + aug_config.COLOR_SCALE
c_low = 1.0 - aug_config.COLOR_SCALE
color_scale = [random.uniform(c_low, c_up), random.uniform(c_low, c_up), random.uniform(c_low, c_up)]
return scale, rot, do_flip, do_extreme_crop, extreme_crop_lvl, color_scale, tx, ty
def rotate_2d(pt_2d: np.array, rot_rad: float) -> np.array:
"""
Rotate a 2D point on the x-y plane.
Args:
pt_2d (np.array): Input 2D point with shape (2,).
rot_rad (float): Rotation angle
Returns:
np.array: Rotated 2D point.
"""
x = pt_2d[0]
y = pt_2d[1]
sn, cs = np.sin(rot_rad), np.cos(rot_rad)
xx = x * cs - y * sn
yy = x * sn + y * cs
return np.array([xx, yy], dtype=np.float32)
def gen_trans_from_patch_cv(c_x: float, c_y: float,
src_width: float, src_height: float,
dst_width: float, dst_height: float,
scale: float, rot: float) -> np.array:
"""
Create transformation matrix for the bounding box crop.
Args:
c_x (float): Bounding box center x coordinate in the original image.
c_y (float): Bounding box center y coordinate in the original image.
src_width (float): Bounding box width.
src_height (float): Bounding box height.
dst_width (float): Output box width.
dst_height (float): Output box height.
scale (float): Rescaling factor for the bounding box (augmentation).
rot (float): Random rotation applied to the box.
Returns:
trans (np.array): Target geometric transformation.
"""
# augment size with scale
src_w = src_width * scale
src_h = src_height * scale
src_center = np.zeros(2)
src_center[0] = c_x
src_center[1] = c_y
# augment rotation
rot_rad = np.pi * rot / 180
src_downdir = rotate_2d(np.array([0, src_h * 0.5], dtype=np.float32), rot_rad)
src_rightdir = rotate_2d(np.array([src_w * 0.5, 0], dtype=np.float32), rot_rad)
dst_w = dst_width
dst_h = dst_height
dst_center = np.array([dst_w * 0.5, dst_h * 0.5], dtype=np.float32)
dst_downdir = np.array([0, dst_h * 0.5], dtype=np.float32)
dst_rightdir = np.array([dst_w * 0.5, 0], dtype=np.float32)
src = np.zeros((3, 2), dtype=np.float32)
src[0, :] = src_center
src[1, :] = src_center + src_downdir
src[2, :] = src_center + src_rightdir
dst = np.zeros((3, 2), dtype=np.float32)
dst[0, :] = dst_center
dst[1, :] = dst_center + dst_downdir
dst[2, :] = dst_center + dst_rightdir
trans = cv2.getAffineTransform(np.float32(src), np.float32(dst))
return trans
def trans_point2d(pt_2d: np.array, trans: np.array):
"""
Transform a 2D point using translation matrix trans.
Args:
pt_2d (np.array): Input 2D point with shape (2,).
trans (np.array): Transformation matrix.
Returns:
np.array: Transformed 2D point.
"""
src_pt = np.array([pt_2d[0], pt_2d[1], 1.]).T
dst_pt = np.dot(trans, src_pt)
return dst_pt[0:2]
def get_transform(center, scale, res, rot=0):
"""Generate transformation matrix."""
"""Taken from PARE: https://github.com/mkocabas/PARE/blob/6e0caca86c6ab49ff80014b661350958e5b72fd8/pare/utils/image_utils.py"""
h = 200 * scale
t = np.zeros((3, 3))
t[0, 0] = float(res[1]) / h
t[1, 1] = float(res[0]) / h
t[0, 2] = res[1] * (-float(center[0]) / h + .5)
t[1, 2] = res[0] * (-float(center[1]) / h + .5)
t[2, 2] = 1
if not rot == 0:
rot = -rot # To match direction of rotation from cropping
rot_mat = np.zeros((3, 3))
rot_rad = rot * np.pi / 180
sn, cs = np.sin(rot_rad), np.cos(rot_rad)
rot_mat[0, :2] = [cs, -sn]
rot_mat[1, :2] = [sn, cs]
rot_mat[2, 2] = 1
# Need to rotate around center
t_mat = np.eye(3)
t_mat[0, 2] = -res[1] / 2
t_mat[1, 2] = -res[0] / 2
t_inv = t_mat.copy()
t_inv[:2, 2] *= -1
t = np.dot(t_inv, np.dot(rot_mat, np.dot(t_mat, t)))
return t
def transform(pt, center, scale, res, invert=0, rot=0, as_int=True):
"""Transform pixel location to different reference."""
"""Taken from PARE: https://github.com/mkocabas/PARE/blob/6e0caca86c6ab49ff80014b661350958e5b72fd8/pare/utils/image_utils.py"""
t = get_transform(center, scale, res, rot=rot)
if invert:
t = np.linalg.inv(t)
new_pt = np.array([pt[0] - 1, pt[1] - 1, 1.]).T
new_pt = np.dot(t, new_pt)
if as_int:
new_pt = new_pt.astype(int)
return new_pt[:2] + 1
def crop_img(img, ul, br, border_mode=cv2.BORDER_CONSTANT, border_value=0):
c_x = (ul[0] + br[0])/2
c_y = (ul[1] + br[1])/2
bb_width = patch_width = br[0] - ul[0]
bb_height = patch_height = br[1] - ul[1]
trans = gen_trans_from_patch_cv(c_x, c_y, bb_width, bb_height, patch_width, patch_height, 1.0, 0)
img_patch = cv2.warpAffine(img, trans, (int(patch_width), int(patch_height)),
flags=cv2.INTER_LINEAR,
borderMode=border_mode,
borderValue=border_value
)
# Force borderValue=cv2.BORDER_CONSTANT for alpha channel
if (img.shape[2] == 4) and (border_mode != cv2.BORDER_CONSTANT):
img_patch[:,:,3] = cv2.warpAffine(img[:,:,3], trans, (int(patch_width), int(patch_height)),
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT,
)
return img_patch
def generate_image_patch_skimage(img: np.array, c_x: float, c_y: float,
bb_width: float, bb_height: float,
patch_width: float, patch_height: float,
do_flip: bool, scale: float, rot: float,
border_mode=cv2.BORDER_CONSTANT, border_value=0) -> Tuple[np.array, np.array]:
"""
Crop image according to the supplied bounding box.
Args:
img (np.array): Input image of shape (H, W, 3)
c_x (float): Bounding box center x coordinate in the original image.
c_y (float): Bounding box center y coordinate in the original image.
bb_width (float): Bounding box width.
bb_height (float): Bounding box height.
patch_width (float): Output box width.
patch_height (float): Output box height.
do_flip (bool): Whether to flip image or not.
scale (float): Rescaling factor for the bounding box (augmentation).
rot (float): Random rotation applied to the box.
Returns:
img_patch (np.array): Cropped image patch of shape (patch_height, patch_height, 3)
trans (np.array): Transformation matrix.
"""
img_height, img_width, img_channels = img.shape
if do_flip:
img = img[:, ::-1, :]
c_x = img_width - c_x - 1
trans = gen_trans_from_patch_cv(c_x, c_y, bb_width, bb_height, patch_width, patch_height, scale, rot)
#img_patch = cv2.warpAffine(img, trans, (int(patch_width), int(patch_height)), flags=cv2.INTER_LINEAR)
# skimage
center = np.zeros(2)
center[0] = c_x
center[1] = c_y
res = np.zeros(2)
res[0] = patch_width
res[1] = patch_height
# assumes bb_width = bb_height
# assumes patch_width = patch_height
assert bb_width == bb_height, f'{bb_width=} != {bb_height=}'
assert patch_width == patch_height, f'{patch_width=} != {patch_height=}'
scale1 = scale*bb_width/200.
# Upper left point
ul = np.array(transform([1, 1], center, scale1, res, invert=1, as_int=False)) - 1
# Bottom right point
br = np.array(transform([res[0] + 1,
res[1] + 1], center, scale1, res, invert=1, as_int=False)) - 1
# Padding so that when rotated proper amount of context is included
try:
pad = int(np.linalg.norm(br - ul) / 2 - float(br[1] - ul[1]) / 2) + 1
except:
breakpoint()
if not rot == 0:
ul -= pad
br += pad
if False:
# Old way of cropping image
ul_int = ul.astype(int)
br_int = br.astype(int)
new_shape = [br_int[1] - ul_int[1], br_int[0] - ul_int[0]]
if len(img.shape) > 2:
new_shape += [img.shape[2]]
new_img = np.zeros(new_shape)
# Range to fill new array
new_x = max(0, -ul_int[0]), min(br_int[0], len(img[0])) - ul_int[0]
new_y = max(0, -ul_int[1]), min(br_int[1], len(img)) - ul_int[1]
# Range to sample from original image
old_x = max(0, ul_int[0]), min(len(img[0]), br_int[0])
old_y = max(0, ul_int[1]), min(len(img), br_int[1])
new_img[new_y[0]:new_y[1], new_x[0]:new_x[1]] = img[old_y[0]:old_y[1],
old_x[0]:old_x[1]]
# New way of cropping image
new_img = crop_img(img, ul, br, border_mode=border_mode, border_value=border_value).astype(np.float32)
# print(f'{new_img.shape=}')
# print(f'{new_img1.shape=}')
# print(f'{np.allclose(new_img, new_img1)=}')
# print(f'{img.dtype=}')
if not rot == 0:
# Remove padding
new_img = rotate(new_img, rot) # scipy.misc.imrotate(new_img, rot)
new_img = new_img[pad:-pad, pad:-pad]
if new_img.shape[0] < 1 or new_img.shape[1] < 1:
print(f'{img.shape=}')
print(f'{new_img.shape=}')
print(f'{ul=}')
print(f'{br=}')
print(f'{pad=}')
print(f'{rot=}')
breakpoint()
# resize image
new_img = resize(new_img, res) # scipy.misc.imresize(new_img, res)
new_img = np.clip(new_img, 0, 255).astype(np.uint8)
return new_img, trans
def generate_image_patch_cv2(img: np.array, c_x: float, c_y: float,
bb_width: float, bb_height: float,
patch_width: float, patch_height: float,
do_flip: bool, scale: float, rot: float,
border_mode=cv2.BORDER_CONSTANT, border_value=0) -> Tuple[np.array, np.array]:
"""
Crop the input image and return the crop and the corresponding transformation matrix.
Args:
img (np.array): Input image of shape (H, W, 3)
c_x (float): Bounding box center x coordinate in the original image.
c_y (float): Bounding box center y coordinate in the original image.
bb_width (float): Bounding box width.
bb_height (float): Bounding box height.
patch_width (float): Output box width.
patch_height (float): Output box height.
do_flip (bool): Whether to flip image or not.
scale (float): Rescaling factor for the bounding box (augmentation).
rot (float): Random rotation applied to the box.
Returns:
img_patch (np.array): Cropped image patch of shape (patch_height, patch_height, 3)
trans (np.array): Transformation matrix.
"""
img_height, img_width, img_channels = img.shape
if do_flip:
img = img[:, ::-1, :]
c_x = img_width - c_x - 1
trans = gen_trans_from_patch_cv(c_x, c_y, bb_width, bb_height, patch_width, patch_height, scale, rot)
img_patch = cv2.warpAffine(img, trans, (int(patch_width), int(patch_height)),
flags=cv2.INTER_LINEAR,
borderMode=border_mode,
borderValue=border_value,
)
# Force borderValue=cv2.BORDER_CONSTANT for alpha channel
if (img.shape[2] == 4) and (border_mode != cv2.BORDER_CONSTANT):
img_patch[:,:,3] = cv2.warpAffine(img[:,:,3], trans, (int(patch_width), int(patch_height)),
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT,
)
return img_patch, trans
def convert_cvimg_to_tensor(cvimg: np.array):
"""
Convert image from HWC to CHW format.
Args:
cvimg (np.array): Image of shape (H, W, 3) as loaded by OpenCV.
Returns:
np.array: Output image of shape (3, H, W).
"""
# from h,w,c(OpenCV) to c,h,w
img = cvimg.copy()
img = np.transpose(img, (2, 0, 1))
# from int to float
img = img.astype(np.float32)
return img
def fliplr_params(mano_params: Dict, has_mano_params: Dict) -> Tuple[Dict, Dict]:
"""
Flip MANO parameters when flipping the image.
Args:
mano_params (Dict): MANO parameter annotations.
has_mano_params (Dict): Whether MANO annotations are valid.
Returns:
Dict, Dict: Flipped MANO parameters and valid flags.
"""
global_orient = mano_params['global_orient'].copy()
hand_pose = mano_params['hand_pose'].copy()
betas = mano_params['betas'].copy()
has_global_orient = has_mano_params['global_orient'].copy()
has_hand_pose = has_mano_params['hand_pose'].copy()
has_betas = has_mano_params['betas'].copy()
global_orient[1::3] *= -1
global_orient[2::3] *= -1
hand_pose[1::3] *= -1
hand_pose[2::3] *= -1
mano_params = {'global_orient': global_orient.astype(np.float32),
'hand_pose': hand_pose.astype(np.float32),
'betas': betas.astype(np.float32)
}
has_mano_params = {'global_orient': has_global_orient,
'hand_pose': has_hand_pose,
'betas': has_betas
}
return mano_params, has_mano_params
def fliplr_keypoints(joints: np.array, width: float, flip_permutation: List[int]) -> np.array:
"""
Flip 2D or 3D keypoints.
Args:
joints (np.array): Array of shape (N, 3) or (N, 4) containing 2D or 3D keypoint locations and confidence.
flip_permutation (List): Permutation to apply after flipping.
Returns:
np.array: Flipped 2D or 3D keypoints with shape (N, 3) or (N, 4) respectively.
"""
joints = joints.copy()
# Flip horizontal
joints[:, 0] = width - joints[:, 0] - 1
joints = joints[flip_permutation, :]
return joints
def keypoint_3d_processing(keypoints_3d: np.array, flip_permutation: List[int], rot: float, do_flip: float) -> np.array:
"""
Process 3D keypoints (rotation/flipping).
Args:
keypoints_3d (np.array): Input array of shape (N, 4) containing the 3D keypoints and confidence.
flip_permutation (List): Permutation to apply after flipping.
rot (float): Random rotation applied to the keypoints.
do_flip (bool): Whether to flip keypoints or not.
Returns:
np.array: Transformed 3D keypoints with shape (N, 4).
"""
if do_flip:
keypoints_3d = fliplr_keypoints(keypoints_3d, 1, flip_permutation)
# in-plane rotation
rot_mat = np.eye(3)
if not rot == 0:
rot_rad = -rot * np.pi / 180
sn,cs = np.sin(rot_rad), np.cos(rot_rad)
rot_mat[0,:2] = [cs, -sn]
rot_mat[1,:2] = [sn, cs]
keypoints_3d[:, :-1] = np.einsum('ij,kj->ki', rot_mat, keypoints_3d[:, :-1])
# flip the x coordinates
keypoints_3d = keypoints_3d.astype('float32')
return keypoints_3d
def rot_aa(aa: np.array, rot: float) -> np.array:
"""
Rotate axis angle parameters.
Args:
aa (np.array): Axis-angle vector of shape (3,).
rot (np.array): Rotation angle in degrees.
Returns:
np.array: Rotated axis-angle vector.
"""
# pose parameters
R = np.array([[np.cos(np.deg2rad(-rot)), -np.sin(np.deg2rad(-rot)), 0],
[np.sin(np.deg2rad(-rot)), np.cos(np.deg2rad(-rot)), 0],
[0, 0, 1]])
# find the rotation of the hand in camera frame
per_rdg, _ = cv2.Rodrigues(aa)
# apply the global rotation to the global orientation
resrot, _ = cv2.Rodrigues(np.dot(R,per_rdg))
aa = (resrot.T)[0]
return aa.astype(np.float32)
def mano_param_processing(mano_params: Dict, has_mano_params: Dict, rot: float, do_flip: bool) -> Tuple[Dict, Dict]:
"""
Apply random augmentations to the MANO parameters.
Args:
mano_params (Dict): MANO parameter annotations.
has_mano_params (Dict): Whether mano annotations are valid.
rot (float): Random rotation applied to the keypoints.
do_flip (bool): Whether to flip keypoints or not.
Returns:
Dict, Dict: Transformed MANO parameters and valid flags.
"""
if do_flip:
mano_params, has_mano_params = fliplr_params(mano_params, has_mano_params)
mano_params['global_orient'] = rot_aa(mano_params['global_orient'], rot)
return mano_params, has_mano_params
def get_example(img_path: str|np.ndarray, center_x: float, center_y: float,
width: float, height: float,
keypoints_2d: np.array, keypoints_3d: np.array,
mano_params: Dict, has_mano_params: Dict,
flip_kp_permutation: List[int],
patch_width: int, patch_height: int,
mean: np.array, std: np.array,
do_augment: bool, is_right: bool, augm_config: CfgNode,
is_bgr: bool = True,
use_skimage_antialias: bool = False,
border_mode: int = cv2.BORDER_CONSTANT,
return_trans: bool = False) -> Tuple:
"""
Get an example from the dataset and (possibly) apply random augmentations.
Args:
img_path (str): Image filename
center_x (float): Bounding box center x coordinate in the original image.
center_y (float): Bounding box center y coordinate in the original image.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array with shape (N,3) containing the 2D keypoints in the original image coordinates.
keypoints_3d (np.array): Array with shape (N,4) containing the 3D keypoints.
mano_params (Dict): MANO parameter annotations.
has_mano_params (Dict): Whether MANO annotations are valid.
flip_kp_permutation (List): Permutation to apply to the keypoints after flipping.
patch_width (float): Output box width.
patch_height (float): Output box height.
mean (np.array): Array of shape (3,) containing the mean for normalizing the input image.
std (np.array): Array of shape (3,) containing the std for normalizing the input image.
do_augment (bool): Whether to apply data augmentation or not.
aug_config (CfgNode): Config containing augmentation parameters.
Returns:
return img_patch, keypoints_2d, keypoints_3d, mano_params, has_mano_params, img_size
img_patch (np.array): Cropped image patch of shape (3, patch_height, patch_height)
keypoints_2d (np.array): Array with shape (N,3) containing the transformed 2D keypoints.
keypoints_3d (np.array): Array with shape (N,4) containing the transformed 3D keypoints.
mano_params (Dict): Transformed MANO parameters.
has_mano_params (Dict): Valid flag for transformed MANO parameters.
img_size (np.array): Image size of the original image.
"""
if isinstance(img_path, str):
# 1. load image
cvimg = cv2.imread(img_path, cv2.IMREAD_COLOR | cv2.IMREAD_IGNORE_ORIENTATION)
if not isinstance(cvimg, np.ndarray):
raise IOError("Fail to read %s" % img_path)
elif isinstance(img_path, np.ndarray):
cvimg = img_path
else:
raise TypeError('img_path must be either a string or a numpy array')
img_height, img_width, img_channels = cvimg.shape
img_size = np.array([img_height, img_width])
# 2. get augmentation params
if do_augment:
scale, rot, do_flip, do_extreme_crop, extreme_crop_lvl, color_scale, tx, ty = do_augmentation(augm_config)
else:
scale, rot, do_flip, do_extreme_crop, extreme_crop_lvl, color_scale, tx, ty = 1.0, 0, False, False, 0, [1.0, 1.0, 1.0], 0., 0.
# if it's a left hand, we flip
if not is_right:
do_flip = True
if width < 1 or height < 1:
breakpoint()
if do_extreme_crop:
if extreme_crop_lvl == 0:
center_x1, center_y1, width1, height1 = extreme_cropping(center_x, center_y, width, height, keypoints_2d)
elif extreme_crop_lvl == 1:
center_x1, center_y1, width1, height1 = extreme_cropping_aggressive(center_x, center_y, width, height, keypoints_2d)
THRESH = 4
if width1 < THRESH or height1 < THRESH:
# print(f'{do_extreme_crop=}')
# print(f'width: {width}, height: {height}')
# print(f'width1: {width1}, height1: {height1}')
# print(f'center_x: {center_x}, center_y: {center_y}')
# print(f'center_x1: {center_x1}, center_y1: {center_y1}')
# print(f'keypoints_2d: {keypoints_2d}')
# print(f'\n\n', flush=True)
# breakpoint()
pass
# print(f'skip ==> width1: {width1}, height1: {height1}, width: {width}, height: {height}')
else:
center_x, center_y, width, height = center_x1, center_y1, width1, height1
center_x += width * tx
center_y += height * ty
# Process 3D keypoints
keypoints_3d = keypoint_3d_processing(keypoints_3d, flip_kp_permutation, rot, do_flip)
# 3. generate image patch
if use_skimage_antialias:
# Blur image to avoid aliasing artifacts
downsampling_factor = (patch_width / (width*scale))
if downsampling_factor > 1.1:
cvimg = gaussian(cvimg, sigma=(downsampling_factor-1)/2, channel_axis=2, preserve_range=True, truncate=3.0)
img_patch_cv, trans = generate_image_patch_cv2(cvimg,
center_x, center_y,
width, height,
patch_width, patch_height,
do_flip, scale, rot,
border_mode=border_mode)
# img_patch_cv, trans = generate_image_patch_skimage(cvimg,
# center_x, center_y,
# width, height,
# patch_width, patch_height,
# do_flip, scale, rot,
# border_mode=border_mode)
image = img_patch_cv.copy()
if is_bgr:
image = image[:, :, ::-1]
img_patch_cv = image.copy()
img_patch = convert_cvimg_to_tensor(image)
mano_params, has_mano_params = mano_param_processing(mano_params, has_mano_params, rot, do_flip)
# apply normalization
for n_c in range(min(img_channels, 3)):
img_patch[n_c, :, :] = np.clip(img_patch[n_c, :, :] * color_scale[n_c], 0, 255)
if mean is not None and std is not None:
img_patch[n_c, :, :] = (img_patch[n_c, :, :] - mean[n_c]) / std[n_c]
if do_flip:
keypoints_2d = fliplr_keypoints(keypoints_2d, img_width, flip_kp_permutation)
for n_jt in range(len(keypoints_2d)):
keypoints_2d[n_jt, 0:2] = trans_point2d(keypoints_2d[n_jt, 0:2], trans)
keypoints_2d[:, :-1] = keypoints_2d[:, :-1] / patch_width - 0.5
if not return_trans:
return img_patch, keypoints_2d, keypoints_3d, mano_params, has_mano_params, img_size
else:
return img_patch, keypoints_2d, keypoints_3d, mano_params, has_mano_params, img_size, trans
def crop_to_hips(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array) -> Tuple:
"""
Extreme cropping: Crop the box up to the hip locations.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
lower_body_keypoints = [10, 11, 13, 14, 19, 20, 21, 22, 23, 24, 25+0, 25+1, 25+4, 25+5]
keypoints_2d[lower_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def crop_to_shoulders(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box up to the shoulder locations.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
lower_body_keypoints = [3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19, 20, 21, 22, 23, 24] + [25 + i for i in [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 14, 15, 16]]
keypoints_2d[lower_body_keypoints, :] = 0
center, scale = get_bbox(keypoints_2d)
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.2 * scale[0]
height = 1.2 * scale[1]
return center_x, center_y, width, height
def crop_to_head(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the head.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
lower_body_keypoints = [3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19, 20, 21, 22, 23, 24] + [25 + i for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16]]
keypoints_2d[lower_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.3 * scale[0]
height = 1.3 * scale[1]
return center_x, center_y, width, height
def crop_torso_only(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the torso.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
nontorso_body_keypoints = [0, 3, 4, 6, 7, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] + [25 + i for i in [0, 1, 4, 5, 6, 7, 10, 11, 13, 17, 18]]
keypoints_2d[nontorso_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def crop_rightarm_only(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the right arm.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
nonrightarm_body_keypoints = [0, 1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] + [25 + i for i in [0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]
keypoints_2d[nonrightarm_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def crop_leftarm_only(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the left arm.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
nonleftarm_body_keypoints = [0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] + [25 + i for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 15, 16, 17, 18]]
keypoints_2d[nonleftarm_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def crop_legs_only(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the legs.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
nonlegs_body_keypoints = [0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 17, 18] + [25 + i for i in [6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18]]
keypoints_2d[nonlegs_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def crop_rightleg_only(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the right leg.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
nonrightleg_body_keypoints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] + [25 + i for i in [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]
keypoints_2d[nonrightleg_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def crop_leftleg_only(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array):
"""
Extreme cropping: Crop the box and keep on only the left leg.
Args:
center_x (float): x coordinate of the bounding box center.
center_y (float): y coordinate of the bounding box center.
width (float): Bounding box width.
height (float): Bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
center_x (float): x coordinate of the new bounding box center.
center_y (float): y coordinate of the new bounding box center.
width (float): New bounding box width.
height (float): New bounding box height.
"""
keypoints_2d = keypoints_2d.copy()
nonleftleg_body_keypoints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 22, 23, 24] + [25 + i for i in [0, 1, 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]
keypoints_2d[nonleftleg_body_keypoints, :] = 0
if keypoints_2d[:, -1].sum() > 1:
center, scale = get_bbox(keypoints_2d)
center_x = center[0]
center_y = center[1]
width = 1.1 * scale[0]
height = 1.1 * scale[1]
return center_x, center_y, width, height
def full_body(keypoints_2d: np.array) -> bool:
"""
Check if all main body joints are visible.
Args:
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
bool: True if all main body joints are visible.
"""
body_keypoints_openpose = [2, 3, 4, 5, 6, 7, 10, 11, 13, 14]
body_keypoints = [25 + i for i in [8, 7, 6, 9, 10, 11, 1, 0, 4, 5]]
return (np.maximum(keypoints_2d[body_keypoints, -1], keypoints_2d[body_keypoints_openpose, -1]) > 0).sum() == len(body_keypoints)
def upper_body(keypoints_2d: np.array):
"""
Check if all upper body joints are visible.
Args:
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
Returns:
bool: True if all main body joints are visible.
"""
lower_body_keypoints_openpose = [10, 11, 13, 14]
lower_body_keypoints = [25 + i for i in [1, 0, 4, 5]]
upper_body_keypoints_openpose = [0, 1, 15, 16, 17, 18]
upper_body_keypoints = [25+8, 25+9, 25+12, 25+13, 25+17, 25+18]
return ((keypoints_2d[lower_body_keypoints + lower_body_keypoints_openpose, -1] > 0).sum() == 0)\
and ((keypoints_2d[upper_body_keypoints + upper_body_keypoints_openpose, -1] > 0).sum() >= 2)
def get_bbox(keypoints_2d: np.array, rescale: float = 1.2) -> Tuple:
"""
Get center and scale for bounding box from openpose detections.
Args:
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
rescale (float): Scale factor to rescale bounding boxes computed from the keypoints.
Returns:
center (np.array): Array of shape (2,) containing the new bounding box center.
scale (float): New bounding box scale.
"""
valid = keypoints_2d[:,-1] > 0
valid_keypoints = keypoints_2d[valid][:,:-1]
center = 0.5 * (valid_keypoints.max(axis=0) + valid_keypoints.min(axis=0))
bbox_size = (valid_keypoints.max(axis=0) - valid_keypoints.min(axis=0))
# adjust bounding box tightness
scale = bbox_size
scale *= rescale
return center, scale
def extreme_cropping(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array) -> Tuple:
"""
Perform extreme cropping
Args:
center_x (float): x coordinate of bounding box center.
center_y (float): y coordinate of bounding box center.
width (float): bounding box width.
height (float): bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
rescale (float): Scale factor to rescale bounding boxes computed from the keypoints.
Returns:
center_x (float): x coordinate of bounding box center.
center_y (float): y coordinate of bounding box center.
width (float): bounding box width.
height (float): bounding box height.
"""
p = torch.rand(1).item()
if full_body(keypoints_2d):
if p < 0.7:
center_x, center_y, width, height = crop_to_hips(center_x, center_y, width, height, keypoints_2d)
elif p < 0.9:
center_x, center_y, width, height = crop_to_shoulders(center_x, center_y, width, height, keypoints_2d)
else:
center_x, center_y, width, height = crop_to_head(center_x, center_y, width, height, keypoints_2d)
elif upper_body(keypoints_2d):
if p < 0.9:
center_x, center_y, width, height = crop_to_shoulders(center_x, center_y, width, height, keypoints_2d)
else:
center_x, center_y, width, height = crop_to_head(center_x, center_y, width, height, keypoints_2d)
return center_x, center_y, max(width, height), max(width, height)
def extreme_cropping_aggressive(center_x: float, center_y: float, width: float, height: float, keypoints_2d: np.array) -> Tuple:
"""
Perform aggressive extreme cropping
Args:
center_x (float): x coordinate of bounding box center.
center_y (float): y coordinate of bounding box center.
width (float): bounding box width.
height (float): bounding box height.
keypoints_2d (np.array): Array of shape (N, 3) containing 2D keypoint locations.
rescale (float): Scale factor to rescale bounding boxes computed from the keypoints.
Returns:
center_x (float): x coordinate of bounding box center.
center_y (float): y coordinate of bounding box center.
width (float): bounding box width.
height (float): bounding box height.
"""
p = torch.rand(1).item()
if full_body(keypoints_2d):
if p < 0.2:
center_x, center_y, width, height = crop_to_hips(center_x, center_y, width, height, keypoints_2d)
elif p < 0.3:
center_x, center_y, width, height = crop_to_shoulders(center_x, center_y, width, height, keypoints_2d)
elif p < 0.4:
center_x, center_y, width, height = crop_to_head(center_x, center_y, width, height, keypoints_2d)
elif p < 0.5:
center_x, center_y, width, height = crop_torso_only(center_x, center_y, width, height, keypoints_2d)
elif p < 0.6:
center_x, center_y, width, height = crop_rightarm_only(center_x, center_y, width, height, keypoints_2d)
elif p < 0.7:
center_x, center_y, width, height = crop_leftarm_only(center_x, center_y, width, height, keypoints_2d)
elif p < 0.8:
center_x, center_y, width, height = crop_legs_only(center_x, center_y, width, height, keypoints_2d)
elif p < 0.9:
center_x, center_y, width, height = crop_rightleg_only(center_x, center_y, width, height, keypoints_2d)
else:
center_x, center_y, width, height = crop_leftleg_only(center_x, center_y, width, height, keypoints_2d)
elif upper_body(keypoints_2d):
if p < 0.2:
center_x, center_y, width, height = crop_to_shoulders(center_x, center_y, width, height, keypoints_2d)
elif p < 0.4:
center_x, center_y, width, height = crop_to_head(center_x, center_y, width, height, keypoints_2d)
elif p < 0.6:
center_x, center_y, width, height = crop_torso_only(center_x, center_y, width, height, keypoints_2d)
elif p < 0.8:
center_x, center_y, width, height = crop_rightarm_only(center_x, center_y, width, height, keypoints_2d)
else:
center_x, center_y, width, height = crop_leftarm_only(center_x, center_y, width, height, keypoints_2d)
return center_x, center_y, max(width, height), max(width, height)
+95
View File
@@ -0,0 +1,95 @@
from typing import Dict
import cv2
import numpy as np
from skimage.filters import gaussian
from yacs.config import CfgNode
import torch
from .utils import (convert_cvimg_to_tensor,
expand_to_aspect_ratio,
generate_image_patch_cv2)
DEFAULT_MEAN = 255. * np.array([0.485, 0.456, 0.406])
DEFAULT_STD = 255. * np.array([0.229, 0.224, 0.225])
class ViTDetDataset(torch.utils.data.Dataset):
def __init__(self,
cfg: CfgNode,
img_cv2: np.array,
boxes: np.array,
right: np.array,
rescale_factor=2.5,
train: bool = False,
**kwargs):
super().__init__()
self.cfg = cfg
self.img_cv2 = img_cv2
# self.boxes = boxes
assert train == False, "ViTDetDataset is only for inference"
self.train = train
self.img_size = cfg.MODEL.IMAGE_SIZE
self.mean = 255. * np.array(self.cfg.MODEL.IMAGE_MEAN)
self.std = 255. * np.array(self.cfg.MODEL.IMAGE_STD)
# Preprocess annotations
boxes = boxes.astype(np.float32)
self.center = (boxes[:, 2:4] + boxes[:, 0:2]) / 2.0
self.scale = rescale_factor * (boxes[:, 2:4] - boxes[:, 0:2]) / 200.0
self.personid = np.arange(len(boxes), dtype=np.int32)
self.right = right.astype(np.float32)
def __len__(self) -> int:
return len(self.personid)
def __getitem__(self, idx: int) -> Dict[str, np.array]:
center = self.center[idx].copy()
center_x = center[0]
center_y = center[1]
scale = self.scale[idx]
BBOX_SHAPE = self.cfg.MODEL.get('BBOX_SHAPE', None)
bbox_size = expand_to_aspect_ratio(scale*200, target_aspect_ratio=BBOX_SHAPE).max()
patch_width = patch_height = self.img_size
right = self.right[idx].copy()
flip = right == 0
# 3. generate image patch
# if use_skimage_antialias:
cvimg = self.img_cv2.copy()
if True:
# Blur image to avoid aliasing artifacts
downsampling_factor = ((bbox_size*1.0) / patch_width)
print(f'{downsampling_factor=}')
downsampling_factor = downsampling_factor / 2.0
if downsampling_factor > 1.1:
cvimg = gaussian(cvimg, sigma=(downsampling_factor-1)/2, channel_axis=2, preserve_range=True)
img_patch_cv, trans = generate_image_patch_cv2(cvimg,
center_x, center_y,
bbox_size, bbox_size,
patch_width, patch_height,
flip, 1.0, 0,
border_mode=cv2.BORDER_CONSTANT)
img_patch_cv = img_patch_cv[:, :, ::-1]
img_patch = convert_cvimg_to_tensor(img_patch_cv)
# apply normalization
for n_c in range(min(self.img_cv2.shape[2], 3)):
img_patch[n_c, :, :] = (img_patch[n_c, :, :] - self.mean[n_c]) / self.std[n_c]
item = {
'img': img_patch,
'personid': int(self.personid[idx]),
}
item['box_center'] = self.center[idx].copy()
item['box_size'] = bbox_size
item['img_size'] = 1.0 * np.array([cvimg.shape[1], cvimg.shape[0]])
item['right'] = self.right[idx].copy()
return item
+52
View File
@@ -0,0 +1,52 @@
from .mano_wrapper import MANO
from .hamer import HAMER
from .discriminator import Discriminator
from ..utils.download import cache_url
from ..configs import CACHE_DIR_HAMER
def download_models(folder=CACHE_DIR_HAMER):
"""Download checkpoints and files for running inference.
"""
import os
os.makedirs(folder, exist_ok=True)
download_files = {
"hamer_demo_data.tar.gz" : ["https://www.cs.utexas.edu/~pavlakos/hamer/data/hamer_demo_data.tar.gz", folder],
}
for file_name, url in download_files.items():
output_path = os.path.join(url[1], file_name)
if not os.path.exists(output_path):
print("Downloading file: " + file_name)
# output = gdown.cached_download(url[0], output_path, fuzzy=True)
output = cache_url(url[0], output_path)
assert os.path.exists(output_path), f"{output} does not exist"
# if ends with tar.gz, tar -xzf
if file_name.endswith(".tar.gz"):
print("Extracting file: " + file_name)
os.system("tar -xvf " + output_path)
DEFAULT_CHECKPOINT=f'{CACHE_DIR_HAMER}/hamer_ckpts/checkpoints/hamer.ckpt'
def load_hamer(checkpoint_path=DEFAULT_CHECKPOINT):
from pathlib import Path
from ..configs import get_config
model_cfg = str(Path(checkpoint_path).parent.parent / 'model_config.yaml')
model_cfg = get_config(model_cfg, update_cachedir=True)
# Override some config values, to crop bbox correctly
if (model_cfg.MODEL.BACKBONE.TYPE == 'vit') and ('BBOX_SHAPE' not in model_cfg.MODEL):
model_cfg.defrost()
assert model_cfg.MODEL.IMAGE_SIZE == 256, f"MODEL.IMAGE_SIZE ({model_cfg.MODEL.IMAGE_SIZE}) should be 256 for ViT backbone"
model_cfg.MODEL.BBOX_SHAPE = [192,256]
model_cfg.freeze()
# Update config to be compatible with demo
if ('PRETRAINED_WEIGHTS' in model_cfg.MODEL.BACKBONE):
model_cfg.defrost()
model_cfg.MODEL.BACKBONE.pop('PRETRAINED_WEIGHTS')
model_cfg.freeze()
model = HAMER.load_from_checkpoint(checkpoint_path, strict=False, cfg=model_cfg)
return model, model_cfg
+7
View File
@@ -0,0 +1,7 @@
from .vit import vit
def create_backbone(cfg):
if cfg.MODEL.BACKBONE.TYPE == 'vit':
return vit(cfg)
else:
raise NotImplementedError('Backbone type is not implemented')
+348
View File
@@ -0,0 +1,348 @@
# Copyright (c) OpenMMLab. All rights reserved.
import math
import torch
from functools import partial
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.checkpoint as checkpoint
from timm.models.layers import drop_path, to_2tuple, trunc_normal_
def vit(cfg):
return ViT(
img_size=(256, 192),
patch_size=16,
embed_dim=1280,
depth=32,
num_heads=16,
ratio=1,
use_checkpoint=False,
mlp_ratio=4,
qkv_bias=True,
drop_path_rate=0.55,
)
def get_abs_pos(abs_pos, h, w, ori_h, ori_w, has_cls_token=True):
"""
Calculate absolute positional embeddings. If needed, resize embeddings and remove cls_token
dimension for the original embeddings.
Args:
abs_pos (Tensor): absolute positional embeddings with (1, num_position, C).
has_cls_token (bool): If true, has 1 embedding in abs_pos for cls token.
hw (Tuple): size of input image tokens.
Returns:
Absolute positional embeddings after processing with shape (1, H, W, C)
"""
cls_token = None
B, L, C = abs_pos.shape
if has_cls_token:
cls_token = abs_pos[:, 0:1]
abs_pos = abs_pos[:, 1:]
if ori_h != h or ori_w != w:
new_abs_pos = F.interpolate(
abs_pos.reshape(1, ori_h, ori_w, -1).permute(0, 3, 1, 2),
size=(h, w),
mode="bicubic",
align_corners=False,
).permute(0, 2, 3, 1).reshape(B, -1, C)
else:
new_abs_pos = abs_pos
if cls_token is not None:
new_abs_pos = torch.cat([cls_token, new_abs_pos], dim=1)
return new_abs_pos
class DropPath(nn.Module):
"""Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
"""
def __init__(self, drop_prob=None):
super(DropPath, self).__init__()
self.drop_prob = drop_prob
def forward(self, x):
return drop_path(x, self.drop_prob, self.training)
def extra_repr(self):
return 'p={}'.format(self.drop_prob)
class Mlp(nn.Module):
def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
super().__init__()
out_features = out_features or in_features
hidden_features = hidden_features or in_features
self.fc1 = nn.Linear(in_features, hidden_features)
self.act = act_layer()
self.fc2 = nn.Linear(hidden_features, out_features)
self.drop = nn.Dropout(drop)
def forward(self, x):
x = self.fc1(x)
x = self.act(x)
x = self.fc2(x)
x = self.drop(x)
return x
class Attention(nn.Module):
def __init__(
self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0.,
proj_drop=0., attn_head_dim=None,):
super().__init__()
self.num_heads = num_heads
head_dim = dim // num_heads
self.dim = dim
if attn_head_dim is not None:
head_dim = attn_head_dim
all_head_dim = head_dim * self.num_heads
self.scale = qk_scale or head_dim ** -0.5
self.qkv = nn.Linear(dim, all_head_dim * 3, bias=qkv_bias)
self.attn_drop = nn.Dropout(attn_drop)
self.proj = nn.Linear(all_head_dim, dim)
self.proj_drop = nn.Dropout(proj_drop)
def forward(self, x):
B, N, C = x.shape
qkv = self.qkv(x)
qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4)
q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
q = q * self.scale
attn = (q @ k.transpose(-2, -1))
attn = attn.softmax(dim=-1)
attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, -1)
x = self.proj(x)
x = self.proj_drop(x)
return x
class Block(nn.Module):
def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None,
drop=0., attn_drop=0., drop_path=0., act_layer=nn.GELU,
norm_layer=nn.LayerNorm, attn_head_dim=None
):
super().__init__()
self.norm1 = norm_layer(dim)
self.attn = Attention(
dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale,
attn_drop=attn_drop, proj_drop=drop, attn_head_dim=attn_head_dim
)
# NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
self.norm2 = norm_layer(dim)
mlp_hidden_dim = int(dim * mlp_ratio)
self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
def forward(self, x):
x = x + self.drop_path(self.attn(self.norm1(x)))
x = x + self.drop_path(self.mlp(self.norm2(x)))
return x
class PatchEmbed(nn.Module):
""" Image to Patch Embedding
"""
def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768, ratio=1):
super().__init__()
img_size = to_2tuple(img_size)
patch_size = to_2tuple(patch_size)
num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0]) * (ratio ** 2)
self.patch_shape = (int(img_size[0] // patch_size[0] * ratio), int(img_size[1] // patch_size[1] * ratio))
self.origin_patch_shape = (int(img_size[0] // patch_size[0]), int(img_size[1] // patch_size[1]))
self.img_size = img_size
self.patch_size = patch_size
self.num_patches = num_patches
self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=(patch_size[0] // ratio), padding=4 + 2 * (ratio//2-1))
def forward(self, x, **kwargs):
B, C, H, W = x.shape
x = self.proj(x)
Hp, Wp = x.shape[2], x.shape[3]
x = x.flatten(2).transpose(1, 2)
return x, (Hp, Wp)
class HybridEmbed(nn.Module):
""" CNN Feature Map Embedding
Extract feature map from CNN, flatten, project to embedding dim.
"""
def __init__(self, backbone, img_size=224, feature_size=None, in_chans=3, embed_dim=768):
super().__init__()
assert isinstance(backbone, nn.Module)
img_size = to_2tuple(img_size)
self.img_size = img_size
self.backbone = backbone
if feature_size is None:
with torch.no_grad():
training = backbone.training
if training:
backbone.eval()
o = self.backbone(torch.zeros(1, in_chans, img_size[0], img_size[1]))[-1]
feature_size = o.shape[-2:]
feature_dim = o.shape[1]
backbone.train(training)
else:
feature_size = to_2tuple(feature_size)
feature_dim = self.backbone.feature_info.channels()[-1]
self.num_patches = feature_size[0] * feature_size[1]
self.proj = nn.Linear(feature_dim, embed_dim)
def forward(self, x):
x = self.backbone(x)[-1]
x = x.flatten(2).transpose(1, 2)
x = self.proj(x)
return x
class ViT(nn.Module):
def __init__(self,
img_size=224, patch_size=16, in_chans=3, num_classes=80, embed_dim=768, depth=12,
num_heads=12, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop_rate=0., attn_drop_rate=0.,
drop_path_rate=0., hybrid_backbone=None, norm_layer=None, use_checkpoint=False,
frozen_stages=-1, ratio=1, last_norm=True,
patch_padding='pad', freeze_attn=False, freeze_ffn=False,
):
# Protect mutable default arguments
super(ViT, self).__init__()
norm_layer = norm_layer or partial(nn.LayerNorm, eps=1e-6)
self.num_classes = num_classes
self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models
self.frozen_stages = frozen_stages
self.use_checkpoint = use_checkpoint
self.patch_padding = patch_padding
self.freeze_attn = freeze_attn
self.freeze_ffn = freeze_ffn
self.depth = depth
if hybrid_backbone is not None:
self.patch_embed = HybridEmbed(
hybrid_backbone, img_size=img_size, in_chans=in_chans, embed_dim=embed_dim)
else:
self.patch_embed = PatchEmbed(
img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim, ratio=ratio)
num_patches = self.patch_embed.num_patches
# since the pretraining model has class token
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))
dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule
self.blocks = nn.ModuleList([
Block(
dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale,
drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer,
)
for i in range(depth)])
self.last_norm = norm_layer(embed_dim) if last_norm else nn.Identity()
if self.pos_embed is not None:
trunc_normal_(self.pos_embed, std=.02)
self._freeze_stages()
def _freeze_stages(self):
"""Freeze parameters."""
if self.frozen_stages >= 0:
self.patch_embed.eval()
for param in self.patch_embed.parameters():
param.requires_grad = False
for i in range(1, self.frozen_stages + 1):
m = self.blocks[i]
m.eval()
for param in m.parameters():
param.requires_grad = False
if self.freeze_attn:
for i in range(0, self.depth):
m = self.blocks[i]
m.attn.eval()
m.norm1.eval()
for param in m.attn.parameters():
param.requires_grad = False
for param in m.norm1.parameters():
param.requires_grad = False
if self.freeze_ffn:
self.pos_embed.requires_grad = False
self.patch_embed.eval()
for param in self.patch_embed.parameters():
param.requires_grad = False
for i in range(0, self.depth):
m = self.blocks[i]
m.mlp.eval()
m.norm2.eval()
for param in m.mlp.parameters():
param.requires_grad = False
for param in m.norm2.parameters():
param.requires_grad = False
def init_weights(self):
"""Initialize the weights in backbone.
Args:
pretrained (str, optional): Path to pre-trained weights.
Defaults to None.
"""
def _init_weights(m):
if isinstance(m, nn.Linear):
trunc_normal_(m.weight, std=.02)
if isinstance(m, nn.Linear) and m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.LayerNorm):
nn.init.constant_(m.bias, 0)
nn.init.constant_(m.weight, 1.0)
self.apply(_init_weights)
def get_num_layers(self):
return len(self.blocks)
@torch.jit.ignore
def no_weight_decay(self):
return {'pos_embed', 'cls_token'}
def forward_features(self, x):
B, C, H, W = x.shape
x, (Hp, Wp) = self.patch_embed(x)
if self.pos_embed is not None:
# fit for multiple GPU training
# since the first element for pos embed (sin-cos manner) is zero, it will cause no difference
x = x + self.pos_embed[:, 1:] + self.pos_embed[:, :1]
for blk in self.blocks:
if self.use_checkpoint:
x = checkpoint.checkpoint(blk, x)
else:
x = blk(x)
x = self.last_norm(x)
xp = x.permute(0, 2, 1).reshape(B, -1, Hp, Wp).contiguous()
return xp
def forward(self, x):
x = self.forward_features(x)
return x
def train(self, mode=True):
"""Convert the model into training mode."""
super().train(mode)
self._freeze_stages()
@@ -0,0 +1,358 @@
from inspect import isfunction
from typing import Callable, Optional
import torch
from einops import rearrange
from einops.layers.torch import Rearrange
from torch import nn
from .t_cond_mlp import (
AdaptiveLayerNorm1D,
FrequencyEmbedder,
normalization_layer,
)
# from .vit import Attention, FeedForward
def exists(val):
return val is not None
def default(val, d):
if exists(val):
return val
return d() if isfunction(d) else d
class PreNorm(nn.Module):
def __init__(self, dim: int, fn: Callable, norm: str = "layer", norm_cond_dim: int = -1):
super().__init__()
self.norm = normalization_layer(norm, dim, norm_cond_dim)
self.fn = fn
def forward(self, x: torch.Tensor, *args, **kwargs):
if isinstance(self.norm, AdaptiveLayerNorm1D):
return self.fn(self.norm(x, *args), **kwargs)
else:
return self.fn(self.norm(x), **kwargs)
class FeedForward(nn.Module):
def __init__(self, dim, hidden_dim, dropout=0.0):
super().__init__()
self.net = nn.Sequential(
nn.Linear(dim, hidden_dim),
nn.GELU(),
nn.Dropout(dropout),
nn.Linear(hidden_dim, dim),
nn.Dropout(dropout),
)
def forward(self, x):
return self.net(x)
class Attention(nn.Module):
def __init__(self, dim, heads=8, dim_head=64, dropout=0.0):
super().__init__()
inner_dim = dim_head * heads
project_out = not (heads == 1 and dim_head == dim)
self.heads = heads
self.scale = dim_head**-0.5
self.attend = nn.Softmax(dim=-1)
self.dropout = nn.Dropout(dropout)
self.to_qkv = nn.Linear(dim, inner_dim * 3, bias=False)
self.to_out = (
nn.Sequential(nn.Linear(inner_dim, dim), nn.Dropout(dropout))
if project_out
else nn.Identity()
)
def forward(self, x):
qkv = self.to_qkv(x).chunk(3, dim=-1)
q, k, v = map(lambda t: rearrange(t, "b n (h d) -> b h n d", h=self.heads), qkv)
dots = torch.matmul(q, k.transpose(-1, -2)) * self.scale
attn = self.attend(dots)
attn = self.dropout(attn)
out = torch.matmul(attn, v)
out = rearrange(out, "b h n d -> b n (h d)")
return self.to_out(out)
class CrossAttention(nn.Module):
def __init__(self, dim, context_dim=None, heads=8, dim_head=64, dropout=0.0):
super().__init__()
inner_dim = dim_head * heads
project_out = not (heads == 1 and dim_head == dim)
self.heads = heads
self.scale = dim_head**-0.5
self.attend = nn.Softmax(dim=-1)
self.dropout = nn.Dropout(dropout)
context_dim = default(context_dim, dim)
self.to_kv = nn.Linear(context_dim, inner_dim * 2, bias=False)
self.to_q = nn.Linear(dim, inner_dim, bias=False)
self.to_out = (
nn.Sequential(nn.Linear(inner_dim, dim), nn.Dropout(dropout))
if project_out
else nn.Identity()
)
def forward(self, x, context=None):
context = default(context, x)
k, v = self.to_kv(context).chunk(2, dim=-1)
q = self.to_q(x)
q, k, v = map(lambda t: rearrange(t, "b n (h d) -> b h n d", h=self.heads), [q, k, v])
dots = torch.matmul(q, k.transpose(-1, -2)) * self.scale
attn = self.attend(dots)
attn = self.dropout(attn)
out = torch.matmul(attn, v)
out = rearrange(out, "b h n d -> b n (h d)")
return self.to_out(out)
class Transformer(nn.Module):
def __init__(
self,
dim: int,
depth: int,
heads: int,
dim_head: int,
mlp_dim: int,
dropout: float = 0.0,
norm: str = "layer",
norm_cond_dim: int = -1,
):
super().__init__()
self.layers = nn.ModuleList([])
for _ in range(depth):
sa = Attention(dim, heads=heads, dim_head=dim_head, dropout=dropout)
ff = FeedForward(dim, mlp_dim, dropout=dropout)
self.layers.append(
nn.ModuleList(
[
PreNorm(dim, sa, norm=norm, norm_cond_dim=norm_cond_dim),
PreNorm(dim, ff, norm=norm, norm_cond_dim=norm_cond_dim),
]
)
)
def forward(self, x: torch.Tensor, *args):
for attn, ff in self.layers:
x = attn(x, *args) + x
x = ff(x, *args) + x
return x
class TransformerCrossAttn(nn.Module):
def __init__(
self,
dim: int,
depth: int,
heads: int,
dim_head: int,
mlp_dim: int,
dropout: float = 0.0,
norm: str = "layer",
norm_cond_dim: int = -1,
context_dim: Optional[int] = None,
):
super().__init__()
self.layers = nn.ModuleList([])
for _ in range(depth):
sa = Attention(dim, heads=heads, dim_head=dim_head, dropout=dropout)
ca = CrossAttention(
dim, context_dim=context_dim, heads=heads, dim_head=dim_head, dropout=dropout
)
ff = FeedForward(dim, mlp_dim, dropout=dropout)
self.layers.append(
nn.ModuleList(
[
PreNorm(dim, sa, norm=norm, norm_cond_dim=norm_cond_dim),
PreNorm(dim, ca, norm=norm, norm_cond_dim=norm_cond_dim),
PreNorm(dim, ff, norm=norm, norm_cond_dim=norm_cond_dim),
]
)
)
def forward(self, x: torch.Tensor, *args, context=None, context_list=None):
if context_list is None:
context_list = [context] * len(self.layers)
if len(context_list) != len(self.layers):
raise ValueError(f"len(context_list) != len(self.layers) ({len(context_list)} != {len(self.layers)})")
for i, (self_attn, cross_attn, ff) in enumerate(self.layers):
x = self_attn(x, *args) + x
x = cross_attn(x, *args, context=context_list[i]) + x
x = ff(x, *args) + x
return x
class DropTokenDropout(nn.Module):
def __init__(self, p: float = 0.1):
super().__init__()
if p < 0 or p > 1:
raise ValueError(
"dropout probability has to be between 0 and 1, " "but got {}".format(p)
)
self.p = p
def forward(self, x: torch.Tensor):
# x: (batch_size, seq_len, dim)
if self.training and self.p > 0:
zero_mask = torch.full_like(x[0, :, 0], self.p).bernoulli().bool()
# TODO: permutation idx for each batch using torch.argsort
if zero_mask.any():
x = x[:, ~zero_mask, :]
return x
class ZeroTokenDropout(nn.Module):
def __init__(self, p: float = 0.1):
super().__init__()
if p < 0 or p > 1:
raise ValueError(
"dropout probability has to be between 0 and 1, " "but got {}".format(p)
)
self.p = p
def forward(self, x: torch.Tensor):
# x: (batch_size, seq_len, dim)
if self.training and self.p > 0:
zero_mask = torch.full_like(x[:, :, 0], self.p).bernoulli().bool()
# Zero-out the masked tokens
x[zero_mask, :] = 0
return x
class TransformerEncoder(nn.Module):
def __init__(
self,
num_tokens: int,
token_dim: int,
dim: int,
depth: int,
heads: int,
mlp_dim: int,
dim_head: int = 64,
dropout: float = 0.0,
emb_dropout: float = 0.0,
emb_dropout_type: str = "drop",
emb_dropout_loc: str = "token",
norm: str = "layer",
norm_cond_dim: int = -1,
token_pe_numfreq: int = -1,
):
super().__init__()
if token_pe_numfreq > 0:
token_dim_new = token_dim * (2 * token_pe_numfreq + 1)
self.to_token_embedding = nn.Sequential(
Rearrange("b n d -> (b n) d", n=num_tokens, d=token_dim),
FrequencyEmbedder(token_pe_numfreq, token_pe_numfreq - 1),
Rearrange("(b n) d -> b n d", n=num_tokens, d=token_dim_new),
nn.Linear(token_dim_new, dim),
)
else:
self.to_token_embedding = nn.Linear(token_dim, dim)
self.pos_embedding = nn.Parameter(torch.randn(1, num_tokens, dim))
if emb_dropout_type == "drop":
self.dropout = DropTokenDropout(emb_dropout)
elif emb_dropout_type == "zero":
self.dropout = ZeroTokenDropout(emb_dropout)
else:
raise ValueError(f"Unknown emb_dropout_type: {emb_dropout_type}")
self.emb_dropout_loc = emb_dropout_loc
self.transformer = Transformer(
dim, depth, heads, dim_head, mlp_dim, dropout, norm=norm, norm_cond_dim=norm_cond_dim
)
def forward(self, inp: torch.Tensor, *args, **kwargs):
x = inp
if self.emb_dropout_loc == "input":
x = self.dropout(x)
x = self.to_token_embedding(x)
if self.emb_dropout_loc == "token":
x = self.dropout(x)
b, n, _ = x.shape
x += self.pos_embedding[:, :n]
if self.emb_dropout_loc == "token_afterpos":
x = self.dropout(x)
x = self.transformer(x, *args)
return x
class TransformerDecoder(nn.Module):
def __init__(
self,
num_tokens: int,
token_dim: int,
dim: int,
depth: int,
heads: int,
mlp_dim: int,
dim_head: int = 64,
dropout: float = 0.0,
emb_dropout: float = 0.0,
emb_dropout_type: str = 'drop',
norm: str = "layer",
norm_cond_dim: int = -1,
context_dim: Optional[int] = None,
skip_token_embedding: bool = False,
):
super().__init__()
if not skip_token_embedding:
self.to_token_embedding = nn.Linear(token_dim, dim)
else:
self.to_token_embedding = nn.Identity()
if token_dim != dim:
raise ValueError(
f"token_dim ({token_dim}) != dim ({dim}) when skip_token_embedding is True"
)
self.pos_embedding = nn.Parameter(torch.randn(1, num_tokens, dim))
if emb_dropout_type == "drop":
self.dropout = DropTokenDropout(emb_dropout)
elif emb_dropout_type == "zero":
self.dropout = ZeroTokenDropout(emb_dropout)
elif emb_dropout_type == "normal":
self.dropout = nn.Dropout(emb_dropout)
self.transformer = TransformerCrossAttn(
dim,
depth,
heads,
dim_head,
mlp_dim,
dropout,
norm=norm,
norm_cond_dim=norm_cond_dim,
context_dim=context_dim,
)
def forward(self, inp: torch.Tensor, *args, context=None, context_list=None):
x = self.to_token_embedding(inp)
b, n, _ = x.shape
x = self.dropout(x)
x += self.pos_embedding[:, :n]
x = self.transformer(x, *args, context=context, context_list=context_list)
return x
+199
View File
@@ -0,0 +1,199 @@
import copy
from typing import List, Optional
import torch
class AdaptiveLayerNorm1D(torch.nn.Module):
def __init__(self, data_dim: int, norm_cond_dim: int):
super().__init__()
if data_dim <= 0:
raise ValueError(f"data_dim must be positive, but got {data_dim}")
if norm_cond_dim <= 0:
raise ValueError(f"norm_cond_dim must be positive, but got {norm_cond_dim}")
self.norm = torch.nn.LayerNorm(
data_dim
) # TODO: Check if elementwise_affine=True is correct
self.linear = torch.nn.Linear(norm_cond_dim, 2 * data_dim)
torch.nn.init.zeros_(self.linear.weight)
torch.nn.init.zeros_(self.linear.bias)
def forward(self, x: torch.Tensor, t: torch.Tensor) -> torch.Tensor:
# x: (batch, ..., data_dim)
# t: (batch, norm_cond_dim)
# return: (batch, data_dim)
x = self.norm(x)
alpha, beta = self.linear(t).chunk(2, dim=-1)
# Add singleton dimensions to alpha and beta
if x.dim() > 2:
alpha = alpha.view(alpha.shape[0], *([1] * (x.dim() - 2)), alpha.shape[1])
beta = beta.view(beta.shape[0], *([1] * (x.dim() - 2)), beta.shape[1])
return x * (1 + alpha) + beta
class SequentialCond(torch.nn.Sequential):
def forward(self, input, *args, **kwargs):
for module in self:
if isinstance(module, (AdaptiveLayerNorm1D, SequentialCond, ResidualMLPBlock)):
# print(f'Passing on args to {module}', [a.shape for a in args])
input = module(input, *args, **kwargs)
else:
# print(f'Skipping passing args to {module}', [a.shape for a in args])
input = module(input)
return input
def normalization_layer(norm: Optional[str], dim: int, norm_cond_dim: int = -1):
if norm == "batch":
return torch.nn.BatchNorm1d(dim)
elif norm == "layer":
return torch.nn.LayerNorm(dim)
elif norm == "ada":
assert norm_cond_dim > 0, f"norm_cond_dim must be positive, got {norm_cond_dim}"
return AdaptiveLayerNorm1D(dim, norm_cond_dim)
elif norm is None:
return torch.nn.Identity()
else:
raise ValueError(f"Unknown norm: {norm}")
def linear_norm_activ_dropout(
input_dim: int,
output_dim: int,
activation: torch.nn.Module = torch.nn.ReLU(),
bias: bool = True,
norm: Optional[str] = "layer", # Options: ada/batch/layer
dropout: float = 0.0,
norm_cond_dim: int = -1,
) -> SequentialCond:
layers = []
layers.append(torch.nn.Linear(input_dim, output_dim, bias=bias))
if norm is not None:
layers.append(normalization_layer(norm, output_dim, norm_cond_dim))
layers.append(copy.deepcopy(activation))
if dropout > 0.0:
layers.append(torch.nn.Dropout(dropout))
return SequentialCond(*layers)
def create_simple_mlp(
input_dim: int,
hidden_dims: List[int],
output_dim: int,
activation: torch.nn.Module = torch.nn.ReLU(),
bias: bool = True,
norm: Optional[str] = "layer", # Options: ada/batch/layer
dropout: float = 0.0,
norm_cond_dim: int = -1,
) -> SequentialCond:
layers = []
prev_dim = input_dim
for hidden_dim in hidden_dims:
layers.extend(
linear_norm_activ_dropout(
prev_dim, hidden_dim, activation, bias, norm, dropout, norm_cond_dim
)
)
prev_dim = hidden_dim
layers.append(torch.nn.Linear(prev_dim, output_dim, bias=bias))
return SequentialCond(*layers)
class ResidualMLPBlock(torch.nn.Module):
def __init__(
self,
input_dim: int,
hidden_dim: int,
num_hidden_layers: int,
output_dim: int,
activation: torch.nn.Module = torch.nn.ReLU(),
bias: bool = True,
norm: Optional[str] = "layer", # Options: ada/batch/layer
dropout: float = 0.0,
norm_cond_dim: int = -1,
):
super().__init__()
if not (input_dim == output_dim == hidden_dim):
raise NotImplementedError(
f"input_dim {input_dim} != output_dim {output_dim} is not implemented"
)
layers = []
prev_dim = input_dim
for i in range(num_hidden_layers):
layers.append(
linear_norm_activ_dropout(
prev_dim, hidden_dim, activation, bias, norm, dropout, norm_cond_dim
)
)
prev_dim = hidden_dim
self.model = SequentialCond(*layers)
self.skip = torch.nn.Identity()
def forward(self, x: torch.Tensor, *args, **kwargs) -> torch.Tensor:
return x + self.model(x, *args, **kwargs)
class ResidualMLP(torch.nn.Module):
def __init__(
self,
input_dim: int,
hidden_dim: int,
num_hidden_layers: int,
output_dim: int,
activation: torch.nn.Module = torch.nn.ReLU(),
bias: bool = True,
norm: Optional[str] = "layer", # Options: ada/batch/layer
dropout: float = 0.0,
num_blocks: int = 1,
norm_cond_dim: int = -1,
):
super().__init__()
self.input_dim = input_dim
self.model = SequentialCond(
linear_norm_activ_dropout(
input_dim, hidden_dim, activation, bias, norm, dropout, norm_cond_dim
),
*[
ResidualMLPBlock(
hidden_dim,
hidden_dim,
num_hidden_layers,
hidden_dim,
activation,
bias,
norm,
dropout,
norm_cond_dim,
)
for _ in range(num_blocks)
],
torch.nn.Linear(hidden_dim, output_dim, bias=bias),
)
def forward(self, x: torch.Tensor, *args, **kwargs) -> torch.Tensor:
return self.model(x, *args, **kwargs)
class FrequencyEmbedder(torch.nn.Module):
def __init__(self, num_frequencies, max_freq_log2):
super().__init__()
frequencies = 2 ** torch.linspace(0, max_freq_log2, steps=num_frequencies)
self.register_buffer("frequencies", frequencies)
def forward(self, x):
# x should be of size (N,) or (N, D)
N = x.size(0)
if x.dim() == 1: # (N,)
x = x.unsqueeze(1) # (N, D) where D=1
x_unsqueezed = x.unsqueeze(-1) # (N, D, 1)
scaled = self.frequencies.view(1, 1, -1) * x_unsqueezed # (N, D, num_frequencies)
s = torch.sin(scaled)
c = torch.cos(scaled)
embedded = torch.cat([s, c, x_unsqueezed], dim=-1).view(
N, -1
) # (N, D * 2 * num_frequencies + D)
return embedded
+98
View File
@@ -0,0 +1,98 @@
import torch
import torch.nn as nn
class Discriminator(nn.Module):
def __init__(self):
"""
Pose + Shape discriminator proposed in HMR
"""
super(Discriminator, self).__init__()
self.num_joints = 15
# poses_alone
self.D_conv1 = nn.Conv2d(9, 32, kernel_size=1)
nn.init.xavier_uniform_(self.D_conv1.weight)
nn.init.zeros_(self.D_conv1.bias)
self.relu = nn.ReLU(inplace=True)
self.D_conv2 = nn.Conv2d(32, 32, kernel_size=1)
nn.init.xavier_uniform_(self.D_conv2.weight)
nn.init.zeros_(self.D_conv2.bias)
pose_out = []
for i in range(self.num_joints):
pose_out_temp = nn.Linear(32, 1)
nn.init.xavier_uniform_(pose_out_temp.weight)
nn.init.zeros_(pose_out_temp.bias)
pose_out.append(pose_out_temp)
self.pose_out = nn.ModuleList(pose_out)
# betas
self.betas_fc1 = nn.Linear(10, 10)
nn.init.xavier_uniform_(self.betas_fc1.weight)
nn.init.zeros_(self.betas_fc1.bias)
self.betas_fc2 = nn.Linear(10, 5)
nn.init.xavier_uniform_(self.betas_fc2.weight)
nn.init.zeros_(self.betas_fc2.bias)
self.betas_out = nn.Linear(5, 1)
nn.init.xavier_uniform_(self.betas_out.weight)
nn.init.zeros_(self.betas_out.bias)
# poses_joint
self.D_alljoints_fc1 = nn.Linear(32*self.num_joints, 1024)
nn.init.xavier_uniform_(self.D_alljoints_fc1.weight)
nn.init.zeros_(self.D_alljoints_fc1.bias)
self.D_alljoints_fc2 = nn.Linear(1024, 1024)
nn.init.xavier_uniform_(self.D_alljoints_fc2.weight)
nn.init.zeros_(self.D_alljoints_fc2.bias)
self.D_alljoints_out = nn.Linear(1024, 1)
nn.init.xavier_uniform_(self.D_alljoints_out.weight)
nn.init.zeros_(self.D_alljoints_out.bias)
def forward(self, poses: torch.Tensor, betas: torch.Tensor) -> torch.Tensor:
"""
Forward pass of the discriminator.
Args:
poses (torch.Tensor): Tensor of shape (B, 23, 3, 3) containing a batch of MANO hand poses (excluding the global orientation).
betas (torch.Tensor): Tensor of shape (B, 10) containign a batch of MANO beta coefficients.
Returns:
torch.Tensor: Discriminator output with shape (B, 25)
"""
#bn = poses.shape[0]
# poses B x 207
#poses = poses.reshape(bn, -1)
# poses B x num_joints x 1 x 9
poses = poses.reshape(-1, self.num_joints, 1, 9)
bn = poses.shape[0]
# poses B x 9 x num_joints x 1
poses = poses.permute(0, 3, 1, 2).contiguous()
# poses_alone
poses = self.D_conv1(poses)
poses = self.relu(poses)
poses = self.D_conv2(poses)
poses = self.relu(poses)
poses_out = []
for i in range(self.num_joints):
poses_out_ = self.pose_out[i](poses[:, :, i, 0])
poses_out.append(poses_out_)
poses_out = torch.cat(poses_out, dim=1)
# betas
betas = self.betas_fc1(betas)
betas = self.relu(betas)
betas = self.betas_fc2(betas)
betas = self.relu(betas)
betas_out = self.betas_out(betas)
# poses_joint
poses = poses.reshape(bn,-1)
poses_all = self.D_alljoints_fc1(poses)
poses_all = self.relu(poses_all)
poses_all = self.D_alljoints_fc2(poses_all)
poses_all = self.relu(poses_all)
poses_all_out = self.D_alljoints_out(poses_all)
disc_out = torch.cat((poses_out, betas_out, poses_all_out), 1)
return disc_out
+355
View File
@@ -0,0 +1,355 @@
import torch
import pytorch_lightning as pl
from typing import Any, Dict, Mapping, Tuple
from yacs.config import CfgNode
from ..utils import SkeletonRenderer, MeshRenderer
from ..utils.geometry import aa_to_rotmat, perspective_projection
from ..utils.pylogger import get_pylogger
from .backbones import create_backbone
from .heads import build_mano_head
from .discriminator import Discriminator
from .losses import Keypoint3DLoss, Keypoint2DLoss, ParameterLoss
from . import MANO
log = get_pylogger(__name__)
class HAMER(pl.LightningModule):
def __init__(self, cfg: CfgNode, init_renderer: bool = True):
"""
Setup HAMER model
Args:
cfg (CfgNode): Config file as a yacs CfgNode
"""
super().__init__()
# Save hyperparameters
self.save_hyperparameters(logger=False, ignore=['init_renderer'])
self.cfg = cfg
# Create backbone feature extractor
self.backbone = create_backbone(cfg)
if cfg.MODEL.BACKBONE.get('PRETRAINED_WEIGHTS', None):
log.info(f'Loading backbone weights from {cfg.MODEL.BACKBONE.PRETRAINED_WEIGHTS}')
self.backbone.load_state_dict(torch.load(cfg.MODEL.BACKBONE.PRETRAINED_WEIGHTS, map_location='cpu')['state_dict'])
# Create MANO head
self.mano_head = build_mano_head(cfg)
# Create discriminator
if self.cfg.LOSS_WEIGHTS.ADVERSARIAL > 0:
self.discriminator = Discriminator()
# Define loss functions
self.keypoint_3d_loss = Keypoint3DLoss(loss_type='l1')
self.keypoint_2d_loss = Keypoint2DLoss(loss_type='l1')
self.mano_parameter_loss = ParameterLoss()
# Instantiate MANO model
mano_cfg = {k.lower(): v for k,v in dict(cfg.MANO).items()}
self.mano = MANO(**mano_cfg)
# Buffer that shows whetheer we need to initialize ActNorm layers
self.register_buffer('initialized', torch.tensor(False))
# Setup renderer for visualization
if init_renderer:
self.renderer = SkeletonRenderer(self.cfg)
self.mesh_renderer = MeshRenderer(self.cfg, faces=self.mano.faces)
else:
self.renderer = None
self.mesh_renderer = None
# Disable automatic optimization since we use adversarial training
self.automatic_optimization = False
def get_parameters(self):
all_params = list(self.mano_head.parameters())
all_params += list(self.backbone.parameters())
return all_params
def configure_optimizers(self) -> Tuple[torch.optim.Optimizer, torch.optim.Optimizer]:
"""
Setup model and distriminator Optimizers
Returns:
Tuple[torch.optim.Optimizer, torch.optim.Optimizer]: Model and discriminator optimizers
"""
param_groups = [{'params': filter(lambda p: p.requires_grad, self.get_parameters()), 'lr': self.cfg.TRAIN.LR}]
optimizer = torch.optim.AdamW(params=param_groups,
# lr=self.cfg.TRAIN.LR,
weight_decay=self.cfg.TRAIN.WEIGHT_DECAY)
optimizer_disc = torch.optim.AdamW(params=self.discriminator.parameters(),
lr=self.cfg.TRAIN.LR,
weight_decay=self.cfg.TRAIN.WEIGHT_DECAY)
return optimizer, optimizer_disc
def forward_step(self, batch: Dict, train: bool = False) -> Dict:
"""
Run a forward step of the network
Args:
batch (Dict): Dictionary containing batch data
train (bool): Flag indicating whether it is training or validation mode
Returns:
Dict: Dictionary containing the regression output
"""
# Use RGB image as input
x = batch['img']
batch_size = x.shape[0]
# Compute conditioning features using the backbone
# if using ViT backbone, we need to use a different aspect ratio
conditioning_feats = self.backbone(x[:,:,:,32:-32])
pred_mano_params, pred_cam, _ = self.mano_head(conditioning_feats)
# Store useful regression outputs to the output dict
output = {}
output['pred_cam'] = pred_cam
output['pred_mano_params'] = {k: v.clone() for k,v in pred_mano_params.items()}
# Compute camera translation
device = pred_mano_params['hand_pose'].device
dtype = pred_mano_params['hand_pose'].dtype
focal_length = self.cfg.EXTRA.FOCAL_LENGTH * torch.ones(batch_size, 2, device=device, dtype=dtype)
pred_cam_t = torch.stack([pred_cam[:, 1],
pred_cam[:, 2],
2*focal_length[:, 0]/(self.cfg.MODEL.IMAGE_SIZE * pred_cam[:, 0] +1e-9)],dim=-1)
output['pred_cam_t'] = pred_cam_t
output['focal_length'] = focal_length
# Compute model vertices, joints and the projected joints
pred_mano_params['global_orient'] = pred_mano_params['global_orient'].reshape(batch_size, -1, 3, 3)
pred_mano_params['hand_pose'] = pred_mano_params['hand_pose'].reshape(batch_size, -1, 3, 3)
pred_mano_params['betas'] = pred_mano_params['betas'].reshape(batch_size, -1)
mano_output = self.mano(**{k: v.float() for k,v in pred_mano_params.items()}, pose2rot=False)
pred_keypoints_3d = mano_output.joints
pred_vertices = mano_output.vertices
output['pred_keypoints_3d'] = pred_keypoints_3d.reshape(batch_size, -1, 3)
output['pred_vertices'] = pred_vertices.reshape(batch_size, -1, 3)
pred_cam_t = pred_cam_t.reshape(-1, 3)
focal_length = focal_length.reshape(-1, 2)
pred_keypoints_2d = perspective_projection(pred_keypoints_3d,
translation=pred_cam_t,
focal_length=focal_length / self.cfg.MODEL.IMAGE_SIZE)
output['pred_keypoints_2d'] = pred_keypoints_2d.reshape(batch_size, -1, 2)
return output
def compute_loss(self, batch: Dict, output: Dict, train: bool = True) -> torch.Tensor:
"""
Compute losses given the input batch and the regression output
Args:
batch (Dict): Dictionary containing batch data
output (Dict): Dictionary containing the regression output
train (bool): Flag indicating whether it is training or validation mode
Returns:
torch.Tensor : Total loss for current batch
"""
pred_mano_params = output['pred_mano_params']
pred_keypoints_2d = output['pred_keypoints_2d']
pred_keypoints_3d = output['pred_keypoints_3d']
batch_size = pred_mano_params['hand_pose'].shape[0]
device = pred_mano_params['hand_pose'].device
dtype = pred_mano_params['hand_pose'].dtype
# Get annotations
gt_keypoints_2d = batch['keypoints_2d']
gt_keypoints_3d = batch['keypoints_3d']
gt_mano_params = batch['mano_params']
has_mano_params = batch['has_mano_params']
is_axis_angle = batch['mano_params_is_axis_angle']
# Compute 3D keypoint loss
loss_keypoints_2d = self.keypoint_2d_loss(pred_keypoints_2d, gt_keypoints_2d)
loss_keypoints_3d = self.keypoint_3d_loss(pred_keypoints_3d, gt_keypoints_3d, pelvis_id=0)
# Compute loss on MANO parameters
loss_mano_params = {}
for k, pred in pred_mano_params.items():
gt = gt_mano_params[k].view(batch_size, -1)
if is_axis_angle[k].all():
gt = aa_to_rotmat(gt.reshape(-1, 3)).view(batch_size, -1, 3, 3)
has_gt = has_mano_params[k]
loss_mano_params[k] = self.mano_parameter_loss(pred.reshape(batch_size, -1), gt.reshape(batch_size, -1), has_gt)
loss = self.cfg.LOSS_WEIGHTS['KEYPOINTS_3D'] * loss_keypoints_3d+\
self.cfg.LOSS_WEIGHTS['KEYPOINTS_2D'] * loss_keypoints_2d+\
sum([loss_mano_params[k] * self.cfg.LOSS_WEIGHTS[k.upper()] for k in loss_mano_params])
losses = dict(loss=loss.detach(),
loss_keypoints_2d=loss_keypoints_2d.detach(),
loss_keypoints_3d=loss_keypoints_3d.detach())
for k, v in loss_mano_params.items():
losses['loss_' + k] = v.detach()
output['losses'] = losses
return loss
# Tensoroboard logging should run from first rank only
@pl.utilities.rank_zero.rank_zero_only
def tensorboard_logging(self, batch: Dict, output: Dict, step_count: int, train: bool = True, write_to_summary_writer: bool = True) -> None:
"""
Log results to Tensorboard
Args:
batch (Dict): Dictionary containing batch data
output (Dict): Dictionary containing the regression output
step_count (int): Global training step count
train (bool): Flag indicating whether it is training or validation mode
"""
mode = 'train' if train else 'val'
batch_size = batch['keypoints_2d'].shape[0]
images = batch['img']
images = images * torch.tensor([0.229, 0.224, 0.225], device=images.device).reshape(1,3,1,1)
images = images + torch.tensor([0.485, 0.456, 0.406], device=images.device).reshape(1,3,1,1)
#images = 255*images.permute(0, 2, 3, 1).cpu().numpy()
pred_keypoints_3d = output['pred_keypoints_3d'].detach().reshape(batch_size, -1, 3)
pred_vertices = output['pred_vertices'].detach().reshape(batch_size, -1, 3)
focal_length = output['focal_length'].detach().reshape(batch_size, 2)
gt_keypoints_3d = batch['keypoints_3d']
gt_keypoints_2d = batch['keypoints_2d']
losses = output['losses']
pred_cam_t = output['pred_cam_t'].detach().reshape(batch_size, 3)
pred_keypoints_2d = output['pred_keypoints_2d'].detach().reshape(batch_size, -1, 2)
if write_to_summary_writer:
summary_writer = self.logger.experiment
for loss_name, val in losses.items():
summary_writer.add_scalar(mode +'/' + loss_name, val.detach().item(), step_count)
num_images = min(batch_size, self.cfg.EXTRA.NUM_LOG_IMAGES)
gt_keypoints_3d = batch['keypoints_3d']
pred_keypoints_3d = output['pred_keypoints_3d'].detach().reshape(batch_size, -1, 3)
# We render the skeletons instead of the full mesh because rendering a lot of meshes will make the training slow.
#predictions = self.renderer(pred_keypoints_3d[:num_images],
# gt_keypoints_3d[:num_images],
# 2 * gt_keypoints_2d[:num_images],
# images=images[:num_images],
# camera_translation=pred_cam_t[:num_images])
predictions = self.mesh_renderer.visualize_tensorboard(pred_vertices[:num_images].cpu().numpy(),
pred_cam_t[:num_images].cpu().numpy(),
images[:num_images].cpu().numpy(),
pred_keypoints_2d[:num_images].cpu().numpy(),
gt_keypoints_2d[:num_images].cpu().numpy(),
focal_length=focal_length[:num_images].cpu().numpy())
if write_to_summary_writer:
summary_writer.add_image('%s/predictions' % mode, predictions, step_count)
return predictions
def forward(self, batch: Dict) -> Dict:
"""
Run a forward step of the network in val mode
Args:
batch (Dict): Dictionary containing batch data
Returns:
Dict: Dictionary containing the regression output
"""
return self.forward_step(batch, train=False)
def training_step_discriminator(self, batch: Dict,
hand_pose: torch.Tensor,
betas: torch.Tensor,
optimizer: torch.optim.Optimizer) -> torch.Tensor:
"""
Run a discriminator training step
Args:
batch (Dict): Dictionary containing mocap batch data
hand_pose (torch.Tensor): Regressed hand pose from current step
betas (torch.Tensor): Regressed betas from current step
optimizer (torch.optim.Optimizer): Discriminator optimizer
Returns:
torch.Tensor: Discriminator loss
"""
batch_size = hand_pose.shape[0]
gt_hand_pose = batch['hand_pose']
gt_betas = batch['betas']
gt_rotmat = aa_to_rotmat(gt_hand_pose.view(-1,3)).view(batch_size, -1, 3, 3)
disc_fake_out = self.discriminator(hand_pose.detach(), betas.detach())
loss_fake = ((disc_fake_out - 0.0) ** 2).sum() / batch_size
disc_real_out = self.discriminator(gt_rotmat, gt_betas)
loss_real = ((disc_real_out - 1.0) ** 2).sum() / batch_size
loss_disc = loss_fake + loss_real
loss = self.cfg.LOSS_WEIGHTS.ADVERSARIAL * loss_disc
optimizer.zero_grad()
self.manual_backward(loss)
optimizer.step()
return loss_disc.detach()
def training_step(self, joint_batch: Dict, batch_idx: int) -> Dict:
"""
Run a full training step
Args:
joint_batch (Dict): Dictionary containing image and mocap batch data
batch_idx (int): Unused.
batch_idx (torch.Tensor): Unused.
Returns:
Dict: Dictionary containing regression output.
"""
batch = joint_batch['img']
mocap_batch = joint_batch['mocap']
optimizer = self.optimizers(use_pl_optimizer=True)
if self.cfg.LOSS_WEIGHTS.ADVERSARIAL > 0:
optimizer, optimizer_disc = optimizer
batch_size = batch['img'].shape[0]
output = self.forward_step(batch, train=True)
pred_mano_params = output['pred_mano_params']
if self.cfg.get('UPDATE_GT_SPIN', False):
self.update_batch_gt_spin(batch, output)
loss = self.compute_loss(batch, output, train=True)
if self.cfg.LOSS_WEIGHTS.ADVERSARIAL > 0:
disc_out = self.discriminator(pred_mano_params['hand_pose'].reshape(batch_size, -1), pred_mano_params['betas'].reshape(batch_size, -1))
loss_adv = ((disc_out - 1.0) ** 2).sum() / batch_size
loss = loss + self.cfg.LOSS_WEIGHTS.ADVERSARIAL * loss_adv
# Error if Nan
if torch.isnan(loss):
raise ValueError('Loss is NaN')
optimizer.zero_grad()
self.manual_backward(loss)
# Clip gradient
if self.cfg.TRAIN.get('GRAD_CLIP_VAL', 0) > 0:
gn = torch.nn.utils.clip_grad_norm_(self.get_parameters(), self.cfg.TRAIN.GRAD_CLIP_VAL, error_if_nonfinite=True)
self.log('train/grad_norm', gn, on_step=True, on_epoch=True, prog_bar=True, logger=True)
optimizer.step()
if self.cfg.LOSS_WEIGHTS.ADVERSARIAL > 0:
loss_disc = self.training_step_discriminator(mocap_batch, pred_mano_params['hand_pose'].reshape(batch_size, -1), pred_mano_params['betas'].reshape(batch_size, -1), optimizer_disc)
output['losses']['loss_gen'] = loss_adv
output['losses']['loss_disc'] = loss_disc
if self.global_step > 0 and self.global_step % self.cfg.GENERAL.LOG_STEPS == 0:
self.tensorboard_logging(batch, output, self.global_step, train=True)
self.log('train/loss', output['losses']['loss'], on_step=True, on_epoch=True, prog_bar=True, logger=False)
return output
def validation_step(self, batch: Dict, batch_idx: int, dataloader_idx=0) -> Dict:
"""
Run a validation step and log to Tensorboard
Args:
batch (Dict): Dictionary containing batch data
batch_idx (int): Unused.
Returns:
Dict: Dictionary containing regression output.
"""
# batch_size = batch['img'].shape[0]
output = self.forward_step(batch, train=False)
loss = self.compute_loss(batch, output, train=False)
output['loss'] = loss
self.tensorboard_logging(batch, output, self.global_step, train=False)
return output
+1
View File
@@ -0,0 +1 @@
from .mano_head import build_mano_head
+111
View File
@@ -0,0 +1,111 @@
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import einops
from ...utils.geometry import rot6d_to_rotmat, aa_to_rotmat
from ..components.pose_transformer import TransformerDecoder
def build_mano_head(cfg):
mano_head_type = cfg.MODEL.MANO_HEAD.get('TYPE', 'hamer')
if mano_head_type == 'transformer_decoder':
return MANOTransformerDecoderHead(cfg)
else:
raise ValueError('Unknown MANO head type: {}'.format(mano_head_type))
class MANOTransformerDecoderHead(nn.Module):
""" Cross-attention based MANO Transformer decoder
"""
def __init__(self, cfg):
super().__init__()
self.cfg = cfg
self.joint_rep_type = cfg.MODEL.MANO_HEAD.get('JOINT_REP', '6d')
self.joint_rep_dim = {'6d': 6, 'aa': 3}[self.joint_rep_type]
npose = self.joint_rep_dim * (cfg.MANO.NUM_HAND_JOINTS + 1)
self.npose = npose
self.input_is_mean_shape = cfg.MODEL.MANO_HEAD.get('TRANSFORMER_INPUT', 'zero') == 'mean_shape'
transformer_args = dict(
num_tokens=1,
token_dim=(npose + 10 + 3) if self.input_is_mean_shape else 1,
dim=1024,
)
transformer_args = (transformer_args | dict(cfg.MODEL.MANO_HEAD.TRANSFORMER_DECODER))
self.transformer = TransformerDecoder(
**transformer_args
)
dim=transformer_args['dim']
self.decpose = nn.Linear(dim, npose)
self.decshape = nn.Linear(dim, 10)
self.deccam = nn.Linear(dim, 3)
if cfg.MODEL.MANO_HEAD.get('INIT_DECODER_XAVIER', False):
# True by default in MLP. False by default in Transformer
nn.init.xavier_uniform_(self.decpose.weight, gain=0.01)
nn.init.xavier_uniform_(self.decshape.weight, gain=0.01)
nn.init.xavier_uniform_(self.deccam.weight, gain=0.01)
mean_params = np.load(cfg.MANO.MEAN_PARAMS)
init_hand_pose = torch.from_numpy(mean_params['pose'].astype(np.float32)).unsqueeze(0)
init_betas = torch.from_numpy(mean_params['shape'].astype('float32')).unsqueeze(0)
init_cam = torch.from_numpy(mean_params['cam'].astype(np.float32)).unsqueeze(0)
self.register_buffer('init_hand_pose', init_hand_pose)
self.register_buffer('init_betas', init_betas)
self.register_buffer('init_cam', init_cam)
def forward(self, x, **kwargs):
batch_size = x.shape[0]
# vit pretrained backbone is channel-first. Change to token-first
x = einops.rearrange(x, 'b c h w -> b (h w) c')
init_hand_pose = self.init_hand_pose.expand(batch_size, -1)
init_betas = self.init_betas.expand(batch_size, -1)
init_cam = self.init_cam.expand(batch_size, -1)
# TODO: Convert init_hand_pose to aa rep if needed
if self.joint_rep_type == 'aa':
raise NotImplementedError
pred_hand_pose = init_hand_pose
pred_betas = init_betas
pred_cam = init_cam
pred_hand_pose_list = []
pred_betas_list = []
pred_cam_list = []
for i in range(self.cfg.MODEL.MANO_HEAD.get('IEF_ITERS', 1)):
# Input token to transformer is zero token
if self.input_is_mean_shape:
token = torch.cat([pred_hand_pose, pred_betas, pred_cam], dim=1)[:,None,:]
else:
token = torch.zeros(batch_size, 1, 1).to(x.device)
# Pass through transformer
token_out = self.transformer(token, context=x)
token_out = token_out.squeeze(1) # (B, C)
# Readout from token_out
pred_hand_pose = self.decpose(token_out) + pred_hand_pose
pred_betas = self.decshape(token_out) + pred_betas
pred_cam = self.deccam(token_out) + pred_cam
pred_hand_pose_list.append(pred_hand_pose)
pred_betas_list.append(pred_betas)
pred_cam_list.append(pred_cam)
# Convert self.joint_rep_type -> rotmat
joint_conversion_fn = {
'6d': rot6d_to_rotmat,
'aa': lambda x: aa_to_rotmat(x.view(-1, 3).contiguous())
}[self.joint_rep_type]
pred_mano_params_list = {}
pred_mano_params_list['hand_pose'] = torch.cat([joint_conversion_fn(pbp).view(batch_size, -1, 3, 3)[:, 1:, :, :] for pbp in pred_hand_pose_list], dim=0)
pred_mano_params_list['betas'] = torch.cat(pred_betas_list, dim=0)
pred_mano_params_list['cam'] = torch.cat(pred_cam_list, dim=0)
pred_hand_pose = joint_conversion_fn(pred_hand_pose).view(batch_size, self.cfg.MANO.NUM_HAND_JOINTS+1, 3, 3)
pred_mano_params = {'global_orient': pred_hand_pose[:, [0]],
'hand_pose': pred_hand_pose[:, 1:],
'betas': pred_betas}
return pred_mano_params, pred_cam, pred_mano_params_list
+92
View File
@@ -0,0 +1,92 @@
import torch
import torch.nn as nn
class Keypoint2DLoss(nn.Module):
def __init__(self, loss_type: str = 'l1'):
"""
2D keypoint loss module.
Args:
loss_type (str): Choose between l1 and l2 losses.
"""
super(Keypoint2DLoss, self).__init__()
if loss_type == 'l1':
self.loss_fn = nn.L1Loss(reduction='none')
elif loss_type == 'l2':
self.loss_fn = nn.MSELoss(reduction='none')
else:
raise NotImplementedError('Unsupported loss function')
def forward(self, pred_keypoints_2d: torch.Tensor, gt_keypoints_2d: torch.Tensor) -> torch.Tensor:
"""
Compute 2D reprojection loss on the keypoints.
Args:
pred_keypoints_2d (torch.Tensor): Tensor of shape [B, S, N, 2] containing projected 2D keypoints (B: batch_size, S: num_samples, N: num_keypoints)
gt_keypoints_2d (torch.Tensor): Tensor of shape [B, S, N, 3] containing the ground truth 2D keypoints and confidence.
Returns:
torch.Tensor: 2D keypoint loss.
"""
conf = gt_keypoints_2d[:, :, -1].unsqueeze(-1).clone()
batch_size = conf.shape[0]
loss = (conf * self.loss_fn(pred_keypoints_2d, gt_keypoints_2d[:, :, :-1])).sum(dim=(1,2))
return loss.sum()
class Keypoint3DLoss(nn.Module):
def __init__(self, loss_type: str = 'l1'):
"""
3D keypoint loss module.
Args:
loss_type (str): Choose between l1 and l2 losses.
"""
super(Keypoint3DLoss, self).__init__()
if loss_type == 'l1':
self.loss_fn = nn.L1Loss(reduction='none')
elif loss_type == 'l2':
self.loss_fn = nn.MSELoss(reduction='none')
else:
raise NotImplementedError('Unsupported loss function')
def forward(self, pred_keypoints_3d: torch.Tensor, gt_keypoints_3d: torch.Tensor, pelvis_id: int = 0):
"""
Compute 3D keypoint loss.
Args:
pred_keypoints_3d (torch.Tensor): Tensor of shape [B, S, N, 3] containing the predicted 3D keypoints (B: batch_size, S: num_samples, N: num_keypoints)
gt_keypoints_3d (torch.Tensor): Tensor of shape [B, S, N, 4] containing the ground truth 3D keypoints and confidence.
Returns:
torch.Tensor: 3D keypoint loss.
"""
batch_size = pred_keypoints_3d.shape[0]
gt_keypoints_3d = gt_keypoints_3d.clone()
pred_keypoints_3d = pred_keypoints_3d - pred_keypoints_3d[:, pelvis_id, :].unsqueeze(dim=1)
gt_keypoints_3d[:, :, :-1] = gt_keypoints_3d[:, :, :-1] - gt_keypoints_3d[:, pelvis_id, :-1].unsqueeze(dim=1)
conf = gt_keypoints_3d[:, :, -1].unsqueeze(-1).clone()
gt_keypoints_3d = gt_keypoints_3d[:, :, :-1]
loss = (conf * self.loss_fn(pred_keypoints_3d, gt_keypoints_3d)).sum(dim=(1,2))
return loss.sum()
class ParameterLoss(nn.Module):
def __init__(self):
"""
MANO parameter loss module.
"""
super(ParameterLoss, self).__init__()
self.loss_fn = nn.MSELoss(reduction='none')
def forward(self, pred_param: torch.Tensor, gt_param: torch.Tensor, has_param: torch.Tensor):
"""
Compute MANO parameter loss.
Args:
pred_param (torch.Tensor): Tensor of shape [B, S, ...] containing the predicted parameters (body pose / global orientation / betas)
gt_param (torch.Tensor): Tensor of shape [B, S, ...] containing the ground truth MANO parameters.
Returns:
torch.Tensor: L2 parameter loss loss.
"""
batch_size = pred_param.shape[0]
num_dims = len(pred_param.shape)
mask_dimension = [batch_size] + [1] * (num_dims-1)
has_param = has_param.type(pred_param.type()).view(*mask_dimension)
loss_param = (has_param * self.loss_fn(pred_param, gt_param))
return loss_param.sum()
+40
View File
@@ -0,0 +1,40 @@
import torch
import numpy as np
import pickle
from typing import Optional
import smplx
from smplx.lbs import vertices2joints
from smplx.utils import MANOOutput, to_tensor
from smplx.vertex_ids import vertex_ids
class MANO(smplx.MANOLayer):
def __init__(self, *args, joint_regressor_extra: Optional[str] = None, **kwargs):
"""
Extension of the official MANO implementation to support more joints.
Args:
Same as MANOLayer.
joint_regressor_extra (str): Path to extra joint regressor.
"""
super(MANO, self).__init__(*args, **kwargs)
mano_to_openpose = [0, 13, 14, 15, 16, 1, 2, 3, 17, 4, 5, 6, 18, 10, 11, 12, 19, 7, 8, 9, 20]
#2, 3, 5, 4, 1
if joint_regressor_extra is not None:
self.register_buffer('joint_regressor_extra', torch.tensor(pickle.load(open(joint_regressor_extra, 'rb'), encoding='latin1'), dtype=torch.float32))
self.register_buffer('extra_joints_idxs', to_tensor(list(vertex_ids['mano'].values()), dtype=torch.long))
self.register_buffer('joint_map', torch.tensor(mano_to_openpose, dtype=torch.long))
def forward(self, *args, **kwargs) -> MANOOutput:
"""
Run forward pass. Same as MANO and also append an extra set of joints if joint_regressor_extra is specified.
"""
mano_output = super(MANO, self).forward(*args, **kwargs)
extra_joints = torch.index_select(mano_output.vertices, 1, self.extra_joints_idxs)
joints = torch.cat([mano_output.joints, extra_joints], dim=1)
joints = joints[:, self.joint_map, :]
if hasattr(self, 'joint_regressor_extra'):
extra_joints = vertices2joints(self.joint_regressor_extra, mano_output.vertices)
joints = torch.cat([joints, extra_joints], dim=1)
mano_output.joints = joints
return mano_output
+25
View File
@@ -0,0 +1,25 @@
import torch
from typing import Any
from .renderer import Renderer
from .mesh_renderer import MeshRenderer
from .skeleton_renderer import SkeletonRenderer
from .pose_utils import eval_pose, Evaluator
def recursive_to(x: Any, target: torch.device):
"""
Recursively transfer a batch of data to the target device
Args:
x (Any): Batch of data.
target (torch.device): Target device.
Returns:
Batch of data where all tensors are transfered to the target device.
"""
if isinstance(x, dict):
return {k: recursive_to(v, target) for k, v in x.items()}
elif isinstance(x, torch.Tensor):
return x.to(target)
elif isinstance(x, list):
return [recursive_to(i, target) for i in x]
else:
return x
+66
View File
@@ -0,0 +1,66 @@
import os
import re
import sys
from urllib import request as urlrequest
def _progress_bar(count, total):
"""Report download progress. Credit:
https://stackoverflow.com/questions/3173320/text-progress-bar-in-the-console/27871113
"""
bar_len = 60
filled_len = int(round(bar_len * count / float(total)))
percents = round(100.0 * count / float(total), 1)
bar = "=" * filled_len + "-" * (bar_len - filled_len)
sys.stdout.write(
" [{}] {}% of {:.1f}MB file \r".format(bar, percents, total / 1024 / 1024)
)
sys.stdout.flush()
if count >= total:
sys.stdout.write("\n")
def download_url(url, dst_file_path, chunk_size=8192, progress_hook=_progress_bar):
"""Download url and write it to dst_file_path. Credit:
https://stackoverflow.com/questions/2028517/python-urllib2-progress-hook
"""
# url = url + "?dl=1" if "dropbox" in url else url
req = urlrequest.Request(url)
response = urlrequest.urlopen(req)
total_size = response.info().get("Content-Length")
if total_size is None:
raise ValueError("Cannot determine size of download from {}".format(url))
total_size = int(total_size.strip())
bytes_so_far = 0
with open(dst_file_path, "wb") as f:
while 1:
chunk = response.read(chunk_size)
bytes_so_far += len(chunk)
if not chunk:
break
if progress_hook:
progress_hook(bytes_so_far, total_size)
f.write(chunk)
return bytes_so_far
def cache_url(url_or_file, cache_file_path, download=True):
"""Download the file specified by the URL to the cache_dir and return the path to
the cached file. If the argument is not a URL, simply return it as is.
"""
is_url = re.match(r"^(?:http)s?://", url_or_file, re.IGNORECASE) is not None
if not is_url:
return url_or_file
url = url_or_file
if os.path.exists(cache_file_path):
return cache_file_path
cache_file_dir = os.path.dirname(cache_file_path)
if not os.path.exists(cache_file_dir):
os.makedirs(cache_file_dir)
if download:
print("Downloading remote file {} to {}".format(url, cache_file_path))
download_url(url, cache_file_path)
return cache_file_path
+102
View File
@@ -0,0 +1,102 @@
from typing import Optional
import torch
from torch.nn import functional as F
def aa_to_rotmat(theta: torch.Tensor):
"""
Convert axis-angle representation to rotation matrix.
Works by first converting it to a quaternion.
Args:
theta (torch.Tensor): Tensor of shape (B, 3) containing axis-angle representations.
Returns:
torch.Tensor: Corresponding rotation matrices with shape (B, 3, 3).
"""
norm = torch.norm(theta + 1e-8, p = 2, dim = 1)
angle = torch.unsqueeze(norm, -1)
normalized = torch.div(theta, angle)
angle = angle * 0.5
v_cos = torch.cos(angle)
v_sin = torch.sin(angle)
quat = torch.cat([v_cos, v_sin * normalized], dim = 1)
return quat_to_rotmat(quat)
def quat_to_rotmat(quat: torch.Tensor) -> torch.Tensor:
"""
Convert quaternion representation to rotation matrix.
Args:
quat (torch.Tensor) of shape (B, 4); 4 <===> (w, x, y, z).
Returns:
torch.Tensor: Corresponding rotation matrices with shape (B, 3, 3).
"""
norm_quat = quat
norm_quat = norm_quat/norm_quat.norm(p=2, dim=1, keepdim=True)
w, x, y, z = norm_quat[:,0], norm_quat[:,1], norm_quat[:,2], norm_quat[:,3]
B = quat.size(0)
w2, x2, y2, z2 = w.pow(2), x.pow(2), y.pow(2), z.pow(2)
wx, wy, wz = w*x, w*y, w*z
xy, xz, yz = x*y, x*z, y*z
rotMat = torch.stack([w2 + x2 - y2 - z2, 2*xy - 2*wz, 2*wy + 2*xz,
2*wz + 2*xy, w2 - x2 + y2 - z2, 2*yz - 2*wx,
2*xz - 2*wy, 2*wx + 2*yz, w2 - x2 - y2 + z2], dim=1).view(B, 3, 3)
return rotMat
def rot6d_to_rotmat(x: torch.Tensor) -> torch.Tensor:
"""
Convert 6D rotation representation to 3x3 rotation matrix.
Based on Zhou et al., "On the Continuity of Rotation Representations in Neural Networks", CVPR 2019
Args:
x (torch.Tensor): (B,6) Batch of 6-D rotation representations.
Returns:
torch.Tensor: Batch of corresponding rotation matrices with shape (B,3,3).
"""
x = x.reshape(-1,2,3).permute(0, 2, 1).contiguous()
a1 = x[:, :, 0]
a2 = x[:, :, 1]
b1 = F.normalize(a1)
b2 = F.normalize(a2 - torch.einsum('bi,bi->b', b1, a2).unsqueeze(-1) * b1)
b3 = torch.cross(b1, b2)
return torch.stack((b1, b2, b3), dim=-1)
def perspective_projection(points: torch.Tensor,
translation: torch.Tensor,
focal_length: torch.Tensor,
camera_center: Optional[torch.Tensor] = None,
rotation: Optional[torch.Tensor] = None) -> torch.Tensor:
"""
Computes the perspective projection of a set of 3D points.
Args:
points (torch.Tensor): Tensor of shape (B, N, 3) containing the input 3D points.
translation (torch.Tensor): Tensor of shape (B, 3) containing the 3D camera translation.
focal_length (torch.Tensor): Tensor of shape (B, 2) containing the focal length in pixels.
camera_center (torch.Tensor): Tensor of shape (B, 2) containing the camera center in pixels.
rotation (torch.Tensor): Tensor of shape (B, 3, 3) containing the camera rotation.
Returns:
torch.Tensor: Tensor of shape (B, N, 2) containing the projection of the input points.
"""
batch_size = points.shape[0]
if rotation is None:
rotation = torch.eye(3, device=points.device, dtype=points.dtype).unsqueeze(0).expand(batch_size, -1, -1)
if camera_center is None:
camera_center = torch.zeros(batch_size, 2, device=points.device, dtype=points.dtype)
# Populate intrinsic camera matrix K.
K = torch.zeros([batch_size, 3, 3], device=points.device, dtype=points.dtype)
K[:,0,0] = focal_length[:,0]
K[:,1,1] = focal_length[:,1]
K[:,2,2] = 1.
K[:,:-1, -1] = camera_center
# Transform points
points = torch.einsum('bij,bkj->bki', rotation, points)
points = points + translation.unsqueeze(1)
# Apply perspective distortion
projected_points = points / points[:,:,-1].unsqueeze(-1)
# Apply camera intrinsics
projected_points = torch.einsum('bij,bkj->bki', K, projected_points)
return projected_points[:, :, :-1]
+149
View File
@@ -0,0 +1,149 @@
import os
if 'PYOPENGL_PLATFORM' not in os.environ:
os.environ['PYOPENGL_PLATFORM'] = 'egl'
import torch
from torchvision.utils import make_grid
import numpy as np
import pyrender
import trimesh
import cv2
import torch.nn.functional as F
from .render_openpose import render_openpose
def create_raymond_lights():
import pyrender
thetas = np.pi * np.array([1.0 / 6.0, 1.0 / 6.0, 1.0 / 6.0])
phis = np.pi * np.array([0.0, 2.0 / 3.0, 4.0 / 3.0])
nodes = []
for phi, theta in zip(phis, thetas):
xp = np.sin(theta) * np.cos(phi)
yp = np.sin(theta) * np.sin(phi)
zp = np.cos(theta)
z = np.array([xp, yp, zp])
z = z / np.linalg.norm(z)
x = np.array([-z[1], z[0], 0.0])
if np.linalg.norm(x) == 0:
x = np.array([1.0, 0.0, 0.0])
x = x / np.linalg.norm(x)
y = np.cross(z, x)
matrix = np.eye(4)
matrix[:3,:3] = np.c_[x,y,z]
nodes.append(pyrender.Node(
light=pyrender.DirectionalLight(color=np.ones(3), intensity=1.0),
matrix=matrix
))
return nodes
class MeshRenderer:
def __init__(self, cfg, faces=None):
self.cfg = cfg
self.focal_length = cfg.EXTRA.FOCAL_LENGTH
self.img_res = cfg.MODEL.IMAGE_SIZE
self.renderer = pyrender.OffscreenRenderer(viewport_width=self.img_res,
viewport_height=self.img_res,
point_size=1.0)
self.camera_center = [self.img_res // 2, self.img_res // 2]
self.faces = faces
def visualize(self, vertices, camera_translation, images, focal_length=None, nrow=3, padding=2):
images_np = np.transpose(images, (0,2,3,1))
rend_imgs = []
for i in range(vertices.shape[0]):
fl = self.focal_length
rend_img = torch.from_numpy(np.transpose(self.__call__(vertices[i], camera_translation[i], images_np[i], focal_length=fl, side_view=False), (2,0,1))).float()
rend_img_side = torch.from_numpy(np.transpose(self.__call__(vertices[i], camera_translation[i], images_np[i], focal_length=fl, side_view=True), (2,0,1))).float()
rend_imgs.append(torch.from_numpy(images[i]))
rend_imgs.append(rend_img)
rend_imgs.append(rend_img_side)
rend_imgs = make_grid(rend_imgs, nrow=nrow, padding=padding)
return rend_imgs
def visualize_tensorboard(self, vertices, camera_translation, images, pred_keypoints, gt_keypoints, focal_length=None, nrow=5, padding=2):
images_np = np.transpose(images, (0,2,3,1))
rend_imgs = []
pred_keypoints = np.concatenate((pred_keypoints, np.ones_like(pred_keypoints)[:, :, [0]]), axis=-1)
pred_keypoints = self.img_res * (pred_keypoints + 0.5)
gt_keypoints[:, :, :-1] = self.img_res * (gt_keypoints[:, :, :-1] + 0.5)
#keypoint_matches = [(1, 12), (2, 8), (3, 7), (4, 6), (5, 9), (6, 10), (7, 11), (8, 14), (9, 2), (10, 1), (11, 0), (12, 3), (13, 4), (14, 5)]
for i in range(vertices.shape[0]):
fl = self.focal_length
rend_img = torch.from_numpy(np.transpose(self.__call__(vertices[i], camera_translation[i], images_np[i], focal_length=fl, side_view=False), (2,0,1))).float()
rend_img_side = torch.from_numpy(np.transpose(self.__call__(vertices[i], camera_translation[i], images_np[i], focal_length=fl, side_view=True), (2,0,1))).float()
hand_keypoints = pred_keypoints[i, :21]
#extra_keypoints = pred_keypoints[i, -19:]
#for pair in keypoint_matches:
# hand_keypoints[pair[0], :] = extra_keypoints[pair[1], :]
pred_keypoints_img = render_openpose(255 * images_np[i].copy(), hand_keypoints) / 255
hand_keypoints = gt_keypoints[i, :21]
#extra_keypoints = gt_keypoints[i, -19:]
#for pair in keypoint_matches:
# if extra_keypoints[pair[1], -1] > 0 and hand_keypoints[pair[0], -1] == 0:
# hand_keypoints[pair[0], :] = extra_keypoints[pair[1], :]
gt_keypoints_img = render_openpose(255*images_np[i].copy(), hand_keypoints) / 255
rend_imgs.append(torch.from_numpy(images[i]))
rend_imgs.append(rend_img)
rend_imgs.append(rend_img_side)
rend_imgs.append(torch.from_numpy(pred_keypoints_img).permute(2,0,1))
rend_imgs.append(torch.from_numpy(gt_keypoints_img).permute(2,0,1))
rend_imgs = make_grid(rend_imgs, nrow=nrow, padding=padding)
return rend_imgs
def __call__(self, vertices, camera_translation, image, focal_length=5000, text=None, resize=None, side_view=False, baseColorFactor=(1.0, 1.0, 0.9, 1.0), rot_angle=90):
renderer = pyrender.OffscreenRenderer(viewport_width=image.shape[1],
viewport_height=image.shape[0],
point_size=1.0)
material = pyrender.MetallicRoughnessMaterial(
metallicFactor=0.0,
alphaMode='OPAQUE',
baseColorFactor=baseColorFactor)
camera_translation[0] *= -1.
mesh = trimesh.Trimesh(vertices.copy(), self.faces.copy())
if side_view:
rot = trimesh.transformations.rotation_matrix(
np.radians(rot_angle), [0, 1, 0])
mesh.apply_transform(rot)
rot = trimesh.transformations.rotation_matrix(
np.radians(180), [1, 0, 0])
mesh.apply_transform(rot)
mesh = pyrender.Mesh.from_trimesh(mesh, material=material)
scene = pyrender.Scene(bg_color=[0.0, 0.0, 0.0, 0.0],
ambient_light=(0.3, 0.3, 0.3))
scene.add(mesh, 'mesh')
camera_pose = np.eye(4)
camera_pose[:3, 3] = camera_translation
camera_center = [image.shape[1] / 2., image.shape[0] / 2.]
camera = pyrender.IntrinsicsCamera(fx=focal_length, fy=focal_length,
cx=camera_center[0], cy=camera_center[1])
scene.add(camera, pose=camera_pose)
light_nodes = create_raymond_lights()
for node in light_nodes:
scene.add_node(node)
color, rend_depth = renderer.render(scene, flags=pyrender.RenderFlags.RGBA)
color = color.astype(np.float32) / 255.0
valid_mask = (color[:, :, -1] > 0)[:, :, np.newaxis]
if not side_view:
output_img = (color[:, :, :3] * valid_mask +
(1 - valid_mask) * image)
else:
output_img = color[:, :, :3]
if resize is not None:
output_img = cv2.resize(output_img, resize)
output_img = output_img.astype(np.float32)
renderer.delete()
return output_img
+203
View File
@@ -0,0 +1,203 @@
import time
import warnings
from importlib.util import find_spec
from pathlib import Path
from typing import Callable, List
import hydra
from omegaconf import DictConfig, OmegaConf
from pytorch_lightning import Callback
from pytorch_lightning.loggers import Logger
from pytorch_lightning.utilities import rank_zero_only
from . import pylogger, rich_utils
log = pylogger.get_pylogger(__name__)
def task_wrapper(task_func: Callable) -> Callable:
"""Optional decorator that wraps the task function in extra utilities.
Makes multirun more resistant to failure.
Utilities:
- Calling the `utils.extras()` before the task is started
- Calling the `utils.close_loggers()` after the task is finished
- Logging the exception if occurs
- Logging the task total execution time
- Logging the output dir
"""
def wrap(cfg: DictConfig):
# apply extra utilities
extras(cfg)
# execute the task
try:
start_time = time.time()
ret = task_func(cfg=cfg)
except Exception as ex:
log.exception("") # save exception to `.log` file
raise ex
finally:
path = Path(cfg.paths.output_dir, "exec_time.log")
content = f"'{cfg.task_name}' execution time: {time.time() - start_time} (s)"
save_file(path, content) # save task execution time (even if exception occurs)
close_loggers() # close loggers (even if exception occurs so multirun won't fail)
log.info(f"Output dir: {cfg.paths.output_dir}")
return ret
return wrap
def extras(cfg: DictConfig) -> None:
"""Applies optional utilities before the task is started.
Utilities:
- Ignoring python warnings
- Setting tags from command line
- Rich config printing
"""
# return if no `extras` config
if not cfg.get("extras"):
log.warning("Extras config not found! <cfg.extras=null>")
return
# disable python warnings
if cfg.extras.get("ignore_warnings"):
log.info("Disabling python warnings! <cfg.extras.ignore_warnings=True>")
warnings.filterwarnings("ignore")
# prompt user to input tags from command line if none are provided in the config
if cfg.extras.get("enforce_tags"):
log.info("Enforcing tags! <cfg.extras.enforce_tags=True>")
rich_utils.enforce_tags(cfg, save_to_file=True)
# pretty print config tree using Rich library
if cfg.extras.get("print_config"):
log.info("Printing config tree with Rich! <cfg.extras.print_config=True>")
rich_utils.print_config_tree(cfg, resolve=True, save_to_file=True)
@rank_zero_only
def save_file(path: str, content: str) -> None:
"""Save file in rank zero mode (only on one process in multi-GPU setup)."""
with open(path, "w+") as file:
file.write(content)
def instantiate_callbacks(callbacks_cfg: DictConfig) -> List[Callback]:
"""Instantiates callbacks from config."""
callbacks: List[Callback] = []
if not callbacks_cfg:
log.warning("Callbacks config is empty.")
return callbacks
if not isinstance(callbacks_cfg, DictConfig):
raise TypeError("Callbacks config must be a DictConfig!")
for _, cb_conf in callbacks_cfg.items():
if isinstance(cb_conf, DictConfig) and "_target_" in cb_conf:
log.info(f"Instantiating callback <{cb_conf._target_}>")
callbacks.append(hydra.utils.instantiate(cb_conf))
return callbacks
def instantiate_loggers(logger_cfg: DictConfig) -> List[Logger]:
"""Instantiates loggers from config."""
logger: List[Logger] = []
if not logger_cfg:
log.warning("Logger config is empty.")
return logger
if not isinstance(logger_cfg, DictConfig):
raise TypeError("Logger config must be a DictConfig!")
for _, lg_conf in logger_cfg.items():
if isinstance(lg_conf, DictConfig) and "_target_" in lg_conf:
log.info(f"Instantiating logger <{lg_conf._target_}>")
logger.append(hydra.utils.instantiate(lg_conf))
return logger
@rank_zero_only
def log_hyperparameters(object_dict: dict) -> None:
"""Controls which config parts are saved by lightning loggers.
Additionally saves:
- Number of model parameters
"""
hparams = {}
cfg = object_dict["cfg"]
model = object_dict["model"]
trainer = object_dict["trainer"]
if not trainer.logger:
log.warning("Logger not found! Skipping hyperparameter logging...")
return
# save number of model parameters
hparams["model/params/total"] = sum(p.numel() for p in model.parameters())
hparams["model/params/trainable"] = sum(
p.numel() for p in model.parameters() if p.requires_grad
)
hparams["model/params/non_trainable"] = sum(
p.numel() for p in model.parameters() if not p.requires_grad
)
for k in cfg.keys():
hparams[k] = cfg.get(k)
# Resolve all interpolations
def _resolve(_cfg):
if isinstance(_cfg, DictConfig):
_cfg = OmegaConf.to_container(_cfg, resolve=True)
return _cfg
hparams = {k: _resolve(v) for k, v in hparams.items()}
# send hparams to all loggers
trainer.logger.log_hyperparams(hparams)
def get_metric_value(metric_dict: dict, metric_name: str) -> float:
"""Safely retrieves value of the metric logged in LightningModule."""
if not metric_name:
log.info("Metric name is None! Skipping metric value retrieval...")
return None
if metric_name not in metric_dict:
raise Exception(
f"Metric value not found! <metric_name={metric_name}>\n"
"Make sure metric name logged in LightningModule is correct!\n"
"Make sure `optimized_metric` name in `hparams_search` config is correct!"
)
metric_value = metric_dict[metric_name].item()
log.info(f"Retrieved metric value! <{metric_name}={metric_value}>")
return metric_value
def close_loggers() -> None:
"""Makes sure all loggers closed properly (prevents logging failure during multirun)."""
log.info("Closing loggers...")
if find_spec("wandb"): # if wandb is installed
import wandb
if wandb.run:
log.info("Closing wandb!")
wandb.finish()
+352
View File
@@ -0,0 +1,352 @@
"""
Code adapted from: https://github.com/akanazawa/hmr/blob/master/src/benchmark/eval_util.py
"""
import torch
import numpy as np
from typing import Optional, Dict, List, Tuple
def compute_similarity_transform(S1: torch.Tensor, S2: torch.Tensor) -> torch.Tensor:
"""
Computes a similarity transform (sR, t) in a batched way that takes
a set of 3D points S1 (B, N, 3) closest to a set of 3D points S2 (B, N, 3),
where R is a 3x3 rotation matrix, t 3x1 translation, s scale.
i.e. solves the orthogonal Procrutes problem.
Args:
S1 (torch.Tensor): First set of points of shape (B, N, 3).
S2 (torch.Tensor): Second set of points of shape (B, N, 3).
Returns:
(torch.Tensor): The first set of points after applying the similarity transformation.
"""
batch_size = S1.shape[0]
S1 = S1.permute(0, 2, 1)
S2 = S2.permute(0, 2, 1)
# 1. Remove mean.
mu1 = S1.mean(dim=2, keepdim=True)
mu2 = S2.mean(dim=2, keepdim=True)
X1 = S1 - mu1
X2 = S2 - mu2
# 2. Compute variance of X1 used for scale.
var1 = (X1**2).sum(dim=(1,2))
# 3. The outer product of X1 and X2.
K = torch.matmul(X1, X2.permute(0, 2, 1))
# 4. Solution that Maximizes trace(R'K) is R=U*V', where U, V are singular vectors of K.
U, s, V = torch.svd(K)
Vh = V.permute(0, 2, 1)
# Construct Z that fixes the orientation of R to get det(R)=1.
Z = torch.eye(U.shape[1], device=U.device).unsqueeze(0).repeat(batch_size, 1, 1)
Z[:, -1, -1] *= torch.sign(torch.linalg.det(torch.matmul(U, Vh)))
# Construct R.
R = torch.matmul(torch.matmul(V, Z), U.permute(0, 2, 1))
# 5. Recover scale.
trace = torch.matmul(R, K).diagonal(offset=0, dim1=-1, dim2=-2).sum(dim=-1)
scale = (trace / var1).unsqueeze(dim=-1).unsqueeze(dim=-1)
# 6. Recover translation.
t = mu2 - scale*torch.matmul(R, mu1)
# 7. Error:
S1_hat = scale*torch.matmul(R, S1) + t
return S1_hat.permute(0, 2, 1)
def reconstruction_error(S1, S2) -> np.array:
"""
Computes the mean Euclidean distance of 2 set of points S1, S2 after performing Procrustes alignment.
Args:
S1 (torch.Tensor): First set of points of shape (B, N, 3).
S2 (torch.Tensor): Second set of points of shape (B, N, 3).
Returns:
(np.array): Reconstruction error.
"""
S1_hat = compute_similarity_transform(S1, S2)
re = torch.sqrt( ((S1_hat - S2)** 2).sum(dim=-1)).mean(dim=-1)
return re
def eval_pose(pred_joints, gt_joints) -> Tuple[np.array, np.array]:
"""
Compute joint errors in mm before and after Procrustes alignment.
Args:
pred_joints (torch.Tensor): Predicted 3D joints of shape (B, N, 3).
gt_joints (torch.Tensor): Ground truth 3D joints of shape (B, N, 3).
Returns:
Tuple[np.array, np.array]: Joint errors in mm before and after alignment.
"""
# Absolute error (MPJPE)
mpjpe = torch.sqrt(((pred_joints - gt_joints) ** 2).sum(dim=-1)).mean(dim=-1).cpu().numpy()
# Reconstruction_error
r_error = reconstruction_error(pred_joints, gt_joints).cpu().numpy()
return 1000 * mpjpe, 1000 * r_error
class Evaluator:
def __init__(self,
dataset_length: int,
dataset: str,
keypoint_list: List,
pelvis_ind: int,
metrics: List = ['mode_mpjpe', 'mode_re', 'min_mpjpe', 'min_re'],
preds: List = ['vertices', 'keypoints_3d'],
pck_thresholds: Optional[List] = None):
"""
Class used for evaluating trained models on different 3D pose datasets.
Args:
dataset_length (int): Total dataset length.
keypoint_list [List]: List of keypoints used for evaluation.
pelvis_ind (int): Index of pelvis keypoint; used for aligning the predictions and ground truth.
metrics [List]: List of evaluation metrics to record.
"""
self.dataset_length = dataset_length
self.dataset = dataset
self.keypoint_list = keypoint_list
self.pelvis_ind = pelvis_ind
self.metrics = metrics
self.preds = preds
if self.metrics is not None:
for metric in self.metrics:
setattr(self, metric, np.zeros((dataset_length,)))
if self.preds is not None:
for pred in self.preds:
if pred == 'vertices':
self.vertices = np.zeros((dataset_length, 778, 3))
if pred == 'keypoints_3d':
self.keypoints_3d = np.zeros((dataset_length, 21, 3))
self.counter = 0
if pck_thresholds is None:
self.pck_evaluator = None
else:
self.pck_evaluator = EvaluatorPCK(pck_thresholds)
def log(self):
"""
Print current evaluation metrics
"""
if self.counter == 0:
print('Evaluation has not started')
return
print(f'{self.counter} / {self.dataset_length} samples')
if self.pck_evaluator is not None:
self.pck_evaluator.log()
if self.metrics is not None:
for metric in self.metrics:
if metric in ['mode_mpjpe', 'mode_re', 'min_mpjpe', 'min_re']:
unit = 'mm'
else:
unit = ''
print(f'{metric}: {getattr(self, metric)[:self.counter].mean()} {unit}')
print('***')
def get_metrics_dict(self) -> Dict:
"""
Returns:
Dict: Dictionary of evaluation metrics.
"""
d1 = {metric: getattr(self, metric)[:self.counter].mean() for metric in self.metrics}
if self.pck_evaluator is not None:
d2 = self.pck_evaluator.get_metrics_dict()
d1.update(d2)
return d1
def get_preds_dict(self) -> Dict:
"""
Returns:
Dict: Dictionary of evaluation preds.
"""
d1 = {pred: getattr(self, pred)[:self.counter] for pred in self.preds}
return d1
def __call__(self, output: Dict, batch: Dict, opt_output: Optional[Dict] = None):
"""
Evaluate current batch.
Args:
output (Dict): Regression output.
batch (Dict): Dictionary containing images and their corresponding annotations.
opt_output (Dict): Optimization output.
"""
if self.pck_evaluator is not None:
self.pck_evaluator(output, batch, opt_output)
pred_keypoints_3d = output['pred_keypoints_3d'].detach()
pred_keypoints_3d = pred_keypoints_3d[:,None,:,:]
batch_size = pred_keypoints_3d.shape[0]
num_samples = pred_keypoints_3d.shape[1]
gt_keypoints_3d = batch['keypoints_3d'][:, :, :-1].unsqueeze(1).repeat(1, num_samples, 1, 1)
pred_vertices = output['pred_vertices'].detach()
# Align predictions and ground truth such that the pelvis location is at the origin
pred_keypoints_3d -= pred_keypoints_3d[:, :, [self.pelvis_ind]]
gt_keypoints_3d -= gt_keypoints_3d[:, :, [self.pelvis_ind]]
# Compute joint errors
mpjpe, re = eval_pose(pred_keypoints_3d.reshape(batch_size * num_samples, -1, 3)[:, self.keypoint_list], gt_keypoints_3d.reshape(batch_size * num_samples, -1 ,3)[:, self.keypoint_list])
mpjpe = mpjpe.reshape(batch_size, num_samples)
re = re.reshape(batch_size, num_samples)
# Compute 2d keypoint errors
bbox_expand_factor = batch['bbox_expand_factor'][:,None,None,None].detach()
pred_keypoints_2d = output['pred_keypoints_2d'].detach()
pred_keypoints_2d = pred_keypoints_2d[:,None,:,:]*bbox_expand_factor
gt_keypoints_2d = batch['keypoints_2d'][:,None,:,:].repeat(1, num_samples, 1, 1)*bbox_expand_factor
conf = gt_keypoints_2d[:, :, :, -1].clone()
kp_err = torch.nn.functional.mse_loss(
pred_keypoints_2d,
gt_keypoints_2d[:, :, :, :-1],
reduction='none'
).sum(dim=3)
kp_l2_loss = (conf * kp_err).mean(dim=2)
kp_l2_loss = kp_l2_loss.detach().cpu().numpy()
# Compute joint errors after optimization, if available.
if opt_output is not None:
opt_keypoints_3d = opt_output['model_joints']
opt_keypoints_3d -= opt_keypoints_3d[:, [self.pelvis_ind]]
opt_mpjpe, opt_re = eval_pose(opt_keypoints_3d[:, self.keypoint_list], gt_keypoints_3d[:, 0, self.keypoint_list])
# The 0-th sample always corresponds to the mode
if hasattr(self, 'mode_mpjpe'):
mode_mpjpe = mpjpe[:, 0]
self.mode_mpjpe[self.counter:self.counter+batch_size] = mode_mpjpe
if hasattr(self, 'mode_re'):
mode_re = re[:, 0]
self.mode_re[self.counter:self.counter+batch_size] = mode_re
if hasattr(self, 'mode_kpl2'):
mode_kpl2 = kp_l2_loss[:, 0]
self.mode_kpl2[self.counter:self.counter+batch_size] = mode_kpl2
if hasattr(self, 'min_mpjpe'):
min_mpjpe = mpjpe.min(axis=-1)
self.min_mpjpe[self.counter:self.counter+batch_size] = min_mpjpe
if hasattr(self, 'min_re'):
min_re = re.min(axis=-1)
self.min_re[self.counter:self.counter+batch_size] = min_re
if hasattr(self, 'min_kpl2'):
min_kpl2 = kp_l2_loss.min(axis=-1)
self.min_kpl2[self.counter:self.counter+batch_size] = min_kpl2
if hasattr(self, 'opt_mpjpe'):
self.opt_mpjpe[self.counter:self.counter+batch_size] = opt_mpjpe
if hasattr(self, 'opt_re'):
self.opt_re[self.counter:self.counter+batch_size] = opt_re
if hasattr(self, 'vertices'):
self.vertices[self.counter:self.counter+batch_size] = pred_vertices.cpu().numpy()
if hasattr(self, 'keypoints_3d'):
if self.dataset == 'HO3D-VAL':
pred_keypoints_3d = pred_keypoints_3d[:,:,[0,5,6,7,9,10,11,17,18,19,13,14,15,1,2,3,4,8,12,16,20]]
self.keypoints_3d[self.counter:self.counter+batch_size] = pred_keypoints_3d.squeeze().cpu().numpy()
self.counter += batch_size
if hasattr(self, 'mode_mpjpe') and hasattr(self, 'mode_re'):
return {
'mode_mpjpe': mode_mpjpe,
'mode_re': mode_re,
}
else:
return {}
class EvaluatorPCK:
def __init__(self, thresholds: List = [0.05, 0.1, 0.2, 0.3, 0.4, 0.5],):
"""
Class used for evaluating trained models on different 3D pose datasets.
Args:
thresholds [List]: List of PCK thresholds to evaluate.
metrics [List]: List of evaluation metrics to record.
"""
self.thresholds = thresholds
self.pred_kp_2d = []
self.gt_kp_2d = []
self.gt_conf_2d = []
self.scale = []
self.counter = 0
def log(self):
"""
Print current evaluation metrics
"""
if self.counter == 0:
print('Evaluation has not started')
return
print(f'{self.counter} samples')
metrics_dict = self.get_metrics_dict()
for metric in metrics_dict:
print(f'{metric}: {metrics_dict[metric]}')
print('***')
def get_metrics_dict(self) -> Dict:
"""
Returns:
Dict: Dictionary of evaluation metrics.
"""
pcks = self.compute_pcks()
metrics = {}
for thr, (acc,avg_acc,cnt) in zip(self.thresholds, pcks):
metrics.update({f'kp{i}_pck_{thr}': float(a) for i, a in enumerate(acc) if a>=0})
metrics.update({f'kpAvg_pck_{thr}': float(avg_acc)})
return metrics
def compute_pcks(self):
pred_kp_2d = np.concatenate(self.pred_kp_2d, axis=0)
gt_kp_2d = np.concatenate(self.gt_kp_2d, axis=0)
gt_conf_2d = np.concatenate(self.gt_conf_2d, axis=0)
scale = np.concatenate(self.scale, axis=0)
assert pred_kp_2d.shape == gt_kp_2d.shape
assert pred_kp_2d[..., 0].shape == gt_conf_2d.shape
assert pred_kp_2d.shape[1] == 1 # num_samples
assert scale.shape[0] == gt_conf_2d.shape[0] # num_samples
pcks = [
self.keypoint_pck_accuracy(
pred_kp_2d[:, 0, :, :],
gt_kp_2d[:, 0, :, :],
gt_conf_2d[:, 0, :]>0.5,
thr=thr,
scale = scale[:,None]
)
for thr in self.thresholds
]
return pcks
def keypoint_pck_accuracy(self, pred, gt, conf, thr, scale):
dist = np.sqrt(np.sum((pred-gt)**2, axis=2))
all_joints = conf>0.5
correct_joints = np.logical_and(dist<=scale*thr, all_joints)
pck = correct_joints.sum(axis=0)/all_joints.sum(axis=0)
return pck, pck.mean(), pck.shape[0]
def __call__(self, output: Dict, batch: Dict, opt_output: Optional[Dict] = None):
"""
Evaluate current batch.
Args:
output (Dict): Regression output.
batch (Dict): Dictionary containing images and their corresponding annotations.
opt_output (Dict): Optimization output.
"""
pred_keypoints_2d = output['pred_keypoints_2d'].detach()
num_samples = 1
batch_size = pred_keypoints_2d.shape[0]
right = batch['right'].detach()
pred_keypoints_2d[:,:,0] = (2*right[:,None]-1)*pred_keypoints_2d[:,:,0]
box_size = batch['box_size'].detach()
box_center = batch['box_center'].detach()
bbox_expand_factor = batch['bbox_expand_factor'].detach()
scale = box_size/bbox_expand_factor
bbox_expand_factor = bbox_expand_factor[:,None,None,None]
pred_keypoints_2d = pred_keypoints_2d*box_size[:,None,None]+box_center[:,None]
pred_keypoints_2d = pred_keypoints_2d[:,None,:,:]
gt_keypoints_2d = batch['orig_keypoints_2d'][:,None,:,:].repeat(1, num_samples, 1, 1)
self.pred_kp_2d.append(pred_keypoints_2d[:, :, :, :2].detach().cpu().numpy())
self.gt_conf_2d.append(gt_keypoints_2d[:, :, :, -1].detach().cpu().numpy())
self.gt_kp_2d.append(gt_keypoints_2d[:, :, :, :2].detach().cpu().numpy())
self.scale.append(scale.detach().cpu().numpy())
self.counter += batch_size
+17
View File
@@ -0,0 +1,17 @@
import logging
from pytorch_lightning.utilities import rank_zero_only
def get_pylogger(name=__name__) -> logging.Logger:
"""Initializes multi-GPU-friendly python command line logger."""
logger = logging.getLogger(name)
# this ensures all logging levels get marked with the rank zero decorator
# otherwise logs would get multiplied for each GPU process in multi-GPU setup
logging_levels = ("debug", "info", "warning", "error", "exception", "fatal", "critical")
for level in logging_levels:
setattr(logger, level, rank_zero_only(getattr(logger, level)))
return logger
+191
View File
@@ -0,0 +1,191 @@
"""
Render OpenPose keypoints.
Code was ported to Python from the official C++ implementation https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/src/openpose/utilities/keypoint.cpp
"""
import cv2
import math
import numpy as np
from typing import List, Tuple
def get_keypoints_rectangle(keypoints: np.array, threshold: float) -> Tuple[float, float, float]:
"""
Compute rectangle enclosing keypoints above the threshold.
Args:
keypoints (np.array): Keypoint array of shape (N, 3).
threshold (float): Confidence visualization threshold.
Returns:
Tuple[float, float, float]: Rectangle width, height and area.
"""
valid_ind = keypoints[:, -1] > threshold
if valid_ind.sum() > 0:
valid_keypoints = keypoints[valid_ind][:, :-1]
max_x = valid_keypoints[:,0].max()
max_y = valid_keypoints[:,1].max()
min_x = valid_keypoints[:,0].min()
min_y = valid_keypoints[:,1].min()
width = max_x - min_x
height = max_y - min_y
area = width * height
return width, height, area
else:
return 0,0,0
def render_keypoints(img: np.array,
keypoints: np.array,
pairs: List,
colors: List,
thickness_circle_ratio: float,
thickness_line_ratio_wrt_circle: float,
pose_scales: List,
threshold: float = 0.1,
alpha: float = 1.0) -> np.array:
"""
Render keypoints on input image.
Args:
img (np.array): Input image of shape (H, W, 3) with pixel values in the [0,255] range.
keypoints (np.array): Keypoint array of shape (N, 3).
pairs (List): List of keypoint pairs per limb.
colors: (List): List of colors per keypoint.
thickness_circle_ratio (float): Circle thickness ratio.
thickness_line_ratio_wrt_circle (float): Line thickness ratio wrt the circle.
pose_scales (List): List of pose scales.
threshold (float): Only visualize keypoints with confidence above the threshold.
Returns:
(np.array): Image of shape (H, W, 3) with keypoints drawn on top of the original image.
"""
img_orig = img.copy()
width, height = img.shape[1], img.shape[2]
area = width * height
lineType = 8
shift = 0
numberColors = len(colors)
thresholdRectangle = 0.1
person_width, person_height, person_area = get_keypoints_rectangle(keypoints, thresholdRectangle)
if person_area > 0:
ratioAreas = min(1, max(person_width / width, person_height / height))
thicknessRatio = np.maximum(np.round(math.sqrt(area) * thickness_circle_ratio * ratioAreas), 2)
thicknessCircle = np.maximum(1, thicknessRatio if ratioAreas > 0.05 else -np.ones_like(thicknessRatio))
thicknessLine = np.maximum(1, np.round(thicknessRatio * thickness_line_ratio_wrt_circle))
radius = thicknessRatio / 2
img = np.ascontiguousarray(img.copy())
for i, pair in enumerate(pairs):
index1, index2 = pair
if keypoints[index1, -1] > threshold and keypoints[index2, -1] > threshold:
thicknessLineScaled = int(round(min(thicknessLine[index1], thicknessLine[index2]) * pose_scales[0]))
colorIndex = index2
color = colors[colorIndex % numberColors]
keypoint1 = keypoints[index1, :-1].astype(np.int32)
keypoint2 = keypoints[index2, :-1].astype(np.int32)
cv2.line(img, tuple(keypoint1.tolist()), tuple(keypoint2.tolist()), tuple(color.tolist()), thicknessLineScaled, lineType, shift)
for part in range(len(keypoints)):
faceIndex = part
if keypoints[faceIndex, -1] > threshold:
radiusScaled = int(round(radius[faceIndex] * pose_scales[0]))
thicknessCircleScaled = int(round(thicknessCircle[faceIndex] * pose_scales[0]))
colorIndex = part
color = colors[colorIndex % numberColors]
center = keypoints[faceIndex, :-1].astype(np.int32)
cv2.circle(img, tuple(center.tolist()), radiusScaled, tuple(color.tolist()), thicknessCircleScaled, lineType, shift)
return img
def render_hand_keypoints(img, right_hand_keypoints, threshold=0.1, use_confidence=False, map_fn=lambda x: np.ones_like(x), alpha=1.0):
if use_confidence and map_fn is not None:
#thicknessCircleRatioLeft = 1./50 * map_fn(left_hand_keypoints[:, -1])
thicknessCircleRatioRight = 1./50 * map_fn(right_hand_keypoints[:, -1])
else:
#thicknessCircleRatioLeft = 1./50 * np.ones(left_hand_keypoints.shape[0])
thicknessCircleRatioRight = 1./50 * np.ones(right_hand_keypoints.shape[0])
thicknessLineRatioWRTCircle = 0.75
pairs = [0,1, 1,2, 2,3, 3,4, 0,5, 5,6, 6,7, 7,8, 0,9, 9,10, 10,11, 11,12, 0,13, 13,14, 14,15, 15,16, 0,17, 17,18, 18,19, 19,20]
pairs = np.array(pairs).reshape(-1,2)
colors = [100., 100., 100.,
100., 0., 0.,
150., 0., 0.,
200., 0., 0.,
255., 0., 0.,
100., 100., 0.,
150., 150., 0.,
200., 200., 0.,
255., 255., 0.,
0., 100., 50.,
0., 150., 75.,
0., 200., 100.,
0., 255., 125.,
0., 50., 100.,
0., 75., 150.,
0., 100., 200.,
0., 125., 255.,
100., 0., 100.,
150., 0., 150.,
200., 0., 200.,
255., 0., 255.]
colors = np.array(colors).reshape(-1,3)
#colors = np.zeros_like(colors)
poseScales = [1]
#img = render_keypoints(img, left_hand_keypoints, pairs, colors, thicknessCircleRatioLeft, thicknessLineRatioWRTCircle, poseScales, threshold, alpha=alpha)
img = render_keypoints(img, right_hand_keypoints, pairs, colors, thicknessCircleRatioRight, thicknessLineRatioWRTCircle, poseScales, threshold, alpha=alpha)
#img = render_keypoints(img, right_hand_keypoints, pairs, colors, thickness_circle_ratio, thickness_line_ratio_wrt_circle, pose_scales, 0.1)
return img
def render_body_keypoints(img: np.array,
body_keypoints: np.array) -> np.array:
"""
Render OpenPose body keypoints on input image.
Args:
img (np.array): Input image of shape (H, W, 3) with pixel values in the [0,255] range.
body_keypoints (np.array): Keypoint array of shape (N, 3); 3 <====> (x, y, confidence).
Returns:
(np.array): Image of shape (H, W, 3) with keypoints drawn on top of the original image.
"""
thickness_circle_ratio = 1./75. * np.ones(body_keypoints.shape[0])
thickness_line_ratio_wrt_circle = 0.75
pairs = []
pairs = [1,8,1,2,1,5,2,3,3,4,5,6,6,7,8,9,9,10,10,11,8,12,12,13,13,14,1,0,0,15,15,17,0,16,16,18,14,19,19,20,14,21,11,22,22,23,11,24]
pairs = np.array(pairs).reshape(-1,2)
colors = [255., 0., 85.,
255., 0., 0.,
255., 85., 0.,
255., 170., 0.,
255., 255., 0.,
170., 255., 0.,
85., 255., 0.,
0., 255., 0.,
255., 0., 0.,
0., 255., 85.,
0., 255., 170.,
0., 255., 255.,
0., 170., 255.,
0., 85., 255.,
0., 0., 255.,
255., 0., 170.,
170., 0., 255.,
255., 0., 255.,
85., 0., 255.,
0., 0., 255.,
0., 0., 255.,
0., 0., 255.,
0., 255., 255.,
0., 255., 255.,
0., 255., 255.]
colors = np.array(colors).reshape(-1,3)
pose_scales = [1]
return render_keypoints(img, body_keypoints, pairs, colors, thickness_circle_ratio, thickness_line_ratio_wrt_circle, pose_scales, 0.1)
def render_openpose(img: np.array,
hand_keypoints: np.array) -> np.array:
"""
Render keypoints in the OpenPose format on input image.
Args:
img (np.array): Input image of shape (H, W, 3) with pixel values in the [0,255] range.
body_keypoints (np.array): Keypoint array of shape (N, 3); 3 <====> (x, y, confidence).
Returns:
(np.array): Image of shape (H, W, 3) with keypoints drawn on top of the original image.
"""
#img = render_body_keypoints(img, body_keypoints)
img = render_hand_keypoints(img, hand_keypoints)
return img
+423
View File
@@ -0,0 +1,423 @@
import os
if 'PYOPENGL_PLATFORM' not in os.environ:
os.environ['PYOPENGL_PLATFORM'] = 'egl'
import torch
import numpy as np
import pyrender
import trimesh
import cv2
from yacs.config import CfgNode
from typing import List, Optional
def cam_crop_to_full(cam_bbox, box_center, box_size, img_size, focal_length=5000.):
# Convert cam_bbox to full image
img_w, img_h = img_size[:, 0], img_size[:, 1]
cx, cy, b = box_center[:, 0], box_center[:, 1], box_size
w_2, h_2 = img_w / 2., img_h / 2.
bs = b * cam_bbox[:, 0] + 1e-9
tz = 2 * focal_length / bs
tx = (2 * (cx - w_2) / bs) + cam_bbox[:, 1]
ty = (2 * (cy - h_2) / bs) + cam_bbox[:, 2]
full_cam = torch.stack([tx, ty, tz], dim=-1)
return full_cam
def get_light_poses(n_lights=5, elevation=np.pi / 3, dist=12):
# get lights in a circle around origin at elevation
thetas = elevation * np.ones(n_lights)
phis = 2 * np.pi * np.arange(n_lights) / n_lights
poses = []
trans = make_translation(torch.tensor([0, 0, dist]))
for phi, theta in zip(phis, thetas):
rot = make_rotation(rx=-theta, ry=phi, order="xyz")
poses.append((rot @ trans).numpy())
return poses
def make_translation(t):
return make_4x4_pose(torch.eye(3), t)
def make_rotation(rx=0, ry=0, rz=0, order="xyz"):
Rx = rotx(rx)
Ry = roty(ry)
Rz = rotz(rz)
if order == "xyz":
R = Rz @ Ry @ Rx
elif order == "xzy":
R = Ry @ Rz @ Rx
elif order == "yxz":
R = Rz @ Rx @ Ry
elif order == "yzx":
R = Rx @ Rz @ Ry
elif order == "zyx":
R = Rx @ Ry @ Rz
elif order == "zxy":
R = Ry @ Rx @ Rz
return make_4x4_pose(R, torch.zeros(3))
def make_4x4_pose(R, t):
"""
:param R (*, 3, 3)
:param t (*, 3)
return (*, 4, 4)
"""
dims = R.shape[:-2]
pose_3x4 = torch.cat([R, t.view(*dims, 3, 1)], dim=-1)
bottom = (
torch.tensor([0, 0, 0, 1], device=R.device)
.reshape(*(1,) * len(dims), 1, 4)
.expand(*dims, 1, 4)
)
return torch.cat([pose_3x4, bottom], dim=-2)
def rotx(theta):
return torch.tensor(
[
[1, 0, 0],
[0, np.cos(theta), -np.sin(theta)],
[0, np.sin(theta), np.cos(theta)],
],
dtype=torch.float32,
)
def roty(theta):
return torch.tensor(
[
[np.cos(theta), 0, np.sin(theta)],
[0, 1, 0],
[-np.sin(theta), 0, np.cos(theta)],
],
dtype=torch.float32,
)
def rotz(theta):
return torch.tensor(
[
[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1],
],
dtype=torch.float32,
)
def create_raymond_lights() -> List[pyrender.Node]:
"""
Return raymond light nodes for the scene.
"""
thetas = np.pi * np.array([1.0 / 6.0, 1.0 / 6.0, 1.0 / 6.0])
phis = np.pi * np.array([0.0, 2.0 / 3.0, 4.0 / 3.0])
nodes = []
for phi, theta in zip(phis, thetas):
xp = np.sin(theta) * np.cos(phi)
yp = np.sin(theta) * np.sin(phi)
zp = np.cos(theta)
z = np.array([xp, yp, zp])
z = z / np.linalg.norm(z)
x = np.array([-z[1], z[0], 0.0])
if np.linalg.norm(x) == 0:
x = np.array([1.0, 0.0, 0.0])
x = x / np.linalg.norm(x)
y = np.cross(z, x)
matrix = np.eye(4)
matrix[:3,:3] = np.c_[x,y,z]
nodes.append(pyrender.Node(
light=pyrender.DirectionalLight(color=np.ones(3), intensity=1.0),
matrix=matrix
))
return nodes
class Renderer:
def __init__(self, cfg: CfgNode, faces: np.array):
"""
Wrapper around the pyrender renderer to render MANO meshes.
Args:
cfg (CfgNode): Model config file.
faces (np.array): Array of shape (F, 3) containing the mesh faces.
"""
self.cfg = cfg
self.focal_length = cfg.EXTRA.FOCAL_LENGTH
self.img_res = cfg.MODEL.IMAGE_SIZE
# add faces that make the hand mesh watertight
faces_new = np.array([[92, 38, 234],
[234, 38, 239],
[38, 122, 239],
[239, 122, 279],
[122, 118, 279],
[279, 118, 215],
[118, 117, 215],
[215, 117, 214],
[117, 119, 214],
[214, 119, 121],
[119, 120, 121],
[121, 120, 78],
[120, 108, 78],
[78, 108, 79]])
faces = np.concatenate([faces, faces_new], axis=0)
self.camera_center = [self.img_res // 2, self.img_res // 2]
self.faces = faces
self.faces_left = self.faces[:,[0,2,1]]
def __call__(self,
vertices: np.array,
camera_translation: np.array,
image: torch.Tensor,
full_frame: bool = False,
imgname: Optional[str] = None,
side_view=False, rot_angle=90,
mesh_base_color=(1.0, 1.0, 0.9),
scene_bg_color=(0,0,0),
return_rgba=False,
) -> np.array:
"""
Render meshes on input image
Args:
vertices (np.array): Array of shape (V, 3) containing the mesh vertices.
camera_translation (np.array): Array of shape (3,) with the camera translation.
image (torch.Tensor): Tensor of shape (3, H, W) containing the image crop with normalized pixel values.
full_frame (bool): If True, then render on the full image.
imgname (Optional[str]): Contains the original image filenamee. Used only if full_frame == True.
"""
if full_frame:
image = cv2.imread(imgname).astype(np.float32)[:, :, ::-1] / 255.
else:
image = image.clone() * torch.tensor(self.cfg.MODEL.IMAGE_STD, device=image.device).reshape(3,1,1)
image = image + torch.tensor(self.cfg.MODEL.IMAGE_MEAN, device=image.device).reshape(3,1,1)
image = image.permute(1, 2, 0).cpu().numpy()
renderer = pyrender.OffscreenRenderer(viewport_width=image.shape[1],
viewport_height=image.shape[0],
point_size=1.0)
material = pyrender.MetallicRoughnessMaterial(
metallicFactor=0.0,
alphaMode='OPAQUE',
baseColorFactor=(*mesh_base_color, 1.0))
camera_translation[0] *= -1.
mesh = trimesh.Trimesh(vertices.copy(), self.faces.copy())
if side_view:
rot = trimesh.transformations.rotation_matrix(
np.radians(rot_angle), [0, 1, 0])
mesh.apply_transform(rot)
rot = trimesh.transformations.rotation_matrix(
np.radians(180), [1, 0, 0])
mesh.apply_transform(rot)
mesh = pyrender.Mesh.from_trimesh(mesh, material=material)
scene = pyrender.Scene(bg_color=[*scene_bg_color, 0.0],
ambient_light=(0.3, 0.3, 0.3))
scene.add(mesh, 'mesh')
camera_pose = np.eye(4)
camera_pose[:3, 3] = camera_translation
camera_center = [image.shape[1] / 2., image.shape[0] / 2.]
camera = pyrender.IntrinsicsCamera(fx=self.focal_length, fy=self.focal_length,
cx=camera_center[0], cy=camera_center[1], zfar=1e12)
scene.add(camera, pose=camera_pose)
light_nodes = create_raymond_lights()
for node in light_nodes:
scene.add_node(node)
color, rend_depth = renderer.render(scene, flags=pyrender.RenderFlags.RGBA)
color = color.astype(np.float32) / 255.0
renderer.delete()
if return_rgba:
return color
valid_mask = (color[:, :, -1])[:, :, np.newaxis]
if not side_view:
output_img = (color[:, :, :3] * valid_mask + (1 - valid_mask) * image)
else:
output_img = color[:, :, :3]
output_img = output_img.astype(np.float32)
return output_img
def vertices_to_trimesh(self, vertices, camera_translation, mesh_base_color=(1.0, 1.0, 0.9),
rot_axis=[1,0,0], rot_angle=0, is_right=1):
# material = pyrender.MetallicRoughnessMaterial(
# metallicFactor=0.0,
# alphaMode='OPAQUE',
# baseColorFactor=(*mesh_base_color, 1.0))
vertex_colors = np.array([(*mesh_base_color, 1.0)] * vertices.shape[0])
if is_right:
mesh = trimesh.Trimesh(vertices.copy() + camera_translation, self.faces.copy(), vertex_colors=vertex_colors)
else:
mesh = trimesh.Trimesh(vertices.copy() + camera_translation, self.faces_left.copy(), vertex_colors=vertex_colors)
# mesh = trimesh.Trimesh(vertices.copy(), self.faces.copy())
rot = trimesh.transformations.rotation_matrix(
np.radians(rot_angle), rot_axis)
mesh.apply_transform(rot)
rot = trimesh.transformations.rotation_matrix(
np.radians(180), [1, 0, 0])
mesh.apply_transform(rot)
return mesh
def render_rgba(
self,
vertices: np.array,
cam_t = None,
rot=None,
rot_axis=[1,0,0],
rot_angle=0,
camera_z=3,
# camera_translation: np.array,
mesh_base_color=(1.0, 1.0, 0.9),
scene_bg_color=(0,0,0),
render_res=[256, 256],
focal_length=None,
is_right=None,
):
renderer = pyrender.OffscreenRenderer(viewport_width=render_res[0],
viewport_height=render_res[1],
point_size=1.0)
# material = pyrender.MetallicRoughnessMaterial(
# metallicFactor=0.0,
# alphaMode='OPAQUE',
# baseColorFactor=(*mesh_base_color, 1.0))
focal_length = focal_length if focal_length is not None else self.focal_length
if cam_t is not None:
camera_translation = cam_t.copy()
camera_translation[0] *= -1.
else:
camera_translation = np.array([0, 0, camera_z * focal_length/render_res[1]])
mesh = self.vertices_to_trimesh(vertices, np.array([0, 0, 0]), mesh_base_color, rot_axis, rot_angle, is_right=is_right)
mesh = pyrender.Mesh.from_trimesh(mesh)
# mesh = pyrender.Mesh.from_trimesh(mesh, material=material)
scene = pyrender.Scene(bg_color=[*scene_bg_color, 0.0],
ambient_light=(0.3, 0.3, 0.3))
scene.add(mesh, 'mesh')
camera_pose = np.eye(4)
camera_pose[:3, 3] = camera_translation
camera_center = [render_res[0] / 2., render_res[1] / 2.]
camera = pyrender.IntrinsicsCamera(fx=focal_length, fy=focal_length,
cx=camera_center[0], cy=camera_center[1], zfar=1e12)
# Create camera node and add it to pyRender scene
camera_node = pyrender.Node(camera=camera, matrix=camera_pose)
scene.add_node(camera_node)
self.add_point_lighting(scene, camera_node)
self.add_lighting(scene, camera_node)
light_nodes = create_raymond_lights()
for node in light_nodes:
scene.add_node(node)
color, rend_depth = renderer.render(scene, flags=pyrender.RenderFlags.RGBA)
color = color.astype(np.float32) / 255.0
renderer.delete()
return color
def render_rgba_multiple(
self,
vertices: List[np.array],
cam_t: List[np.array],
rot_axis=[1,0,0],
rot_angle=0,
mesh_base_color=(1.0, 1.0, 0.9),
scene_bg_color=(0,0,0),
render_res=[256, 256],
focal_length=None,
is_right=None,
):
renderer = pyrender.OffscreenRenderer(viewport_width=render_res[0],
viewport_height=render_res[1],
point_size=1.0)
# material = pyrender.MetallicRoughnessMaterial(
# metallicFactor=0.0,
# alphaMode='OPAQUE',
# baseColorFactor=(*mesh_base_color, 1.0))
if is_right is None:
is_right = [1 for _ in range(len(vertices))]
mesh_list = [pyrender.Mesh.from_trimesh(self.vertices_to_trimesh(vvv, ttt.copy(), mesh_base_color, rot_axis, rot_angle, is_right=sss)) for vvv,ttt,sss in zip(vertices, cam_t, is_right)]
scene = pyrender.Scene(bg_color=[*scene_bg_color, 0.0],
ambient_light=(0.3, 0.3, 0.3))
for i,mesh in enumerate(mesh_list):
scene.add(mesh, f'mesh_{i}')
camera_pose = np.eye(4)
# camera_pose[:3, 3] = camera_translation
camera_center = [render_res[0] / 2., render_res[1] / 2.]
focal_length = focal_length if focal_length is not None else self.focal_length
camera = pyrender.IntrinsicsCamera(fx=focal_length, fy=focal_length,
cx=camera_center[0], cy=camera_center[1], zfar=1e12)
# Create camera node and add it to pyRender scene
camera_node = pyrender.Node(camera=camera, matrix=camera_pose)
scene.add_node(camera_node)
self.add_point_lighting(scene, camera_node)
self.add_lighting(scene, camera_node)
light_nodes = create_raymond_lights()
for node in light_nodes:
scene.add_node(node)
color, rend_depth = renderer.render(scene, flags=pyrender.RenderFlags.RGBA)
color = color.astype(np.float32) / 255.0
renderer.delete()
return color
def add_lighting(self, scene, cam_node, color=np.ones(3), intensity=1.0):
# from phalp.visualize.py_renderer import get_light_poses
light_poses = get_light_poses()
light_poses.append(np.eye(4))
cam_pose = scene.get_pose(cam_node)
for i, pose in enumerate(light_poses):
matrix = cam_pose @ pose
node = pyrender.Node(
name=f"light-{i:02d}",
light=pyrender.DirectionalLight(color=color, intensity=intensity),
matrix=matrix,
)
if scene.has_node(node):
continue
scene.add_node(node)
def add_point_lighting(self, scene, cam_node, color=np.ones(3), intensity=1.0):
# from phalp.visualize.py_renderer import get_light_poses
light_poses = get_light_poses(dist=0.5)
light_poses.append(np.eye(4))
cam_pose = scene.get_pose(cam_node)
for i, pose in enumerate(light_poses):
matrix = cam_pose @ pose
# node = pyrender.Node(
# name=f"light-{i:02d}",
# light=pyrender.DirectionalLight(color=color, intensity=intensity),
# matrix=matrix,
# )
node = pyrender.Node(
name=f"plight-{i:02d}",
light=pyrender.PointLight(color=color, intensity=intensity),
matrix=matrix,
)
if scene.has_node(node):
continue
scene.add_node(node)
+105
View File
@@ -0,0 +1,105 @@
from pathlib import Path
from typing import Sequence
import rich
import rich.syntax
import rich.tree
from hydra.core.hydra_config import HydraConfig
from omegaconf import DictConfig, OmegaConf, open_dict
from pytorch_lightning.utilities import rank_zero_only
from rich.prompt import Prompt
from . import pylogger
log = pylogger.get_pylogger(__name__)
@rank_zero_only
def print_config_tree(
cfg: DictConfig,
print_order: Sequence[str] = (
"datamodule",
"model",
"callbacks",
"logger",
"trainer",
"paths",
"extras",
),
resolve: bool = False,
save_to_file: bool = False,
) -> None:
"""Prints content of DictConfig using Rich library and its tree structure.
Args:
cfg (DictConfig): Configuration composed by Hydra.
print_order (Sequence[str], optional): Determines in what order config components are printed.
resolve (bool, optional): Whether to resolve reference fields of DictConfig.
save_to_file (bool, optional): Whether to export config to the hydra output folder.
"""
style = "dim"
tree = rich.tree.Tree("CONFIG", style=style, guide_style=style)
queue = []
# add fields from `print_order` to queue
for field in print_order:
queue.append(field) if field in cfg else log.warning(
f"Field '{field}' not found in config. Skipping '{field}' config printing..."
)
# add all the other fields to queue (not specified in `print_order`)
for field in cfg:
if field not in queue:
queue.append(field)
# generate config tree from queue
for field in queue:
branch = tree.add(field, style=style, guide_style=style)
config_group = cfg[field]
if isinstance(config_group, DictConfig):
branch_content = OmegaConf.to_yaml(config_group, resolve=resolve)
else:
branch_content = str(config_group)
branch.add(rich.syntax.Syntax(branch_content, "yaml"))
# print config tree
rich.print(tree)
# save config tree to file
if save_to_file:
with open(Path(cfg.paths.output_dir, "config_tree.log"), "w") as file:
rich.print(tree, file=file)
@rank_zero_only
def enforce_tags(cfg: DictConfig, save_to_file: bool = False) -> None:
"""Prompts user to input tags from command line if no tags are provided in config."""
if not cfg.get("tags"):
if "id" in HydraConfig().cfg.hydra.job:
raise ValueError("Specify tags before launching a multirun!")
log.warning("No tags provided in config. Prompting user to input tags...")
tags = Prompt.ask("Enter a list of comma separated tags", default="dev")
tags = [t.strip() for t in tags.split(",") if t != ""]
with open_dict(cfg):
cfg.tags = tags
log.info(f"Tags: {cfg.tags}")
if save_to_file:
with open(Path(cfg.paths.output_dir, "tags.log"), "w") as file:
rich.print(cfg.tags, file=file)
if __name__ == "__main__":
from hydra import compose, initialize
with initialize(version_base="1.2", config_path="../../configs"):
cfg = compose(config_name="train.yaml", return_hydra_config=False, overrides=[])
print_config_tree(cfg, resolve=False, save_to_file=False)
+124
View File
@@ -0,0 +1,124 @@
import torch
import numpy as np
import trimesh
from typing import Optional
from yacs.config import CfgNode
from .geometry import perspective_projection
from .render_openpose import render_openpose
class SkeletonRenderer:
def __init__(self, cfg: CfgNode):
"""
Object used to render 3D keypoints. Faster for use during training.
Args:
cfg (CfgNode): Model config file.
"""
self.cfg = cfg
def __call__(self,
pred_keypoints_3d: torch.Tensor,
gt_keypoints_3d: torch.Tensor,
gt_keypoints_2d: torch.Tensor,
images: Optional[np.array] = None,
camera_translation: Optional[torch.Tensor] = None) -> np.array:
"""
Render batch of 3D keypoints.
Args:
pred_keypoints_3d (torch.Tensor): Tensor of shape (B, S, N, 3) containing a batch of predicted 3D keypoints, with S samples per image.
gt_keypoints_3d (torch.Tensor): Tensor of shape (B, N, 4) containing corresponding ground truth 3D keypoints; last value is the confidence.
gt_keypoints_2d (torch.Tensor): Tensor of shape (B, N, 3) containing corresponding ground truth 2D keypoints.
images (torch.Tensor): Tensor of shape (B, H, W, 3) containing images with values in the [0,255] range.
camera_translation (torch.Tensor): Tensor of shape (B, 3) containing the camera translation.
Returns:
np.array : Image with the following layout. Each row contains the a) input image,
b) image with gt 2D keypoints,
c) image with projected gt 3D keypoints,
d_1, ... , d_S) image with projected predicted 3D keypoints,
e) gt 3D keypoints rendered from a side view,
f_1, ... , f_S) predicted 3D keypoints frorm a side view
"""
batch_size = pred_keypoints_3d.shape[0]
# num_samples = pred_keypoints_3d.shape[1]
pred_keypoints_3d = pred_keypoints_3d.clone().cpu().float()
gt_keypoints_3d = gt_keypoints_3d.clone().cpu().float()
gt_keypoints_3d[:, :, :-1] = gt_keypoints_3d[:, :, :-1] - gt_keypoints_3d[:, [0], :-1] + pred_keypoints_3d[:, [0]]
gt_keypoints_2d = gt_keypoints_2d.clone().cpu().float().numpy()
gt_keypoints_2d[:, :, :-1] = self.cfg.MODEL.IMAGE_SIZE * (gt_keypoints_2d[:, :, :-1] + 1.0) / 2.0
#openpose_indices = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
#gt_indices = [12, 8, 7, 6, 9, 10, 11, 14, 2, 1, 0, 3, 4, 5]
#gt_indices = [25 + i for i in gt_indices]
openpose_indices = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
gt_indices = openpose_indices
keypoints_to_render = torch.ones(batch_size, gt_keypoints_3d.shape[1], 1)
rotation = torch.eye(3).unsqueeze(0)
if camera_translation is None:
camera_translation = torch.tensor([0.0, 0.0, 2 * self.cfg.EXTRA.FOCAL_LENGTH / (0.8 * self.cfg.MODEL.IMAGE_SIZE)]).unsqueeze(0).repeat(batch_size, 1)
else:
camera_translation = camera_translation.cpu()
if images is None:
images = np.zeros((batch_size, self.cfg.MODEL.IMAGE_SIZE, self.cfg.MODEL.IMAGE_SIZE, 3))
focal_length = torch.tensor([self.cfg.EXTRA.FOCAL_LENGTH, self.cfg.EXTRA.FOCAL_LENGTH]).reshape(1, 2)
camera_center = torch.tensor([self.cfg.MODEL.IMAGE_SIZE, self.cfg.MODEL.IMAGE_SIZE], dtype=torch.float).reshape(1, 2) / 2.
gt_keypoints_3d_proj = perspective_projection(gt_keypoints_3d[:, :, :-1], rotation=rotation.repeat(batch_size, 1, 1), translation=camera_translation[:, :], focal_length=focal_length.repeat(batch_size, 1), camera_center=camera_center.repeat(batch_size, 1))
pred_keypoints_3d_proj = perspective_projection(pred_keypoints_3d.reshape(batch_size, -1, 3), rotation=rotation.repeat(batch_size, 1, 1), translation=camera_translation.reshape(batch_size, -1), focal_length=focal_length.repeat(batch_size, 1), camera_center=camera_center.repeat(batch_size, 1)).reshape(batch_size, -1, 2)
gt_keypoints_3d_proj = torch.cat([gt_keypoints_3d_proj, gt_keypoints_3d[:, :, [-1]]], dim=-1).cpu().numpy()
pred_keypoints_3d_proj = torch.cat([pred_keypoints_3d_proj, keypoints_to_render.reshape(batch_size, -1, 1)], dim=-1).cpu().numpy()
rows = []
# Rotate keypoints to visualize side view
R = torch.tensor(trimesh.transformations.rotation_matrix(np.radians(90), [0, 1, 0])[:3, :3]).float()
gt_keypoints_3d_side = gt_keypoints_3d.clone()
gt_keypoints_3d_side[:, :, :-1] = torch.einsum('bni,ij->bnj', gt_keypoints_3d_side[:, :, :-1], R)
pred_keypoints_3d_side = pred_keypoints_3d.clone()
pred_keypoints_3d_side = torch.einsum('bni,ij->bnj', pred_keypoints_3d_side, R)
gt_keypoints_3d_proj_side = perspective_projection(gt_keypoints_3d_side[:, :, :-1], rotation=rotation.repeat(batch_size, 1, 1), translation=camera_translation[:, :], focal_length=focal_length.repeat(batch_size, 1), camera_center=camera_center.repeat(batch_size, 1))
pred_keypoints_3d_proj_side = perspective_projection(pred_keypoints_3d_side.reshape(batch_size, -1, 3), rotation=rotation.repeat(batch_size, 1, 1), translation=camera_translation.reshape(batch_size, -1), focal_length=focal_length.repeat(batch_size, 1), camera_center=camera_center.repeat(batch_size, 1)).reshape(batch_size, -1, 2)
gt_keypoints_3d_proj_side = torch.cat([gt_keypoints_3d_proj_side, gt_keypoints_3d_side[:, :, [-1]]], dim=-1).cpu().numpy()
pred_keypoints_3d_proj_side = torch.cat([pred_keypoints_3d_proj_side, keypoints_to_render.reshape(batch_size, -1, 1)], dim=-1).cpu().numpy()
for i in range(batch_size):
img = images[i]
side_img = np.zeros((self.cfg.MODEL.IMAGE_SIZE, self.cfg.MODEL.IMAGE_SIZE, 3))
# gt 2D keypoints
body_keypoints_2d = gt_keypoints_2d[i, :21].copy()
for op, gt in zip(openpose_indices, gt_indices):
if gt_keypoints_2d[i, gt, -1] > body_keypoints_2d[op, -1]:
body_keypoints_2d[op] = gt_keypoints_2d[i, gt]
gt_keypoints_img = render_openpose(img, body_keypoints_2d) / 255.
# gt 3D keypoints
body_keypoints_3d_proj = gt_keypoints_3d_proj[i, :21].copy()
for op, gt in zip(openpose_indices, gt_indices):
if gt_keypoints_3d_proj[i, gt, -1] > body_keypoints_3d_proj[op, -1]:
body_keypoints_3d_proj[op] = gt_keypoints_3d_proj[i, gt]
gt_keypoints_3d_proj_img = render_openpose(img, body_keypoints_3d_proj) / 255.
# gt 3D keypoints from the side
body_keypoints_3d_proj = gt_keypoints_3d_proj_side[i, :21].copy()
for op, gt in zip(openpose_indices, gt_indices):
if gt_keypoints_3d_proj_side[i, gt, -1] > body_keypoints_3d_proj[op, -1]:
body_keypoints_3d_proj[op] = gt_keypoints_3d_proj_side[i, gt]
gt_keypoints_3d_proj_img_side = render_openpose(side_img, body_keypoints_3d_proj) / 255.
# pred 3D keypoints
pred_keypoints_3d_proj_imgs = []
body_keypoints_3d_proj = pred_keypoints_3d_proj[i, :21].copy()
for op, gt in zip(openpose_indices, gt_indices):
if pred_keypoints_3d_proj[i, gt, -1] >= body_keypoints_3d_proj[op, -1]:
body_keypoints_3d_proj[op] = pred_keypoints_3d_proj[i, gt]
pred_keypoints_3d_proj_imgs.append(render_openpose(img, body_keypoints_3d_proj) / 255.)
pred_keypoints_3d_proj_img = np.concatenate(pred_keypoints_3d_proj_imgs, axis=1)
# gt 3D keypoints from the side
pred_keypoints_3d_proj_imgs_side = []
body_keypoints_3d_proj = pred_keypoints_3d_proj_side[i, :21].copy()
for op, gt in zip(openpose_indices, gt_indices):
if pred_keypoints_3d_proj_side[i, gt, -1] >= body_keypoints_3d_proj[op, -1]:
body_keypoints_3d_proj[op] = pred_keypoints_3d_proj_side[i, gt]
pred_keypoints_3d_proj_imgs_side.append(render_openpose(side_img, body_keypoints_3d_proj) / 255.)
pred_keypoints_3d_proj_img_side = np.concatenate(pred_keypoints_3d_proj_imgs_side, axis=1)
rows.append(np.concatenate((gt_keypoints_img, gt_keypoints_3d_proj_img, pred_keypoints_3d_proj_img, gt_keypoints_3d_proj_img_side, pred_keypoints_3d_proj_img_side), axis=1))
# Concatenate images
img = np.concatenate(rows, axis=0)
img[:, ::self.cfg.MODEL.IMAGE_SIZE, :] = 1.0
img[::self.cfg.MODEL.IMAGE_SIZE, :, :] = 1.0
img[:, (1+1+1)*self.cfg.MODEL.IMAGE_SIZE, :] = 0.5
return img
+93
View File
@@ -0,0 +1,93 @@
import detectron2.data.transforms as T
import torch
from detectron2.checkpoint import DetectionCheckpointer
from detectron2.config import CfgNode, instantiate
from detectron2.data import MetadataCatalog
from omegaconf import OmegaConf
class DefaultPredictor_Lazy:
"""Create a simple end-to-end predictor with the given config that runs on single device for a
single input image.
Compared to using the model directly, this class does the following additions:
1. Load checkpoint from the weights specified in config (cfg.MODEL.WEIGHTS).
2. Always take BGR image as the input and apply format conversion internally.
3. Apply resizing defined by the config (`cfg.INPUT.{MIN,MAX}_SIZE_TEST`).
4. Take one input image and produce a single output, instead of a batch.
This is meant for simple demo purposes, so it does the above steps automatically.
This is not meant for benchmarks or running complicated inference logic.
If you'd like to do anything more complicated, please refer to its source code as
examples to build and use the model manually.
Attributes:
metadata (Metadata): the metadata of the underlying dataset, obtained from
test dataset name in the config.
Examples:
::
pred = DefaultPredictor(cfg)
inputs = cv2.imread("input.jpg")
outputs = pred(inputs)
"""
def __init__(self, cfg):
"""
Args:
cfg: a yacs CfgNode or a omegaconf dict object.
"""
if isinstance(cfg, CfgNode):
self.cfg = cfg.clone() # cfg can be modified by model
self.model = build_model(self.cfg) # noqa: F821
if len(cfg.DATASETS.TEST):
test_dataset = cfg.DATASETS.TEST[0]
checkpointer = DetectionCheckpointer(self.model)
checkpointer.load(cfg.MODEL.WEIGHTS)
self.aug = T.ResizeShortestEdge(
[cfg.INPUT.MIN_SIZE_TEST, cfg.INPUT.MIN_SIZE_TEST], cfg.INPUT.MAX_SIZE_TEST
)
self.input_format = cfg.INPUT.FORMAT
else: # new LazyConfig
self.cfg = cfg
self.model = instantiate(cfg.model)
test_dataset = OmegaConf.select(cfg, "dataloader.test.dataset.names", default=None)
if isinstance(test_dataset, (list, tuple)):
test_dataset = test_dataset[0]
checkpointer = DetectionCheckpointer(self.model)
checkpointer.load(OmegaConf.select(cfg, "train.init_checkpoint", default=""))
mapper = instantiate(cfg.dataloader.test.mapper)
self.aug = mapper.augmentations
self.input_format = mapper.image_format
self.model.eval().cuda()
if test_dataset:
self.metadata = MetadataCatalog.get(test_dataset)
assert self.input_format in ["RGB", "BGR"], self.input_format
def __call__(self, original_image):
"""
Args:
original_image (np.ndarray): an image of shape (H, W, C) (in BGR order).
Returns:
predictions (dict):
the output of the model for one image only.
See :doc:`/tutorials/models` for details about the format.
"""
with torch.no_grad():
if self.input_format == "RGB":
original_image = original_image[:, :, ::-1]
height, width = original_image.shape[:2]
image = self.aug(T.AugInput(original_image)).apply_image(original_image)
image = torch.as_tensor(image.astype("float32").transpose(2, 0, 1))
inputs = {"image": image, "height": height, "width": width}
predictions = self.model([inputs])[0]
return predictions
+37
View File
@@ -0,0 +1,37 @@
from setuptools import setup, find_packages
print('Found packages:', find_packages())
setup(
description='HaMeR as a package',
name='hamer',
packages=find_packages(),
install_requires=[
'gdown',
'numpy',
'opencv-python',
'pyrender',
'pytorch-lightning',
'scikit-image',
'smplx==0.1.28',
'torch',
'torchvision',
'yacs',
'detectron2 @ git+https://github.com/facebookresearch/detectron2',
'chumpy @ git+https://github.com/mattloper/chumpy',
'mmcv==1.3.9',
'timm',
'einops',
'xtcocotools',
'pandas',
],
extras_require={
'all': [
'hydra-core',
'hydra-submitit-launcher',
'hydra-colorlog',
'pyrootutils',
'rich',
'webdataset',
],
},
)
+203
View File
@@ -0,0 +1,203 @@
Copyright 2018-2020 Open-MMLab. All rights reserved.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-2020 Open-MMLab.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+5
View File
@@ -0,0 +1,5 @@
include requirements/*.txt
include mmpose/.mim/model-index.yml
recursive-include mmpose/.mim/configs *.py *.yml
recursive-include mmpose/.mim/tools *.py *.sh
recursive-include mmpose/.mim/demo *.py
+293
View File
@@ -0,0 +1,293 @@
<h1 align="left">ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation<a href="https://arxiv.org/abs/2204.12484"><img src="https://img.shields.io/badge/arXiv-Paper-<COLOR>.svg" ></a> </h1>
[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/vitpose-simple-vision-transformer-baselines/pose-estimation-on-coco-test-dev)](https://paperswithcode.com/sota/pose-estimation-on-coco-test-dev?p=vitpose-simple-vision-transformer-baselines)
[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/vitpose-simple-vision-transformer-baselines/pose-estimation-on-aic)](https://paperswithcode.com/sota/pose-estimation-on-aic?p=vitpose-simple-vision-transformer-baselines)
[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/vitpose-simple-vision-transformer-baselines/pose-estimation-on-crowdpose)](https://paperswithcode.com/sota/pose-estimation-on-crowdpose?p=vitpose-simple-vision-transformer-baselines)
[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/vitpose-simple-vision-transformer-baselines/pose-estimation-on-ochuman)](https://paperswithcode.com/sota/pose-estimation-on-ochuman?p=vitpose-simple-vision-transformer-baselines)
<p align="center">
<a href="#Results">Results</a> |
<a href="#Updates">Updates</a> |
<a href="#Usage">Usage</a> |
<a href='#Todo'>Todo</a> |
<a href="#Acknowledge">Acknowledge</a>
</p>
<p align="center">
<a href="https://giphy.com/gifs/UfPQB1qKir7Vqem6sL/fullscreen"><img src="https://media.giphy.com/media/ZewXwZuixYKS2lZmNL/giphy.gif"></a> <a href="https://giphy.com/gifs/DCvf1DrWZgbwPa8bWZ/fullscreen"><img src="https://media.giphy.com/media/2AEeuicbIjwqp2mbug/giphy.gif"></a>
</p>
<p align="center">
<a href="https://giphy.com/gifs/r3GaZz7H1H6zpuIvPI/fullscreen"><img src="https://media.giphy.com/media/13oe6zo6b2B7CdsOac/giphy.gif"></a> <a href="https://giphy.com/gifs/FjzrGJxsOzZAXaW7Vi/fullscreen"><img src="https://media.giphy.com/media/4JLERHxOEgH0tt5DZO/giphy.gif"></a>
</p>
This branch contains the pytorch implementation of <a href="https://arxiv.org/abs/2204.12484">ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation</a> and <a href="https://arxiv.org/abs/2212.04246">ViTPose+: Vision Transformer Foundation Model for Generic Body Pose Estimation</a>. It obtains 81.1 AP on MS COCO Keypoint test-dev set.
<img src="figures/Throughput.png" class="left" width='80%'>
## Web Demo
- Integrated into [Huggingface Spaces 🤗](https://huggingface.co/spaces) using [Gradio](https://github.com/gradio-app/gradio). Try out the Web Demo for video: [![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/hysts/ViTPose_video) and images [![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/Gradio-Blocks/ViTPose)
## MAE Pre-trained model
- The small size MAE pre-trained model can be found in [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccZeiFjh4DJ7gjYyg?e=iTMdMq).
- The base, large, and huge pre-trained models using MAE can be found in the [MAE official repo](https://github.com/facebookresearch/mae).
## Results from this repo on MS COCO val set (single-task training)
Using detection results from a detector that obtains 56 mAP on person. The configs here are for both training and test.
> With classic decoder
| Model | Pretrain | Resolution | AP | AR | config | log | weight |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-S | MAE | 256x192 | 73.8 | 79.2 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_small_coco_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcchdNXBAh7ClS14pA?e=dKXmJ6) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccifT1XlGRatxg3vw?e=9wz7BY) |
| ViTPose-B | MAE | 256x192 | 75.8 | 81.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_base_coco_256x192.py) | [log](logs/vitpose-b.log.json) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSMjp1_NrV3VRSmK?e=Q1uZKs) |
| ViTPose-L | MAE | 256x192 | 78.3 | 83.5 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_large_coco_256x192.py) | [log](logs/vitpose-l.log.json) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSd9k_kuktPtiP4F?e=K7DGYT) |
| ViTPose-H | MAE | 256x192 | 79.1 | 84.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_huge_coco_256x192.py) | [log](logs/vitpose-h.log.json) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgShLMI-kkmvNfF_h?e=dEhGHe) |
> With simple decoder
| Model | Pretrain | Resolution | AP | AR | config | log | weight |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-S | MAE | 256x192 | 73.5 | 78.9 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_small_simple_coco_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccfkqELJqE67kpRtw?e=InSjJP) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccgb_50jIgiYkHvdw?e=D7RbH2) |
| ViTPose-B | MAE | 256x192 | 75.5 | 80.9 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_base_simple_coco_256x192.py) | [log](logs/vitpose-b-simple.log.json) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSRPKrD5PmDRiv0R?e=jifvOe) |
| ViTPose-L | MAE | 256x192 | 78.2 | 83.4 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_large_simple_coco_256x192.py) | [log](logs/vitpose-l-simple.log.json) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSVS6DP2LmKwZ3sm?e=MmCvDT) |
| ViTPose-H | MAE | 256x192 | 78.9 | 84.0 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_huge_simple_coco_256x192.py) | [log](logs/vitpose-h-simple.log.json) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSbHyN2mjh2n2LyG?e=y0FgMK) |
## Results with multi-task training
**Note** \* There may exist duplicate images in the crowdpose training set and the validation images in other datasets, as discussed in [issue #24](https://github.com/ViTAE-Transformer/ViTPose/issues/24). Please be careful when using these models for evaluation. We provide the results without the crowpose dataset for reference.
### Human datasets (MS COCO, AIC, MPII, CrowdPose)
> Results on MS COCO val set
Using detection results from a detector that obtains 56 mAP on person. Note the configs here are only for evaluation.
| Model | Dataset | Resolution | AP | AR | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-B | COCO+AIC+MPII | 256x192 | 77.1 | 82.2 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_base_coco_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcccwaTZ8xCFFM3Sjg?e=chmiK5) |
| ViTPose-L | COCO+AIC+MPII | 256x192 | 78.7 | 83.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_large_coco_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccdOLQqSo6E87GfMw?e=TEurgW) |
| ViTPose-H | COCO+AIC+MPII | 256x192 | 79.5 | 84.5 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_huge_coco_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccmHofkmfJDQDukVw?e=gRK224) |
| ViTPose-G | COCO+AIC+MPII | 576x432 | 81.0 | 85.6 | | |
| ViTPose-B* | COCO+AIC+MPII+CrowdPose | 256x192 | 77.5 | 82.6 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_base_coco_256x192.py) |[Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSrlMB093JzJtqq-?e=Jr5S3R) |
| ViTPose-L* | COCO+AIC+MPII+CrowdPose | 256x192 | 79.1 | 84.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_large_coco_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgTBm3dCVmBUbHYT6?e=fHUrTq) |
| ViTPose-H* | COCO+AIC+MPII+CrowdPose | 256x192 | 79.8 | 84.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/ViTPose_huge_coco_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgS5rLeRAJiWobCdh?e=41GsDd) |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 75.8 | 82.6 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vitPose+_small_coco+aic+mpii+ap10k+apt36k+wholebody_256x192_udp.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 77.0 | 82.6 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vitPose+_base_coco+aic+mpii+ap10k+apt36k+wholebody_256x192_udp.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 78.6 | 84.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vitPose+_large_coco+aic+mpii+ap10k+apt36k+wholebody_256x192_udp.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 79.4 | 84.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vitPose+_huge_coco+aic+mpii+ap10k+apt36k+wholebody_256x192_udp.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
> Results on OCHuman test set
Using groundtruth bounding boxes. Note the configs here are only for evaluation.
| Model | Dataset | Resolution | AP | AR | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-B | COCO+AIC+MPII | 256x192 | 88.0 | 89.6 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_base_ochuman_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcccwaTZ8xCFFM3Sjg?e=chmiK5) |
| ViTPose-L | COCO+AIC+MPII | 256x192 | 90.9 | 92.2 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_large_ochuman_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccdOLQqSo6E87GfMw?e=TEurgW) |
| ViTPose-H | COCO+AIC+MPII | 256x192 | 90.9 | 92.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_huge_ochuman_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccmHofkmfJDQDukVw?e=gRK224) |
| ViTPose-G | COCO+AIC+MPII | 576x432 | 93.3 | 94.3 | | |
| ViTPose-B* | COCO+AIC+MPII+CrowdPose | 256x192 | 88.2 | 90.0 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_base_ochuman_256x192.py) |[Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSrlMB093JzJtqq-?e=Jr5S3R) |
| ViTPose-L* | COCO+AIC+MPII+CrowdPose | 256x192 | 91.5 | 92.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_large_ochuman_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgTBm3dCVmBUbHYT6?e=fHUrTq) |
| ViTPose-H* | COCO+AIC+MPII+CrowdPose | 256x192 | 91.6 | 92.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_huge_ochuman_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgS5rLeRAJiWobCdh?e=41GsDd) |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 78.4 | 80.6 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_small_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 82.6 | 84.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_base_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 85.7 | 87.5 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_large_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 85.7 | 87.4 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_huge_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
> Results on MPII val set
Using groundtruth bounding boxes. Note the configs here are only for evaluation. The metric is PCKh.
| Model | Dataset | Resolution | Mean | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-B | COCO+AIC+MPII | 256x192 | 93.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_base_mpii_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcccwaTZ8xCFFM3Sjg?e=chmiK5) |
| ViTPose-L | COCO+AIC+MPII | 256x192 | 94.0 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_large_mpii_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccdOLQqSo6E87GfMw?e=TEurgW) |
| ViTPose-H | COCO+AIC+MPII | 256x192 | 94.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_huge_mpii_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccmHofkmfJDQDukVw?e=gRK224) |
| ViTPose-G | COCO+AIC+MPII | 576x432 | 94.3 | | |
| ViTPose-B* | COCO+AIC+MPII+CrowdPose | 256x192 | 93.4 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_base_mpii_256x192.py) |[Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSy_OSEm906wd2LB?e=GOSg14) |
| ViTPose-L* | COCO+AIC+MPII+CrowdPose | 256x192 | 93.9 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_large_mpii_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgTM32I6Kpjr-esl6?e=qvh0Yl) |
| ViTPose-H* | COCO+AIC+MPII+CrowdPose | 256x192 | 94.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_huge_mpii_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgTT90XEQBKy-scIH?e=D2WhTS) |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 92.7 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_small_mpii_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 92.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_base_mpii_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 94.0 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_large_mpii_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 94.2 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/mpii/ViTPose_huge_mpii_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
> Results on AI Challenger test set
Using groundtruth bounding boxes. Note the configs here are only for evaluation.
| Model | Dataset | Resolution | AP | AR | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-B | COCO+AIC+MPII | 256x192 | 32.0 | 36.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/aic/ViTPose_base_aic_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcccwaTZ8xCFFM3Sjg?e=chmiK5) |
| ViTPose-L | COCO+AIC+MPII | 256x192 | 34.5 | 39.0 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/aic/ViTPose_large_aic_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccdOLQqSo6E87GfMw?e=TEurgW) |
| ViTPose-H | COCO+AIC+MPII | 256x192 | 35.4 | 39.9 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/aic/ViTPose_huge_aic_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccmHofkmfJDQDukVw?e=gRK224) |
| ViTPose-G | COCO+AIC+MPII | 576x432 | 43.2 | 47.1 | | |
| ViTPose-B* | COCO+AIC+MPII+CrowdPose | 256x192 | 31.9 | 36.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/aic/ViTPose_base_aic_256x192.py) |[Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgSlvdVaXTC92SHYH?e=j7iqcp) |
| ViTPose-L* | COCO+AIC+MPII+CrowdPose | 256x192 | 34.6 | 39.0 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/aic/ViTPose_large_aic_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgTF06FX3FSAm0MOH?e=rYts9F) |
| ViTPose-H* | COCO+AIC+MPII+CrowdPose | 256x192 | 35.3 | 39.8 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/aic/ViTPose_huge_aic_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgS1MRmb2mcow_K04?e=q9jPab) |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 29.7 | 34.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_small_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 31.8 | 36.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_base_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 34.3 | 38.9 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_large_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 34.8 | 39.1 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/ochuman/ViTPose_huge_ochuman_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
> Results on CrowdPose test set
Using YOLOv3 human detector. Note the configs here are only for evaluation.
| Model | Dataset | Resolution | AP | AP(H) | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| ViTPose-B* | COCO+AIC+MPII+CrowdPose | 256x192 | 74.7 | 63.3 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/crowdpose/ViTPose_base_crowdpose_256x192.py) |[Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgStrrCb91cPlaxJx?e=6Xobo6) |
| ViTPose-L* | COCO+AIC+MPII+CrowdPose | 256x192 | 76.6 | 65.9 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/crowdpose/ViTPose_large_crowdpose_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgTK3dug-r7c6GFyu?e=1ZBpEG) |
| ViTPose-H* | COCO+AIC+MPII+CrowdPose | 256x192 | 76.3 | 65.6 | [config](configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/crowdpose/ViTPose_huge_crowdpose_256x192.py) | [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgS-oAvEV4MTD--Xr?e=EeW2Fu) |
### Animal datasets (AP10K, APT36K)
> Results on AP-10K test set
| Model | Dataset | Resolution | AP | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 71.4 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/ap10k/ViTPose_small_ap10k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 74.5 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/ap10k/ViTPose_base_ap10k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 80.4 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/ap10k/ViTPose_large_ap10k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 82.4 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/ap10k/ViTPose_huge_ap10k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
> Results on APT-36K val set
| Model | Dataset | Resolution | AP | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 74.2 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/apt36k/ViTPose_small_apt36k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 75.9 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/apt36k/ViTPose_base_apt36k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 80.8 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/apt36k/ViTPose_large_apt36k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 82.3 | [config](configs/animal/2d_kpt_sview_rgb_img/topdown_heatmap/apt36k/ViTPose_huge_apt36k_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
### WholeBody dataset
| Model | Dataset | Resolution | AP | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: |
| **ViTPose+-S** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 54.4 | [config](configs/wholebody/2d_kpt_sview_rgb_img/topdown_heatmap/coco-wholebody/ViTPose_small_wholebody_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccqO1JBHtBjNaeCbQ?e=ZN5NSz) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccrwORr61gT9E4n8g?e=kz9sz5) |
| **ViTPose+-B** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 57.4 | [config](cconfigs/wholebody/2d_kpt_sview_rgb_img/topdown_heatmap/coco-wholebody/ViTPose_base_wholebody_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccjj9lgPTlkGT1HTw?e=OlS5zv) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgcckRZk1bIAuRa_E1w?e=ylDB2G) |
| **ViTPose+-L** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 60.6 | [config](configs/wholebody/2d_kpt_sview_rgb_img/topdown_heatmap/coco-wholebody/ViTPose_large_wholebody_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgccp7HJf4QMeQQpeyA?e=JagPNt) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccs1SNFUGSTsmRJ8w?e=a9zKwZ) |
| **ViTPose+-H** | COCO+AIC+MPII+AP10K+APT36K+WholeBody | 256x192 | 61.2 | [config](configs/wholebody/2d_kpt_sview_rgb_img/topdown_heatmap/coco-wholebody/ViTPose_huge_wholebody_256x192.py) | [log](https://1drv.ms/u/s!AimBgYV7JjTlgcclxZOlwRJdqpIIjA?e=nFQgVC) \| [Onedrive](https://1drv.ms/u/s!AimBgYV7JjTlgccoXv8rCUgVe7oD9Q?e=ZBw6gR) |
### Transfer results on the hand dataset (InterHand2.6M)
| Model | Dataset | Resolution | AUC | config | weight |
| :----: | :----: | :----: | :----: | :----: | :----: |
| **ViTPose+-S** | COCO+AIC+MPII+WholeBody | 256x192 | 86.5 | [config](configs/hand/2d_kpt_sview_rgb_img/topdown_heatmap/interhand2d/ViTPose_small_interhand2d_all_256x192.py) | Coming Soon |
| **ViTPose+-B** | COCO+AIC+MPII+WholeBody | 256x192 | 87.0 | [config](configs/hand/2d_kpt_sview_rgb_img/topdown_heatmap/interhand2d/ViTPose_base_interhand2d_all_256x192.py) | Coming Soon |
| **ViTPose+-L** | COCO+AIC+MPII+WholeBody | 256x192 | 87.5 | [config](configs/hand/2d_kpt_sview_rgb_img/topdown_heatmap/interhand2d/ViTPose_large_interhand2d_all_256x192.py) | Coming Soon |
| **ViTPose+-H** | COCO+AIC+MPII+WholeBody | 256x192 | 87.6 | [config](configs/hand/2d_kpt_sview_rgb_img/topdown_heatmap/interhand2d/ViTPose_huge_interhand2d_all_256x192.py) | Coming Soon |
## Updates
> [2023-01-10] Update ViTPose+! It uses MoE strategies to jointly deal with human, animal, and wholebody pose estimation tasks.
> [2022-05-24] Upload the single-task training code, single-task pre-trained models, and multi-task pretrained models.
> [2022-05-06] Upload the logs for the base, large, and huge models!
> [2022-04-27] Our ViTPose with ViTAE-G obtains 81.1 AP on COCO test-dev set!
> Applications of ViTAE Transformer include: [image classification](https://github.com/ViTAE-Transformer/ViTAE-Transformer/tree/main/Image-Classification) | [object detection](https://github.com/ViTAE-Transformer/ViTAE-Transformer/tree/main/Object-Detection) | [semantic segmentation](https://github.com/ViTAE-Transformer/ViTAE-Transformer/tree/main/Semantic-Segmentation) | [animal pose segmentation](https://github.com/ViTAE-Transformer/ViTAE-Transformer/tree/main/Animal-Pose-Estimation) | [remote sensing](https://github.com/ViTAE-Transformer/ViTAE-Transformer-Remote-Sensing) | [matting](https://github.com/ViTAE-Transformer/ViTAE-Transformer-Matting) | [VSA](https://github.com/ViTAE-Transformer/ViTAE-VSA) | [ViTDet](https://github.com/ViTAE-Transformer/ViTDet)
## Usage
We use PyTorch 1.9.0 or NGC docker 21.06, and mmcv 1.3.9 for the experiments.
```bash
git clone https://github.com/open-mmlab/mmcv.git
cd mmcv
git checkout v1.3.9
MMCV_WITH_OPS=1 pip install -e .
cd ..
git clone https://github.com/ViTAE-Transformer/ViTPose.git
cd ViTPose
pip install -v -e .
```
After install the two repos, install timm and einops, i.e.,
```bash
pip install timm==0.4.9 einops
```
After downloading the pretrained models, please conduct the experiments by running
```bash
# for single machine
bash tools/dist_train.sh <Config PATH> <NUM GPUs> --cfg-options model.pretrained=<Pretrained PATH> --seed 0
# for multiple machines
python -m torch.distributed.launch --nnodes <Num Machines> --node_rank <Rank of Machine> --nproc_per_node <GPUs Per Machine> --master_addr <Master Addr> --master_port <Master Port> tools/train.py <Config PATH> --cfg-options model.pretrained=<Pretrained PATH> --launcher pytorch --seed 0
```
To test the pretrained models performance, please run
```bash
bash tools/dist_test.sh <Config PATH> <Checkpoint PATH> <NUM GPUs>
```
For ViTPose+ pre-trained models, please first re-organize the pre-trained weights using
```bash
python tools/model_split.py --source <Pretrained PATH>
```
## Todo
This repo current contains modifications including:
- [x] Upload configs and pretrained models
- [x] More models with SOTA results
- [x] Upload multi-task training config
## Acknowledge
We acknowledge the excellent implementation from [mmpose](https://github.com/open-mmlab/mmdetection) and [MAE](https://github.com/facebookresearch/mae).
## Citing ViTPose
For ViTPose
```
@inproceedings{
xu2022vitpose,
title={Vi{TP}ose: Simple Vision Transformer Baselines for Human Pose Estimation},
author={Yufei Xu and Jing Zhang and Qiming Zhang and Dacheng Tao},
booktitle={Advances in Neural Information Processing Systems},
year={2022},
}
```
For ViTPose+
```
@article{xu2022vitpose+,
title={ViTPose+: Vision Transformer Foundation Model for Generic Body Pose Estimation},
author={Xu, Yufei and Zhang, Jing and Zhang, Qiming and Tao, Dacheng},
journal={arXiv preprint arXiv:2212.04246},
year={2022}
}
```
For ViTAE and ViTAEv2, please refer to:
```
@article{xu2021vitae,
title={Vitae: Vision transformer advanced by exploring intrinsic inductive bias},
author={Xu, Yufei and Zhang, Qiming and Zhang, Jing and Tao, Dacheng},
journal={Advances in Neural Information Processing Systems},
volume={34},
year={2021}
}
@article{zhang2022vitaev2,
title={ViTAEv2: Vision Transformer Advanced by Exploring Inductive Bias for Image Recognition and Beyond},
author={Zhang, Qiming and Xu, Yufei and Zhang, Jing and Tao, Dacheng},
journal={arXiv preprint arXiv:2202.10108},
year={2022}
}
```
@@ -0,0 +1,384 @@
dataset_info = dict(
dataset_name='300w',
paper_info=dict(
author='Sagonas, Christos and Antonakos, Epameinondas '
'and Tzimiropoulos, Georgios and Zafeiriou, Stefanos '
'and Pantic, Maja',
title='300 faces in-the-wild challenge: '
'Database and results',
container='Image and vision computing',
year='2016',
homepage='https://ibug.doc.ic.ac.uk/resources/300-W/',
),
keypoint_info={
0:
dict(
name='kpt-0', id=0, color=[255, 255, 255], type='', swap='kpt-16'),
1:
dict(
name='kpt-1', id=1, color=[255, 255, 255], type='', swap='kpt-15'),
2:
dict(
name='kpt-2', id=2, color=[255, 255, 255], type='', swap='kpt-14'),
3:
dict(
name='kpt-3', id=3, color=[255, 255, 255], type='', swap='kpt-13'),
4:
dict(
name='kpt-4', id=4, color=[255, 255, 255], type='', swap='kpt-12'),
5:
dict(
name='kpt-5', id=5, color=[255, 255, 255], type='', swap='kpt-11'),
6:
dict(
name='kpt-6', id=6, color=[255, 255, 255], type='', swap='kpt-10'),
7:
dict(name='kpt-7', id=7, color=[255, 255, 255], type='', swap='kpt-9'),
8:
dict(name='kpt-8', id=8, color=[255, 255, 255], type='', swap=''),
9:
dict(name='kpt-9', id=9, color=[255, 255, 255], type='', swap='kpt-7'),
10:
dict(
name='kpt-10', id=10, color=[255, 255, 255], type='',
swap='kpt-6'),
11:
dict(
name='kpt-11', id=11, color=[255, 255, 255], type='',
swap='kpt-5'),
12:
dict(
name='kpt-12', id=12, color=[255, 255, 255], type='',
swap='kpt-4'),
13:
dict(
name='kpt-13', id=13, color=[255, 255, 255], type='',
swap='kpt-3'),
14:
dict(
name='kpt-14', id=14, color=[255, 255, 255], type='',
swap='kpt-2'),
15:
dict(
name='kpt-15', id=15, color=[255, 255, 255], type='',
swap='kpt-1'),
16:
dict(
name='kpt-16', id=16, color=[255, 255, 255], type='',
swap='kpt-0'),
17:
dict(
name='kpt-17',
id=17,
color=[255, 255, 255],
type='',
swap='kpt-26'),
18:
dict(
name='kpt-18',
id=18,
color=[255, 255, 255],
type='',
swap='kpt-25'),
19:
dict(
name='kpt-19',
id=19,
color=[255, 255, 255],
type='',
swap='kpt-24'),
20:
dict(
name='kpt-20',
id=20,
color=[255, 255, 255],
type='',
swap='kpt-23'),
21:
dict(
name='kpt-21',
id=21,
color=[255, 255, 255],
type='',
swap='kpt-22'),
22:
dict(
name='kpt-22',
id=22,
color=[255, 255, 255],
type='',
swap='kpt-21'),
23:
dict(
name='kpt-23',
id=23,
color=[255, 255, 255],
type='',
swap='kpt-20'),
24:
dict(
name='kpt-24',
id=24,
color=[255, 255, 255],
type='',
swap='kpt-19'),
25:
dict(
name='kpt-25',
id=25,
color=[255, 255, 255],
type='',
swap='kpt-18'),
26:
dict(
name='kpt-26',
id=26,
color=[255, 255, 255],
type='',
swap='kpt-17'),
27:
dict(name='kpt-27', id=27, color=[255, 255, 255], type='', swap=''),
28:
dict(name='kpt-28', id=28, color=[255, 255, 255], type='', swap=''),
29:
dict(name='kpt-29', id=29, color=[255, 255, 255], type='', swap=''),
30:
dict(name='kpt-30', id=30, color=[255, 255, 255], type='', swap=''),
31:
dict(
name='kpt-31',
id=31,
color=[255, 255, 255],
type='',
swap='kpt-35'),
32:
dict(
name='kpt-32',
id=32,
color=[255, 255, 255],
type='',
swap='kpt-34'),
33:
dict(name='kpt-33', id=33, color=[255, 255, 255], type='', swap=''),
34:
dict(
name='kpt-34',
id=34,
color=[255, 255, 255],
type='',
swap='kpt-32'),
35:
dict(
name='kpt-35',
id=35,
color=[255, 255, 255],
type='',
swap='kpt-31'),
36:
dict(
name='kpt-36',
id=36,
color=[255, 255, 255],
type='',
swap='kpt-45'),
37:
dict(
name='kpt-37',
id=37,
color=[255, 255, 255],
type='',
swap='kpt-44'),
38:
dict(
name='kpt-38',
id=38,
color=[255, 255, 255],
type='',
swap='kpt-43'),
39:
dict(
name='kpt-39',
id=39,
color=[255, 255, 255],
type='',
swap='kpt-42'),
40:
dict(
name='kpt-40',
id=40,
color=[255, 255, 255],
type='',
swap='kpt-47'),
41:
dict(
name='kpt-41',
id=41,
color=[255, 255, 255],
type='',
swap='kpt-46'),
42:
dict(
name='kpt-42',
id=42,
color=[255, 255, 255],
type='',
swap='kpt-39'),
43:
dict(
name='kpt-43',
id=43,
color=[255, 255, 255],
type='',
swap='kpt-38'),
44:
dict(
name='kpt-44',
id=44,
color=[255, 255, 255],
type='',
swap='kpt-37'),
45:
dict(
name='kpt-45',
id=45,
color=[255, 255, 255],
type='',
swap='kpt-36'),
46:
dict(
name='kpt-46',
id=46,
color=[255, 255, 255],
type='',
swap='kpt-41'),
47:
dict(
name='kpt-47',
id=47,
color=[255, 255, 255],
type='',
swap='kpt-40'),
48:
dict(
name='kpt-48',
id=48,
color=[255, 255, 255],
type='',
swap='kpt-54'),
49:
dict(
name='kpt-49',
id=49,
color=[255, 255, 255],
type='',
swap='kpt-53'),
50:
dict(
name='kpt-50',
id=50,
color=[255, 255, 255],
type='',
swap='kpt-52'),
51:
dict(name='kpt-51', id=51, color=[255, 255, 255], type='', swap=''),
52:
dict(
name='kpt-52',
id=52,
color=[255, 255, 255],
type='',
swap='kpt-50'),
53:
dict(
name='kpt-53',
id=53,
color=[255, 255, 255],
type='',
swap='kpt-49'),
54:
dict(
name='kpt-54',
id=54,
color=[255, 255, 255],
type='',
swap='kpt-48'),
55:
dict(
name='kpt-55',
id=55,
color=[255, 255, 255],
type='',
swap='kpt-59'),
56:
dict(
name='kpt-56',
id=56,
color=[255, 255, 255],
type='',
swap='kpt-58'),
57:
dict(name='kpt-57', id=57, color=[255, 255, 255], type='', swap=''),
58:
dict(
name='kpt-58',
id=58,
color=[255, 255, 255],
type='',
swap='kpt-56'),
59:
dict(
name='kpt-59',
id=59,
color=[255, 255, 255],
type='',
swap='kpt-55'),
60:
dict(
name='kpt-60',
id=60,
color=[255, 255, 255],
type='',
swap='kpt-64'),
61:
dict(
name='kpt-61',
id=61,
color=[255, 255, 255],
type='',
swap='kpt-63'),
62:
dict(name='kpt-62', id=62, color=[255, 255, 255], type='', swap=''),
63:
dict(
name='kpt-63',
id=63,
color=[255, 255, 255],
type='',
swap='kpt-61'),
64:
dict(
name='kpt-64',
id=64,
color=[255, 255, 255],
type='',
swap='kpt-60'),
65:
dict(
name='kpt-65',
id=65,
color=[255, 255, 255],
type='',
swap='kpt-67'),
66:
dict(name='kpt-66', id=66, color=[255, 255, 255], type='', swap=''),
67:
dict(
name='kpt-67',
id=67,
color=[255, 255, 255],
type='',
swap='kpt-65'),
},
skeleton_info={},
joint_weights=[1.] * 68,
sigmas=[])
@@ -0,0 +1,83 @@
dataset_info = dict(
dataset_name='aflw',
paper_info=dict(
author='Koestinger, Martin and Wohlhart, Paul and '
'Roth, Peter M and Bischof, Horst',
title='Annotated facial landmarks in the wild: '
'A large-scale, real-world database for facial '
'landmark localization',
container='2011 IEEE international conference on computer '
'vision workshops (ICCV workshops)',
year='2011',
homepage='https://www.tugraz.at/institute/icg/research/'
'team-bischof/lrs/downloads/aflw/',
),
keypoint_info={
0:
dict(name='kpt-0', id=0, color=[255, 255, 255], type='', swap='kpt-5'),
1:
dict(name='kpt-1', id=1, color=[255, 255, 255], type='', swap='kpt-4'),
2:
dict(name='kpt-2', id=2, color=[255, 255, 255], type='', swap='kpt-3'),
3:
dict(name='kpt-3', id=3, color=[255, 255, 255], type='', swap='kpt-2'),
4:
dict(name='kpt-4', id=4, color=[255, 255, 255], type='', swap='kpt-1'),
5:
dict(name='kpt-5', id=5, color=[255, 255, 255], type='', swap='kpt-0'),
6:
dict(
name='kpt-6', id=6, color=[255, 255, 255], type='', swap='kpt-11'),
7:
dict(
name='kpt-7', id=7, color=[255, 255, 255], type='', swap='kpt-10'),
8:
dict(name='kpt-8', id=8, color=[255, 255, 255], type='', swap='kpt-9'),
9:
dict(name='kpt-9', id=9, color=[255, 255, 255], type='', swap='kpt-8'),
10:
dict(
name='kpt-10', id=10, color=[255, 255, 255], type='',
swap='kpt-7'),
11:
dict(
name='kpt-11', id=11, color=[255, 255, 255], type='',
swap='kpt-6'),
12:
dict(
name='kpt-12',
id=12,
color=[255, 255, 255],
type='',
swap='kpt-14'),
13:
dict(name='kpt-13', id=13, color=[255, 255, 255], type='', swap=''),
14:
dict(
name='kpt-14',
id=14,
color=[255, 255, 255],
type='',
swap='kpt-12'),
15:
dict(
name='kpt-15',
id=15,
color=[255, 255, 255],
type='',
swap='kpt-17'),
16:
dict(name='kpt-16', id=16, color=[255, 255, 255], type='', swap=''),
17:
dict(
name='kpt-17',
id=17,
color=[255, 255, 255],
type='',
swap='kpt-15'),
18:
dict(name='kpt-18', id=18, color=[255, 255, 255], type='', swap='')
},
skeleton_info={},
joint_weights=[1.] * 19,
sigmas=[])
@@ -0,0 +1,140 @@
dataset_info = dict(
dataset_name='aic',
paper_info=dict(
author='Wu, Jiahong and Zheng, He and Zhao, Bo and '
'Li, Yixin and Yan, Baoming and Liang, Rui and '
'Wang, Wenjia and Zhou, Shipei and Lin, Guosen and '
'Fu, Yanwei and others',
title='Ai challenger: A large-scale dataset for going '
'deeper in image understanding',
container='arXiv',
year='2017',
homepage='https://github.com/AIChallenger/AI_Challenger_2017',
),
keypoint_info={
0:
dict(
name='right_shoulder',
id=0,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
1:
dict(
name='right_elbow',
id=1,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
2:
dict(
name='right_wrist',
id=2,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
3:
dict(
name='left_shoulder',
id=3,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
4:
dict(
name='left_elbow',
id=4,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
5:
dict(
name='left_wrist',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
6:
dict(
name='right_hip',
id=6,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
7:
dict(
name='right_knee',
id=7,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
8:
dict(
name='right_ankle',
id=8,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
9:
dict(
name='left_hip',
id=9,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
10:
dict(
name='left_knee',
id=10,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
11:
dict(
name='left_ankle',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
12:
dict(
name='head_top',
id=12,
color=[51, 153, 255],
type='upper',
swap=''),
13:
dict(name='neck', id=13, color=[51, 153, 255], type='upper', swap='')
},
skeleton_info={
0:
dict(link=('right_wrist', 'right_elbow'), id=0, color=[255, 128, 0]),
1: dict(
link=('right_elbow', 'right_shoulder'), id=1, color=[255, 128, 0]),
2: dict(link=('right_shoulder', 'neck'), id=2, color=[51, 153, 255]),
3: dict(link=('neck', 'left_shoulder'), id=3, color=[51, 153, 255]),
4: dict(link=('left_shoulder', 'left_elbow'), id=4, color=[0, 255, 0]),
5: dict(link=('left_elbow', 'left_wrist'), id=5, color=[0, 255, 0]),
6: dict(link=('right_ankle', 'right_knee'), id=6, color=[255, 128, 0]),
7: dict(link=('right_knee', 'right_hip'), id=7, color=[255, 128, 0]),
8: dict(link=('right_hip', 'left_hip'), id=8, color=[51, 153, 255]),
9: dict(link=('left_hip', 'left_knee'), id=9, color=[0, 255, 0]),
10: dict(link=('left_knee', 'left_ankle'), id=10, color=[0, 255, 0]),
11: dict(link=('head_top', 'neck'), id=11, color=[51, 153, 255]),
12: dict(
link=('right_shoulder', 'right_hip'), id=12, color=[51, 153, 255]),
13:
dict(link=('left_shoulder', 'left_hip'), id=13, color=[51, 153, 255])
},
joint_weights=[
1., 1.2, 1.5, 1., 1.2, 1.5, 1., 1.2, 1.5, 1., 1.2, 1.5, 1., 1.
],
# 'https://github.com/AIChallenger/AI_Challenger_2017/blob/master/'
# 'Evaluation/keypoint_eval/keypoint_eval.py#L50'
# delta = 2 x sigma
sigmas=[
0.01388152, 0.01515228, 0.01057665, 0.01417709, 0.01497891, 0.01402144,
0.03909642, 0.03686941, 0.01981803, 0.03843971, 0.03412318, 0.02415081,
0.01291456, 0.01236173
])
@@ -0,0 +1,140 @@
aic_info = dict(
dataset_name='aic',
paper_info=dict(
author='Wu, Jiahong and Zheng, He and Zhao, Bo and '
'Li, Yixin and Yan, Baoming and Liang, Rui and '
'Wang, Wenjia and Zhou, Shipei and Lin, Guosen and '
'Fu, Yanwei and others',
title='Ai challenger: A large-scale dataset for going '
'deeper in image understanding',
container='arXiv',
year='2017',
homepage='https://github.com/AIChallenger/AI_Challenger_2017',
),
keypoint_info={
0:
dict(
name='right_shoulder',
id=0,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
1:
dict(
name='right_elbow',
id=1,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
2:
dict(
name='right_wrist',
id=2,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
3:
dict(
name='left_shoulder',
id=3,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
4:
dict(
name='left_elbow',
id=4,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
5:
dict(
name='left_wrist',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
6:
dict(
name='right_hip',
id=6,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
7:
dict(
name='right_knee',
id=7,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
8:
dict(
name='right_ankle',
id=8,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
9:
dict(
name='left_hip',
id=9,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
10:
dict(
name='left_knee',
id=10,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
11:
dict(
name='left_ankle',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
12:
dict(
name='head_top',
id=12,
color=[51, 153, 255],
type='upper',
swap=''),
13:
dict(name='neck', id=13, color=[51, 153, 255], type='upper', swap='')
},
skeleton_info={
0:
dict(link=('right_wrist', 'right_elbow'), id=0, color=[255, 128, 0]),
1: dict(
link=('right_elbow', 'right_shoulder'), id=1, color=[255, 128, 0]),
2: dict(link=('right_shoulder', 'neck'), id=2, color=[51, 153, 255]),
3: dict(link=('neck', 'left_shoulder'), id=3, color=[51, 153, 255]),
4: dict(link=('left_shoulder', 'left_elbow'), id=4, color=[0, 255, 0]),
5: dict(link=('left_elbow', 'left_wrist'), id=5, color=[0, 255, 0]),
6: dict(link=('right_ankle', 'right_knee'), id=6, color=[255, 128, 0]),
7: dict(link=('right_knee', 'right_hip'), id=7, color=[255, 128, 0]),
8: dict(link=('right_hip', 'left_hip'), id=8, color=[51, 153, 255]),
9: dict(link=('left_hip', 'left_knee'), id=9, color=[0, 255, 0]),
10: dict(link=('left_knee', 'left_ankle'), id=10, color=[0, 255, 0]),
11: dict(link=('head_top', 'neck'), id=11, color=[51, 153, 255]),
12: dict(
link=('right_shoulder', 'right_hip'), id=12, color=[51, 153, 255]),
13:
dict(link=('left_shoulder', 'left_hip'), id=13, color=[51, 153, 255])
},
joint_weights=[
1., 1.2, 1.5, 1., 1.2, 1.5, 1., 1.2, 1.5, 1., 1.2, 1.5, 1., 1.
],
# 'https://github.com/AIChallenger/AI_Challenger_2017/blob/master/'
# 'Evaluation/keypoint_eval/keypoint_eval.py#L50'
# delta = 2 x sigma
sigmas=[
0.01388152, 0.01515228, 0.01057665, 0.01417709, 0.01497891, 0.01402144,
0.03909642, 0.03686941, 0.01981803, 0.03843971, 0.03412318, 0.02415081,
0.01291456, 0.01236173
])
@@ -0,0 +1,166 @@
dataset_info = dict(
dataset_name='animalpose',
paper_info=dict(
author='Cao, Jinkun and Tang, Hongyang and Fang, Hao-Shu and '
'Shen, Xiaoyong and Lu, Cewu and Tai, Yu-Wing',
title='Cross-Domain Adaptation for Animal Pose Estimation',
container='The IEEE International Conference on '
'Computer Vision (ICCV)',
year='2019',
homepage='https://sites.google.com/view/animal-pose/',
),
keypoint_info={
0:
dict(
name='L_Eye', id=0, color=[0, 255, 0], type='upper', swap='R_Eye'),
1:
dict(
name='R_Eye',
id=1,
color=[255, 128, 0],
type='upper',
swap='L_Eye'),
2:
dict(
name='L_EarBase',
id=2,
color=[0, 255, 0],
type='upper',
swap='R_EarBase'),
3:
dict(
name='R_EarBase',
id=3,
color=[255, 128, 0],
type='upper',
swap='L_EarBase'),
4:
dict(name='Nose', id=4, color=[51, 153, 255], type='upper', swap=''),
5:
dict(name='Throat', id=5, color=[51, 153, 255], type='upper', swap=''),
6:
dict(
name='TailBase', id=6, color=[51, 153, 255], type='lower',
swap=''),
7:
dict(
name='Withers', id=7, color=[51, 153, 255], type='upper', swap=''),
8:
dict(
name='L_F_Elbow',
id=8,
color=[0, 255, 0],
type='upper',
swap='R_F_Elbow'),
9:
dict(
name='R_F_Elbow',
id=9,
color=[255, 128, 0],
type='upper',
swap='L_F_Elbow'),
10:
dict(
name='L_B_Elbow',
id=10,
color=[0, 255, 0],
type='lower',
swap='R_B_Elbow'),
11:
dict(
name='R_B_Elbow',
id=11,
color=[255, 128, 0],
type='lower',
swap='L_B_Elbow'),
12:
dict(
name='L_F_Knee',
id=12,
color=[0, 255, 0],
type='upper',
swap='R_F_Knee'),
13:
dict(
name='R_F_Knee',
id=13,
color=[255, 128, 0],
type='upper',
swap='L_F_Knee'),
14:
dict(
name='L_B_Knee',
id=14,
color=[0, 255, 0],
type='lower',
swap='R_B_Knee'),
15:
dict(
name='R_B_Knee',
id=15,
color=[255, 128, 0],
type='lower',
swap='L_B_Knee'),
16:
dict(
name='L_F_Paw',
id=16,
color=[0, 255, 0],
type='upper',
swap='R_F_Paw'),
17:
dict(
name='R_F_Paw',
id=17,
color=[255, 128, 0],
type='upper',
swap='L_F_Paw'),
18:
dict(
name='L_B_Paw',
id=18,
color=[0, 255, 0],
type='lower',
swap='R_B_Paw'),
19:
dict(
name='R_B_Paw',
id=19,
color=[255, 128, 0],
type='lower',
swap='L_B_Paw')
},
skeleton_info={
0: dict(link=('L_Eye', 'R_Eye'), id=0, color=[51, 153, 255]),
1: dict(link=('L_Eye', 'L_EarBase'), id=1, color=[0, 255, 0]),
2: dict(link=('R_Eye', 'R_EarBase'), id=2, color=[255, 128, 0]),
3: dict(link=('L_Eye', 'Nose'), id=3, color=[0, 255, 0]),
4: dict(link=('R_Eye', 'Nose'), id=4, color=[255, 128, 0]),
5: dict(link=('Nose', 'Throat'), id=5, color=[51, 153, 255]),
6: dict(link=('Throat', 'Withers'), id=6, color=[51, 153, 255]),
7: dict(link=('TailBase', 'Withers'), id=7, color=[51, 153, 255]),
8: dict(link=('Throat', 'L_F_Elbow'), id=8, color=[0, 255, 0]),
9: dict(link=('L_F_Elbow', 'L_F_Knee'), id=9, color=[0, 255, 0]),
10: dict(link=('L_F_Knee', 'L_F_Paw'), id=10, color=[0, 255, 0]),
11: dict(link=('Throat', 'R_F_Elbow'), id=11, color=[255, 128, 0]),
12: dict(link=('R_F_Elbow', 'R_F_Knee'), id=12, color=[255, 128, 0]),
13: dict(link=('R_F_Knee', 'R_F_Paw'), id=13, color=[255, 128, 0]),
14: dict(link=('TailBase', 'L_B_Elbow'), id=14, color=[0, 255, 0]),
15: dict(link=('L_B_Elbow', 'L_B_Knee'), id=15, color=[0, 255, 0]),
16: dict(link=('L_B_Knee', 'L_B_Paw'), id=16, color=[0, 255, 0]),
17: dict(link=('TailBase', 'R_B_Elbow'), id=17, color=[255, 128, 0]),
18: dict(link=('R_B_Elbow', 'R_B_Knee'), id=18, color=[255, 128, 0]),
19: dict(link=('R_B_Knee', 'R_B_Paw'), id=19, color=[255, 128, 0])
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.2, 1.2,
1.5, 1.5, 1.5, 1.5
],
# Note: The original paper did not provide enough information about
# the sigmas. We modified from 'https://github.com/cocodataset/'
# 'cocoapi/blob/master/PythonAPI/pycocotools/cocoeval.py#L523'
sigmas=[
0.025, 0.025, 0.026, 0.035, 0.035, 0.10, 0.10, 0.10, 0.107, 0.107,
0.107, 0.107, 0.087, 0.087, 0.087, 0.087, 0.089, 0.089, 0.089, 0.089
])
@@ -0,0 +1,142 @@
dataset_info = dict(
dataset_name='ap10k',
paper_info=dict(
author='Yu, Hang and Xu, Yufei and Zhang, Jing and '
'Zhao, Wei and Guan, Ziyu and Tao, Dacheng',
title='AP-10K: A Benchmark for Animal Pose Estimation in the Wild',
container='35th Conference on Neural Information Processing Systems '
'(NeurIPS 2021) Track on Datasets and Bench-marks.',
year='2021',
homepage='https://github.com/AlexTheBad/AP-10K',
),
keypoint_info={
0:
dict(
name='L_Eye', id=0, color=[0, 255, 0], type='upper', swap='R_Eye'),
1:
dict(
name='R_Eye',
id=1,
color=[255, 128, 0],
type='upper',
swap='L_Eye'),
2:
dict(name='Nose', id=2, color=[51, 153, 255], type='upper', swap=''),
3:
dict(name='Neck', id=3, color=[51, 153, 255], type='upper', swap=''),
4:
dict(
name='Root of tail',
id=4,
color=[51, 153, 255],
type='lower',
swap=''),
5:
dict(
name='L_Shoulder',
id=5,
color=[51, 153, 255],
type='upper',
swap='R_Shoulder'),
6:
dict(
name='L_Elbow',
id=6,
color=[51, 153, 255],
type='upper',
swap='R_Elbow'),
7:
dict(
name='L_F_Paw',
id=7,
color=[0, 255, 0],
type='upper',
swap='R_F_Paw'),
8:
dict(
name='R_Shoulder',
id=8,
color=[0, 255, 0],
type='upper',
swap='L_Shoulder'),
9:
dict(
name='R_Elbow',
id=9,
color=[255, 128, 0],
type='upper',
swap='L_Elbow'),
10:
dict(
name='R_F_Paw',
id=10,
color=[0, 255, 0],
type='lower',
swap='L_F_Paw'),
11:
dict(
name='L_Hip',
id=11,
color=[255, 128, 0],
type='lower',
swap='R_Hip'),
12:
dict(
name='L_Knee',
id=12,
color=[255, 128, 0],
type='lower',
swap='R_Knee'),
13:
dict(
name='L_B_Paw',
id=13,
color=[0, 255, 0],
type='lower',
swap='R_B_Paw'),
14:
dict(
name='R_Hip', id=14, color=[0, 255, 0], type='lower',
swap='L_Hip'),
15:
dict(
name='R_Knee',
id=15,
color=[0, 255, 0],
type='lower',
swap='L_Knee'),
16:
dict(
name='R_B_Paw',
id=16,
color=[0, 255, 0],
type='lower',
swap='L_B_Paw'),
},
skeleton_info={
0: dict(link=('L_Eye', 'R_Eye'), id=0, color=[0, 0, 255]),
1: dict(link=('L_Eye', 'Nose'), id=1, color=[0, 0, 255]),
2: dict(link=('R_Eye', 'Nose'), id=2, color=[0, 0, 255]),
3: dict(link=('Nose', 'Neck'), id=3, color=[0, 255, 0]),
4: dict(link=('Neck', 'Root of tail'), id=4, color=[0, 255, 0]),
5: dict(link=('Neck', 'L_Shoulder'), id=5, color=[0, 255, 255]),
6: dict(link=('L_Shoulder', 'L_Elbow'), id=6, color=[0, 255, 255]),
7: dict(link=('L_Elbow', 'L_F_Paw'), id=6, color=[0, 255, 255]),
8: dict(link=('Neck', 'R_Shoulder'), id=7, color=[6, 156, 250]),
9: dict(link=('R_Shoulder', 'R_Elbow'), id=8, color=[6, 156, 250]),
10: dict(link=('R_Elbow', 'R_F_Paw'), id=9, color=[6, 156, 250]),
11: dict(link=('Root of tail', 'L_Hip'), id=10, color=[0, 255, 255]),
12: dict(link=('L_Hip', 'L_Knee'), id=11, color=[0, 255, 255]),
13: dict(link=('L_Knee', 'L_B_Paw'), id=12, color=[0, 255, 255]),
14: dict(link=('Root of tail', 'R_Hip'), id=13, color=[6, 156, 250]),
15: dict(link=('R_Hip', 'R_Knee'), id=14, color=[6, 156, 250]),
16: dict(link=('R_Knee', 'R_B_Paw'), id=15, color=[6, 156, 250]),
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5,
1.5
],
sigmas=[
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
])
@@ -0,0 +1,142 @@
ap10k_info = dict(
dataset_name='ap10k',
paper_info=dict(
author='Yu, Hang and Xu, Yufei and Zhang, Jing and '
'Zhao, Wei and Guan, Ziyu and Tao, Dacheng',
title='AP-10K: A Benchmark for Animal Pose Estimation in the Wild',
container='35th Conference on Neural Information Processing Systems '
'(NeurIPS 2021) Track on Datasets and Bench-marks.',
year='2021',
homepage='https://github.com/AlexTheBad/AP-10K',
),
keypoint_info={
0:
dict(
name='L_Eye', id=0, color=[0, 255, 0], type='upper', swap='R_Eye'),
1:
dict(
name='R_Eye',
id=1,
color=[255, 128, 0],
type='upper',
swap='L_Eye'),
2:
dict(name='Nose', id=2, color=[51, 153, 255], type='upper', swap=''),
3:
dict(name='Neck', id=3, color=[51, 153, 255], type='upper', swap=''),
4:
dict(
name='Root of tail',
id=4,
color=[51, 153, 255],
type='lower',
swap=''),
5:
dict(
name='L_Shoulder',
id=5,
color=[51, 153, 255],
type='upper',
swap='R_Shoulder'),
6:
dict(
name='L_Elbow',
id=6,
color=[51, 153, 255],
type='upper',
swap='R_Elbow'),
7:
dict(
name='L_F_Paw',
id=7,
color=[0, 255, 0],
type='upper',
swap='R_F_Paw'),
8:
dict(
name='R_Shoulder',
id=8,
color=[0, 255, 0],
type='upper',
swap='L_Shoulder'),
9:
dict(
name='R_Elbow',
id=9,
color=[255, 128, 0],
type='upper',
swap='L_Elbow'),
10:
dict(
name='R_F_Paw',
id=10,
color=[0, 255, 0],
type='lower',
swap='L_F_Paw'),
11:
dict(
name='L_Hip',
id=11,
color=[255, 128, 0],
type='lower',
swap='R_Hip'),
12:
dict(
name='L_Knee',
id=12,
color=[255, 128, 0],
type='lower',
swap='R_Knee'),
13:
dict(
name='L_B_Paw',
id=13,
color=[0, 255, 0],
type='lower',
swap='R_B_Paw'),
14:
dict(
name='R_Hip', id=14, color=[0, 255, 0], type='lower',
swap='L_Hip'),
15:
dict(
name='R_Knee',
id=15,
color=[0, 255, 0],
type='lower',
swap='L_Knee'),
16:
dict(
name='R_B_Paw',
id=16,
color=[0, 255, 0],
type='lower',
swap='L_B_Paw'),
},
skeleton_info={
0: dict(link=('L_Eye', 'R_Eye'), id=0, color=[0, 0, 255]),
1: dict(link=('L_Eye', 'Nose'), id=1, color=[0, 0, 255]),
2: dict(link=('R_Eye', 'Nose'), id=2, color=[0, 0, 255]),
3: dict(link=('Nose', 'Neck'), id=3, color=[0, 255, 0]),
4: dict(link=('Neck', 'Root of tail'), id=4, color=[0, 255, 0]),
5: dict(link=('Neck', 'L_Shoulder'), id=5, color=[0, 255, 255]),
6: dict(link=('L_Shoulder', 'L_Elbow'), id=6, color=[0, 255, 255]),
7: dict(link=('L_Elbow', 'L_F_Paw'), id=6, color=[0, 255, 255]),
8: dict(link=('Neck', 'R_Shoulder'), id=7, color=[6, 156, 250]),
9: dict(link=('R_Shoulder', 'R_Elbow'), id=8, color=[6, 156, 250]),
10: dict(link=('R_Elbow', 'R_F_Paw'), id=9, color=[6, 156, 250]),
11: dict(link=('Root of tail', 'L_Hip'), id=10, color=[0, 255, 255]),
12: dict(link=('L_Hip', 'L_Knee'), id=11, color=[0, 255, 255]),
13: dict(link=('L_Knee', 'L_B_Paw'), id=12, color=[0, 255, 255]),
14: dict(link=('Root of tail', 'R_Hip'), id=13, color=[6, 156, 250]),
15: dict(link=('R_Hip', 'R_Knee'), id=14, color=[6, 156, 250]),
16: dict(link=('R_Knee', 'R_B_Paw'), id=15, color=[6, 156, 250]),
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5,
1.5
],
sigmas=[
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
])
@@ -0,0 +1,144 @@
dataset_info = dict(
dataset_name='atrw',
paper_info=dict(
author='Li, Shuyuan and Li, Jianguo and Tang, Hanlin '
'and Qian, Rui and Lin, Weiyao',
title='ATRW: A Benchmark for Amur Tiger '
'Re-identification in the Wild',
container='Proceedings of the 28th ACM '
'International Conference on Multimedia',
year='2020',
homepage='https://cvwc2019.github.io/challenge.html',
),
keypoint_info={
0:
dict(
name='left_ear',
id=0,
color=[51, 153, 255],
type='upper',
swap='right_ear'),
1:
dict(
name='right_ear',
id=1,
color=[51, 153, 255],
type='upper',
swap='left_ear'),
2:
dict(name='nose', id=2, color=[51, 153, 255], type='upper', swap=''),
3:
dict(
name='right_shoulder',
id=3,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
4:
dict(
name='right_front_paw',
id=4,
color=[255, 128, 0],
type='upper',
swap='left_front_paw'),
5:
dict(
name='left_shoulder',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
6:
dict(
name='left_front_paw',
id=6,
color=[0, 255, 0],
type='upper',
swap='right_front_paw'),
7:
dict(
name='right_hip',
id=7,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
8:
dict(
name='right_knee',
id=8,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
9:
dict(
name='right_back_paw',
id=9,
color=[255, 128, 0],
type='lower',
swap='left_back_paw'),
10:
dict(
name='left_hip',
id=10,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
11:
dict(
name='left_knee',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
12:
dict(
name='left_back_paw',
id=12,
color=[0, 255, 0],
type='lower',
swap='right_back_paw'),
13:
dict(name='tail', id=13, color=[51, 153, 255], type='lower', swap=''),
14:
dict(
name='center', id=14, color=[51, 153, 255], type='lower', swap=''),
},
skeleton_info={
0:
dict(link=('left_ear', 'nose'), id=0, color=[51, 153, 255]),
1:
dict(link=('right_ear', 'nose'), id=1, color=[51, 153, 255]),
2:
dict(link=('nose', 'center'), id=2, color=[51, 153, 255]),
3:
dict(
link=('left_shoulder', 'left_front_paw'), id=3, color=[0, 255, 0]),
4:
dict(link=('left_shoulder', 'center'), id=4, color=[0, 255, 0]),
5:
dict(
link=('right_shoulder', 'right_front_paw'),
id=5,
color=[255, 128, 0]),
6:
dict(link=('right_shoulder', 'center'), id=6, color=[255, 128, 0]),
7:
dict(link=('tail', 'center'), id=7, color=[51, 153, 255]),
8:
dict(link=('right_back_paw', 'right_knee'), id=8, color=[255, 128, 0]),
9:
dict(link=('right_knee', 'right_hip'), id=9, color=[255, 128, 0]),
10:
dict(link=('right_hip', 'tail'), id=10, color=[255, 128, 0]),
11:
dict(link=('left_back_paw', 'left_knee'), id=11, color=[0, 255, 0]),
12:
dict(link=('left_knee', 'left_hip'), id=12, color=[0, 255, 0]),
13:
dict(link=('left_hip', 'tail'), id=13, color=[0, 255, 0]),
},
joint_weights=[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
sigmas=[
0.0277, 0.0823, 0.0831, 0.0202, 0.0716, 0.0263, 0.0646, 0.0302, 0.0440,
0.0316, 0.0333, 0.0547, 0.0263, 0.0683, 0.0539
])
@@ -0,0 +1,181 @@
dataset_info = dict(
dataset_name='coco',
paper_info=dict(
author='Lin, Tsung-Yi and Maire, Michael and '
'Belongie, Serge and Hays, James and '
'Perona, Pietro and Ramanan, Deva and '
r'Doll{\'a}r, Piotr and Zitnick, C Lawrence',
title='Microsoft coco: Common objects in context',
container='European conference on computer vision',
year='2014',
homepage='http://cocodataset.org/',
),
keypoint_info={
0:
dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''),
1:
dict(
name='left_eye',
id=1,
color=[51, 153, 255],
type='upper',
swap='right_eye'),
2:
dict(
name='right_eye',
id=2,
color=[51, 153, 255],
type='upper',
swap='left_eye'),
3:
dict(
name='left_ear',
id=3,
color=[51, 153, 255],
type='upper',
swap='right_ear'),
4:
dict(
name='right_ear',
id=4,
color=[51, 153, 255],
type='upper',
swap='left_ear'),
5:
dict(
name='left_shoulder',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
6:
dict(
name='right_shoulder',
id=6,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
7:
dict(
name='left_elbow',
id=7,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
8:
dict(
name='right_elbow',
id=8,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
9:
dict(
name='left_wrist',
id=9,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='left_hip',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
12:
dict(
name='right_hip',
id=12,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
13:
dict(
name='left_knee',
id=13,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
14:
dict(
name='right_knee',
id=14,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
15:
dict(
name='left_ankle',
id=15,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
16:
dict(
name='right_ankle',
id=16,
color=[255, 128, 0],
type='lower',
swap='left_ankle')
},
skeleton_info={
0:
dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]),
1:
dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]),
2:
dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]),
3:
dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]),
4:
dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]),
5:
dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]),
6:
dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]),
7:
dict(
link=('left_shoulder', 'right_shoulder'),
id=7,
color=[51, 153, 255]),
8:
dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]),
9:
dict(
link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]),
10:
dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('left_eye', 'right_eye'), id=12, color=[51, 153, 255]),
13:
dict(link=('nose', 'left_eye'), id=13, color=[51, 153, 255]),
14:
dict(link=('nose', 'right_eye'), id=14, color=[51, 153, 255]),
15:
dict(link=('left_eye', 'left_ear'), id=15, color=[51, 153, 255]),
16:
dict(link=('right_eye', 'right_ear'), id=16, color=[51, 153, 255]),
17:
dict(link=('left_ear', 'left_shoulder'), id=17, color=[51, 153, 255]),
18:
dict(
link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255])
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5,
1.5
],
sigmas=[
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
])
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,448 @@
dataset_info = dict(
dataset_name='coco_wholebody_face',
paper_info=dict(
author='Jin, Sheng and Xu, Lumin and Xu, Jin and '
'Wang, Can and Liu, Wentao and '
'Qian, Chen and Ouyang, Wanli and Luo, Ping',
title='Whole-Body Human Pose Estimation in the Wild',
container='Proceedings of the European '
'Conference on Computer Vision (ECCV)',
year='2020',
homepage='https://github.com/jin-s13/COCO-WholeBody/',
),
keypoint_info={
0:
dict(
name='face-0',
id=0,
color=[255, 255, 255],
type='',
swap='face-16'),
1:
dict(
name='face-1',
id=1,
color=[255, 255, 255],
type='',
swap='face-15'),
2:
dict(
name='face-2',
id=2,
color=[255, 255, 255],
type='',
swap='face-14'),
3:
dict(
name='face-3',
id=3,
color=[255, 255, 255],
type='',
swap='face-13'),
4:
dict(
name='face-4',
id=4,
color=[255, 255, 255],
type='',
swap='face-12'),
5:
dict(
name='face-5',
id=5,
color=[255, 255, 255],
type='',
swap='face-11'),
6:
dict(
name='face-6',
id=6,
color=[255, 255, 255],
type='',
swap='face-10'),
7:
dict(
name='face-7', id=7, color=[255, 255, 255], type='',
swap='face-9'),
8:
dict(name='face-8', id=8, color=[255, 255, 255], type='', swap=''),
9:
dict(
name='face-9', id=9, color=[255, 255, 255], type='',
swap='face-7'),
10:
dict(
name='face-10',
id=10,
color=[255, 255, 255],
type='',
swap='face-6'),
11:
dict(
name='face-11',
id=11,
color=[255, 255, 255],
type='',
swap='face-5'),
12:
dict(
name='face-12',
id=12,
color=[255, 255, 255],
type='',
swap='face-4'),
13:
dict(
name='face-13',
id=13,
color=[255, 255, 255],
type='',
swap='face-3'),
14:
dict(
name='face-14',
id=14,
color=[255, 255, 255],
type='',
swap='face-2'),
15:
dict(
name='face-15',
id=15,
color=[255, 255, 255],
type='',
swap='face-1'),
16:
dict(
name='face-16',
id=16,
color=[255, 255, 255],
type='',
swap='face-0'),
17:
dict(
name='face-17',
id=17,
color=[255, 255, 255],
type='',
swap='face-26'),
18:
dict(
name='face-18',
id=18,
color=[255, 255, 255],
type='',
swap='face-25'),
19:
dict(
name='face-19',
id=19,
color=[255, 255, 255],
type='',
swap='face-24'),
20:
dict(
name='face-20',
id=20,
color=[255, 255, 255],
type='',
swap='face-23'),
21:
dict(
name='face-21',
id=21,
color=[255, 255, 255],
type='',
swap='face-22'),
22:
dict(
name='face-22',
id=22,
color=[255, 255, 255],
type='',
swap='face-21'),
23:
dict(
name='face-23',
id=23,
color=[255, 255, 255],
type='',
swap='face-20'),
24:
dict(
name='face-24',
id=24,
color=[255, 255, 255],
type='',
swap='face-19'),
25:
dict(
name='face-25',
id=25,
color=[255, 255, 255],
type='',
swap='face-18'),
26:
dict(
name='face-26',
id=26,
color=[255, 255, 255],
type='',
swap='face-17'),
27:
dict(name='face-27', id=27, color=[255, 255, 255], type='', swap=''),
28:
dict(name='face-28', id=28, color=[255, 255, 255], type='', swap=''),
29:
dict(name='face-29', id=29, color=[255, 255, 255], type='', swap=''),
30:
dict(name='face-30', id=30, color=[255, 255, 255], type='', swap=''),
31:
dict(
name='face-31',
id=31,
color=[255, 255, 255],
type='',
swap='face-35'),
32:
dict(
name='face-32',
id=32,
color=[255, 255, 255],
type='',
swap='face-34'),
33:
dict(name='face-33', id=33, color=[255, 255, 255], type='', swap=''),
34:
dict(
name='face-34',
id=34,
color=[255, 255, 255],
type='',
swap='face-32'),
35:
dict(
name='face-35',
id=35,
color=[255, 255, 255],
type='',
swap='face-31'),
36:
dict(
name='face-36',
id=36,
color=[255, 255, 255],
type='',
swap='face-45'),
37:
dict(
name='face-37',
id=37,
color=[255, 255, 255],
type='',
swap='face-44'),
38:
dict(
name='face-38',
id=38,
color=[255, 255, 255],
type='',
swap='face-43'),
39:
dict(
name='face-39',
id=39,
color=[255, 255, 255],
type='',
swap='face-42'),
40:
dict(
name='face-40',
id=40,
color=[255, 255, 255],
type='',
swap='face-47'),
41:
dict(
name='face-41',
id=41,
color=[255, 255, 255],
type='',
swap='face-46'),
42:
dict(
name='face-42',
id=42,
color=[255, 255, 255],
type='',
swap='face-39'),
43:
dict(
name='face-43',
id=43,
color=[255, 255, 255],
type='',
swap='face-38'),
44:
dict(
name='face-44',
id=44,
color=[255, 255, 255],
type='',
swap='face-37'),
45:
dict(
name='face-45',
id=45,
color=[255, 255, 255],
type='',
swap='face-36'),
46:
dict(
name='face-46',
id=46,
color=[255, 255, 255],
type='',
swap='face-41'),
47:
dict(
name='face-47',
id=47,
color=[255, 255, 255],
type='',
swap='face-40'),
48:
dict(
name='face-48',
id=48,
color=[255, 255, 255],
type='',
swap='face-54'),
49:
dict(
name='face-49',
id=49,
color=[255, 255, 255],
type='',
swap='face-53'),
50:
dict(
name='face-50',
id=50,
color=[255, 255, 255],
type='',
swap='face-52'),
51:
dict(name='face-51', id=52, color=[255, 255, 255], type='', swap=''),
52:
dict(
name='face-52',
id=52,
color=[255, 255, 255],
type='',
swap='face-50'),
53:
dict(
name='face-53',
id=53,
color=[255, 255, 255],
type='',
swap='face-49'),
54:
dict(
name='face-54',
id=54,
color=[255, 255, 255],
type='',
swap='face-48'),
55:
dict(
name='face-55',
id=55,
color=[255, 255, 255],
type='',
swap='face-59'),
56:
dict(
name='face-56',
id=56,
color=[255, 255, 255],
type='',
swap='face-58'),
57:
dict(name='face-57', id=57, color=[255, 255, 255], type='', swap=''),
58:
dict(
name='face-58',
id=58,
color=[255, 255, 255],
type='',
swap='face-56'),
59:
dict(
name='face-59',
id=59,
color=[255, 255, 255],
type='',
swap='face-55'),
60:
dict(
name='face-60',
id=60,
color=[255, 255, 255],
type='',
swap='face-64'),
61:
dict(
name='face-61',
id=61,
color=[255, 255, 255],
type='',
swap='face-63'),
62:
dict(name='face-62', id=62, color=[255, 255, 255], type='', swap=''),
63:
dict(
name='face-63',
id=63,
color=[255, 255, 255],
type='',
swap='face-61'),
64:
dict(
name='face-64',
id=64,
color=[255, 255, 255],
type='',
swap='face-60'),
65:
dict(
name='face-65',
id=65,
color=[255, 255, 255],
type='',
swap='face-67'),
66:
dict(name='face-66', id=66, color=[255, 255, 255], type='', swap=''),
67:
dict(
name='face-67',
id=67,
color=[255, 255, 255],
type='',
swap='face-65')
},
skeleton_info={},
joint_weights=[1.] * 68,
# 'https://github.com/jin-s13/COCO-WholeBody/blob/master/'
# 'evaluation/myeval_wholebody.py#L177'
sigmas=[
0.042, 0.043, 0.044, 0.043, 0.040, 0.035, 0.031, 0.025, 0.020, 0.023,
0.029, 0.032, 0.037, 0.038, 0.043, 0.041, 0.045, 0.013, 0.012, 0.011,
0.011, 0.012, 0.012, 0.011, 0.011, 0.013, 0.015, 0.009, 0.007, 0.007,
0.007, 0.012, 0.009, 0.008, 0.016, 0.010, 0.017, 0.011, 0.009, 0.011,
0.009, 0.007, 0.013, 0.008, 0.011, 0.012, 0.010, 0.034, 0.008, 0.008,
0.009, 0.008, 0.008, 0.007, 0.010, 0.008, 0.009, 0.009, 0.009, 0.007,
0.007, 0.008, 0.011, 0.008, 0.008, 0.008, 0.01, 0.008
])
@@ -0,0 +1,147 @@
dataset_info = dict(
dataset_name='coco_wholebody_hand',
paper_info=dict(
author='Jin, Sheng and Xu, Lumin and Xu, Jin and '
'Wang, Can and Liu, Wentao and '
'Qian, Chen and Ouyang, Wanli and Luo, Ping',
title='Whole-Body Human Pose Estimation in the Wild',
container='Proceedings of the European '
'Conference on Computer Vision (ECCV)',
year='2020',
homepage='https://github.com/jin-s13/COCO-WholeBody/',
),
keypoint_info={
0:
dict(name='wrist', id=0, color=[255, 255, 255], type='', swap=''),
1:
dict(name='thumb1', id=1, color=[255, 128, 0], type='', swap=''),
2:
dict(name='thumb2', id=2, color=[255, 128, 0], type='', swap=''),
3:
dict(name='thumb3', id=3, color=[255, 128, 0], type='', swap=''),
4:
dict(name='thumb4', id=4, color=[255, 128, 0], type='', swap=''),
5:
dict(
name='forefinger1', id=5, color=[255, 153, 255], type='', swap=''),
6:
dict(
name='forefinger2', id=6, color=[255, 153, 255], type='', swap=''),
7:
dict(
name='forefinger3', id=7, color=[255, 153, 255], type='', swap=''),
8:
dict(
name='forefinger4', id=8, color=[255, 153, 255], type='', swap=''),
9:
dict(
name='middle_finger1',
id=9,
color=[102, 178, 255],
type='',
swap=''),
10:
dict(
name='middle_finger2',
id=10,
color=[102, 178, 255],
type='',
swap=''),
11:
dict(
name='middle_finger3',
id=11,
color=[102, 178, 255],
type='',
swap=''),
12:
dict(
name='middle_finger4',
id=12,
color=[102, 178, 255],
type='',
swap=''),
13:
dict(
name='ring_finger1', id=13, color=[255, 51, 51], type='', swap=''),
14:
dict(
name='ring_finger2', id=14, color=[255, 51, 51], type='', swap=''),
15:
dict(
name='ring_finger3', id=15, color=[255, 51, 51], type='', swap=''),
16:
dict(
name='ring_finger4', id=16, color=[255, 51, 51], type='', swap=''),
17:
dict(name='pinky_finger1', id=17, color=[0, 255, 0], type='', swap=''),
18:
dict(name='pinky_finger2', id=18, color=[0, 255, 0], type='', swap=''),
19:
dict(name='pinky_finger3', id=19, color=[0, 255, 0], type='', swap=''),
20:
dict(name='pinky_finger4', id=20, color=[0, 255, 0], type='', swap='')
},
skeleton_info={
0:
dict(link=('wrist', 'thumb1'), id=0, color=[255, 128, 0]),
1:
dict(link=('thumb1', 'thumb2'), id=1, color=[255, 128, 0]),
2:
dict(link=('thumb2', 'thumb3'), id=2, color=[255, 128, 0]),
3:
dict(link=('thumb3', 'thumb4'), id=3, color=[255, 128, 0]),
4:
dict(link=('wrist', 'forefinger1'), id=4, color=[255, 153, 255]),
5:
dict(link=('forefinger1', 'forefinger2'), id=5, color=[255, 153, 255]),
6:
dict(link=('forefinger2', 'forefinger3'), id=6, color=[255, 153, 255]),
7:
dict(link=('forefinger3', 'forefinger4'), id=7, color=[255, 153, 255]),
8:
dict(link=('wrist', 'middle_finger1'), id=8, color=[102, 178, 255]),
9:
dict(
link=('middle_finger1', 'middle_finger2'),
id=9,
color=[102, 178, 255]),
10:
dict(
link=('middle_finger2', 'middle_finger3'),
id=10,
color=[102, 178, 255]),
11:
dict(
link=('middle_finger3', 'middle_finger4'),
id=11,
color=[102, 178, 255]),
12:
dict(link=('wrist', 'ring_finger1'), id=12, color=[255, 51, 51]),
13:
dict(
link=('ring_finger1', 'ring_finger2'), id=13, color=[255, 51, 51]),
14:
dict(
link=('ring_finger2', 'ring_finger3'), id=14, color=[255, 51, 51]),
15:
dict(
link=('ring_finger3', 'ring_finger4'), id=15, color=[255, 51, 51]),
16:
dict(link=('wrist', 'pinky_finger1'), id=16, color=[0, 255, 0]),
17:
dict(
link=('pinky_finger1', 'pinky_finger2'), id=17, color=[0, 255, 0]),
18:
dict(
link=('pinky_finger2', 'pinky_finger3'), id=18, color=[0, 255, 0]),
19:
dict(
link=('pinky_finger3', 'pinky_finger4'), id=19, color=[0, 255, 0])
},
joint_weights=[1.] * 21,
sigmas=[
0.029, 0.022, 0.035, 0.037, 0.047, 0.026, 0.025, 0.024, 0.035, 0.018,
0.024, 0.022, 0.026, 0.017, 0.021, 0.021, 0.032, 0.02, 0.019, 0.022,
0.031
])
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,134 @@
dataset_info = dict(
dataset_name='cofw',
paper_info=dict(
author='Burgos-Artizzu, Xavier P and Perona, '
r'Pietro and Doll{\'a}r, Piotr',
title='Robust face landmark estimation under occlusion',
container='Proceedings of the IEEE international '
'conference on computer vision',
year='2013',
homepage='http://www.vision.caltech.edu/xpburgos/ICCV13/',
),
keypoint_info={
0:
dict(name='kpt-0', id=0, color=[255, 255, 255], type='', swap='kpt-1'),
1:
dict(name='kpt-1', id=1, color=[255, 255, 255], type='', swap='kpt-0'),
2:
dict(name='kpt-2', id=2, color=[255, 255, 255], type='', swap='kpt-3'),
3:
dict(name='kpt-3', id=3, color=[255, 255, 255], type='', swap='kpt-2'),
4:
dict(name='kpt-4', id=4, color=[255, 255, 255], type='', swap='kpt-6'),
5:
dict(name='kpt-5', id=5, color=[255, 255, 255], type='', swap='kpt-7'),
6:
dict(name='kpt-6', id=6, color=[255, 255, 255], type='', swap='kpt-4'),
7:
dict(name='kpt-7', id=7, color=[255, 255, 255], type='', swap='kpt-5'),
8:
dict(name='kpt-8', id=8, color=[255, 255, 255], type='', swap='kpt-9'),
9:
dict(name='kpt-9', id=9, color=[255, 255, 255], type='', swap='kpt-8'),
10:
dict(
name='kpt-10',
id=10,
color=[255, 255, 255],
type='',
swap='kpt-11'),
11:
dict(
name='kpt-11',
id=11,
color=[255, 255, 255],
type='',
swap='kpt-10'),
12:
dict(
name='kpt-12',
id=12,
color=[255, 255, 255],
type='',
swap='kpt-14'),
13:
dict(
name='kpt-13',
id=13,
color=[255, 255, 255],
type='',
swap='kpt-15'),
14:
dict(
name='kpt-14',
id=14,
color=[255, 255, 255],
type='',
swap='kpt-12'),
15:
dict(
name='kpt-15',
id=15,
color=[255, 255, 255],
type='',
swap='kpt-13'),
16:
dict(
name='kpt-16',
id=16,
color=[255, 255, 255],
type='',
swap='kpt-17'),
17:
dict(
name='kpt-17',
id=17,
color=[255, 255, 255],
type='',
swap='kpt-16'),
18:
dict(
name='kpt-18',
id=18,
color=[255, 255, 255],
type='',
swap='kpt-19'),
19:
dict(
name='kpt-19',
id=19,
color=[255, 255, 255],
type='',
swap='kpt-18'),
20:
dict(name='kpt-20', id=20, color=[255, 255, 255], type='', swap=''),
21:
dict(name='kpt-21', id=21, color=[255, 255, 255], type='', swap=''),
22:
dict(
name='kpt-22',
id=22,
color=[255, 255, 255],
type='',
swap='kpt-23'),
23:
dict(
name='kpt-23',
id=23,
color=[255, 255, 255],
type='',
swap='kpt-22'),
24:
dict(name='kpt-24', id=24, color=[255, 255, 255], type='', swap=''),
25:
dict(name='kpt-25', id=25, color=[255, 255, 255], type='', swap=''),
26:
dict(name='kpt-26', id=26, color=[255, 255, 255], type='', swap=''),
27:
dict(name='kpt-27', id=27, color=[255, 255, 255], type='', swap=''),
28:
dict(name='kpt-28', id=28, color=[255, 255, 255], type='', swap='')
},
skeleton_info={},
joint_weights=[1.] * 29,
sigmas=[])
@@ -0,0 +1,147 @@
dataset_info = dict(
dataset_name='crowdpose',
paper_info=dict(
author='Li, Jiefeng and Wang, Can and Zhu, Hao and '
'Mao, Yihuan and Fang, Hao-Shu and Lu, Cewu',
title='CrowdPose: Efficient Crowded Scenes Pose Estimation '
'and A New Benchmark',
container='Proceedings of IEEE Conference on Computer '
'Vision and Pattern Recognition (CVPR)',
year='2019',
homepage='https://github.com/Jeff-sjtu/CrowdPose',
),
keypoint_info={
0:
dict(
name='left_shoulder',
id=0,
color=[51, 153, 255],
type='upper',
swap='right_shoulder'),
1:
dict(
name='right_shoulder',
id=1,
color=[51, 153, 255],
type='upper',
swap='left_shoulder'),
2:
dict(
name='left_elbow',
id=2,
color=[51, 153, 255],
type='upper',
swap='right_elbow'),
3:
dict(
name='right_elbow',
id=3,
color=[51, 153, 255],
type='upper',
swap='left_elbow'),
4:
dict(
name='left_wrist',
id=4,
color=[51, 153, 255],
type='upper',
swap='right_wrist'),
5:
dict(
name='right_wrist',
id=5,
color=[0, 255, 0],
type='upper',
swap='left_wrist'),
6:
dict(
name='left_hip',
id=6,
color=[255, 128, 0],
type='lower',
swap='right_hip'),
7:
dict(
name='right_hip',
id=7,
color=[0, 255, 0],
type='lower',
swap='left_hip'),
8:
dict(
name='left_knee',
id=8,
color=[255, 128, 0],
type='lower',
swap='right_knee'),
9:
dict(
name='right_knee',
id=9,
color=[0, 255, 0],
type='lower',
swap='left_knee'),
10:
dict(
name='left_ankle',
id=10,
color=[255, 128, 0],
type='lower',
swap='right_ankle'),
11:
dict(
name='right_ankle',
id=11,
color=[0, 255, 0],
type='lower',
swap='left_ankle'),
12:
dict(
name='top_head', id=12, color=[255, 128, 0], type='upper',
swap=''),
13:
dict(name='neck', id=13, color=[0, 255, 0], type='upper', swap='')
},
skeleton_info={
0:
dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]),
1:
dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]),
2:
dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]),
3:
dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]),
4:
dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]),
5:
dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]),
6:
dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]),
7:
dict(
link=('left_shoulder', 'right_shoulder'),
id=7,
color=[51, 153, 255]),
8:
dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]),
9:
dict(
link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]),
10:
dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('top_head', 'neck'), id=12, color=[51, 153, 255]),
13:
dict(link=('right_shoulder', 'neck'), id=13, color=[51, 153, 255]),
14:
dict(link=('left_shoulder', 'neck'), id=14, color=[51, 153, 255])
},
joint_weights=[
0.2, 0.2, 0.2, 1.3, 1.5, 0.2, 1.3, 1.5, 0.2, 0.2, 0.5, 0.2, 0.2, 0.5
],
sigmas=[
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
])
@@ -0,0 +1,74 @@
dataset_info = dict(
dataset_name='deepfashion_full',
paper_info=dict(
author='Liu, Ziwei and Luo, Ping and Qiu, Shi '
'and Wang, Xiaogang and Tang, Xiaoou',
title='DeepFashion: Powering Robust Clothes Recognition '
'and Retrieval with Rich Annotations',
container='Proceedings of IEEE Conference on Computer '
'Vision and Pattern Recognition (CVPR)',
year='2016',
homepage='http://mmlab.ie.cuhk.edu.hk/projects/'
'DeepFashion/LandmarkDetection.html',
),
keypoint_info={
0:
dict(
name='left collar',
id=0,
color=[255, 255, 255],
type='',
swap='right collar'),
1:
dict(
name='right collar',
id=1,
color=[255, 255, 255],
type='',
swap='left collar'),
2:
dict(
name='left sleeve',
id=2,
color=[255, 255, 255],
type='',
swap='right sleeve'),
3:
dict(
name='right sleeve',
id=3,
color=[255, 255, 255],
type='',
swap='left sleeve'),
4:
dict(
name='left waistline',
id=0,
color=[255, 255, 255],
type='',
swap='right waistline'),
5:
dict(
name='right waistline',
id=1,
color=[255, 255, 255],
type='',
swap='left waistline'),
6:
dict(
name='left hem',
id=2,
color=[255, 255, 255],
type='',
swap='right hem'),
7:
dict(
name='right hem',
id=3,
color=[255, 255, 255],
type='',
swap='left hem'),
},
skeleton_info={},
joint_weights=[1.] * 8,
sigmas=[])
@@ -0,0 +1,46 @@
dataset_info = dict(
dataset_name='deepfashion_lower',
paper_info=dict(
author='Liu, Ziwei and Luo, Ping and Qiu, Shi '
'and Wang, Xiaogang and Tang, Xiaoou',
title='DeepFashion: Powering Robust Clothes Recognition '
'and Retrieval with Rich Annotations',
container='Proceedings of IEEE Conference on Computer '
'Vision and Pattern Recognition (CVPR)',
year='2016',
homepage='http://mmlab.ie.cuhk.edu.hk/projects/'
'DeepFashion/LandmarkDetection.html',
),
keypoint_info={
0:
dict(
name='left waistline',
id=0,
color=[255, 255, 255],
type='',
swap='right waistline'),
1:
dict(
name='right waistline',
id=1,
color=[255, 255, 255],
type='',
swap='left waistline'),
2:
dict(
name='left hem',
id=2,
color=[255, 255, 255],
type='',
swap='right hem'),
3:
dict(
name='right hem',
id=3,
color=[255, 255, 255],
type='',
swap='left hem'),
},
skeleton_info={},
joint_weights=[1.] * 4,
sigmas=[])
@@ -0,0 +1,60 @@
dataset_info = dict(
dataset_name='deepfashion_upper',
paper_info=dict(
author='Liu, Ziwei and Luo, Ping and Qiu, Shi '
'and Wang, Xiaogang and Tang, Xiaoou',
title='DeepFashion: Powering Robust Clothes Recognition '
'and Retrieval with Rich Annotations',
container='Proceedings of IEEE Conference on Computer '
'Vision and Pattern Recognition (CVPR)',
year='2016',
homepage='http://mmlab.ie.cuhk.edu.hk/projects/'
'DeepFashion/LandmarkDetection.html',
),
keypoint_info={
0:
dict(
name='left collar',
id=0,
color=[255, 255, 255],
type='',
swap='right collar'),
1:
dict(
name='right collar',
id=1,
color=[255, 255, 255],
type='',
swap='left collar'),
2:
dict(
name='left sleeve',
id=2,
color=[255, 255, 255],
type='',
swap='right sleeve'),
3:
dict(
name='right sleeve',
id=3,
color=[255, 255, 255],
type='',
swap='left sleeve'),
4:
dict(
name='left hem',
id=4,
color=[255, 255, 255],
type='',
swap='right hem'),
5:
dict(
name='right hem',
id=5,
color=[255, 255, 255],
type='',
swap='left hem'),
},
skeleton_info={},
joint_weights=[1.] * 6,
sigmas=[])
@@ -0,0 +1,237 @@
dataset_info = dict(
dataset_name='fly',
paper_info=dict(
author='Pereira, Talmo D and Aldarondo, Diego E and '
'Willmore, Lindsay and Kislin, Mikhail and '
'Wang, Samuel S-H and Murthy, Mala and Shaevitz, Joshua W',
title='Fast animal pose estimation using deep neural networks',
container='Nature methods',
year='2019',
homepage='https://github.com/jgraving/DeepPoseKit-Data',
),
keypoint_info={
0:
dict(name='head', id=0, color=[255, 255, 255], type='', swap=''),
1:
dict(name='eyeL', id=1, color=[255, 255, 255], type='', swap='eyeR'),
2:
dict(name='eyeR', id=2, color=[255, 255, 255], type='', swap='eyeL'),
3:
dict(name='neck', id=3, color=[255, 255, 255], type='', swap=''),
4:
dict(name='thorax', id=4, color=[255, 255, 255], type='', swap=''),
5:
dict(name='abdomen', id=5, color=[255, 255, 255], type='', swap=''),
6:
dict(
name='forelegR1',
id=6,
color=[255, 255, 255],
type='',
swap='forelegL1'),
7:
dict(
name='forelegR2',
id=7,
color=[255, 255, 255],
type='',
swap='forelegL2'),
8:
dict(
name='forelegR3',
id=8,
color=[255, 255, 255],
type='',
swap='forelegL3'),
9:
dict(
name='forelegR4',
id=9,
color=[255, 255, 255],
type='',
swap='forelegL4'),
10:
dict(
name='midlegR1',
id=10,
color=[255, 255, 255],
type='',
swap='midlegL1'),
11:
dict(
name='midlegR2',
id=11,
color=[255, 255, 255],
type='',
swap='midlegL2'),
12:
dict(
name='midlegR3',
id=12,
color=[255, 255, 255],
type='',
swap='midlegL3'),
13:
dict(
name='midlegR4',
id=13,
color=[255, 255, 255],
type='',
swap='midlegL4'),
14:
dict(
name='hindlegR1',
id=14,
color=[255, 255, 255],
type='',
swap='hindlegL1'),
15:
dict(
name='hindlegR2',
id=15,
color=[255, 255, 255],
type='',
swap='hindlegL2'),
16:
dict(
name='hindlegR3',
id=16,
color=[255, 255, 255],
type='',
swap='hindlegL3'),
17:
dict(
name='hindlegR4',
id=17,
color=[255, 255, 255],
type='',
swap='hindlegL4'),
18:
dict(
name='forelegL1',
id=18,
color=[255, 255, 255],
type='',
swap='forelegR1'),
19:
dict(
name='forelegL2',
id=19,
color=[255, 255, 255],
type='',
swap='forelegR2'),
20:
dict(
name='forelegL3',
id=20,
color=[255, 255, 255],
type='',
swap='forelegR3'),
21:
dict(
name='forelegL4',
id=21,
color=[255, 255, 255],
type='',
swap='forelegR4'),
22:
dict(
name='midlegL1',
id=22,
color=[255, 255, 255],
type='',
swap='midlegR1'),
23:
dict(
name='midlegL2',
id=23,
color=[255, 255, 255],
type='',
swap='midlegR2'),
24:
dict(
name='midlegL3',
id=24,
color=[255, 255, 255],
type='',
swap='midlegR3'),
25:
dict(
name='midlegL4',
id=25,
color=[255, 255, 255],
type='',
swap='midlegR4'),
26:
dict(
name='hindlegL1',
id=26,
color=[255, 255, 255],
type='',
swap='hindlegR1'),
27:
dict(
name='hindlegL2',
id=27,
color=[255, 255, 255],
type='',
swap='hindlegR2'),
28:
dict(
name='hindlegL3',
id=28,
color=[255, 255, 255],
type='',
swap='hindlegR3'),
29:
dict(
name='hindlegL4',
id=29,
color=[255, 255, 255],
type='',
swap='hindlegR4'),
30:
dict(
name='wingL', id=30, color=[255, 255, 255], type='', swap='wingR'),
31:
dict(
name='wingR', id=31, color=[255, 255, 255], type='', swap='wingL'),
},
skeleton_info={
0: dict(link=('eyeL', 'head'), id=0, color=[255, 255, 255]),
1: dict(link=('eyeR', 'head'), id=1, color=[255, 255, 255]),
2: dict(link=('neck', 'head'), id=2, color=[255, 255, 255]),
3: dict(link=('thorax', 'neck'), id=3, color=[255, 255, 255]),
4: dict(link=('abdomen', 'thorax'), id=4, color=[255, 255, 255]),
5: dict(link=('forelegR2', 'forelegR1'), id=5, color=[255, 255, 255]),
6: dict(link=('forelegR3', 'forelegR2'), id=6, color=[255, 255, 255]),
7: dict(link=('forelegR4', 'forelegR3'), id=7, color=[255, 255, 255]),
8: dict(link=('midlegR2', 'midlegR1'), id=8, color=[255, 255, 255]),
9: dict(link=('midlegR3', 'midlegR2'), id=9, color=[255, 255, 255]),
10: dict(link=('midlegR4', 'midlegR3'), id=10, color=[255, 255, 255]),
11:
dict(link=('hindlegR2', 'hindlegR1'), id=11, color=[255, 255, 255]),
12:
dict(link=('hindlegR3', 'hindlegR2'), id=12, color=[255, 255, 255]),
13:
dict(link=('hindlegR4', 'hindlegR3'), id=13, color=[255, 255, 255]),
14:
dict(link=('forelegL2', 'forelegL1'), id=14, color=[255, 255, 255]),
15:
dict(link=('forelegL3', 'forelegL2'), id=15, color=[255, 255, 255]),
16:
dict(link=('forelegL4', 'forelegL3'), id=16, color=[255, 255, 255]),
17: dict(link=('midlegL2', 'midlegL1'), id=17, color=[255, 255, 255]),
18: dict(link=('midlegL3', 'midlegL2'), id=18, color=[255, 255, 255]),
19: dict(link=('midlegL4', 'midlegL3'), id=19, color=[255, 255, 255]),
20:
dict(link=('hindlegL2', 'hindlegL1'), id=20, color=[255, 255, 255]),
21:
dict(link=('hindlegL3', 'hindlegL2'), id=21, color=[255, 255, 255]),
22:
dict(link=('hindlegL4', 'hindlegL3'), id=22, color=[255, 255, 255]),
23: dict(link=('wingL', 'neck'), id=23, color=[255, 255, 255]),
24: dict(link=('wingR', 'neck'), id=24, color=[255, 255, 255])
},
joint_weights=[1.] * 32,
sigmas=[])
@@ -0,0 +1,144 @@
dataset_info = dict(
dataset_name='freihand',
paper_info=dict(
author='Zimmermann, Christian and Ceylan, Duygu and '
'Yang, Jimei and Russell, Bryan and '
'Argus, Max and Brox, Thomas',
title='Freihand: A dataset for markerless capture of hand pose '
'and shape from single rgb images',
container='Proceedings of the IEEE International '
'Conference on Computer Vision',
year='2019',
homepage='https://lmb.informatik.uni-freiburg.de/projects/freihand/',
),
keypoint_info={
0:
dict(name='wrist', id=0, color=[255, 255, 255], type='', swap=''),
1:
dict(name='thumb1', id=1, color=[255, 128, 0], type='', swap=''),
2:
dict(name='thumb2', id=2, color=[255, 128, 0], type='', swap=''),
3:
dict(name='thumb3', id=3, color=[255, 128, 0], type='', swap=''),
4:
dict(name='thumb4', id=4, color=[255, 128, 0], type='', swap=''),
5:
dict(
name='forefinger1', id=5, color=[255, 153, 255], type='', swap=''),
6:
dict(
name='forefinger2', id=6, color=[255, 153, 255], type='', swap=''),
7:
dict(
name='forefinger3', id=7, color=[255, 153, 255], type='', swap=''),
8:
dict(
name='forefinger4', id=8, color=[255, 153, 255], type='', swap=''),
9:
dict(
name='middle_finger1',
id=9,
color=[102, 178, 255],
type='',
swap=''),
10:
dict(
name='middle_finger2',
id=10,
color=[102, 178, 255],
type='',
swap=''),
11:
dict(
name='middle_finger3',
id=11,
color=[102, 178, 255],
type='',
swap=''),
12:
dict(
name='middle_finger4',
id=12,
color=[102, 178, 255],
type='',
swap=''),
13:
dict(
name='ring_finger1', id=13, color=[255, 51, 51], type='', swap=''),
14:
dict(
name='ring_finger2', id=14, color=[255, 51, 51], type='', swap=''),
15:
dict(
name='ring_finger3', id=15, color=[255, 51, 51], type='', swap=''),
16:
dict(
name='ring_finger4', id=16, color=[255, 51, 51], type='', swap=''),
17:
dict(name='pinky_finger1', id=17, color=[0, 255, 0], type='', swap=''),
18:
dict(name='pinky_finger2', id=18, color=[0, 255, 0], type='', swap=''),
19:
dict(name='pinky_finger3', id=19, color=[0, 255, 0], type='', swap=''),
20:
dict(name='pinky_finger4', id=20, color=[0, 255, 0], type='', swap='')
},
skeleton_info={
0:
dict(link=('wrist', 'thumb1'), id=0, color=[255, 128, 0]),
1:
dict(link=('thumb1', 'thumb2'), id=1, color=[255, 128, 0]),
2:
dict(link=('thumb2', 'thumb3'), id=2, color=[255, 128, 0]),
3:
dict(link=('thumb3', 'thumb4'), id=3, color=[255, 128, 0]),
4:
dict(link=('wrist', 'forefinger1'), id=4, color=[255, 153, 255]),
5:
dict(link=('forefinger1', 'forefinger2'), id=5, color=[255, 153, 255]),
6:
dict(link=('forefinger2', 'forefinger3'), id=6, color=[255, 153, 255]),
7:
dict(link=('forefinger3', 'forefinger4'), id=7, color=[255, 153, 255]),
8:
dict(link=('wrist', 'middle_finger1'), id=8, color=[102, 178, 255]),
9:
dict(
link=('middle_finger1', 'middle_finger2'),
id=9,
color=[102, 178, 255]),
10:
dict(
link=('middle_finger2', 'middle_finger3'),
id=10,
color=[102, 178, 255]),
11:
dict(
link=('middle_finger3', 'middle_finger4'),
id=11,
color=[102, 178, 255]),
12:
dict(link=('wrist', 'ring_finger1'), id=12, color=[255, 51, 51]),
13:
dict(
link=('ring_finger1', 'ring_finger2'), id=13, color=[255, 51, 51]),
14:
dict(
link=('ring_finger2', 'ring_finger3'), id=14, color=[255, 51, 51]),
15:
dict(
link=('ring_finger3', 'ring_finger4'), id=15, color=[255, 51, 51]),
16:
dict(link=('wrist', 'pinky_finger1'), id=16, color=[0, 255, 0]),
17:
dict(
link=('pinky_finger1', 'pinky_finger2'), id=17, color=[0, 255, 0]),
18:
dict(
link=('pinky_finger2', 'pinky_finger3'), id=18, color=[0, 255, 0]),
19:
dict(
link=('pinky_finger3', 'pinky_finger4'), id=19, color=[0, 255, 0])
},
joint_weights=[1.] * 21,
sigmas=[])
@@ -0,0 +1,152 @@
dataset_info = dict(
dataset_name='h36m',
paper_info=dict(
author='Ionescu, Catalin and Papava, Dragos and '
'Olaru, Vlad and Sminchisescu, Cristian',
title='Human3.6M: Large Scale Datasets and Predictive '
'Methods for 3D Human Sensing in Natural Environments',
container='IEEE Transactions on Pattern Analysis and '
'Machine Intelligence',
year='2014',
homepage='http://vision.imar.ro/human3.6m/description.php',
),
keypoint_info={
0:
dict(name='root', id=0, color=[51, 153, 255], type='lower', swap=''),
1:
dict(
name='right_hip',
id=1,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
2:
dict(
name='right_knee',
id=2,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
3:
dict(
name='right_foot',
id=3,
color=[255, 128, 0],
type='lower',
swap='left_foot'),
4:
dict(
name='left_hip',
id=4,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
5:
dict(
name='left_knee',
id=5,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
6:
dict(
name='left_foot',
id=6,
color=[0, 255, 0],
type='lower',
swap='right_foot'),
7:
dict(name='spine', id=7, color=[51, 153, 255], type='upper', swap=''),
8:
dict(name='thorax', id=8, color=[51, 153, 255], type='upper', swap=''),
9:
dict(
name='neck_base',
id=9,
color=[51, 153, 255],
type='upper',
swap=''),
10:
dict(name='head', id=10, color=[51, 153, 255], type='upper', swap=''),
11:
dict(
name='left_shoulder',
id=11,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
12:
dict(
name='left_elbow',
id=12,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
13:
dict(
name='left_wrist',
id=13,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
14:
dict(
name='right_shoulder',
id=14,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
15:
dict(
name='right_elbow',
id=15,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
16:
dict(
name='right_wrist',
id=16,
color=[255, 128, 0],
type='upper',
swap='left_wrist')
},
skeleton_info={
0:
dict(link=('root', 'left_hip'), id=0, color=[0, 255, 0]),
1:
dict(link=('left_hip', 'left_knee'), id=1, color=[0, 255, 0]),
2:
dict(link=('left_knee', 'left_foot'), id=2, color=[0, 255, 0]),
3:
dict(link=('root', 'right_hip'), id=3, color=[255, 128, 0]),
4:
dict(link=('right_hip', 'right_knee'), id=4, color=[255, 128, 0]),
5:
dict(link=('right_knee', 'right_foot'), id=5, color=[255, 128, 0]),
6:
dict(link=('root', 'spine'), id=6, color=[51, 153, 255]),
7:
dict(link=('spine', 'thorax'), id=7, color=[51, 153, 255]),
8:
dict(link=('thorax', 'neck_base'), id=8, color=[51, 153, 255]),
9:
dict(link=('neck_base', 'head'), id=9, color=[51, 153, 255]),
10:
dict(link=('thorax', 'left_shoulder'), id=10, color=[0, 255, 0]),
11:
dict(link=('left_shoulder', 'left_elbow'), id=11, color=[0, 255, 0]),
12:
dict(link=('left_elbow', 'left_wrist'), id=12, color=[0, 255, 0]),
13:
dict(link=('thorax', 'right_shoulder'), id=13, color=[255, 128, 0]),
14:
dict(
link=('right_shoulder', 'right_elbow'), id=14, color=[255, 128,
0]),
15:
dict(link=('right_elbow', 'right_wrist'), id=15, color=[255, 128, 0])
},
joint_weights=[1.] * 17,
sigmas=[],
stats_info=dict(bbox_center=(528., 427.), bbox_scale=400.))
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,201 @@
dataset_info = dict(
dataset_name='horse10',
paper_info=dict(
author='Mathis, Alexander and Biasi, Thomas and '
'Schneider, Steffen and '
'Yuksekgonul, Mert and Rogers, Byron and '
'Bethge, Matthias and '
'Mathis, Mackenzie W',
title='Pretraining boosts out-of-domain robustness '
'for pose estimation',
container='Proceedings of the IEEE/CVF Winter Conference on '
'Applications of Computer Vision',
year='2021',
homepage='http://www.mackenziemathislab.org/horse10',
),
keypoint_info={
0:
dict(name='Nose', id=0, color=[255, 153, 255], type='upper', swap=''),
1:
dict(name='Eye', id=1, color=[255, 153, 255], type='upper', swap=''),
2:
dict(
name='Nearknee',
id=2,
color=[255, 102, 255],
type='upper',
swap=''),
3:
dict(
name='Nearfrontfetlock',
id=3,
color=[255, 102, 255],
type='upper',
swap=''),
4:
dict(
name='Nearfrontfoot',
id=4,
color=[255, 102, 255],
type='upper',
swap=''),
5:
dict(
name='Offknee', id=5, color=[255, 102, 255], type='upper',
swap=''),
6:
dict(
name='Offfrontfetlock',
id=6,
color=[255, 102, 255],
type='upper',
swap=''),
7:
dict(
name='Offfrontfoot',
id=7,
color=[255, 102, 255],
type='upper',
swap=''),
8:
dict(
name='Shoulder',
id=8,
color=[255, 153, 255],
type='upper',
swap=''),
9:
dict(
name='Midshoulder',
id=9,
color=[255, 153, 255],
type='upper',
swap=''),
10:
dict(
name='Elbow', id=10, color=[255, 153, 255], type='upper', swap=''),
11:
dict(
name='Girth', id=11, color=[255, 153, 255], type='upper', swap=''),
12:
dict(
name='Wither', id=12, color=[255, 153, 255], type='upper',
swap=''),
13:
dict(
name='Nearhindhock',
id=13,
color=[255, 51, 255],
type='lower',
swap=''),
14:
dict(
name='Nearhindfetlock',
id=14,
color=[255, 51, 255],
type='lower',
swap=''),
15:
dict(
name='Nearhindfoot',
id=15,
color=[255, 51, 255],
type='lower',
swap=''),
16:
dict(name='Hip', id=16, color=[255, 153, 255], type='lower', swap=''),
17:
dict(
name='Stifle', id=17, color=[255, 153, 255], type='lower',
swap=''),
18:
dict(
name='Offhindhock',
id=18,
color=[255, 51, 255],
type='lower',
swap=''),
19:
dict(
name='Offhindfetlock',
id=19,
color=[255, 51, 255],
type='lower',
swap=''),
20:
dict(
name='Offhindfoot',
id=20,
color=[255, 51, 255],
type='lower',
swap=''),
21:
dict(
name='Ischium',
id=21,
color=[255, 153, 255],
type='lower',
swap='')
},
skeleton_info={
0:
dict(link=('Nose', 'Eye'), id=0, color=[255, 153, 255]),
1:
dict(link=('Eye', 'Wither'), id=1, color=[255, 153, 255]),
2:
dict(link=('Wither', 'Hip'), id=2, color=[255, 153, 255]),
3:
dict(link=('Hip', 'Ischium'), id=3, color=[255, 153, 255]),
4:
dict(link=('Ischium', 'Stifle'), id=4, color=[255, 153, 255]),
5:
dict(link=('Stifle', 'Girth'), id=5, color=[255, 153, 255]),
6:
dict(link=('Girth', 'Elbow'), id=6, color=[255, 153, 255]),
7:
dict(link=('Elbow', 'Shoulder'), id=7, color=[255, 153, 255]),
8:
dict(link=('Shoulder', 'Midshoulder'), id=8, color=[255, 153, 255]),
9:
dict(link=('Midshoulder', 'Wither'), id=9, color=[255, 153, 255]),
10:
dict(
link=('Nearknee', 'Nearfrontfetlock'),
id=10,
color=[255, 102, 255]),
11:
dict(
link=('Nearfrontfetlock', 'Nearfrontfoot'),
id=11,
color=[255, 102, 255]),
12:
dict(
link=('Offknee', 'Offfrontfetlock'), id=12, color=[255, 102, 255]),
13:
dict(
link=('Offfrontfetlock', 'Offfrontfoot'),
id=13,
color=[255, 102, 255]),
14:
dict(
link=('Nearhindhock', 'Nearhindfetlock'),
id=14,
color=[255, 51, 255]),
15:
dict(
link=('Nearhindfetlock', 'Nearhindfoot'),
id=15,
color=[255, 51, 255]),
16:
dict(
link=('Offhindhock', 'Offhindfetlock'),
id=16,
color=[255, 51, 255]),
17:
dict(
link=('Offhindfetlock', 'Offhindfoot'),
id=17,
color=[255, 51, 255])
},
joint_weights=[1.] * 22,
sigmas=[])
@@ -0,0 +1,142 @@
dataset_info = dict(
dataset_name='interhand2d',
paper_info=dict(
author='Moon, Gyeongsik and Yu, Shoou-I and Wen, He and '
'Shiratori, Takaaki and Lee, Kyoung Mu',
title='InterHand2.6M: A dataset and baseline for 3D '
'interacting hand pose estimation from a single RGB image',
container='arXiv',
year='2020',
homepage='https://mks0601.github.io/InterHand2.6M/',
),
keypoint_info={
0:
dict(name='thumb4', id=0, color=[255, 128, 0], type='', swap=''),
1:
dict(name='thumb3', id=1, color=[255, 128, 0], type='', swap=''),
2:
dict(name='thumb2', id=2, color=[255, 128, 0], type='', swap=''),
3:
dict(name='thumb1', id=3, color=[255, 128, 0], type='', swap=''),
4:
dict(
name='forefinger4', id=4, color=[255, 153, 255], type='', swap=''),
5:
dict(
name='forefinger3', id=5, color=[255, 153, 255], type='', swap=''),
6:
dict(
name='forefinger2', id=6, color=[255, 153, 255], type='', swap=''),
7:
dict(
name='forefinger1', id=7, color=[255, 153, 255], type='', swap=''),
8:
dict(
name='middle_finger4',
id=8,
color=[102, 178, 255],
type='',
swap=''),
9:
dict(
name='middle_finger3',
id=9,
color=[102, 178, 255],
type='',
swap=''),
10:
dict(
name='middle_finger2',
id=10,
color=[102, 178, 255],
type='',
swap=''),
11:
dict(
name='middle_finger1',
id=11,
color=[102, 178, 255],
type='',
swap=''),
12:
dict(
name='ring_finger4', id=12, color=[255, 51, 51], type='', swap=''),
13:
dict(
name='ring_finger3', id=13, color=[255, 51, 51], type='', swap=''),
14:
dict(
name='ring_finger2', id=14, color=[255, 51, 51], type='', swap=''),
15:
dict(
name='ring_finger1', id=15, color=[255, 51, 51], type='', swap=''),
16:
dict(name='pinky_finger4', id=16, color=[0, 255, 0], type='', swap=''),
17:
dict(name='pinky_finger3', id=17, color=[0, 255, 0], type='', swap=''),
18:
dict(name='pinky_finger2', id=18, color=[0, 255, 0], type='', swap=''),
19:
dict(name='pinky_finger1', id=19, color=[0, 255, 0], type='', swap=''),
20:
dict(name='wrist', id=20, color=[255, 255, 255], type='', swap='')
},
skeleton_info={
0:
dict(link=('wrist', 'thumb1'), id=0, color=[255, 128, 0]),
1:
dict(link=('thumb1', 'thumb2'), id=1, color=[255, 128, 0]),
2:
dict(link=('thumb2', 'thumb3'), id=2, color=[255, 128, 0]),
3:
dict(link=('thumb3', 'thumb4'), id=3, color=[255, 128, 0]),
4:
dict(link=('wrist', 'forefinger1'), id=4, color=[255, 153, 255]),
5:
dict(link=('forefinger1', 'forefinger2'), id=5, color=[255, 153, 255]),
6:
dict(link=('forefinger2', 'forefinger3'), id=6, color=[255, 153, 255]),
7:
dict(link=('forefinger3', 'forefinger4'), id=7, color=[255, 153, 255]),
8:
dict(link=('wrist', 'middle_finger1'), id=8, color=[102, 178, 255]),
9:
dict(
link=('middle_finger1', 'middle_finger2'),
id=9,
color=[102, 178, 255]),
10:
dict(
link=('middle_finger2', 'middle_finger3'),
id=10,
color=[102, 178, 255]),
11:
dict(
link=('middle_finger3', 'middle_finger4'),
id=11,
color=[102, 178, 255]),
12:
dict(link=('wrist', 'ring_finger1'), id=12, color=[255, 51, 51]),
13:
dict(
link=('ring_finger1', 'ring_finger2'), id=13, color=[255, 51, 51]),
14:
dict(
link=('ring_finger2', 'ring_finger3'), id=14, color=[255, 51, 51]),
15:
dict(
link=('ring_finger3', 'ring_finger4'), id=15, color=[255, 51, 51]),
16:
dict(link=('wrist', 'pinky_finger1'), id=16, color=[0, 255, 0]),
17:
dict(
link=('pinky_finger1', 'pinky_finger2'), id=17, color=[0, 255, 0]),
18:
dict(
link=('pinky_finger2', 'pinky_finger3'), id=18, color=[0, 255, 0]),
19:
dict(
link=('pinky_finger3', 'pinky_finger4'), id=19, color=[0, 255, 0])
},
joint_weights=[1.] * 21,
sigmas=[])
@@ -0,0 +1,487 @@
dataset_info = dict(
dataset_name='interhand3d',
paper_info=dict(
author='Moon, Gyeongsik and Yu, Shoou-I and Wen, He and '
'Shiratori, Takaaki and Lee, Kyoung Mu',
title='InterHand2.6M: A dataset and baseline for 3D '
'interacting hand pose estimation from a single RGB image',
container='arXiv',
year='2020',
homepage='https://mks0601.github.io/InterHand2.6M/',
),
keypoint_info={
0:
dict(
name='right_thumb4',
id=0,
color=[255, 128, 0],
type='',
swap='left_thumb4'),
1:
dict(
name='right_thumb3',
id=1,
color=[255, 128, 0],
type='',
swap='left_thumb3'),
2:
dict(
name='right_thumb2',
id=2,
color=[255, 128, 0],
type='',
swap='left_thumb2'),
3:
dict(
name='right_thumb1',
id=3,
color=[255, 128, 0],
type='',
swap='left_thumb1'),
4:
dict(
name='right_forefinger4',
id=4,
color=[255, 153, 255],
type='',
swap='left_forefinger4'),
5:
dict(
name='right_forefinger3',
id=5,
color=[255, 153, 255],
type='',
swap='left_forefinger3'),
6:
dict(
name='right_forefinger2',
id=6,
color=[255, 153, 255],
type='',
swap='left_forefinger2'),
7:
dict(
name='right_forefinger1',
id=7,
color=[255, 153, 255],
type='',
swap='left_forefinger1'),
8:
dict(
name='right_middle_finger4',
id=8,
color=[102, 178, 255],
type='',
swap='left_middle_finger4'),
9:
dict(
name='right_middle_finger3',
id=9,
color=[102, 178, 255],
type='',
swap='left_middle_finger3'),
10:
dict(
name='right_middle_finger2',
id=10,
color=[102, 178, 255],
type='',
swap='left_middle_finger2'),
11:
dict(
name='right_middle_finger1',
id=11,
color=[102, 178, 255],
type='',
swap='left_middle_finger1'),
12:
dict(
name='right_ring_finger4',
id=12,
color=[255, 51, 51],
type='',
swap='left_ring_finger4'),
13:
dict(
name='right_ring_finger3',
id=13,
color=[255, 51, 51],
type='',
swap='left_ring_finger3'),
14:
dict(
name='right_ring_finger2',
id=14,
color=[255, 51, 51],
type='',
swap='left_ring_finger2'),
15:
dict(
name='right_ring_finger1',
id=15,
color=[255, 51, 51],
type='',
swap='left_ring_finger1'),
16:
dict(
name='right_pinky_finger4',
id=16,
color=[0, 255, 0],
type='',
swap='left_pinky_finger4'),
17:
dict(
name='right_pinky_finger3',
id=17,
color=[0, 255, 0],
type='',
swap='left_pinky_finger3'),
18:
dict(
name='right_pinky_finger2',
id=18,
color=[0, 255, 0],
type='',
swap='left_pinky_finger2'),
19:
dict(
name='right_pinky_finger1',
id=19,
color=[0, 255, 0],
type='',
swap='left_pinky_finger1'),
20:
dict(
name='right_wrist',
id=20,
color=[255, 255, 255],
type='',
swap='left_wrist'),
21:
dict(
name='left_thumb4',
id=21,
color=[255, 128, 0],
type='',
swap='right_thumb4'),
22:
dict(
name='left_thumb3',
id=22,
color=[255, 128, 0],
type='',
swap='right_thumb3'),
23:
dict(
name='left_thumb2',
id=23,
color=[255, 128, 0],
type='',
swap='right_thumb2'),
24:
dict(
name='left_thumb1',
id=24,
color=[255, 128, 0],
type='',
swap='right_thumb1'),
25:
dict(
name='left_forefinger4',
id=25,
color=[255, 153, 255],
type='',
swap='right_forefinger4'),
26:
dict(
name='left_forefinger3',
id=26,
color=[255, 153, 255],
type='',
swap='right_forefinger3'),
27:
dict(
name='left_forefinger2',
id=27,
color=[255, 153, 255],
type='',
swap='right_forefinger2'),
28:
dict(
name='left_forefinger1',
id=28,
color=[255, 153, 255],
type='',
swap='right_forefinger1'),
29:
dict(
name='left_middle_finger4',
id=29,
color=[102, 178, 255],
type='',
swap='right_middle_finger4'),
30:
dict(
name='left_middle_finger3',
id=30,
color=[102, 178, 255],
type='',
swap='right_middle_finger3'),
31:
dict(
name='left_middle_finger2',
id=31,
color=[102, 178, 255],
type='',
swap='right_middle_finger2'),
32:
dict(
name='left_middle_finger1',
id=32,
color=[102, 178, 255],
type='',
swap='right_middle_finger1'),
33:
dict(
name='left_ring_finger4',
id=33,
color=[255, 51, 51],
type='',
swap='right_ring_finger4'),
34:
dict(
name='left_ring_finger3',
id=34,
color=[255, 51, 51],
type='',
swap='right_ring_finger3'),
35:
dict(
name='left_ring_finger2',
id=35,
color=[255, 51, 51],
type='',
swap='right_ring_finger2'),
36:
dict(
name='left_ring_finger1',
id=36,
color=[255, 51, 51],
type='',
swap='right_ring_finger1'),
37:
dict(
name='left_pinky_finger4',
id=37,
color=[0, 255, 0],
type='',
swap='right_pinky_finger4'),
38:
dict(
name='left_pinky_finger3',
id=38,
color=[0, 255, 0],
type='',
swap='right_pinky_finger3'),
39:
dict(
name='left_pinky_finger2',
id=39,
color=[0, 255, 0],
type='',
swap='right_pinky_finger2'),
40:
dict(
name='left_pinky_finger1',
id=40,
color=[0, 255, 0],
type='',
swap='right_pinky_finger1'),
41:
dict(
name='left_wrist',
id=41,
color=[255, 255, 255],
type='',
swap='right_wrist'),
},
skeleton_info={
0:
dict(link=('right_wrist', 'right_thumb1'), id=0, color=[255, 128, 0]),
1:
dict(link=('right_thumb1', 'right_thumb2'), id=1, color=[255, 128, 0]),
2:
dict(link=('right_thumb2', 'right_thumb3'), id=2, color=[255, 128, 0]),
3:
dict(link=('right_thumb3', 'right_thumb4'), id=3, color=[255, 128, 0]),
4:
dict(
link=('right_wrist', 'right_forefinger1'),
id=4,
color=[255, 153, 255]),
5:
dict(
link=('right_forefinger1', 'right_forefinger2'),
id=5,
color=[255, 153, 255]),
6:
dict(
link=('right_forefinger2', 'right_forefinger3'),
id=6,
color=[255, 153, 255]),
7:
dict(
link=('right_forefinger3', 'right_forefinger4'),
id=7,
color=[255, 153, 255]),
8:
dict(
link=('right_wrist', 'right_middle_finger1'),
id=8,
color=[102, 178, 255]),
9:
dict(
link=('right_middle_finger1', 'right_middle_finger2'),
id=9,
color=[102, 178, 255]),
10:
dict(
link=('right_middle_finger2', 'right_middle_finger3'),
id=10,
color=[102, 178, 255]),
11:
dict(
link=('right_middle_finger3', 'right_middle_finger4'),
id=11,
color=[102, 178, 255]),
12:
dict(
link=('right_wrist', 'right_ring_finger1'),
id=12,
color=[255, 51, 51]),
13:
dict(
link=('right_ring_finger1', 'right_ring_finger2'),
id=13,
color=[255, 51, 51]),
14:
dict(
link=('right_ring_finger2', 'right_ring_finger3'),
id=14,
color=[255, 51, 51]),
15:
dict(
link=('right_ring_finger3', 'right_ring_finger4'),
id=15,
color=[255, 51, 51]),
16:
dict(
link=('right_wrist', 'right_pinky_finger1'),
id=16,
color=[0, 255, 0]),
17:
dict(
link=('right_pinky_finger1', 'right_pinky_finger2'),
id=17,
color=[0, 255, 0]),
18:
dict(
link=('right_pinky_finger2', 'right_pinky_finger3'),
id=18,
color=[0, 255, 0]),
19:
dict(
link=('right_pinky_finger3', 'right_pinky_finger4'),
id=19,
color=[0, 255, 0]),
20:
dict(link=('left_wrist', 'left_thumb1'), id=20, color=[255, 128, 0]),
21:
dict(link=('left_thumb1', 'left_thumb2'), id=21, color=[255, 128, 0]),
22:
dict(link=('left_thumb2', 'left_thumb3'), id=22, color=[255, 128, 0]),
23:
dict(link=('left_thumb3', 'left_thumb4'), id=23, color=[255, 128, 0]),
24:
dict(
link=('left_wrist', 'left_forefinger1'),
id=24,
color=[255, 153, 255]),
25:
dict(
link=('left_forefinger1', 'left_forefinger2'),
id=25,
color=[255, 153, 255]),
26:
dict(
link=('left_forefinger2', 'left_forefinger3'),
id=26,
color=[255, 153, 255]),
27:
dict(
link=('left_forefinger3', 'left_forefinger4'),
id=27,
color=[255, 153, 255]),
28:
dict(
link=('left_wrist', 'left_middle_finger1'),
id=28,
color=[102, 178, 255]),
29:
dict(
link=('left_middle_finger1', 'left_middle_finger2'),
id=29,
color=[102, 178, 255]),
30:
dict(
link=('left_middle_finger2', 'left_middle_finger3'),
id=30,
color=[102, 178, 255]),
31:
dict(
link=('left_middle_finger3', 'left_middle_finger4'),
id=31,
color=[102, 178, 255]),
32:
dict(
link=('left_wrist', 'left_ring_finger1'),
id=32,
color=[255, 51, 51]),
33:
dict(
link=('left_ring_finger1', 'left_ring_finger2'),
id=33,
color=[255, 51, 51]),
34:
dict(
link=('left_ring_finger2', 'left_ring_finger3'),
id=34,
color=[255, 51, 51]),
35:
dict(
link=('left_ring_finger3', 'left_ring_finger4'),
id=35,
color=[255, 51, 51]),
36:
dict(
link=('left_wrist', 'left_pinky_finger1'),
id=36,
color=[0, 255, 0]),
37:
dict(
link=('left_pinky_finger1', 'left_pinky_finger2'),
id=37,
color=[0, 255, 0]),
38:
dict(
link=('left_pinky_finger2', 'left_pinky_finger3'),
id=38,
color=[0, 255, 0]),
39:
dict(
link=('left_pinky_finger3', 'left_pinky_finger4'),
id=39,
color=[0, 255, 0]),
},
joint_weights=[1.] * 42,
sigmas=[])
@@ -0,0 +1,129 @@
dataset_info = dict(
dataset_name='jhmdb',
paper_info=dict(
author='H. Jhuang and J. Gall and S. Zuffi and '
'C. Schmid and M. J. Black',
title='Towards understanding action recognition',
container='International Conf. on Computer Vision (ICCV)',
year='2013',
homepage='http://jhmdb.is.tue.mpg.de/dataset',
),
keypoint_info={
0:
dict(name='neck', id=0, color=[255, 128, 0], type='upper', swap=''),
1:
dict(name='belly', id=1, color=[255, 128, 0], type='upper', swap=''),
2:
dict(name='head', id=2, color=[255, 128, 0], type='upper', swap=''),
3:
dict(
name='right_shoulder',
id=3,
color=[0, 255, 0],
type='upper',
swap='left_shoulder'),
4:
dict(
name='left_shoulder',
id=4,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
5:
dict(
name='right_hip',
id=5,
color=[0, 255, 0],
type='lower',
swap='left_hip'),
6:
dict(
name='left_hip',
id=6,
color=[51, 153, 255],
type='lower',
swap='right_hip'),
7:
dict(
name='right_elbow',
id=7,
color=[51, 153, 255],
type='upper',
swap='left_elbow'),
8:
dict(
name='left_elbow',
id=8,
color=[51, 153, 255],
type='upper',
swap='right_elbow'),
9:
dict(
name='right_knee',
id=9,
color=[51, 153, 255],
type='lower',
swap='left_knee'),
10:
dict(
name='left_knee',
id=10,
color=[255, 128, 0],
type='lower',
swap='right_knee'),
11:
dict(
name='right_wrist',
id=11,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
12:
dict(
name='left_wrist',
id=12,
color=[255, 128, 0],
type='upper',
swap='right_wrist'),
13:
dict(
name='right_ankle',
id=13,
color=[0, 255, 0],
type='lower',
swap='left_ankle'),
14:
dict(
name='left_ankle',
id=14,
color=[0, 255, 0],
type='lower',
swap='right_ankle')
},
skeleton_info={
0: dict(link=('right_ankle', 'right_knee'), id=0, color=[255, 128, 0]),
1: dict(link=('right_knee', 'right_hip'), id=1, color=[255, 128, 0]),
2: dict(link=('right_hip', 'belly'), id=2, color=[255, 128, 0]),
3: dict(link=('belly', 'left_hip'), id=3, color=[0, 255, 0]),
4: dict(link=('left_hip', 'left_knee'), id=4, color=[0, 255, 0]),
5: dict(link=('left_knee', 'left_ankle'), id=5, color=[0, 255, 0]),
6: dict(link=('belly', 'neck'), id=6, color=[51, 153, 255]),
7: dict(link=('neck', 'head'), id=7, color=[51, 153, 255]),
8: dict(link=('neck', 'right_shoulder'), id=8, color=[255, 128, 0]),
9: dict(
link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]),
10:
dict(link=('right_elbow', 'right_wrist'), id=10, color=[255, 128, 0]),
11: dict(link=('neck', 'left_shoulder'), id=11, color=[0, 255, 0]),
12:
dict(link=('left_shoulder', 'left_elbow'), id=12, color=[0, 255, 0]),
13: dict(link=('left_elbow', 'left_wrist'), id=13, color=[0, 255, 0])
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.2, 1.2, 1.5, 1.5, 1.5, 1.5
],
# Adapted from COCO dataset.
sigmas=[
0.025, 0.107, 0.025, 0.079, 0.079, 0.107, 0.107, 0.072, 0.072, 0.087,
0.087, 0.062, 0.062, 0.089, 0.089
])
@@ -0,0 +1,263 @@
dataset_info = dict(
dataset_name='locust',
paper_info=dict(
author='Graving, Jacob M and Chae, Daniel and Naik, Hemal and '
'Li, Liang and Koger, Benjamin and Costelloe, Blair R and '
'Couzin, Iain D',
title='DeepPoseKit, a software toolkit for fast and robust '
'animal pose estimation using deep learning',
container='Elife',
year='2019',
homepage='https://github.com/jgraving/DeepPoseKit-Data',
),
keypoint_info={
0:
dict(name='head', id=0, color=[255, 255, 255], type='', swap=''),
1:
dict(name='neck', id=1, color=[255, 255, 255], type='', swap=''),
2:
dict(name='thorax', id=2, color=[255, 255, 255], type='', swap=''),
3:
dict(name='abdomen1', id=3, color=[255, 255, 255], type='', swap=''),
4:
dict(name='abdomen2', id=4, color=[255, 255, 255], type='', swap=''),
5:
dict(
name='anttipL',
id=5,
color=[255, 255, 255],
type='',
swap='anttipR'),
6:
dict(
name='antbaseL',
id=6,
color=[255, 255, 255],
type='',
swap='antbaseR'),
7:
dict(name='eyeL', id=7, color=[255, 255, 255], type='', swap='eyeR'),
8:
dict(
name='forelegL1',
id=8,
color=[255, 255, 255],
type='',
swap='forelegR1'),
9:
dict(
name='forelegL2',
id=9,
color=[255, 255, 255],
type='',
swap='forelegR2'),
10:
dict(
name='forelegL3',
id=10,
color=[255, 255, 255],
type='',
swap='forelegR3'),
11:
dict(
name='forelegL4',
id=11,
color=[255, 255, 255],
type='',
swap='forelegR4'),
12:
dict(
name='midlegL1',
id=12,
color=[255, 255, 255],
type='',
swap='midlegR1'),
13:
dict(
name='midlegL2',
id=13,
color=[255, 255, 255],
type='',
swap='midlegR2'),
14:
dict(
name='midlegL3',
id=14,
color=[255, 255, 255],
type='',
swap='midlegR3'),
15:
dict(
name='midlegL4',
id=15,
color=[255, 255, 255],
type='',
swap='midlegR4'),
16:
dict(
name='hindlegL1',
id=16,
color=[255, 255, 255],
type='',
swap='hindlegR1'),
17:
dict(
name='hindlegL2',
id=17,
color=[255, 255, 255],
type='',
swap='hindlegR2'),
18:
dict(
name='hindlegL3',
id=18,
color=[255, 255, 255],
type='',
swap='hindlegR3'),
19:
dict(
name='hindlegL4',
id=19,
color=[255, 255, 255],
type='',
swap='hindlegR4'),
20:
dict(
name='anttipR',
id=20,
color=[255, 255, 255],
type='',
swap='anttipL'),
21:
dict(
name='antbaseR',
id=21,
color=[255, 255, 255],
type='',
swap='antbaseL'),
22:
dict(name='eyeR', id=22, color=[255, 255, 255], type='', swap='eyeL'),
23:
dict(
name='forelegR1',
id=23,
color=[255, 255, 255],
type='',
swap='forelegL1'),
24:
dict(
name='forelegR2',
id=24,
color=[255, 255, 255],
type='',
swap='forelegL2'),
25:
dict(
name='forelegR3',
id=25,
color=[255, 255, 255],
type='',
swap='forelegL3'),
26:
dict(
name='forelegR4',
id=26,
color=[255, 255, 255],
type='',
swap='forelegL4'),
27:
dict(
name='midlegR1',
id=27,
color=[255, 255, 255],
type='',
swap='midlegL1'),
28:
dict(
name='midlegR2',
id=28,
color=[255, 255, 255],
type='',
swap='midlegL2'),
29:
dict(
name='midlegR3',
id=29,
color=[255, 255, 255],
type='',
swap='midlegL3'),
30:
dict(
name='midlegR4',
id=30,
color=[255, 255, 255],
type='',
swap='midlegL4'),
31:
dict(
name='hindlegR1',
id=31,
color=[255, 255, 255],
type='',
swap='hindlegL1'),
32:
dict(
name='hindlegR2',
id=32,
color=[255, 255, 255],
type='',
swap='hindlegL2'),
33:
dict(
name='hindlegR3',
id=33,
color=[255, 255, 255],
type='',
swap='hindlegL3'),
34:
dict(
name='hindlegR4',
id=34,
color=[255, 255, 255],
type='',
swap='hindlegL4')
},
skeleton_info={
0: dict(link=('neck', 'head'), id=0, color=[255, 255, 255]),
1: dict(link=('thorax', 'neck'), id=1, color=[255, 255, 255]),
2: dict(link=('abdomen1', 'thorax'), id=2, color=[255, 255, 255]),
3: dict(link=('abdomen2', 'abdomen1'), id=3, color=[255, 255, 255]),
4: dict(link=('antbaseL', 'anttipL'), id=4, color=[255, 255, 255]),
5: dict(link=('eyeL', 'antbaseL'), id=5, color=[255, 255, 255]),
6: dict(link=('forelegL2', 'forelegL1'), id=6, color=[255, 255, 255]),
7: dict(link=('forelegL3', 'forelegL2'), id=7, color=[255, 255, 255]),
8: dict(link=('forelegL4', 'forelegL3'), id=8, color=[255, 255, 255]),
9: dict(link=('midlegL2', 'midlegL1'), id=9, color=[255, 255, 255]),
10: dict(link=('midlegL3', 'midlegL2'), id=10, color=[255, 255, 255]),
11: dict(link=('midlegL4', 'midlegL3'), id=11, color=[255, 255, 255]),
12:
dict(link=('hindlegL2', 'hindlegL1'), id=12, color=[255, 255, 255]),
13:
dict(link=('hindlegL3', 'hindlegL2'), id=13, color=[255, 255, 255]),
14:
dict(link=('hindlegL4', 'hindlegL3'), id=14, color=[255, 255, 255]),
15: dict(link=('antbaseR', 'anttipR'), id=15, color=[255, 255, 255]),
16: dict(link=('eyeR', 'antbaseR'), id=16, color=[255, 255, 255]),
17:
dict(link=('forelegR2', 'forelegR1'), id=17, color=[255, 255, 255]),
18:
dict(link=('forelegR3', 'forelegR2'), id=18, color=[255, 255, 255]),
19:
dict(link=('forelegR4', 'forelegR3'), id=19, color=[255, 255, 255]),
20: dict(link=('midlegR2', 'midlegR1'), id=20, color=[255, 255, 255]),
21: dict(link=('midlegR3', 'midlegR2'), id=21, color=[255, 255, 255]),
22: dict(link=('midlegR4', 'midlegR3'), id=22, color=[255, 255, 255]),
23:
dict(link=('hindlegR2', 'hindlegR1'), id=23, color=[255, 255, 255]),
24:
dict(link=('hindlegR3', 'hindlegR2'), id=24, color=[255, 255, 255]),
25:
dict(link=('hindlegR4', 'hindlegR3'), id=25, color=[255, 255, 255])
},
joint_weights=[1.] * 35,
sigmas=[])
@@ -0,0 +1,183 @@
dataset_info = dict(
dataset_name='macaque',
paper_info=dict(
author='Labuguen, Rollyn and Matsumoto, Jumpei and '
'Negrete, Salvador and Nishimaru, Hiroshi and '
'Nishijo, Hisao and Takada, Masahiko and '
'Go, Yasuhiro and Inoue, Ken-ichi and Shibata, Tomohiro',
title='MacaquePose: A novel "in the wild" macaque monkey pose dataset '
'for markerless motion capture',
container='bioRxiv',
year='2020',
homepage='http://www.pri.kyoto-u.ac.jp/datasets/'
'macaquepose/index.html',
),
keypoint_info={
0:
dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''),
1:
dict(
name='left_eye',
id=1,
color=[51, 153, 255],
type='upper',
swap='right_eye'),
2:
dict(
name='right_eye',
id=2,
color=[51, 153, 255],
type='upper',
swap='left_eye'),
3:
dict(
name='left_ear',
id=3,
color=[51, 153, 255],
type='upper',
swap='right_ear'),
4:
dict(
name='right_ear',
id=4,
color=[51, 153, 255],
type='upper',
swap='left_ear'),
5:
dict(
name='left_shoulder',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
6:
dict(
name='right_shoulder',
id=6,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
7:
dict(
name='left_elbow',
id=7,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
8:
dict(
name='right_elbow',
id=8,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
9:
dict(
name='left_wrist',
id=9,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='left_hip',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
12:
dict(
name='right_hip',
id=12,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
13:
dict(
name='left_knee',
id=13,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
14:
dict(
name='right_knee',
id=14,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
15:
dict(
name='left_ankle',
id=15,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
16:
dict(
name='right_ankle',
id=16,
color=[255, 128, 0],
type='lower',
swap='left_ankle')
},
skeleton_info={
0:
dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]),
1:
dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]),
2:
dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]),
3:
dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]),
4:
dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]),
5:
dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]),
6:
dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]),
7:
dict(
link=('left_shoulder', 'right_shoulder'),
id=7,
color=[51, 153, 255]),
8:
dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]),
9:
dict(
link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]),
10:
dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('left_eye', 'right_eye'), id=12, color=[51, 153, 255]),
13:
dict(link=('nose', 'left_eye'), id=13, color=[51, 153, 255]),
14:
dict(link=('nose', 'right_eye'), id=14, color=[51, 153, 255]),
15:
dict(link=('left_eye', 'left_ear'), id=15, color=[51, 153, 255]),
16:
dict(link=('right_eye', 'right_ear'), id=16, color=[51, 153, 255]),
17:
dict(link=('left_ear', 'left_shoulder'), id=17, color=[51, 153, 255]),
18:
dict(
link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255])
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5,
1.5
],
sigmas=[
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
])
@@ -0,0 +1,156 @@
dataset_info = dict(
dataset_name='mhp',
paper_info=dict(
author='Zhao, Jian and Li, Jianshu and Cheng, Yu and '
'Sim, Terence and Yan, Shuicheng and Feng, Jiashi',
title='Understanding humans in crowded scenes: '
'Deep nested adversarial learning and a '
'new benchmark for multi-human parsing',
container='Proceedings of the 26th ACM '
'international conference on Multimedia',
year='2018',
homepage='https://lv-mhp.github.io/dataset',
),
keypoint_info={
0:
dict(
name='right_ankle',
id=0,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
1:
dict(
name='right_knee',
id=1,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
2:
dict(
name='right_hip',
id=2,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
3:
dict(
name='left_hip',
id=3,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
4:
dict(
name='left_knee',
id=4,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
5:
dict(
name='left_ankle',
id=5,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
6:
dict(name='pelvis', id=6, color=[51, 153, 255], type='lower', swap=''),
7:
dict(name='thorax', id=7, color=[51, 153, 255], type='upper', swap=''),
8:
dict(
name='upper_neck',
id=8,
color=[51, 153, 255],
type='upper',
swap=''),
9:
dict(
name='head_top', id=9, color=[51, 153, 255], type='upper',
swap=''),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='right_elbow',
id=11,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
12:
dict(
name='right_shoulder',
id=12,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
13:
dict(
name='left_shoulder',
id=13,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
14:
dict(
name='left_elbow',
id=14,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
15:
dict(
name='left_wrist',
id=15,
color=[0, 255, 0],
type='upper',
swap='right_wrist')
},
skeleton_info={
0:
dict(link=('right_ankle', 'right_knee'), id=0, color=[255, 128, 0]),
1:
dict(link=('right_knee', 'right_hip'), id=1, color=[255, 128, 0]),
2:
dict(link=('right_hip', 'pelvis'), id=2, color=[255, 128, 0]),
3:
dict(link=('pelvis', 'left_hip'), id=3, color=[0, 255, 0]),
4:
dict(link=('left_hip', 'left_knee'), id=4, color=[0, 255, 0]),
5:
dict(link=('left_knee', 'left_ankle'), id=5, color=[0, 255, 0]),
6:
dict(link=('pelvis', 'thorax'), id=6, color=[51, 153, 255]),
7:
dict(link=('thorax', 'upper_neck'), id=7, color=[51, 153, 255]),
8:
dict(link=('upper_neck', 'head_top'), id=8, color=[51, 153, 255]),
9:
dict(link=('upper_neck', 'right_shoulder'), id=9, color=[255, 128, 0]),
10:
dict(
link=('right_shoulder', 'right_elbow'), id=10, color=[255, 128,
0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('upper_neck', 'left_shoulder'), id=12, color=[0, 255, 0]),
13:
dict(link=('left_shoulder', 'left_elbow'), id=13, color=[0, 255, 0]),
14:
dict(link=('left_elbow', 'left_wrist'), id=14, color=[0, 255, 0])
},
joint_weights=[
1.5, 1.2, 1., 1., 1.2, 1.5, 1., 1., 1., 1., 1.5, 1.2, 1., 1., 1.2, 1.5
],
# Adapted from COCO dataset.
sigmas=[
0.089, 0.083, 0.107, 0.107, 0.083, 0.089, 0.026, 0.026, 0.026, 0.026,
0.062, 0.072, 0.179, 0.179, 0.072, 0.062
])
@@ -0,0 +1,132 @@
dataset_info = dict(
dataset_name='mpi_inf_3dhp',
paper_info=dict(
author='ehta, Dushyant and Rhodin, Helge and Casas, Dan and '
'Fua, Pascal and Sotnychenko, Oleksandr and Xu, Weipeng and '
'Theobalt, Christian',
title='Monocular 3D Human Pose Estimation In The Wild Using Improved '
'CNN Supervision',
container='2017 international conference on 3D vision (3DV)',
year='2017',
homepage='http://gvv.mpi-inf.mpg.de/3dhp-dataset',
),
keypoint_info={
0:
dict(
name='head_top', id=0, color=[51, 153, 255], type='upper',
swap=''),
1:
dict(name='neck', id=1, color=[51, 153, 255], type='upper', swap=''),
2:
dict(
name='right_shoulder',
id=2,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
3:
dict(
name='right_elbow',
id=3,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
4:
dict(
name='right_wrist',
id=4,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
5:
dict(
name='left_shoulder',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
6:
dict(
name='left_elbow',
id=6,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
7:
dict(
name='left_wrist',
id=7,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
8:
dict(
name='right_hip',
id=8,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
9:
dict(
name='right_knee',
id=9,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
10:
dict(
name='right_ankle',
id=10,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
11:
dict(
name='left_hip',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
12:
dict(
name='left_knee',
id=12,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
13:
dict(
name='left_ankle',
id=13,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
14:
dict(name='root', id=14, color=[51, 153, 255], type='lower', swap=''),
15:
dict(name='spine', id=15, color=[51, 153, 255], type='upper', swap=''),
16:
dict(name='head', id=16, color=[51, 153, 255], type='upper', swap='')
},
skeleton_info={
0: dict(link=('neck', 'right_shoulder'), id=0, color=[255, 128, 0]),
1: dict(
link=('right_shoulder', 'right_elbow'), id=1, color=[255, 128, 0]),
2:
dict(link=('right_elbow', 'right_wrist'), id=2, color=[255, 128, 0]),
3: dict(link=('neck', 'left_shoulder'), id=3, color=[0, 255, 0]),
4: dict(link=('left_shoulder', 'left_elbow'), id=4, color=[0, 255, 0]),
5: dict(link=('left_elbow', 'left_wrist'), id=5, color=[0, 255, 0]),
6: dict(link=('root', 'right_hip'), id=6, color=[255, 128, 0]),
7: dict(link=('right_hip', 'right_knee'), id=7, color=[255, 128, 0]),
8: dict(link=('right_knee', 'right_ankle'), id=8, color=[255, 128, 0]),
9: dict(link=('root', 'left_hip'), id=9, color=[0, 255, 0]),
10: dict(link=('left_hip', 'left_knee'), id=10, color=[0, 255, 0]),
11: dict(link=('left_knee', 'left_ankle'), id=11, color=[0, 255, 0]),
12: dict(link=('head_top', 'head'), id=12, color=[51, 153, 255]),
13: dict(link=('head', 'neck'), id=13, color=[51, 153, 255]),
14: dict(link=('neck', 'spine'), id=14, color=[51, 153, 255]),
15: dict(link=('spine', 'root'), id=15, color=[51, 153, 255])
},
joint_weights=[1.] * 17,
sigmas=[])
@@ -0,0 +1,155 @@
dataset_info = dict(
dataset_name='mpii',
paper_info=dict(
author='Mykhaylo Andriluka and Leonid Pishchulin and '
'Peter Gehler and Schiele, Bernt',
title='2D Human Pose Estimation: New Benchmark and '
'State of the Art Analysis',
container='IEEE Conference on Computer Vision and '
'Pattern Recognition (CVPR)',
year='2014',
homepage='http://human-pose.mpi-inf.mpg.de/',
),
keypoint_info={
0:
dict(
name='right_ankle',
id=0,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
1:
dict(
name='right_knee',
id=1,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
2:
dict(
name='right_hip',
id=2,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
3:
dict(
name='left_hip',
id=3,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
4:
dict(
name='left_knee',
id=4,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
5:
dict(
name='left_ankle',
id=5,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
6:
dict(name='pelvis', id=6, color=[51, 153, 255], type='lower', swap=''),
7:
dict(name='thorax', id=7, color=[51, 153, 255], type='upper', swap=''),
8:
dict(
name='upper_neck',
id=8,
color=[51, 153, 255],
type='upper',
swap=''),
9:
dict(
name='head_top', id=9, color=[51, 153, 255], type='upper',
swap=''),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='right_elbow',
id=11,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
12:
dict(
name='right_shoulder',
id=12,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
13:
dict(
name='left_shoulder',
id=13,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
14:
dict(
name='left_elbow',
id=14,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
15:
dict(
name='left_wrist',
id=15,
color=[0, 255, 0],
type='upper',
swap='right_wrist')
},
skeleton_info={
0:
dict(link=('right_ankle', 'right_knee'), id=0, color=[255, 128, 0]),
1:
dict(link=('right_knee', 'right_hip'), id=1, color=[255, 128, 0]),
2:
dict(link=('right_hip', 'pelvis'), id=2, color=[255, 128, 0]),
3:
dict(link=('pelvis', 'left_hip'), id=3, color=[0, 255, 0]),
4:
dict(link=('left_hip', 'left_knee'), id=4, color=[0, 255, 0]),
5:
dict(link=('left_knee', 'left_ankle'), id=5, color=[0, 255, 0]),
6:
dict(link=('pelvis', 'thorax'), id=6, color=[51, 153, 255]),
7:
dict(link=('thorax', 'upper_neck'), id=7, color=[51, 153, 255]),
8:
dict(link=('upper_neck', 'head_top'), id=8, color=[51, 153, 255]),
9:
dict(link=('upper_neck', 'right_shoulder'), id=9, color=[255, 128, 0]),
10:
dict(
link=('right_shoulder', 'right_elbow'), id=10, color=[255, 128,
0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('upper_neck', 'left_shoulder'), id=12, color=[0, 255, 0]),
13:
dict(link=('left_shoulder', 'left_elbow'), id=13, color=[0, 255, 0]),
14:
dict(link=('left_elbow', 'left_wrist'), id=14, color=[0, 255, 0])
},
joint_weights=[
1.5, 1.2, 1., 1., 1.2, 1.5, 1., 1., 1., 1., 1.5, 1.2, 1., 1., 1.2, 1.5
],
# Adapted from COCO dataset.
sigmas=[
0.089, 0.083, 0.107, 0.107, 0.083, 0.089, 0.026, 0.026, 0.026, 0.026,
0.062, 0.072, 0.179, 0.179, 0.072, 0.062
])
@@ -0,0 +1,155 @@
mpii_info = dict(
dataset_name='mpii',
paper_info=dict(
author='Mykhaylo Andriluka and Leonid Pishchulin and '
'Peter Gehler and Schiele, Bernt',
title='2D Human Pose Estimation: New Benchmark and '
'State of the Art Analysis',
container='IEEE Conference on Computer Vision and '
'Pattern Recognition (CVPR)',
year='2014',
homepage='http://human-pose.mpi-inf.mpg.de/',
),
keypoint_info={
0:
dict(
name='right_ankle',
id=0,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
1:
dict(
name='right_knee',
id=1,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
2:
dict(
name='right_hip',
id=2,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
3:
dict(
name='left_hip',
id=3,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
4:
dict(
name='left_knee',
id=4,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
5:
dict(
name='left_ankle',
id=5,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
6:
dict(name='pelvis', id=6, color=[51, 153, 255], type='lower', swap=''),
7:
dict(name='thorax', id=7, color=[51, 153, 255], type='upper', swap=''),
8:
dict(
name='upper_neck',
id=8,
color=[51, 153, 255],
type='upper',
swap=''),
9:
dict(
name='head_top', id=9, color=[51, 153, 255], type='upper',
swap=''),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='right_elbow',
id=11,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
12:
dict(
name='right_shoulder',
id=12,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
13:
dict(
name='left_shoulder',
id=13,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
14:
dict(
name='left_elbow',
id=14,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
15:
dict(
name='left_wrist',
id=15,
color=[0, 255, 0],
type='upper',
swap='right_wrist')
},
skeleton_info={
0:
dict(link=('right_ankle', 'right_knee'), id=0, color=[255, 128, 0]),
1:
dict(link=('right_knee', 'right_hip'), id=1, color=[255, 128, 0]),
2:
dict(link=('right_hip', 'pelvis'), id=2, color=[255, 128, 0]),
3:
dict(link=('pelvis', 'left_hip'), id=3, color=[0, 255, 0]),
4:
dict(link=('left_hip', 'left_knee'), id=4, color=[0, 255, 0]),
5:
dict(link=('left_knee', 'left_ankle'), id=5, color=[0, 255, 0]),
6:
dict(link=('pelvis', 'thorax'), id=6, color=[51, 153, 255]),
7:
dict(link=('thorax', 'upper_neck'), id=7, color=[51, 153, 255]),
8:
dict(link=('upper_neck', 'head_top'), id=8, color=[51, 153, 255]),
9:
dict(link=('upper_neck', 'right_shoulder'), id=9, color=[255, 128, 0]),
10:
dict(
link=('right_shoulder', 'right_elbow'), id=10, color=[255, 128,
0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('upper_neck', 'left_shoulder'), id=12, color=[0, 255, 0]),
13:
dict(link=('left_shoulder', 'left_elbow'), id=13, color=[0, 255, 0]),
14:
dict(link=('left_elbow', 'left_wrist'), id=14, color=[0, 255, 0])
},
joint_weights=[
1.5, 1.2, 1., 1., 1.2, 1.5, 1., 1., 1., 1., 1.5, 1.2, 1., 1., 1.2, 1.5
],
# Adapted from COCO dataset.
sigmas=[
0.089, 0.083, 0.107, 0.107, 0.083, 0.089, 0.026, 0.026, 0.026, 0.026,
0.062, 0.072, 0.179, 0.179, 0.072, 0.062
])
@@ -0,0 +1,380 @@
dataset_info = dict(
dataset_name='mpii_trb',
paper_info=dict(
author='Duan, Haodong and Lin, Kwan-Yee and Jin, Sheng and '
'Liu, Wentao and Qian, Chen and Ouyang, Wanli',
title='TRB: A Novel Triplet Representation for '
'Understanding 2D Human Body',
container='Proceedings of the IEEE International '
'Conference on Computer Vision',
year='2019',
homepage='https://github.com/kennymckormick/'
'Triplet-Representation-of-human-Body',
),
keypoint_info={
0:
dict(
name='left_shoulder',
id=0,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
1:
dict(
name='right_shoulder',
id=1,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
2:
dict(
name='left_elbow',
id=2,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
3:
dict(
name='right_elbow',
id=3,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
4:
dict(
name='left_wrist',
id=4,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
5:
dict(
name='right_wrist',
id=5,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
6:
dict(
name='left_hip',
id=6,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
7:
dict(
name='right_hip',
id=7,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
8:
dict(
name='left_knee',
id=8,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
9:
dict(
name='right_knee',
id=9,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
10:
dict(
name='left_ankle',
id=10,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
11:
dict(
name='right_ankle',
id=11,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
12:
dict(name='head', id=12, color=[51, 153, 255], type='upper', swap=''),
13:
dict(name='neck', id=13, color=[51, 153, 255], type='upper', swap=''),
14:
dict(
name='right_neck',
id=14,
color=[255, 255, 255],
type='upper',
swap='left_neck'),
15:
dict(
name='left_neck',
id=15,
color=[255, 255, 255],
type='upper',
swap='right_neck'),
16:
dict(
name='medial_right_shoulder',
id=16,
color=[255, 255, 255],
type='upper',
swap='medial_left_shoulder'),
17:
dict(
name='lateral_right_shoulder',
id=17,
color=[255, 255, 255],
type='upper',
swap='lateral_left_shoulder'),
18:
dict(
name='medial_right_bow',
id=18,
color=[255, 255, 255],
type='upper',
swap='medial_left_bow'),
19:
dict(
name='lateral_right_bow',
id=19,
color=[255, 255, 255],
type='upper',
swap='lateral_left_bow'),
20:
dict(
name='medial_right_wrist',
id=20,
color=[255, 255, 255],
type='upper',
swap='medial_left_wrist'),
21:
dict(
name='lateral_right_wrist',
id=21,
color=[255, 255, 255],
type='upper',
swap='lateral_left_wrist'),
22:
dict(
name='medial_left_shoulder',
id=22,
color=[255, 255, 255],
type='upper',
swap='medial_right_shoulder'),
23:
dict(
name='lateral_left_shoulder',
id=23,
color=[255, 255, 255],
type='upper',
swap='lateral_right_shoulder'),
24:
dict(
name='medial_left_bow',
id=24,
color=[255, 255, 255],
type='upper',
swap='medial_right_bow'),
25:
dict(
name='lateral_left_bow',
id=25,
color=[255, 255, 255],
type='upper',
swap='lateral_right_bow'),
26:
dict(
name='medial_left_wrist',
id=26,
color=[255, 255, 255],
type='upper',
swap='medial_right_wrist'),
27:
dict(
name='lateral_left_wrist',
id=27,
color=[255, 255, 255],
type='upper',
swap='lateral_right_wrist'),
28:
dict(
name='medial_right_hip',
id=28,
color=[255, 255, 255],
type='lower',
swap='medial_left_hip'),
29:
dict(
name='lateral_right_hip',
id=29,
color=[255, 255, 255],
type='lower',
swap='lateral_left_hip'),
30:
dict(
name='medial_right_knee',
id=30,
color=[255, 255, 255],
type='lower',
swap='medial_left_knee'),
31:
dict(
name='lateral_right_knee',
id=31,
color=[255, 255, 255],
type='lower',
swap='lateral_left_knee'),
32:
dict(
name='medial_right_ankle',
id=32,
color=[255, 255, 255],
type='lower',
swap='medial_left_ankle'),
33:
dict(
name='lateral_right_ankle',
id=33,
color=[255, 255, 255],
type='lower',
swap='lateral_left_ankle'),
34:
dict(
name='medial_left_hip',
id=34,
color=[255, 255, 255],
type='lower',
swap='medial_right_hip'),
35:
dict(
name='lateral_left_hip',
id=35,
color=[255, 255, 255],
type='lower',
swap='lateral_right_hip'),
36:
dict(
name='medial_left_knee',
id=36,
color=[255, 255, 255],
type='lower',
swap='medial_right_knee'),
37:
dict(
name='lateral_left_knee',
id=37,
color=[255, 255, 255],
type='lower',
swap='lateral_right_knee'),
38:
dict(
name='medial_left_ankle',
id=38,
color=[255, 255, 255],
type='lower',
swap='medial_right_ankle'),
39:
dict(
name='lateral_left_ankle',
id=39,
color=[255, 255, 255],
type='lower',
swap='lateral_right_ankle'),
},
skeleton_info={
0:
dict(link=('head', 'neck'), id=0, color=[51, 153, 255]),
1:
dict(link=('neck', 'left_shoulder'), id=1, color=[51, 153, 255]),
2:
dict(link=('neck', 'right_shoulder'), id=2, color=[51, 153, 255]),
3:
dict(link=('left_shoulder', 'left_elbow'), id=3, color=[0, 255, 0]),
4:
dict(
link=('right_shoulder', 'right_elbow'), id=4, color=[255, 128, 0]),
5:
dict(link=('left_elbow', 'left_wrist'), id=5, color=[0, 255, 0]),
6:
dict(link=('right_elbow', 'right_wrist'), id=6, color=[255, 128, 0]),
7:
dict(link=('left_shoulder', 'left_hip'), id=7, color=[51, 153, 255]),
8:
dict(link=('right_shoulder', 'right_hip'), id=8, color=[51, 153, 255]),
9:
dict(link=('left_hip', 'right_hip'), id=9, color=[51, 153, 255]),
10:
dict(link=('left_hip', 'left_knee'), id=10, color=[0, 255, 0]),
11:
dict(link=('right_hip', 'right_knee'), id=11, color=[255, 128, 0]),
12:
dict(link=('left_knee', 'left_ankle'), id=12, color=[0, 255, 0]),
13:
dict(link=('right_knee', 'right_ankle'), id=13, color=[255, 128, 0]),
14:
dict(link=('right_neck', 'left_neck'), id=14, color=[255, 255, 255]),
15:
dict(
link=('medial_right_shoulder', 'lateral_right_shoulder'),
id=15,
color=[255, 255, 255]),
16:
dict(
link=('medial_right_bow', 'lateral_right_bow'),
id=16,
color=[255, 255, 255]),
17:
dict(
link=('medial_right_wrist', 'lateral_right_wrist'),
id=17,
color=[255, 255, 255]),
18:
dict(
link=('medial_left_shoulder', 'lateral_left_shoulder'),
id=18,
color=[255, 255, 255]),
19:
dict(
link=('medial_left_bow', 'lateral_left_bow'),
id=19,
color=[255, 255, 255]),
20:
dict(
link=('medial_left_wrist', 'lateral_left_wrist'),
id=20,
color=[255, 255, 255]),
21:
dict(
link=('medial_right_hip', 'lateral_right_hip'),
id=21,
color=[255, 255, 255]),
22:
dict(
link=('medial_right_knee', 'lateral_right_knee'),
id=22,
color=[255, 255, 255]),
23:
dict(
link=('medial_right_ankle', 'lateral_right_ankle'),
id=23,
color=[255, 255, 255]),
24:
dict(
link=('medial_left_hip', 'lateral_left_hip'),
id=24,
color=[255, 255, 255]),
25:
dict(
link=('medial_left_knee', 'lateral_left_knee'),
id=25,
color=[255, 255, 255]),
26:
dict(
link=('medial_left_ankle', 'lateral_left_ankle'),
id=26,
color=[255, 255, 255])
},
joint_weights=[1.] * 40,
sigmas=[])
@@ -0,0 +1,181 @@
dataset_info = dict(
dataset_name='ochuman',
paper_info=dict(
author='Zhang, Song-Hai and Li, Ruilong and Dong, Xin and '
'Rosin, Paul and Cai, Zixi and Han, Xi and '
'Yang, Dingcheng and Huang, Haozhi and Hu, Shi-Min',
title='Pose2seg: Detection free human instance segmentation',
container='Proceedings of the IEEE conference on computer '
'vision and pattern recognition',
year='2019',
homepage='https://github.com/liruilong940607/OCHumanApi',
),
keypoint_info={
0:
dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''),
1:
dict(
name='left_eye',
id=1,
color=[51, 153, 255],
type='upper',
swap='right_eye'),
2:
dict(
name='right_eye',
id=2,
color=[51, 153, 255],
type='upper',
swap='left_eye'),
3:
dict(
name='left_ear',
id=3,
color=[51, 153, 255],
type='upper',
swap='right_ear'),
4:
dict(
name='right_ear',
id=4,
color=[51, 153, 255],
type='upper',
swap='left_ear'),
5:
dict(
name='left_shoulder',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
6:
dict(
name='right_shoulder',
id=6,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
7:
dict(
name='left_elbow',
id=7,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
8:
dict(
name='right_elbow',
id=8,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
9:
dict(
name='left_wrist',
id=9,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='left_hip',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
12:
dict(
name='right_hip',
id=12,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
13:
dict(
name='left_knee',
id=13,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
14:
dict(
name='right_knee',
id=14,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
15:
dict(
name='left_ankle',
id=15,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
16:
dict(
name='right_ankle',
id=16,
color=[255, 128, 0],
type='lower',
swap='left_ankle')
},
skeleton_info={
0:
dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]),
1:
dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]),
2:
dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]),
3:
dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]),
4:
dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]),
5:
dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]),
6:
dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]),
7:
dict(
link=('left_shoulder', 'right_shoulder'),
id=7,
color=[51, 153, 255]),
8:
dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]),
9:
dict(
link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]),
10:
dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('left_eye', 'right_eye'), id=12, color=[51, 153, 255]),
13:
dict(link=('nose', 'left_eye'), id=13, color=[51, 153, 255]),
14:
dict(link=('nose', 'right_eye'), id=14, color=[51, 153, 255]),
15:
dict(link=('left_eye', 'left_ear'), id=15, color=[51, 153, 255]),
16:
dict(link=('right_eye', 'right_ear'), id=16, color=[51, 153, 255]),
17:
dict(link=('left_ear', 'left_shoulder'), id=17, color=[51, 153, 255]),
18:
dict(
link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255])
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5,
1.5
],
sigmas=[
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
])
@@ -0,0 +1,142 @@
dataset_info = dict(
dataset_name='onehand10k',
paper_info=dict(
author='Wang, Yangang and Peng, Cong and Liu, Yebin',
title='Mask-pose cascaded cnn for 2d hand pose estimation '
'from single color image',
container='IEEE Transactions on Circuits and Systems '
'for Video Technology',
year='2018',
homepage='https://www.yangangwang.com/papers/WANG-MCC-2018-10.html',
),
keypoint_info={
0:
dict(name='wrist', id=0, color=[255, 255, 255], type='', swap=''),
1:
dict(name='thumb1', id=1, color=[255, 128, 0], type='', swap=''),
2:
dict(name='thumb2', id=2, color=[255, 128, 0], type='', swap=''),
3:
dict(name='thumb3', id=3, color=[255, 128, 0], type='', swap=''),
4:
dict(name='thumb4', id=4, color=[255, 128, 0], type='', swap=''),
5:
dict(
name='forefinger1', id=5, color=[255, 153, 255], type='', swap=''),
6:
dict(
name='forefinger2', id=6, color=[255, 153, 255], type='', swap=''),
7:
dict(
name='forefinger3', id=7, color=[255, 153, 255], type='', swap=''),
8:
dict(
name='forefinger4', id=8, color=[255, 153, 255], type='', swap=''),
9:
dict(
name='middle_finger1',
id=9,
color=[102, 178, 255],
type='',
swap=''),
10:
dict(
name='middle_finger2',
id=10,
color=[102, 178, 255],
type='',
swap=''),
11:
dict(
name='middle_finger3',
id=11,
color=[102, 178, 255],
type='',
swap=''),
12:
dict(
name='middle_finger4',
id=12,
color=[102, 178, 255],
type='',
swap=''),
13:
dict(
name='ring_finger1', id=13, color=[255, 51, 51], type='', swap=''),
14:
dict(
name='ring_finger2', id=14, color=[255, 51, 51], type='', swap=''),
15:
dict(
name='ring_finger3', id=15, color=[255, 51, 51], type='', swap=''),
16:
dict(
name='ring_finger4', id=16, color=[255, 51, 51], type='', swap=''),
17:
dict(name='pinky_finger1', id=17, color=[0, 255, 0], type='', swap=''),
18:
dict(name='pinky_finger2', id=18, color=[0, 255, 0], type='', swap=''),
19:
dict(name='pinky_finger3', id=19, color=[0, 255, 0], type='', swap=''),
20:
dict(name='pinky_finger4', id=20, color=[0, 255, 0], type='', swap='')
},
skeleton_info={
0:
dict(link=('wrist', 'thumb1'), id=0, color=[255, 128, 0]),
1:
dict(link=('thumb1', 'thumb2'), id=1, color=[255, 128, 0]),
2:
dict(link=('thumb2', 'thumb3'), id=2, color=[255, 128, 0]),
3:
dict(link=('thumb3', 'thumb4'), id=3, color=[255, 128, 0]),
4:
dict(link=('wrist', 'forefinger1'), id=4, color=[255, 153, 255]),
5:
dict(link=('forefinger1', 'forefinger2'), id=5, color=[255, 153, 255]),
6:
dict(link=('forefinger2', 'forefinger3'), id=6, color=[255, 153, 255]),
7:
dict(link=('forefinger3', 'forefinger4'), id=7, color=[255, 153, 255]),
8:
dict(link=('wrist', 'middle_finger1'), id=8, color=[102, 178, 255]),
9:
dict(
link=('middle_finger1', 'middle_finger2'),
id=9,
color=[102, 178, 255]),
10:
dict(
link=('middle_finger2', 'middle_finger3'),
id=10,
color=[102, 178, 255]),
11:
dict(
link=('middle_finger3', 'middle_finger4'),
id=11,
color=[102, 178, 255]),
12:
dict(link=('wrist', 'ring_finger1'), id=12, color=[255, 51, 51]),
13:
dict(
link=('ring_finger1', 'ring_finger2'), id=13, color=[255, 51, 51]),
14:
dict(
link=('ring_finger2', 'ring_finger3'), id=14, color=[255, 51, 51]),
15:
dict(
link=('ring_finger3', 'ring_finger4'), id=15, color=[255, 51, 51]),
16:
dict(link=('wrist', 'pinky_finger1'), id=16, color=[0, 255, 0]),
17:
dict(
link=('pinky_finger1', 'pinky_finger2'), id=17, color=[0, 255, 0]),
18:
dict(
link=('pinky_finger2', 'pinky_finger3'), id=18, color=[0, 255, 0]),
19:
dict(
link=('pinky_finger3', 'pinky_finger4'), id=19, color=[0, 255, 0])
},
joint_weights=[1.] * 21,
sigmas=[])
@@ -0,0 +1,160 @@
dataset_info = dict(
dataset_name='panoptic_pose_3d',
paper_info=dict(
author='Joo, Hanbyul and Simon, Tomas and Li, Xulong'
'and Liu, Hao and Tan, Lei and Gui, Lin and Banerjee, Sean'
'and Godisart, Timothy and Nabbe, Bart and Matthews, Iain'
'and Kanade, Takeo and Nobuhara, Shohei and Sheikh, Yaser',
title='Panoptic Studio: A Massively Multiview System '
'for Interaction Motion Capture',
container='IEEE Transactions on Pattern Analysis'
' and Machine Intelligence',
year='2017',
homepage='http://domedb.perception.cs.cmu.edu',
),
keypoint_info={
0:
dict(name='neck', id=0, color=[51, 153, 255], type='upper', swap=''),
1:
dict(name='nose', id=1, color=[51, 153, 255], type='upper', swap=''),
2:
dict(name='mid_hip', id=2, color=[0, 255, 0], type='lower', swap=''),
3:
dict(
name='left_shoulder',
id=3,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
4:
dict(
name='left_elbow',
id=4,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
5:
dict(
name='left_wrist',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
6:
dict(
name='left_hip',
id=6,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
7:
dict(
name='left_knee',
id=7,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
8:
dict(
name='left_ankle',
id=8,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
9:
dict(
name='right_shoulder',
id=9,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
10:
dict(
name='right_elbow',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
11:
dict(
name='right_wrist',
id=11,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
12:
dict(
name='right_hip',
id=12,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
13:
dict(
name='right_knee',
id=13,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
14:
dict(
name='right_ankle',
id=14,
color=[255, 128, 0],
type='lower',
swap='left_ankle'),
15:
dict(
name='left_eye',
id=15,
color=[51, 153, 255],
type='upper',
swap='right_eye'),
16:
dict(
name='left_ear',
id=16,
color=[51, 153, 255],
type='upper',
swap='right_ear'),
17:
dict(
name='right_eye',
id=17,
color=[51, 153, 255],
type='upper',
swap='left_eye'),
18:
dict(
name='right_ear',
id=18,
color=[51, 153, 255],
type='upper',
swap='left_ear')
},
skeleton_info={
0: dict(link=('nose', 'neck'), id=0, color=[51, 153, 255]),
1: dict(link=('neck', 'left_shoulder'), id=1, color=[0, 255, 0]),
2: dict(link=('neck', 'right_shoulder'), id=2, color=[255, 128, 0]),
3: dict(link=('left_shoulder', 'left_elbow'), id=3, color=[0, 255, 0]),
4: dict(
link=('right_shoulder', 'right_elbow'), id=4, color=[255, 128, 0]),
5: dict(link=('left_elbow', 'left_wrist'), id=5, color=[0, 255, 0]),
6:
dict(link=('right_elbow', 'right_wrist'), id=6, color=[255, 128, 0]),
7: dict(link=('left_ankle', 'left_knee'), id=7, color=[0, 255, 0]),
8: dict(link=('left_knee', 'left_hip'), id=8, color=[0, 255, 0]),
9: dict(link=('right_ankle', 'right_knee'), id=9, color=[255, 128, 0]),
10: dict(link=('right_knee', 'right_hip'), id=10, color=[255, 128, 0]),
11: dict(link=('mid_hip', 'left_hip'), id=11, color=[0, 255, 0]),
12: dict(link=('mid_hip', 'right_hip'), id=12, color=[255, 128, 0]),
13: dict(link=('mid_hip', 'neck'), id=13, color=[51, 153, 255]),
},
joint_weights=[
1.0, 1.0, 1.0, 1.0, 1.2, 1.5, 1.0, 1.2, 1.5, 1.0, 1.2, 1.5, 1.0, 1.2,
1.5, 1.0, 1.0, 1.0, 1.0
],
sigmas=[
0.026, 0.026, 0.107, 0.079, 0.072, 0.062, 0.107, 0.087, 0.089, 0.079,
0.072, 0.062, 0.107, 0.087, 0.089, 0.025, 0.035, 0.025, 0.035
])
@@ -0,0 +1,143 @@
dataset_info = dict(
dataset_name='panoptic_hand2d',
paper_info=dict(
author='Simon, Tomas and Joo, Hanbyul and '
'Matthews, Iain and Sheikh, Yaser',
title='Hand keypoint detection in single images using '
'multiview bootstrapping',
container='Proceedings of the IEEE conference on '
'Computer Vision and Pattern Recognition',
year='2017',
homepage='http://domedb.perception.cs.cmu.edu/handdb.html',
),
keypoint_info={
0:
dict(name='wrist', id=0, color=[255, 255, 255], type='', swap=''),
1:
dict(name='thumb1', id=1, color=[255, 128, 0], type='', swap=''),
2:
dict(name='thumb2', id=2, color=[255, 128, 0], type='', swap=''),
3:
dict(name='thumb3', id=3, color=[255, 128, 0], type='', swap=''),
4:
dict(name='thumb4', id=4, color=[255, 128, 0], type='', swap=''),
5:
dict(
name='forefinger1', id=5, color=[255, 153, 255], type='', swap=''),
6:
dict(
name='forefinger2', id=6, color=[255, 153, 255], type='', swap=''),
7:
dict(
name='forefinger3', id=7, color=[255, 153, 255], type='', swap=''),
8:
dict(
name='forefinger4', id=8, color=[255, 153, 255], type='', swap=''),
9:
dict(
name='middle_finger1',
id=9,
color=[102, 178, 255],
type='',
swap=''),
10:
dict(
name='middle_finger2',
id=10,
color=[102, 178, 255],
type='',
swap=''),
11:
dict(
name='middle_finger3',
id=11,
color=[102, 178, 255],
type='',
swap=''),
12:
dict(
name='middle_finger4',
id=12,
color=[102, 178, 255],
type='',
swap=''),
13:
dict(
name='ring_finger1', id=13, color=[255, 51, 51], type='', swap=''),
14:
dict(
name='ring_finger2', id=14, color=[255, 51, 51], type='', swap=''),
15:
dict(
name='ring_finger3', id=15, color=[255, 51, 51], type='', swap=''),
16:
dict(
name='ring_finger4', id=16, color=[255, 51, 51], type='', swap=''),
17:
dict(name='pinky_finger1', id=17, color=[0, 255, 0], type='', swap=''),
18:
dict(name='pinky_finger2', id=18, color=[0, 255, 0], type='', swap=''),
19:
dict(name='pinky_finger3', id=19, color=[0, 255, 0], type='', swap=''),
20:
dict(name='pinky_finger4', id=20, color=[0, 255, 0], type='', swap='')
},
skeleton_info={
0:
dict(link=('wrist', 'thumb1'), id=0, color=[255, 128, 0]),
1:
dict(link=('thumb1', 'thumb2'), id=1, color=[255, 128, 0]),
2:
dict(link=('thumb2', 'thumb3'), id=2, color=[255, 128, 0]),
3:
dict(link=('thumb3', 'thumb4'), id=3, color=[255, 128, 0]),
4:
dict(link=('wrist', 'forefinger1'), id=4, color=[255, 153, 255]),
5:
dict(link=('forefinger1', 'forefinger2'), id=5, color=[255, 153, 255]),
6:
dict(link=('forefinger2', 'forefinger3'), id=6, color=[255, 153, 255]),
7:
dict(link=('forefinger3', 'forefinger4'), id=7, color=[255, 153, 255]),
8:
dict(link=('wrist', 'middle_finger1'), id=8, color=[102, 178, 255]),
9:
dict(
link=('middle_finger1', 'middle_finger2'),
id=9,
color=[102, 178, 255]),
10:
dict(
link=('middle_finger2', 'middle_finger3'),
id=10,
color=[102, 178, 255]),
11:
dict(
link=('middle_finger3', 'middle_finger4'),
id=11,
color=[102, 178, 255]),
12:
dict(link=('wrist', 'ring_finger1'), id=12, color=[255, 51, 51]),
13:
dict(
link=('ring_finger1', 'ring_finger2'), id=13, color=[255, 51, 51]),
14:
dict(
link=('ring_finger2', 'ring_finger3'), id=14, color=[255, 51, 51]),
15:
dict(
link=('ring_finger3', 'ring_finger4'), id=15, color=[255, 51, 51]),
16:
dict(link=('wrist', 'pinky_finger1'), id=16, color=[0, 255, 0]),
17:
dict(
link=('pinky_finger1', 'pinky_finger2'), id=17, color=[0, 255, 0]),
18:
dict(
link=('pinky_finger2', 'pinky_finger3'), id=18, color=[0, 255, 0]),
19:
dict(
link=('pinky_finger3', 'pinky_finger4'), id=19, color=[0, 255, 0])
},
joint_weights=[1.] * 21,
sigmas=[])

Some files were not shown because too many files have changed in this diff Show More