Spaces:
Build error
Build error
# Copyright (c) OpenMMLab. All rights reserved. | |
import numpy as np | |
import torch | |
from mmpose.core.post_processing import (get_warp_matrix, transform_preds, | |
warp_affine_joints) | |
def split_ae_outputs(outputs, num_joints, with_heatmaps, with_ae, | |
select_output_index): | |
"""Split multi-stage outputs into heatmaps & tags. | |
Args: | |
outputs (list(Tensor)): Outputs of network | |
num_joints (int): Number of joints | |
with_heatmaps (list[bool]): Option to output | |
heatmaps for different stages. | |
with_ae (list[bool]): Option to output | |
ae tags for different stages. | |
select_output_index (list[int]): Output keep the selected index | |
Returns: | |
tuple: A tuple containing multi-stage outputs. | |
- list[Tensor]: multi-stage heatmaps. | |
- list[Tensor]: multi-stage tags. | |
""" | |
heatmaps = [] | |
tags = [] | |
# aggregate heatmaps from different stages | |
for i, output in enumerate(outputs): | |
if i not in select_output_index: | |
continue | |
# staring index of the associative embeddings | |
offset_feat = num_joints if with_heatmaps[i] else 0 | |
if with_heatmaps[i]: | |
heatmaps.append(output[:, :num_joints]) | |
if with_ae[i]: | |
tags.append(output[:, offset_feat:]) | |
return heatmaps, tags | |
def flip_feature_maps(feature_maps, flip_index=None): | |
"""Flip the feature maps and swap the channels. | |
Args: | |
feature_maps (list[Tensor]): Feature maps. | |
flip_index (list[int] | None): Channel-flip indexes. | |
If None, do not flip channels. | |
Returns: | |
list[Tensor]: Flipped feature_maps. | |
""" | |
flipped_feature_maps = [] | |
for feature_map in feature_maps: | |
feature_map = torch.flip(feature_map, [3]) | |
if flip_index is not None: | |
flipped_feature_maps.append(feature_map[:, flip_index, :, :]) | |
else: | |
flipped_feature_maps.append(feature_map) | |
return flipped_feature_maps | |
def _resize_average(feature_maps, align_corners, index=-1, resize_size=None): | |
"""Resize the feature maps and compute the average. | |
Args: | |
feature_maps (list[Tensor]): Feature maps. | |
align_corners (bool): Align corners when performing interpolation. | |
index (int): Only used when `resize_size' is None. | |
If `resize_size' is None, the target size is the size | |
of the indexed feature maps. | |
resize_size (list[int, int]): The target size [w, h]. | |
Returns: | |
list[Tensor]: Averaged feature_maps. | |
""" | |
if feature_maps is None: | |
return None | |
feature_maps_avg = 0 | |
feature_map_list = _resize_concate( | |
feature_maps, align_corners, index=index, resize_size=resize_size) | |
for feature_map in feature_map_list: | |
feature_maps_avg += feature_map | |
feature_maps_avg /= len(feature_map_list) | |
return [feature_maps_avg] | |
def _resize_unsqueeze_concat(feature_maps, | |
align_corners, | |
index=-1, | |
resize_size=None): | |
"""Resize, unsqueeze and concatenate the feature_maps. | |
Args: | |
feature_maps (list[Tensor]): Feature maps. | |
align_corners (bool): Align corners when performing interpolation. | |
index (int): Only used when `resize_size' is None. | |
If `resize_size' is None, the target size is the size | |
of the indexed feature maps. | |
resize_size (list[int, int]): The target size [w, h]. | |
Returns: | |
list[Tensor]: Averaged feature_maps. | |
""" | |
if feature_maps is None: | |
return None | |
feature_map_list = _resize_concate( | |
feature_maps, align_corners, index=index, resize_size=resize_size) | |
feat_dim = len(feature_map_list[0].shape) - 1 | |
output_feature_maps = torch.cat( | |
[torch.unsqueeze(fmap, dim=feat_dim + 1) for fmap in feature_map_list], | |
dim=feat_dim + 1) | |
return [output_feature_maps] | |
def _resize_concate(feature_maps, align_corners, index=-1, resize_size=None): | |
"""Resize and concatenate the feature_maps. | |
Args: | |
feature_maps (list[Tensor]): Feature maps. | |
align_corners (bool): Align corners when performing interpolation. | |
index (int): Only used when `resize_size' is None. | |
If `resize_size' is None, the target size is the size | |
of the indexed feature maps. | |
resize_size (list[int, int]): The target size [w, h]. | |
Returns: | |
list[Tensor]: Averaged feature_maps. | |
""" | |
if feature_maps is None: | |
return None | |
feature_map_list = [] | |
if index < 0: | |
index += len(feature_maps) | |
if resize_size is None: | |
resize_size = (feature_maps[index].size(2), | |
feature_maps[index].size(3)) | |
for feature_map in feature_maps: | |
ori_size = (feature_map.size(2), feature_map.size(3)) | |
if ori_size != resize_size: | |
feature_map = torch.nn.functional.interpolate( | |
feature_map, | |
size=resize_size, | |
mode='bilinear', | |
align_corners=align_corners) | |
feature_map_list.append(feature_map) | |
return feature_map_list | |
def aggregate_stage_flip(feature_maps, | |
feature_maps_flip, | |
index=-1, | |
project2image=True, | |
size_projected=None, | |
align_corners=False, | |
aggregate_stage='concat', | |
aggregate_flip='average'): | |
"""Inference the model to get multi-stage outputs (heatmaps & tags), and | |
resize them to base sizes. | |
Args: | |
feature_maps (list[Tensor]): feature_maps can be heatmaps, | |
tags, and pafs. | |
feature_maps_flip (list[Tensor] | None): flipped feature_maps. | |
feature maps can be heatmaps, tags, and pafs. | |
project2image (bool): Option to resize to base scale. | |
size_projected (list[int, int]): Base size of heatmaps [w, h]. | |
align_corners (bool): Align corners when performing interpolation. | |
aggregate_stage (str): Methods to aggregate multi-stage feature maps. | |
Options: 'concat', 'average'. Default: 'concat. | |
- 'concat': Concatenate the original and the flipped feature maps. | |
- 'average': Get the average of the original and the flipped | |
feature maps. | |
aggregate_flip (str): Methods to aggregate the original and | |
the flipped feature maps. Options: 'concat', 'average', 'none'. | |
Default: 'average. | |
- 'concat': Concatenate the original and the flipped feature maps. | |
- 'average': Get the average of the original and the flipped | |
feature maps.. | |
- 'none': no flipped feature maps. | |
Returns: | |
list[Tensor]: Aggregated feature maps with shape [NxKxWxH]. | |
""" | |
if feature_maps_flip is None: | |
aggregate_flip = 'none' | |
output_feature_maps = [] | |
if aggregate_stage == 'average': | |
_aggregate_stage_func = _resize_average | |
elif aggregate_stage == 'concat': | |
_aggregate_stage_func = _resize_concate | |
else: | |
NotImplementedError() | |
if project2image and size_projected: | |
_origin = _aggregate_stage_func( | |
feature_maps, | |
align_corners, | |
index=index, | |
resize_size=(size_projected[1], size_projected[0])) | |
_flipped = _aggregate_stage_func( | |
feature_maps_flip, | |
align_corners, | |
index=index, | |
resize_size=(size_projected[1], size_projected[0])) | |
else: | |
_origin = _aggregate_stage_func( | |
feature_maps, align_corners, index=index, resize_size=None) | |
_flipped = _aggregate_stage_func( | |
feature_maps_flip, align_corners, index=index, resize_size=None) | |
if aggregate_flip == 'average': | |
assert feature_maps_flip is not None | |
for _ori, _fli in zip(_origin, _flipped): | |
output_feature_maps.append((_ori + _fli) / 2.0) | |
elif aggregate_flip == 'concat': | |
assert feature_maps_flip is not None | |
output_feature_maps.append(*_origin) | |
output_feature_maps.append(*_flipped) | |
elif aggregate_flip == 'none': | |
if isinstance(_origin, list): | |
output_feature_maps.append(*_origin) | |
else: | |
output_feature_maps.append(_origin) | |
else: | |
NotImplementedError() | |
return output_feature_maps | |
def aggregate_scale(feature_maps_list, | |
align_corners=False, | |
aggregate_scale='average'): | |
"""Aggregate multi-scale outputs. | |
Note: | |
batch size: N | |
keypoints num : K | |
heatmap width: W | |
heatmap height: H | |
Args: | |
feature_maps_list (list[Tensor]): Aggregated feature maps. | |
project2image (bool): Option to resize to base scale. | |
align_corners (bool): Align corners when performing interpolation. | |
aggregate_scale (str): Methods to aggregate multi-scale feature maps. | |
Options: 'average', 'unsqueeze_concat'. | |
- 'average': Get the average of the feature maps. | |
- 'unsqueeze_concat': Concatenate the feature maps along new axis. | |
Default: 'average. | |
Returns: | |
Tensor: Aggregated feature maps. | |
""" | |
if aggregate_scale == 'average': | |
output_feature_maps = _resize_average( | |
feature_maps_list, align_corners, index=0, resize_size=None) | |
elif aggregate_scale == 'unsqueeze_concat': | |
output_feature_maps = _resize_unsqueeze_concat( | |
feature_maps_list, align_corners, index=0, resize_size=None) | |
else: | |
NotImplementedError() | |
return output_feature_maps[0] | |
def get_group_preds(grouped_joints, | |
center, | |
scale, | |
heatmap_size, | |
use_udp=False): | |
"""Transform the grouped joints back to the image. | |
Args: | |
grouped_joints (list): Grouped person joints. | |
center (np.ndarray[2, ]): Center of the bounding box (x, y). | |
scale (np.ndarray[2, ]): Scale of the bounding box | |
wrt [width, height]. | |
heatmap_size (np.ndarray[2, ]): Size of the destination heatmaps. | |
use_udp (bool): Unbiased data processing. | |
Paper ref: Huang et al. The Devil is in the Details: Delving into | |
Unbiased Data Processing for Human Pose Estimation (CVPR'2020). | |
Returns: | |
list: List of the pose result for each person. | |
""" | |
if len(grouped_joints) == 0: | |
return [] | |
if use_udp: | |
if grouped_joints[0].shape[0] > 0: | |
heatmap_size_t = np.array(heatmap_size, dtype=np.float32) - 1.0 | |
trans = get_warp_matrix( | |
theta=0, | |
size_input=heatmap_size_t, | |
size_dst=scale, | |
size_target=heatmap_size_t) | |
grouped_joints[0][..., :2] = \ | |
warp_affine_joints(grouped_joints[0][..., :2], trans) | |
results = [person for person in grouped_joints[0]] | |
else: | |
results = [] | |
for person in grouped_joints[0]: | |
joints = transform_preds(person, center, scale, heatmap_size) | |
results.append(joints) | |
return results | |