HumanSD / mmpose /codecs /utils /post_processing.py
liyy201912's picture
Upload folder using huggingface_hub
cc0dd3c
raw
history blame
7.05 kB
# Copyright (c) OpenMMLab. All rights reserved.
from itertools import product
from typing import Tuple
import cv2
import numpy as np
import torch
import torch.nn.functional as F
from torch import Tensor
def get_simcc_normalized(batch_pred_simcc, sigma=None):
"""Normalize the predicted SimCC.
Args:
batch_pred_simcc (torch.Tensor): The predicted SimCC.
sigma (float): The sigma of the Gaussian distribution.
Returns:
torch.Tensor: The normalized SimCC.
"""
B, K, _ = batch_pred_simcc.shape
# Scale and clamp the tensor
if sigma is not None:
batch_pred_simcc = batch_pred_simcc / (sigma * np.sqrt(np.pi * 2))
batch_pred_simcc = batch_pred_simcc.clamp(min=0)
# Compute the binary mask
mask = (batch_pred_simcc.amax(dim=-1) > 1).reshape(B, K, 1)
# Normalize the tensor using the maximum value
norm = (batch_pred_simcc / batch_pred_simcc.amax(dim=-1).reshape(B, K, 1))
# Apply normalization
batch_pred_simcc = torch.where(mask, norm, batch_pred_simcc)
return batch_pred_simcc
def get_simcc_maximum(simcc_x: np.ndarray,
simcc_y: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
"""Get maximum response location and value from simcc representations.
Note:
instance number: N
num_keypoints: K
heatmap height: H
heatmap width: W
Args:
simcc_x (np.ndarray): x-axis SimCC in shape (K, Wx) or (N, K, Wx)
simcc_y (np.ndarray): y-axis SimCC in shape (K, Wy) or (N, K, Wy)
Returns:
tuple:
- locs (np.ndarray): locations of maximum heatmap responses in shape
(K, 2) or (N, K, 2)
- vals (np.ndarray): values of maximum heatmap responses in shape
(K,) or (N, K)
"""
assert isinstance(simcc_x, np.ndarray), ('simcc_x should be numpy.ndarray')
assert isinstance(simcc_y, np.ndarray), ('simcc_y should be numpy.ndarray')
assert simcc_x.ndim == 2 or simcc_x.ndim == 3, (
f'Invalid shape {simcc_x.shape}')
assert simcc_y.ndim == 2 or simcc_y.ndim == 3, (
f'Invalid shape {simcc_y.shape}')
assert simcc_x.ndim == simcc_y.ndim, (
f'{simcc_x.shape} != {simcc_y.shape}')
if simcc_x.ndim == 3:
N, K, Wx = simcc_x.shape
simcc_x = simcc_x.reshape(N * K, -1)
simcc_y = simcc_y.reshape(N * K, -1)
else:
N = None
x_locs = np.argmax(simcc_x, axis=1)
y_locs = np.argmax(simcc_y, axis=1)
locs = np.stack((x_locs, y_locs), axis=-1).astype(np.float32)
max_val_x = np.amax(simcc_x, axis=1)
max_val_y = np.amax(simcc_y, axis=1)
mask = max_val_x > max_val_y
max_val_x[mask] = max_val_y[mask]
vals = max_val_x
locs[vals <= 0.] = -1
if N:
locs = locs.reshape(N, K, 2)
vals = vals.reshape(N, K)
return locs, vals
def get_heatmap_maximum(heatmaps: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
"""Get maximum response location and value from heatmaps.
Note:
batch_size: B
num_keypoints: K
heatmap height: H
heatmap width: W
Args:
heatmaps (np.ndarray): Heatmaps in shape (K, H, W) or (B, K, H, W)
Returns:
tuple:
- locs (np.ndarray): locations of maximum heatmap responses in shape
(K, 2) or (B, K, 2)
- vals (np.ndarray): values of maximum heatmap responses in shape
(K,) or (B, K)
"""
assert isinstance(heatmaps,
np.ndarray), ('heatmaps should be numpy.ndarray')
assert heatmaps.ndim == 3 or heatmaps.ndim == 4, (
f'Invalid shape {heatmaps.shape}')
if heatmaps.ndim == 3:
K, H, W = heatmaps.shape
B = None
heatmaps_flatten = heatmaps.reshape(K, -1)
else:
B, K, H, W = heatmaps.shape
heatmaps_flatten = heatmaps.reshape(B * K, -1)
y_locs, x_locs = np.unravel_index(
np.argmax(heatmaps_flatten, axis=1), shape=(H, W))
locs = np.stack((x_locs, y_locs), axis=-1).astype(np.float32)
vals = np.amax(heatmaps_flatten, axis=1)
locs[vals <= 0.] = -1
if B:
locs = locs.reshape(B, K, 2)
vals = vals.reshape(B, K)
return locs, vals
def gaussian_blur(heatmaps: np.ndarray, kernel: int = 11) -> np.ndarray:
"""Modulate heatmap distribution with Gaussian.
Note:
- num_keypoints: K
- heatmap height: H
- heatmap width: W
Args:
heatmaps (np.ndarray[K, H, W]): model predicted heatmaps.
kernel (int): Gaussian kernel size (K) for modulation, which should
match the heatmap gaussian sigma when training.
K=17 for sigma=3 and k=11 for sigma=2.
Returns:
np.ndarray ([K, H, W]): Modulated heatmap distribution.
"""
assert kernel % 2 == 1
border = (kernel - 1) // 2
K, H, W = heatmaps.shape
for k in range(K):
origin_max = np.max(heatmaps[k])
dr = np.zeros((H + 2 * border, W + 2 * border), dtype=np.float32)
dr[border:-border, border:-border] = heatmaps[k].copy()
dr = cv2.GaussianBlur(dr, (kernel, kernel), 0)
heatmaps[k] = dr[border:-border, border:-border].copy()
heatmaps[k] *= origin_max / np.max(heatmaps[k])
return heatmaps
def gaussian_blur1d(simcc: np.ndarray, kernel: int = 11) -> np.ndarray:
"""Modulate simcc distribution with Gaussian.
Note:
- num_keypoints: K
- simcc length: Wx
Args:
simcc (np.ndarray[K, Wx]): model predicted simcc.
kernel (int): Gaussian kernel size (K) for modulation, which should
match the simcc gaussian sigma when training.
K=17 for sigma=3 and k=11 for sigma=2.
Returns:
np.ndarray ([K, Wx]): Modulated simcc distribution.
"""
assert kernel % 2 == 1
border = (kernel - 1) // 2
N, K, Wx = simcc.shape
for n, k in product(range(N), range(K)):
origin_max = np.max(simcc[n, k])
dr = np.zeros((1, Wx + 2 * border), dtype=np.float32)
dr[0, border:-border] = simcc[n, k].copy()
dr = cv2.GaussianBlur(dr, (kernel, 1), 0)
simcc[n, k] = dr[0, border:-border].copy()
simcc[n, k] *= origin_max / np.max(simcc[n, k])
return simcc
def batch_heatmap_nms(batch_heatmaps: Tensor, kernel_size: int = 5):
"""Apply NMS on a batch of heatmaps.
Args:
batch_heatmaps (Tensor): batch heatmaps in shape (B, K, H, W)
kernel_size (int): The kernel size of the NMS which should be
a odd integer. Defaults to 5
Returns:
Tensor: The batch heatmaps after NMS.
"""
assert isinstance(kernel_size, int) and kernel_size % 2 == 1, \
f'The kernel_size should be an odd integer, got {kernel_size}'
padding = (kernel_size - 1) // 2
maximum = F.max_pool2d(
batch_heatmaps, kernel_size, stride=1, padding=padding)
maximum_indicator = torch.eq(batch_heatmaps, maximum)
batch_heatmaps = batch_heatmaps * maximum_indicator.float()
return batch_heatmaps