import numpy as np
from shapely import geometry
import sys
import os
import json
import glob
from tabulate import tabulate
from termcolor import colored
import logging

sys.path.insert(0, '/media/jion/D/chenhaoming/Code/tracking_network/rectifier/rectifier_lib/poseval/py')
from .convert import convert_videos

MIN_SCORE = -9999
MAX_TRACK_ID = 10000


class Joint:
    def __init__(self):
        self.count = 15
        self.right_ankle = 0
        self.right_knee = 1
        self.right_hip = 2
        self.left_hip = 3
        self.left_knee = 4
        self.left_ankle = 5
        self.right_wrist = 6
        self.right_elbow = 7
        self.right_shoulder = 8
        self.left_shoulder = 9
        self.left_elbow = 10
        self.left_wrist = 11
        self.neck = 12
        self.nose = 13
        self.head_top = 14

        self.name = {}
        self.name[self.right_ankle] = "right_ankle"
        self.name[self.right_knee] = "right_knee"
        self.name[self.right_hip] = "right_hip"
        self.name[self.right_shoulder] = "right_shoulder"
        self.name[self.right_elbow] = "right_elbow"
        self.name[self.right_wrist] = "right_wrist"
        self.name[self.left_ankle] = "left_ankle"
        self.name[self.left_knee] = "left_knee"
        self.name[self.left_hip] = "left_hip"
        self.name[self.left_shoulder] = "left_shoulder"
        self.name[self.left_elbow] = "left_elbow"
        self.name[self.left_wrist] = "left_wrist"
        self.name[self.neck] = "neck"
        self.name[self.nose] = "nose"
        self.name[self.head_top] = "head_top"

        self.symmetric_joint = {}
        self.symmetric_joint[self.right_ankle] = self.left_ankle
        self.symmetric_joint[self.right_knee] = self.left_knee
        self.symmetric_joint[self.right_hip] = self.left_hip
        self.symmetric_joint[self.right_shoulder] = self.left_shoulder
        self.symmetric_joint[self.right_elbow] = self.left_elbow
        self.symmetric_joint[self.right_wrist] = self.left_wrist
        self.symmetric_joint[self.left_ankle] = self.right_ankle
        self.symmetric_joint[self.left_knee] = self.right_knee
        self.symmetric_joint[self.left_hip] = self.right_hip
        self.symmetric_joint[self.left_shoulder] = self.right_shoulder
        self.symmetric_joint[self.left_elbow] = self.right_elbow
        self.symmetric_joint[self.left_wrist] = self.right_wrist
        self.symmetric_joint[self.neck] = -1
        self.symmetric_joint[self.nose] = -1
        self.symmetric_joint[self.head_top] = -1


def getPointGTbyID(points, pidx):
    point = []
    for i in range(len(points)):
        if (points[i]["id"] != None and points[i]["id"][0] == pidx):  # if joint id matches
            point = points[i]
            break

    return point


def getHeadSize(x1, y1, x2, y2):
    headSize = 0.6 * np.linalg.norm(np.subtract([x2, y2], [x1, y1]));
    return headSize


def formatCell(val, delim):
    return "{:>5}".format("%1.1f" % val) + delim


def getHeader():
    strHeader = "&"
    strHeader += " Head &"
    strHeader += " Shou &"
    strHeader += " Elb  &"
    strHeader += " Wri  &"
    strHeader += " Hip  &"
    strHeader += " Knee &"
    strHeader += " Ankl &"
    strHeader += " Total%s" % ("\\" + "\\")
    return strHeader


def getMotHeader():
    strHeader = "&"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTA &"
    strHeader += " MOTP &"
    strHeader += " Prec &"
    strHeader += " Rec  %s\n" % ("\\" + "\\")
    strHeader += "&"
    strHeader += " Head &"
    strHeader += " Shou &"
    strHeader += " Elb  &"
    strHeader += " Wri  &"
    strHeader += " Hip  &"
    strHeader += " Knee &"
    strHeader += " Ankl &"
    strHeader += " Total&"
    strHeader += " Total&"
    strHeader += " Total&"
    strHeader += " Total%s" % ("\\" + "\\")

    return strHeader


def getCum(vals):
    cum = [];
    n = -1
    cum += [(vals[[Joint().head_top, Joint().neck, Joint().nose], 0].mean())]
    # cum += [(vals[[Joint().neck],0].mean())]

    cum += [(vals[[Joint().right_shoulder, Joint().left_shoulder], 0].mean())]
    cum += [(vals[[Joint().right_elbow, Joint().left_elbow], 0].mean())]
    cum += [(vals[[Joint().right_wrist, Joint().left_wrist], 0].mean())]
    cum += [(vals[[Joint().right_hip, Joint().left_hip], 0].mean())]
    cum += [(vals[[Joint().right_knee, Joint().left_knee], 0].mean())]
    cum += [(vals[[Joint().right_ankle, Joint().left_ankle], 0].mean())]
    for i in range(Joint().count, len(vals)):
        cum += [vals[i, 0]]
    return cum


def getFormatRow(cum):
    """
        cum  - val list
    """
    row = "&"
    for i in range(len(cum) - 1):
        row += formatCell(cum[i], " &")
    row += formatCell(cum[len(cum) - 1], (" %s" % "\\" + "\\"))
    return row


def printTable(vals, motHeader=False):
    cum = getCum(vals)
    row = getFormatRow(cum)
    if (motHeader):
        header = getMotHeader()
    else:
        header = getHeader()
        # header = ["Head", "Shou", "Elb", "Wri", "Hip", "Knee", "Ankl", "# Total"]

    # result = []
    # for item in cum:
    # result.append(item)
    # table = tabulate([result], tablefmt="pipe", headers=header, numalign="left",)
    # logger = logging.getLogger(__name__)
    # print()
    # logger.info(f"=> Result Table: \n" + colored(table, "magenta"))
    print(header)
    print(row)
    # return header+"\n", row+"\n"
    return cum


def printTableTracking(valsPerPart):
    cum = getCum(vals)
    row = getFormatRow(cum)
    print(getHeader())
    print(row)
    return getHeader() + "\n", row + "\n"


# compute recall/precision curve (RPC) values
def computeRPC(scores, labels, totalPos):
    precision = np.zeros(len(scores))
    recall = np.zeros(len(scores))
    npos = 0

    idxsSort = np.array(scores).argsort()[::-1]
    labelsSort = labels[idxsSort]

    for sidx in range(len(idxsSort)):
        if (labelsSort[sidx] == 1):
            npos += 1
        # recall: how many true positives were found out of the total number of positives?
        recall[sidx] = 1.0 * npos / totalPos
        # precision: how many true positives were found out of the total number of samples?
        precision[sidx] = 1.0 * npos / (sidx + 1)

    return precision, recall, idxsSort


# compute Average Precision using recall/precision values
def VOCap(rec, prec):
    mpre = np.zeros([1, 2 + len(prec)])
    mpre[0, 1:len(prec) + 1] = prec
    mrec = np.zeros([1, 2 + len(rec)])
    mrec[0, 1:len(rec) + 1] = rec
    mrec[0, len(rec) + 1] = 1.0

    for i in range(mpre.size - 2, -1, -1):
        mpre[0, i] = max(mpre[0, i], mpre[0, i + 1])

    i = np.argwhere(~np.equal(mrec[0, 1:], mrec[0, :mrec.shape[1] - 1])) + 1
    i = i.flatten()

    # compute area under the curve
    ap = np.sum(np.multiply(np.subtract(mrec[0, i], mrec[0, i - 1]), mpre[0, i]))

    return ap


def get_data_dir():
    dataDir = "./"
    return dataDir


def help(msg=''):
    sys.stderr.write(msg + '\n')
    exit()


def process_arguments(argv):
    mode = 'multi'

    if len(argv) > 3:
        mode = str.lower(argv[3])
    elif len(argv) < 3 or len(argv) > 4:
        help()

    gt_file = argv[1]
    pred_file = argv[2]

    if not os.path.exists(gt_file):
        help('Given ground truth directory does not exist!\n')

    if not os.path.exists(pred_file):
        help('Given prediction directory does not exist!\n')

    return gt_file, pred_file, mode


def process_arguments_server(argv):
    mode = 'multi'

    print(len(argv))
    assert len(argv) == 10, "Wrong number of arguments"

    gt_dir = argv[1]
    pred_dir = argv[2]
    mode = str.lower(argv[3])
    evaltrack = argv[4]
    shortname = argv[5]
    chl = argv[6]
    shortname_uid = argv[7]
    shakey = argv[8]
    timestamp = argv[9]
    if not os.path.exists(gt_dir):
        help('Given ground truth does not exist!\n')

    if not os.path.exists(pred_dir):
        help('Given prediction does not exist!\n')

    return gt_dir, pred_dir, mode, evaltrack, shortname, chl, shortname_uid, shakey, timestamp


def load_data(argv):
    dataDir = get_data_dir()

    gt_file, pred_file, mode = process_arguments(argv)
    gtFilename = dataDir + gt_file
    predFilename = dataDir + pred_file

    # load ground truth (GT)
    with open(gtFilename) as data_file:
        data = json.load(data_file)
    gtFramesAll = data

    # load predictions
    with open(predFilename) as data_file:
        data = json.load(data_file)
    prFramesAll = data

    return gtFramesAll, prFramesAll


def cleanupData(gtFramesAll, prFramesAll):
    # remove all GT frames with empty annorects and remove corresponding entries from predictions
    imgidxs = []
    for imgidx in range(len(gtFramesAll)):
        if (len(gtFramesAll[imgidx]["annorect"]) > 0):
            imgidxs += [imgidx]
    gtFramesAll = [gtFramesAll[imgidx] for imgidx in imgidxs]
    prFramesAll = [prFramesAll[imgidx] for imgidx in imgidxs]

    # remove all gt rectangles that do not have annotations
    for imgidx in range(len(gtFramesAll)):
        gtFramesAll[imgidx]["annorect"] = removeRectsWithoutPoints(gtFramesAll[imgidx]["annorect"])
        prFramesAll[imgidx]["annorect"] = removeRectsWithoutPoints(prFramesAll[imgidx]["annorect"])

    return gtFramesAll, prFramesAll


def removeIgnoredPointsRects(rects, polyList):
    ridxs = list(range(len(rects)))
    for ridx in range(len(rects)):
        points = rects[ridx]["annopoints"][0]["point"]
        pidxs = list(range(len(points)))
        for pidx in range(len(points)):
            pt = geometry.Point(points[pidx]["x"][0], points[pidx]["y"][0])
            bIgnore = False
            for poidx in range(len(polyList)):
                poly = polyList[poidx]
                if (poly.contains(pt)):
                    bIgnore = True
                    break
            if (bIgnore):
                pidxs.remove(pidx)
        points = [points[pidx] for pidx in pidxs]
        if (len(points) > 0):
            rects[ridx]["annopoints"][0]["point"] = points
        else:
            ridxs.remove(ridx)
    rects = [rects[ridx] for ridx in ridxs]
    return rects


def removeIgnoredPoints(gtFramesAll, prFramesAll):
    imgidxs = []
    for imgidx in range(len(gtFramesAll)):
        if ("ignore_regions" in gtFramesAll[imgidx].keys() and
                len(gtFramesAll[imgidx]["ignore_regions"]) > 0):
            regions = gtFramesAll[imgidx]["ignore_regions"]
            polyList = []
            for ridx in range(len(regions)):
                points = regions[ridx]["point"]
                pointList = []
                for pidx in range(len(points)):
                    pt = geometry.Point(points[pidx]["x"][0], points[pidx]["y"][0])
                    pointList += [pt]
                poly = geometry.Polygon([[p.x, p.y] for p in pointList])
                polyList += [poly]

            rects = prFramesAll[imgidx]["annorect"]
            prFramesAll[imgidx]["annorect"] = removeIgnoredPointsRects(rects, polyList)
            rects = gtFramesAll[imgidx]["annorect"]
            gtFramesAll[imgidx]["annorect"] = removeIgnoredPointsRects(rects, polyList)

    return gtFramesAll, prFramesAll


def rectHasPoints(rect):
    return (("annopoints" in rect.keys()) and
            (len(rect["annopoints"]) > 0 and len(rect["annopoints"][0]) > 0) and
            ("point" in rect["annopoints"][0].keys()))


def removeRectsWithoutPoints(rects):
    idxsPr = []
    for ridxPr in range(len(rects)):
        if (rectHasPoints(rects[ridxPr])):
            idxsPr += [ridxPr]
    rects = [rects[ridx] for ridx in idxsPr]
    return rects


def load_data_dir(argv):
    gt_dir, pred_dir, mode = process_arguments(argv)
    if not os.path.exists(gt_dir):
        help('Given GT directory ' + gt_dir + ' does not exist!\n')
    if not os.path.exists(pred_dir):
        help('Given prediction directory ' + pred_dir + ' does not exist!\n')
    filenames = glob.glob(gt_dir + "/*.json")
    gtFramesAll = []
    prFramesAll = []

    for i in range(len(filenames)):
        # load each annotation json file
        # print('GT:')
        with open(filenames[i]) as data_file:
            data = json.load(data_file)
        if (not "annolist" in data):
            data = convert_videos(data)[0]
        gt = data["annolist"]
        for imgidx in range(len(gt)):
            gt[imgidx]["seq_id"] = i
            gt[imgidx]["seq_name"] = os.path.basename(filenames[i]).split('.')[0]
            for ridxGT in range(len(gt[imgidx]["annorect"])):
                if ("track_id" in gt[imgidx]["annorect"][ridxGT].keys()):
                    # adjust track_ids to make them unique across all sequences
                    #                print(os.path.basename(filenames[i]).split('.')[0])
                    #                print(gt[imgidx]["annorect"][ridxGT]["track_id"][0])
                    assert (gt[imgidx]["annorect"][ridxGT]["track_id"][0] < MAX_TRACK_ID)
                    gt[imgidx]["annorect"][ridxGT]["track_id"][0] += i * MAX_TRACK_ID
        gtFramesAll += gt
        gtBasename = os.path.basename(filenames[i])
        # predFilename = pred_dir + gtBasename
        predFilename = os.path.join(pred_dir, gtBasename)
        # print(xy)

        if (not os.path.exists(predFilename)):
            raise IOError('Prediction file ' + predFilename + ' does not exist')

        # load predictions
        #    print('PRED:')
        with open(predFilename) as data_file:
            data = json.load(data_file)
        if (not "annolist" in data):
            data = convert_videos(data)[0]
        pr = data["annolist"]
        if (len(pr) != len(gt)):
            raise Exception('# prediction frames %d != # GT frames %d for %s' % (len(pr), len(gt), predFilename))
        for imgidx in range(len(pr)):
            for ridxPr in range(len(pr[imgidx]["annorect"])):
                if ("track_id" in pr[imgidx]["annorect"][ridxPr].keys()):
                    # adjust track_ids to make them unique across all sequences
                    #                print(os.path.basename(filenames[i]).split('.')[0])
                    #                print(pr[imgidx]["annorect"][ridxPr]["track_id"][0])
                    assert (pr[imgidx]["annorect"][ridxPr]["track_id"][0] < MAX_TRACK_ID)
                    pr[imgidx]["annorect"][ridxPr]["track_id"][0] += i * MAX_TRACK_ID
        prFramesAll += pr
    #    print(xy)

    gtFramesAll, prFramesAll = cleanupData(gtFramesAll, prFramesAll)

    gtFramesAll, prFramesAll = removeIgnoredPoints(gtFramesAll, prFramesAll)
    return gtFramesAll, prFramesAll


def writeJson(val, fname):
    with open(fname, 'w') as data_file:
        json.dump(val, data_file)


def assignGTmulti(gtFrames, prFrames, distThresh):
    assert (len(gtFrames) == len(prFrames))

    nJoints = Joint().count
    # part detection scores
    scoresAll = {}
    # positive / negative labels
    labelsAll = {}
    # number of annotated GT joints per image
    nGTall = np.zeros([nJoints, len(gtFrames)])
    for pidx in range(nJoints):
        scoresAll[pidx] = {}
        labelsAll[pidx] = {}
        for imgidx in range(len(gtFrames)):
            scoresAll[pidx][imgidx] = np.zeros([0, 0], dtype=np.float32)
            labelsAll[pidx][imgidx] = np.zeros([0, 0], dtype=np.int8)

    # GT track IDs
    trackidxGT = []

    # prediction track IDs
    trackidxPr = []

    # number of GT poses
    nGTPeople = np.zeros((len(gtFrames), 1))
    # number of predicted poses
    nPrPeople = np.zeros((len(gtFrames), 1))

    # container to save info for computing MOT metrics
    motAll = {}

    for imgidx in range(len(gtFrames)):
        # distance between predicted and GT joints
        dist = np.full((len(prFrames[imgidx]["annorect"]), len(gtFrames[imgidx]["annorect"]), nJoints), np.inf)
        # score of the predicted joint
        score = np.full((len(prFrames[imgidx]["annorect"]), nJoints), np.nan)
        # body joint prediction exist
        hasPr = np.zeros((len(prFrames[imgidx]["annorect"]), nJoints), dtype=bool)
        # body joint is annotated
        hasGT = np.zeros((len(gtFrames[imgidx]["annorect"]), nJoints), dtype=bool)

        trackidxGT = []
        trackidxPr = []
        idxsPr = []
        for ridxPr in range(len(prFrames[imgidx]["annorect"])):
            if (("annopoints" in prFrames[imgidx]["annorect"][ridxPr].keys()) and
                    ("point" in prFrames[imgidx]["annorect"][ridxPr]["annopoints"][0].keys())):
                idxsPr += [ridxPr]
        prFrames[imgidx]["annorect"] = [prFrames[imgidx]["annorect"][ridx] for ridx in idxsPr]

        nPrPeople[imgidx, 0] = len(prFrames[imgidx]["annorect"])
        nGTPeople[imgidx, 0] = len(gtFrames[imgidx]["annorect"])
        # iterate over GT poses
        for ridxGT in range(len(gtFrames[imgidx]["annorect"])):
            # GT pose
            rectGT = gtFrames[imgidx]["annorect"][ridxGT]
            if ("track_id" in rectGT.keys()):
                trackidxGT += [rectGT["track_id"][0]]
            pointsGT = []
            if len(rectGT["annopoints"]) > 0:
                pointsGT = rectGT["annopoints"][0]["point"]
            # iterate over all possible body joints
            for i in range(nJoints):
                # GT joint in LSP format
                ppGT = getPointGTbyID(pointsGT, i)
                if len(ppGT) > 0:
                    hasGT[ridxGT, i] = True

        # iterate over predicted poses
        for ridxPr in range(len(prFrames[imgidx]["annorect"])):
            # predicted pose
            rectPr = prFrames[imgidx]["annorect"][ridxPr]
            if ("track_id" in rectPr.keys()):
                trackidxPr += [rectPr["track_id"][0]]
            pointsPr = rectPr["annopoints"][0]["point"]
            for i in range(nJoints):
                # predicted joint in LSP format
                ppPr = getPointGTbyID(pointsPr, i)
                if len(ppPr) > 0:
                    if not ("score" in ppPr.keys()):
                        # use minimum score if predicted score is missing
                        if (imgidx == 0):
                            print('WARNING: prediction score is missing. Setting fallback score={}'.format(MIN_SCORE))
                        score[ridxPr, i] = MIN_SCORE
                    else:
                        score[ridxPr, i] = ppPr["score"][0]
                    hasPr[ridxPr, i] = True

        if len(prFrames[imgidx]["annorect"]) and len(gtFrames[imgidx]["annorect"]):
            # predictions and GT are present
            # iterate over GT poses
            for ridxGT in range(len(gtFrames[imgidx]["annorect"])):
                # GT pose
                rectGT = gtFrames[imgidx]["annorect"][ridxGT]
                # compute reference distance as head size
                headSize = getHeadSize(rectGT["x1"][0], rectGT["y1"][0],
                                       rectGT["x2"][0], rectGT["y2"][0])
                pointsGT = []
                if len(rectGT["annopoints"]) > 0:
                    pointsGT = rectGT["annopoints"][0]["point"]
                # iterate over predicted poses
                for ridxPr in range(len(prFrames[imgidx]["annorect"])):
                    # predicted pose
                    rectPr = prFrames[imgidx]["annorect"][ridxPr]
                    pointsPr = rectPr["annopoints"][0]["point"]

                    # iterate over all possible body joints
                    for i in range(nJoints):
                        # GT joint
                        ppGT = getPointGTbyID(pointsGT, i)
                        # predicted joint
                        ppPr = getPointGTbyID(pointsPr, i)
                        # compute distance between predicted and GT joint locations
                        if hasPr[ridxPr, i] and hasGT[ridxGT, i]:
                            pointGT = [ppGT["x"][0], ppGT["y"][0]]
                            pointPr = [ppPr["x"][0], ppPr["y"][0]]
                            dist[ridxPr, ridxGT, i] = np.linalg.norm(np.subtract(pointGT, pointPr)) / headSize  # 每个关节独自算的

            dist = np.array(dist)
            hasGT = np.array(hasGT)

            # number of annotated joints
            nGTp = np.sum(hasGT, axis=1)
            match = dist <= distThresh
            pck = 1.0 * np.sum(match, axis=2)
            for i in range(hasPr.shape[0]):
                for j in range(hasGT.shape[0]):
                    if nGTp[j] > 0:
                        pck[i, j] = pck[i, j] / nGTp[j]

            # preserve best GT match only
            idx = np.argmax(pck, axis=1)
            val = np.max(pck, axis=1)
            for ridxPr in range(pck.shape[0]):
                for ridxGT in range(pck.shape[1]):
                    if (ridxGT != idx[ridxPr]):
                        pck[ridxPr, ridxGT] = 0
            prToGT = np.argmax(pck, axis=0)
            val = np.max(pck, axis=0)
            prToGT[val == 0] = -1

            # info to compute MOT metrics
            mot = {}
            for i in range(nJoints):
                mot[i] = {}

            for i in range(nJoints):
                ridxsGT = np.argwhere(hasGT[:, i] == True)
                ridxsGT = ridxsGT.flatten().tolist()
                ridxsPr = np.argwhere(hasPr[:, i] == True)
                ridxsPr = ridxsPr.flatten().tolist()
                mot[i]["trackidxGT"] = [trackidxGT[idx] for idx in ridxsGT]
                mot[i]["trackidxPr"] = [trackidxPr[idx] for idx in ridxsPr]
                mot[i]["ridxsGT"] = np.array(ridxsGT)
                mot[i]["ridxsPr"] = np.array(ridxsPr)
                mot[i]["dist"] = np.full((len(ridxsGT), len(ridxsPr)), np.nan)
                for iPr in range(len(ridxsPr)):
                    for iGT in range(len(ridxsGT)):
                        if (match[ridxsPr[iPr], ridxsGT[iGT], i]):
                            mot[i]["dist"][iGT, iPr] = dist[ridxsPr[iPr], ridxsGT[iGT], i]

            # assign predicted poses to GT poses
            for ridxPr in range(hasPr.shape[0]):
                if (ridxPr in prToGT):  # pose matches to GT
                    # GT pose that matches the predicted pose
                    ridxGT = np.argwhere(prToGT == ridxPr)
                    assert (ridxGT.size == 1)
                    ridxGT = ridxGT[0, 0]
                    s = score[ridxPr, :]
                    m = np.squeeze(match[ridxPr, ridxGT, :])
                    hp = hasPr[ridxPr, :]
                    for i in range(len(hp)):
                        if (hp[i]):
                            scoresAll[i][imgidx] = np.append(scoresAll[i][imgidx], s[i])
                            labelsAll[i][imgidx] = np.append(labelsAll[i][imgidx], m[i])

                else:  # no matching to GT
                    s = score[ridxPr, :]
                    m = np.zeros([match.shape[2], 1], dtype=bool)
                    hp = hasPr[ridxPr, :]
                    for i in range(len(hp)):
                        if (hp[i]):
                            scoresAll[i][imgidx] = np.append(scoresAll[i][imgidx], s[i])
                            labelsAll[i][imgidx] = np.append(labelsAll[i][imgidx], m[i])
        else:
            if not len(gtFrames[imgidx]["annorect"]):
                # No GT available. All predictions are false positives
                for ridxPr in range(hasPr.shape[0]):
                    s = score[ridxPr, :]
                    m = np.zeros([nJoints, 1], dtype=bool)
                    hp = hasPr[ridxPr, :]
                    for i in range(len(hp)):
                        if hp[i]:
                            scoresAll[i][imgidx] = np.append(scoresAll[i][imgidx], s[i])
                            labelsAll[i][imgidx] = np.append(labelsAll[i][imgidx], m[i])
            mot = {}
            for i in range(nJoints):
                mot[i] = {}
            for i in range(nJoints):
                ridxsGT = [0]
                ridxsPr = [0]
                mot[i]["trackidxGT"] = [0]
                mot[i]["trackidxPr"] = [0]
                mot[i]["ridxsGT"] = np.array(ridxsGT)
                mot[i]["ridxsPr"] = np.array(ridxsPr)
                mot[i]["dist"] = np.full((len(ridxsGT), len(ridxsPr)), np.nan)

        # save number of GT joints
        for ridxGT in range(hasGT.shape[0]):
            hg = hasGT[ridxGT, :]
            for i in range(len(hg)):
                nGTall[i, imgidx] += hg[i]

        motAll[imgidx] = mot

    return scoresAll, labelsAll, nGTall, motAll
