关键点估计 - 人体关键点(姿态估计) 和服饰关键点(FashionAI/DeepFashion).
单人关键点估计,评测.

1. PCK - Percentage of Correct Keypoints

关键点正确估计的比例
计算检测的关键点与其对应的groundtruth间的归一化距离小于设定阈值的比例(the percentage of detections that fall within a normalized distance of the ground truth).

FLIC 中是以躯干直径(torso size) 作为归一化参考.
MPII 中是以头部长度(head length) 作为归一化参考,即 PCKh.

    function eval_pck(pred, joints, symmetry_joint_id, joint_name, name)
    % PCK 的实现
    % torso height: || left_shoulder - right hip ||
    % symmetry_joint_id: 具有对称关系的关键点 ID
    % joint_name: 具有对称关系的关键点名字
    
    range = 0:0.01:0.1;
    show_joint_ids = (symmetry_joint_id >= 1:numel(symmetry_joint_id));
    
    % compute distance to ground truth joints
    dist = get_dist_pck(pred, joints(1:2,:,:));
    
    % 计算 PCK
    pck_all = compute_pck(dist,range);
    pck = pck_all(end, :);
    pck(1:end-1) = (pck(1:end-1) + pck(symmetry_joint_id))/2;
    
    % 可视化结果
    pck = [pck(show_joint_ids) pck(end)];
    fprintf('------------ PCK Evaluation: %s -------------\n', name);
    fprintf('Parts '); fprintf('& %s ', joint_name{:}); fprintf('& Mean\n');
    fprintf('PCK   '); fprintf('& %.1f  ', pck); fprintf('\n');
    
    % -------------------------------------------------------------------------
    function dist = get_dist_pck(pred, gt)
    assert(size(pred,1) == size(gt,1) && size(pred,2) == size(gt,2) && size(pred,3) == size(gt,3));
    
    dist = nan(1,size(pred, 2), size(pred,3));
    
    for imgidx = 1:size(pred,3)
      % torso diameter 躯干直径
      if size(gt, 2) == 14
        refDist = norm(gt(:,10,imgidx) - gt(:,3,imgidx));
      elseif size(gt, 2) == 10 % 10 joints FLIC
        refDist = norm(gt(:,7,imgidx) - gt(:,6,imgidx));
      elseif size(gt, 2) == 11 % 11 joints FLIC
        refDist = norm(gt(:,4,imgidx) - gt(:,11,imgidx));
      else
        error('Number of joints should be 14 or 10 or 11');
      end
    
      % 预测的关键点与 gt 关键点的距离
      dist(1,:,imgidx) = sqrt(sum((pred(:,:,imgidx) - gt(:,:,imgidx)).^2,1))./refDist;
    
    end
    
    % -------------------------------------------------------------------------
    function pck = compute_pck(dist,range)
    pck = zeros(numel(range),size(dist,2)+1);
    
    for jidx = 1:size(dist,2)
      % 计算每个设定阈值的 PCK
      for k = 1:numel(range)
        pck(k,jidx) = 100*mean(squeeze(dist(1,jidx,:)) <= range(k));
      end
    end
    
    % 计算平均 PCK
    for k = 1:numel(range)
      pck(k,end) = 100*mean(reshape(squeeze(dist(1,:,:)),size(dist,2)*size(dist,3),1) <= range(k));
    end

输出结果如下:

------------ PCK Evaluation: Single_People -------------
    Parts & Ankle & Knee & Hip & Wris & Elbo & Shou & Head & Mean
    PCK   & 93.2  & 88.3  & 70.4  & 92.1  & 92.6  & 94.6  & 95.9  & 89.6

1.1 PCKh

    % 计算 head 的长度
    headSize = getHeadSizeAll(annolist_test_flat(single_person_test_flat == 1));
    
    % 计算预测的关键点与 gt 关键点间的归一化距离
    dist = getDistPCKh(pred,gt,headSize);
    
    % 计算 PCKh
    pck = computePCK(dist,range);
    
    function headSizeAll = getHeadSizeAll(annolist)
    headSizeAll = nan(length(annolist),1);
    for imgidx = 1:length(annolist)
        rect = annolist(imgidx).annorect;
        headSizeAll(imgidx) =  util_get_head_size(rect);
    end
    end
    
    function headSize = util_get_head_size(rect)
    SC_BIAS = 0.6; % 0.8*0.75
    headSize = SC_BIAS*norm([rect.x2 rect.y2] - [rect.x1 rect.y1]); # head 的两个点间的距离
    end
    
    function dist = getDistPCKh(pred,gt,refDist)
    assert(size(pred,1) == size(gt,1) && size(pred,2) == size(gt,2) && size(pred,3) == size(gt,3));
    assert(size(refDist,1) == size(gt,3));
    
    dist = nan(1,size(pred,2),size(pred,3));
    for imgidx = 1:size(pred,3)
        % pred joints 与 gt joints 的归一化距离
        dist(1,:,imgidx) = sqrt(sum((pred(:,:,imgidx) - gt(:,:,imgidx)).^2,1))./refDist(imgidx);
    end
    
    function pck = computePCK(dist,range)
    pck = zeros(numel(range),size(dist,2)+2);
    for jidx = 1:size(dist,2)
        % 计算各阈值的 PCK
        for k = 1:numel(range)
            d = squeeze(dist(1,jidx,:));
            % dist is NaN if gt is missing; ignore dist in this case
            pck(k,jidx) = 100*mean(d(~isnan(d))<=range(k));
        end
    end
    
    % 计算上半身关键点的平均 PCK
    for k = 1:numel(range)
        d = reshape(squeeze(dist(1,7:12,:)),6*size(dist,3),1);
        pck(k,end-1) = 100*mean(d(~isnan(d))<=range(k));
    end
    
    % 计算全身关键点的 PCK
    for k = 1:numel(range)
        d = reshape(squeeze(dist(1,:,:)),size(dist,2)*size(dist,3),1);
        pck(k,end) = 100*mean(d(~isnan(d))<=range(k));
    end
    end

2. PDJ - Percentage of Detected Joints

检测到的关键点比例.

function [accs, range] = eval_pdj(pred, joints, reference_joints_pair, symmetry_joint_id, joint_name, eval_name)
    % 设定选定的参考点:reference_joints_pair = [3, 10];     % 右肩点到左臀点
    % symmetry_joint_id: 具有对称关系的关键点 ID
    assert(numel(reference_joints_pair) == 2);
    show_joint_ids = find(symmetry_joint_id >= 1:numel(symmetry_joint_id)); 
    range = 0:0.01:0.5;
    
    num = size(pred, 3);
    assert(num >= 1);
    % the number of joints
    joint_n = size(joints, 2);
    
    scale = zeros(1, num);
    for ii = 1:num
      scale(ii) = norm( joints(:,reference_joints_pair(1), ii) - joints(:,reference_joints_pair(2), ii) );
      %scale(ii) = 100;
    end
    
    dists = zeros(num, joint_n);
    for ii = 1:num
      dists(ii,:) = sqrt(sum( (pred(:, :, ii) - joints(:,:,ii)).^2, 1 ));
      dists(ii,:) = dists(ii,:) / scale(ii);
    end
    
    accs = zeros(numel(range), joint_n);
    for ii = 1:numel(range)
      accs(ii,:) = mean(dists <= range(ii),1);
    end
    
    accs = (accs + accs(:,symmetry_joint_id)) / 2;
    accs = accs(:, show_joint_ids);
    % print
    fprintf('-------------- PDJ Evaluation ---------------\n')
    fprintf('Joints    '); fprintf('& %s ', joint_name{:}); fprintf('\n');
    sample_pdj_thresholds = [0.1, 0.2, 0.3, 0.4];
    for ii = 1:length(sample_pdj_thresholds)
      t = sample_pdj_thresholds(ii);
      idx = (range == t);
      fprintf('PDJ@%.2f  ', t); fprintf('& %.1f ', accs(idx,:)*100); fprintf('\n');
    end
    
    % plot
    line_width = 2;
    p_color = {'g','y','b','r','c','k','m'};
    
    % visualize
    figure; hold on; grid on;
    for ii = 1:numel(show_joint_ids)
      plot(range, accs(:, ii), p_color{mod(ii, numel(p_color))+1}, 'linewidth', line_width);
    end
    leg_str = cell(numel(show_joint_ids), 1);
    for ii = 1:numel(show_joint_ids)
      leg_str{ii} = sprintf('%s', joint_name{ii});
    end
    h_leg = legend(leg_str, 'FontSize', 12);
    set(h_leg, 'location', 'southeast', 'linewidth', 1);
    
    axis([range(1),range(end), 0, 1]);
    set(gca,'ytick', 0:0.1:1);
    set(gca, 'linewidth', 1);
    
    % --- titles
    xlabel('Normalized  Threshold') % x-axis label
    ylabel('Detection Rate') % y-axis label
    
    title([eval_name ' PDJ']);
    hold off;

输出结果为:

-------------- PDJ Evaluation ---------------
    Joints    & Ankle & Knee & Hip & Wris & Elbo & Shou & Head 
    PDJ@0.10  & 93.3 & 87.6 & 66.4 & 91.8 & 92.6 & 95.5 & 96.1 
    PDJ@0.20  & 97.5 & 94.7 & 93.4 & 96.8 & 97.9 & 98.8 & 99.1 
    PDJ@0.30  & 97.9 & 95.7 & 97.6 & 97.8 & 98.4 & 99.1 & 99.2 
    PDJ@0.40  & 98.1 & 96.1 & 98.4 & 98.1 & 98.6 & 99.2 & 99.2 
Last modification:June 13th, 2022 at 09:43 am