Spaces:
Build error
Build error
File size: 11,398 Bytes
d7a991a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# 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
|