function evaluate_poses_comparison

opt = globals();
% your results
resdir = '/var/Projects/PoseRNN/output/lov/lov_keyframe/vgg16_fcn_color_single_frame_2d_lov_iter_80000/mat';

% read class names
fid = fopen('classes.txt', 'r');
C = textscan(fid, '%s');
object_names = C{1};
fclose(fid);

% load model points
num_objects = numel(object_names);
models = cell(num_objects, 1);
for i = 1:num_objects
    filename = fullfile(opt.root, 'models', object_names{i}, 'points.xyz');
    disp(filename);
    models{i} = load(filename);
end

% load the keyframe indexes
fid = fopen('keyframe.txt', 'r');
C = textscan(fid, '%s');
keyframes = C{1};
fclose(fid);

% save results
distances_sys = zeros(100000, 2);
distances_non = zeros(100000, 2);
errors_rotation = zeros(100000, 2); 
errors_translation = zeros(100000, 2);
results_seq_id = zeros(100000, 1);
results_frame_id = zeros(100000, 1);
results_object_id = zeros(100000, 1);
results_cls_id = zeros(100000, 1);

% for each image
count = 0;
for i = 1:numel(keyframes)
    
    % parse keyframe name
    name = keyframes{i};
    pos = strfind(name, '/');
    seq_id = str2double(name(1:pos-1));
    frame_id = str2double(name(pos+1:end));
            
    % load PoseCNN result
    filename = sprintf('results_PoseCNN/%04d.mat', i - 1);
    result = load(filename);

    % load 3D coordinate regression result
    filename = sprintf('%s/%04d.mat', resdir, i - 1);
    result_new = load(filename);

    % load gt poses
    filename = fullfile(opt.root, 'data', sprintf('%04d/%06d-meta.mat', seq_id, frame_id));
    disp(filename);
    gt = load(filename);

    % for each gt poses
    for j = 1:numel(gt.cls_indexes)
        count = count + 1;
        cls_index = gt.cls_indexes(j);
        RT_gt = gt.poses(:, :, j);

        results_seq_id(count) = seq_id;
        results_frame_id(count) = frame_id;
        results_object_id(count) = j;
        results_cls_id(count) = cls_index;

        % network result
        roi_index = find(result.rois(:, 2) == cls_index);
        if isempty(roi_index) == 0
            RT = zeros(3, 4);

            % pose from network
            RT(1:3, 1:3) = quat2rotm(result.poses(roi_index, 1:4));
            RT(:, 4) = result.poses(roi_index, 5:7);
            distances_sys(count, 1) = adi(RT, RT_gt, models{cls_index}');
            distances_non(count, 1) = add(RT, RT_gt, models{cls_index}');
            errors_rotation(count, 1) = re(RT(1:3, 1:3), RT_gt(1:3, 1:3));
            errors_translation(count, 1) = te(RT(:, 4), RT_gt(:, 4));                    
        else
            distances_sys(count, 1) = inf;
            distances_non(count, 1) = inf;
            errors_rotation(count, 1) = inf;
            errors_translation(count, 1) = inf;
        end

        % your result
        roi_index = find(result_new.rois(:, 2) == cls_index);
        if isempty(roi_index) == 0
            RT = zeros(3, 4);
            RT(1:3, 1:3) = quat2rotm(result_new.poses(roi_index, 1:4));
            RT(:, 4) = result_new.poses(roi_index, 5:7);
            distances_sys(count, 2) = adi(RT, RT_gt, models{cls_index}');
            distances_non(count, 2) = add(RT, RT_gt, models{cls_index}');
            errors_rotation(count, 2) = re(RT(1:3, 1:3), RT_gt(1:3, 1:3));
            errors_translation(count, 2) = te(RT(:, 4), RT_gt(:, 4));                    
        else
            distances_sys(count, 2) = inf;
            distances_non(count, 2) = inf;
            errors_rotation(count, 2) = inf;
            errors_translation(count, 2) = inf;
        end
    end
end
distances_sys = distances_sys(1:count, :);
distances_non = distances_non(1:count, :);
errors_rotation = errors_rotation(1:count, :);
errors_translation = errors_translation(1:count, :);
results_seq_id = results_seq_id(1:count);
results_frame_id = results_frame_id(1:count);
results_object_id = results_object_id(1:count, :);
results_cls_id = results_cls_id(1:count, :);
save('results_comparison.mat', 'distances_sys', 'distances_non', 'errors_rotation', 'errors_translation',...
    'results_seq_id', 'results_frame_id', 'results_object_id', 'results_cls_id');

function pts_new = transform_pts_Rt(pts, RT)
%     """
%     Applies a rigid transformation to 3D points.
% 
%     :param pts: nx3 ndarray with 3D points.
%     :param R: 3x3 rotation matrix.
%     :param t: 3x1 translation vector.
%     :return: nx3 ndarray with transformed 3D points.
%     """
n = size(pts, 2);
pts_new = RT * [pts; ones(1, n)];

function error = add(RT_est, RT_gt, pts)
%     """
%     Average Distance of Model Points for objects with no indistinguishable views
%     - by Hinterstoisser et al. (ACCV 2012).
% 
%     :param R_est, t_est: Estimated pose (3x3 rot. matrix and 3x1 trans. vector).
%     :param R_gt, t_gt: GT pose (3x3 rot. matrix and 3x1 trans. vector).
%     :param model: Object model given by a dictionary where item 'pts'
%     is nx3 ndarray with 3D model points.
%     :return: Error of pose_est w.r.t. pose_gt.
%     """
pts_est = transform_pts_Rt(pts, RT_est);
pts_gt = transform_pts_Rt(pts, RT_gt);
diff = pts_est - pts_gt;
error = mean(sqrt(sum(diff.^2, 1)));

function error = adi(RT_est, RT_gt, pts)
%     """
%     Average Distance of Model Points for objects with indistinguishable views
%     - by Hinterstoisser et al. (ACCV 2012).
% 
%     :param R_est, t_est: Estimated pose (3x3 rot. matrix and 3x1 trans. vector).
%     :param R_gt, t_gt: GT pose (3x3 rot. matrix and 3x1 trans. vector).
%     :param model: Object model given by a dictionary where item 'pts'
%     is nx3 ndarray with 3D model points.
%     :return: Error of pose_est w.r.t. pose_gt.
%     """
pts_est = transform_pts_Rt(pts, RT_est);
pts_gt = transform_pts_Rt(pts, RT_gt);

% Calculate distances to the nearest neighbors from pts_gt to pts_est
MdlKDT = KDTreeSearcher(pts_est');
[~, D] = knnsearch(MdlKDT, pts_gt');
error = mean(D);

function error = re(R_est, R_gt)
%     """
%     Rotational Error.
% 
%     :param R_est: Rotational element of the estimated pose (3x1 vector).
%     :param R_gt: Rotational element of the ground truth pose (3x1 vector).
%     :return: Error of t_est w.r.t. t_gt.
%     """

error_cos = 0.5 * (trace(R_est * inv(R_gt)) - 1.0);
error_cos = min(1.0, max(-1.0, error_cos));
error = acos(error_cos);
error = 180.0 * error / pi;

function error = te(t_est, t_gt)
% """
% Translational Error.
% 
% :param t_est: Translation element of the estimated pose (3x1 vector).
% :param t_gt: Translation element of the ground truth pose (3x1 vector).
% :return: Error of t_est w.r.t. t_gt.
% """
error = norm(t_gt - t_est);