Implementation of NMS using OKS. Args: predictions: The predicted poses, of shape (num_predictions, num_keypoints, 3). oks_threshold: The threshold for NMS. Keeps predictions for which the OKS score is below this threshold. oks_sigmas: The sigmas to use to co
(
predictions: np.ndarray,
oks_threshold: float,
oks_sigmas: float | np.ndarray = 0.1,
oks_margin: float = 1.0,
score_threshold: float | None = None,
order: np.ndarray | None = None,
)
| 16 | |
| 17 | |
| 18 | def nms_oks( |
| 19 | predictions: np.ndarray, |
| 20 | oks_threshold: float, |
| 21 | oks_sigmas: float | np.ndarray = 0.1, |
| 22 | oks_margin: float = 1.0, |
| 23 | score_threshold: float | None = None, |
| 24 | order: np.ndarray | None = None, |
| 25 | ) -> np.ndarray: |
| 26 | """Implementation of NMS using OKS. |
| 27 | |
| 28 | Args: |
| 29 | predictions: The predicted poses, of shape (num_predictions, num_keypoints, 3). |
| 30 | oks_threshold: The threshold for NMS. Keeps predictions for which the OKS score |
| 31 | is below this threshold. |
| 32 | oks_sigmas: The sigmas to use to compute OKS scores. |
| 33 | oks_margin: The margin to add around keypoints when computing area. |
| 34 | score_threshold: If not None, computes NMS using only keypoints for which the |
| 35 | score is above this threshold. |
| 36 | order: If predictions should be sorted by another means than score, the order |
| 37 | to use in NMS. |
| 38 | |
| 39 | Returns: |
| 40 | An array of length num_predictions indicating which keypoints should be kept. |
| 41 | """ |
| 42 | if len(predictions) == 0: |
| 43 | return np.zeros(0, dtype=bool) |
| 44 | elif len(predictions) == 1: |
| 45 | return np.ones(1, dtype=bool) |
| 46 | |
| 47 | predictions = predictions.copy() |
| 48 | |
| 49 | # mask keypoints with score below the threshold |
| 50 | if score_threshold is None: |
| 51 | score_threshold = 0.0 |
| 52 | predictions[predictions[:, :, 2] < score_threshold] = np.nan |
| 53 | |
| 54 | # get visibility masks for the keypoints and individuals |
| 55 | kpt_vis = np.all(~np.isnan(predictions), axis=-1) |
| 56 | idv_vis = np.sum(kpt_vis, axis=-1) > 1 # need at least 2 keypoints to compute OKS |
| 57 | |
| 58 | # if no keypoints match the visibility criteria, mask all |
| 59 | if np.sum(idv_vis) == 0: |
| 60 | return np.zeros(len(predictions), dtype=bool) |
| 61 | |
| 62 | # mask keypoints that aren't visible |
| 63 | predictions[~kpt_vis] = np.nan |
| 64 | |
| 65 | if order is None: |
| 66 | # compute scores for each individual |
| 67 | scores = np.zeros(len(predictions)) |
| 68 | scores[idv_vis] = np.nanmean(predictions[idv_vis, :, 2], axis=-1) |
| 69 | |
| 70 | # only compute OKS for non-zero score poses |
| 71 | order = scores.argsort()[::-1] |
| 72 | order = order[scores[order] > 0] |
| 73 | |
| 74 | # NMS suppression |
| 75 | keep = np.zeros(len(predictions), dtype=bool) |
nothing calls this directly
no test coverage detected