# Copyright (c) 2019-present, Baidu, Inc. # # 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. ############################################################################## """Interface for MPII evaluation.""" import os import numpy as np from collections import OrderedDict from scipy.io import loadmat, savemat from utils.base_evaluator import BaseEvaluator class MPIIEvaluator(BaseEvaluator): def __init__(self, root, kp_dim=16): """ :param root: the root dir of dataset :param kp_dim: the dimension of keypoints """ super(MPIIEvaluator, self).__init__(root, kp_dim) self.root = root self.kp_dim = kp_dim self.sc_bias = 0.6 self.threshold = 0.5 def evaluate(self, preds, output_dir, *args, **kwargs): """ :param preds: the predictions to be evaluated :param output_dir: target directory to save evaluation results :return: """ # Convert 0-based index to 1-based index preds = preds[:, :, 0:2] + 1.0 if output_dir: pred_file = os.path.join(output_dir, 'pred.mat') savemat(pred_file, mdict={'preds': preds}) gt_file = os.path.join(self.root, 'annot', 'gt_valid.mat') gt_dict = loadmat(gt_file) dataset_joints = gt_dict['dataset_joints'] jnt_missing = gt_dict['jnt_missing'] pos_gt_src = gt_dict['pos_gt_src'] headboxes_src = gt_dict['headboxes_src'] pos_pred_src = np.transpose(preds, [1, 2, 0]) head = np.where(dataset_joints == 'head')[1][0] lsho = np.where(dataset_joints == 'lsho')[1][0] lelb = np.where(dataset_joints == 'lelb')[1][0] lwri = np.where(dataset_joints == 'lwri')[1][0] lhip = np.where(dataset_joints == 'lhip')[1][0] lkne = np.where(dataset_joints == 'lkne')[1][0] lank = np.where(dataset_joints == 'lank')[1][0] rsho = np.where(dataset_joints == 'rsho')[1][0] relb = np.where(dataset_joints == 'relb')[1][0] rwri = np.where(dataset_joints == 'rwri')[1][0] rkne = np.where(dataset_joints == 'rkne')[1][0] rank = np.where(dataset_joints == 'rank')[1][0] rhip = np.where(dataset_joints == 'rhip')[1][0] jnt_visible = 1 - jnt_missing uv_error = pos_pred_src - pos_gt_src uv_err = np.linalg.norm(uv_error, axis=1) headsizes = headboxes_src[1, :, :] - headboxes_src[0, :, :] headsizes = np.linalg.norm(headsizes, axis=0) headsizes *= self.sc_bias scale = np.multiply(headsizes, np.ones((len(uv_err), 1))) scaled_uv_err = np.divide(uv_err, scale) scaled_uv_err = np.multiply(scaled_uv_err, jnt_visible) jnt_count = np.sum(jnt_visible, axis=1) less_than_threshold = np.multiply((scaled_uv_err <= self.threshold), jnt_visible) PCKh = np.divide(100. * np.sum(less_than_threshold, axis=1), jnt_count) # Save rng = np.arange(0, 0.5 + 0.01, 0.01) pckAll = np.zeros((len(rng), self.kp_dim)) for r in range(len(rng)): thresh = rng[r] less_than_threshold = np.multiply(scaled_uv_err <= thresh, jnt_visible) pckAll[r, :] = np.divide(100. * np.sum(less_than_threshold, axis=1), jnt_count) PCKh = np.ma.array(PCKh, mask=False) PCKh.mask[6:8] = True jnt_count = np.ma.array(jnt_count, mask=False) jnt_count.mask[6:8] = True jnt_ratio = jnt_count / np.sum(jnt_count).astype(np.float64) name_value = [ ('Head', PCKh[head]), ('Shoulder', 0.5 * (PCKh[lsho] + PCKh[rsho])), ('Elbow', 0.5 * (PCKh[lelb] + PCKh[relb])), ('Wrist', 0.5 * (PCKh[lwri] + PCKh[rwri])), ('Hip', 0.5 * (PCKh[lhip] + PCKh[rhip])), ('Knee', 0.5 * (PCKh[lkne] + PCKh[rkne])), ('Ankle', 0.5 * (PCKh[lank] + PCKh[rank])), ('Mean', np.sum(PCKh * jnt_ratio)), ('Mean@0.1', np.sum(pckAll[11, :] * jnt_ratio)) ] name_value = OrderedDict(name_value) return name_value, name_value['Mean']