Пример #1
0
    def get_pair(self, idxA):
        maskA = np.zeros(shape=self.out_frame, dtype=self.dtype)
        maskB = np.zeros(shape=self.out_frame, dtype=self.dtype)

        scale = self.bvh_scale
        aug_q = Quaternions.id(1)

        if self.scale_augment:
            t = random.gauss(1, self.scale_std)
            t = max(t, 0.1)
            scale *= t

        if self.rot_augment:
            rot = random.random()
            rot = (rot - 0.5) * 2 * np.pi

            aug_q = Quaternions.from_angle_axis(rot, np.array([0, 1, 0])) * aug_q

        quatA, localA, rtjA, skelA = self.get_normalized_data(idxA, scale, aug_q)
        random_slice = get_random_slice(localA, self.out_frame)
        maskA[:np.min([self.out_frame, localA.shape[0]])] = 1.0
        localA = repeat_last_frame(localA[random_slice], self.out_frame)
        rtjA = repeat_last_frame(rtjA[random_slice], self.out_frame)
        skelA = repeat_last_frame(skelA[random_slice], self.out_frame)
        quatA = repeat_last_frame(quatA[random_slice], self.out_frame)

        # get real skeleton and motion
        skelA_name, _, _ = self.train[idxA]
        idxB = np.random.randint(self.__len__())
        while skelA_name == self.train[idxB][0]:
            idxB = np.random.randint(self.__len__())

        quatB, localB, rtjB, skelB = self.get_normalized_data(idxB, scale, aug_q)
        random_slice = get_random_slice(localB, self.out_frame)
        maskB[:np.min([self.out_frame, localB.shape[0]])] = 1.0
        localB = repeat_last_frame(localB[random_slice], self.out_frame)
        rtjB = repeat_last_frame(rtjB[random_slice], self.out_frame)
        skelB = repeat_last_frame(skelB[random_slice], self.out_frame)
        quatB = repeat_last_frame(quatB[random_slice], self.out_frame)

        localA = localA.astype(self.dtype)
        rtjA = rtjA.astype(self.dtype)
        skelA = skelA.astype(self.dtype)
        quatA = quatA.astype(self.dtype)

        localB = localB.astype(self.dtype)
        rtjB = rtjB.astype(self.dtype)
        skelB = skelB.astype(self.dtype)
        quatB = quatB.astype(self.dtype)

        return (localA, rtjA, skelA, quatA, maskA,
                localB, rtjB, skelB, quatB, maskB)
Пример #2
0
def rotations_global(anim):
    """
    Global Animation Rotations
    
    This relies on joint ordering
    being incremental. That means a joint
    J1 must not be a ancestor of J0 if
    J0 appears before J1 in the joint
    ordering.
    
    Parameters
    ----------
    
    anim : Animation
        Input animation
        
    Returns
    -------
    
    points : (F, J) Quaternions
        global rotations for every frame F 
        and joint J
    """

    joints = np.arange(anim.shape[1])
    parents = np.arange(anim.shape[1])
    locals = anim.rotations
    globals = Quaternions.id(anim.shape)

    globals[:, 0] = locals[:, 0]

    for i in range(1, anim.shape[1]):
        globals[:, i] = globals[:, anim.parents[i]] * locals[:, i]

    return globals
Пример #3
0
def orients_global(anim):
    joints = np.arange(anim.shape[1])
    parents = np.arange(anim.shape[1])
    locals = anim.orients
    globals = Quaternions.id(anim.shape[1])

    globals[:, 0] = locals[:, 0]

    for i in range(1, anim.shape[1]):
        globals[:, i] = globals[:, anim.parents[i]] * locals[:, i]

    return globals
Пример #4
0
def load(filename, start=None, end=None, order=None, world=False):
    """
    Reads a BVH file and constructs an animation
    
    Parameters
    ----------
    filename: str
        File to be opened
        
    start : int
        Optional Starting Frame
        
    end : int
        Optional Ending Frame
    
    order : str
        Optional Specifier for joint order.
        Given as string E.G 'xyz', 'zxy'
        
    world : bool
        If set to true euler angles are applied
        together in world space rather than local
        space

    Returns
    -------
    
    (animation, joint_names, frametime)
        Tuple of loaded animation and joint names
    """

    f = open(filename, "r")

    i = 0
    active = -1
    end_site = False

    names = []
    orients = Quaternions.id(0)
    offsets = np.array([]).reshape((0, 3))
    parents = np.array([], dtype=int)

    for line in f:

        if "HIERARCHY" in line: continue
        if "MOTION" in line: continue
        """ Modified line read to handle mixamo data """
        #        rmatch = re.match(r"ROOT (\w+)", line)
        rmatch = re.match(r"ROOT (\w+:?\w+)", line)
        if rmatch:
            names.append(rmatch.group(1))
            offsets = np.append(offsets, np.array([[0, 0, 0]]), axis=0)
            orients.qs = np.append(orients.qs,
                                   np.array([[1, 0, 0, 0]]),
                                   axis=0)
            parents = np.append(parents, active)
            active = (len(parents) - 1)
            continue

        if "{" in line:
            continue

        if "}" in line:
            if end_site:
                end_site = False
            else:
                active = parents[active]
            continue

        offmatch = re.match(
            r"\s*OFFSET\s+([\-\d\.e]+)\s+([\-\d\.e]+)\s+([\-\d\.e]+)", line)
        if offmatch:
            if not end_site:
                offsets[active] = np.array(
                    [list(map(float, offmatch.groups()))])
            continue

        chanmatch = re.match(r"\s*CHANNELS\s+(\d+)", line)
        if chanmatch:
            channels = int(chanmatch.group(1))
            if order is None:
                channelis = 0 if channels == 3 else 3
                channelie = 3 if channels == 3 else 6
                parts = line.split()[2 + channelis:2 + channelie]
                if any([p not in channelmap for p in parts]):
                    continue
                order = "".join([channelmap[p] for p in parts])
            continue
        """ Modified line read to handle mixamo data """
        #        jmatch = re.match("\s*JOINT\s+(\w+)", line)
        jmatch = re.match("\s*JOINT\s+(\w+:?\w+)", line)
        if jmatch:
            names.append(jmatch.group(1))
            offsets = np.append(offsets, np.array([[0, 0, 0]]), axis=0)
            orients.qs = np.append(orients.qs,
                                   np.array([[1, 0, 0, 0]]),
                                   axis=0)
            parents = np.append(parents, active)
            active = (len(parents) - 1)
            continue

        if "End Site" in line:
            end_site = True
            continue

        fmatch = re.match("\s*Frames:\s+(\d+)", line)
        if fmatch:
            if start and end:
                fnum = (end - start) - 1
            else:
                fnum = int(fmatch.group(1))
            jnum = len(parents)
            positions = offsets[np.newaxis].repeat(fnum, axis=0)
            rotations = np.zeros((fnum, len(orients), 3))
            continue

        fmatch = re.match("\s*Frame Time:\s+([\d\.]+)", line)
        if fmatch:
            frametime = float(fmatch.group(1))
            continue

        if (start and end) and (i < start or i >= end - 1):
            i += 1
            continue

        dmatch = line.strip().split(' ')
        if dmatch:
            data_block = np.array(list(map(float, dmatch)))
            N = len(parents)
            fi = i - start if start else i
            if channels == 3:
                positions[fi, 0:1] = data_block[0:3]
                rotations[fi, :] = data_block[3:].reshape(N, 3)
            elif channels == 6:
                data_block = data_block.reshape(N, 6)
                positions[fi, :] = data_block[:, 0:3]
                rotations[fi, :] = data_block[:, 3:6]
            elif channels == 9:
                positions[fi, 0] = data_block[0:3]
                data_block = data_block[3:].reshape(N - 1, 9)
                rotations[fi, 1:] = data_block[:, 3:6]
                positions[fi, 1:] += data_block[:, 0:3] * data_block[:, 6:9]
            else:
                raise Exception("Too many channels! %i" % channels)

            i += 1

    f.close()

    eulers = np.radians(rotations)
    rotations = Quaternions.from_euler(eulers, order=order, world=world)
    # print("BVH.load: {} done. ({} order)".format(filename, order))

    return Animation(rotations, positions, orients, offsets, parents,
                     eulers), names, frametime
Пример #5
0
def rotations_parents_global(anim):
    rotations = rotations_global(anim)
    rotations = rotations[:, anim.parents]
    rotations[:, 0] = Quaternions.id(len(anim))
    return rotations
Пример #6
0
def load_from_maya(root, start, end):
    """
    Load Animation Object from Maya Joint Skeleton    
    
    Parameters
    ----------
    
    root : PyNode
        Root Joint of Maya Skeleton
        
    start, end : int, int
        Start and End frame index of Maya Animation
    
    Returns
    -------
    
    animation : Animation
        Loaded animation from maya
        
    names : [str]
        Joint names from maya   
    """

    import pymel.core as pm

    original_time = pm.currentTime(q=True)
    pm.currentTime(start)
    """ Build Structure """

    names, parents = astruct.load_from_maya(root)
    descendants = astruct.descendants_list(parents)
    orients = Quaternions.id(len(names))
    offsets = np.array([pm.xform(j, q=True, translation=True) for j in names])

    for j, name in enumerate(names):
        scale = pm.xform(pm.PyNode(name), q=True, scale=True, relative=True)
        if len(descendants[j]) == 0: continue
        offsets[descendants[j]] *= scale
    """ Load Animation """

    eulers = np.zeros((end - start, len(names), 3))
    positions = np.zeros((end - start, len(names), 3))
    rotations = Quaternions.id((end - start, len(names)))

    for i in range(end - start):

        pm.currentTime(start + i + 1, u=True)

        scales = {}

        for j, name, parent in zip(range(len(names)), names, parents):

            node = pm.PyNode(name)

            if i == 0 and pm.hasAttr(node, 'jointOrient'):
                ort = node.getOrientation()
                orients[j] = Quaternions(
                    np.array([ort[3], ort[0], ort[1], ort[2]]))

            if pm.hasAttr(node, 'rotate'):
                eulers[i, j] = np.radians(pm.xform(node, q=True,
                                                   rotation=True))
            if pm.hasAttr(node, 'translate'):
                positions[i, j] = pm.xform(node, q=True, translation=True)
            if pm.hasAttr(node, 'scale'):
                scales[j] = pm.xform(node, q=True, scale=True, relative=True)

        for j in scales:
            if len(descendants[j]) == 0: continue
            positions[i, descendants[j]] *= scales[j]

        positions[i, 0] = pm.xform(root,
                                   q=True,
                                   translation=True,
                                   worldSpace=True)

    rotations = orients[np.newaxis] * Quaternions.from_euler(
        eulers, order='xyz', world=True)
    """ Done """

    pm.currentTime(original_time)

    return Animation(rotations, positions, orients, offsets, parents), names
Пример #7
0
def load_to_maya(anim, names=None, radius=0.5):
    """
    Load Animation Object into Maya as Joint Skeleton
    loads each frame as a new keyfame in maya.
    
    If the animation is too slow or too fast perhaps
    the framerate needs adjusting before being loaded
    such that it matches the maya scene framerate.
    
    
    Parameters
    ----------
    
    anim : Animation
        Animation to load into Scene
        
    names : [str]
        Optional list of Joint names for Skeleton
    
    Returns
    -------
    
    List of Maya Joint Nodes loaded into scene
    """

    import pymel.core as pm

    joints = []
    frames = range(1, len(anim) + 1)

    if names is None:
        names = ["joint_" + str(i) for i in range(len(anim.parents))]

    for i, offset, orient, parent, name in zip(range(len(anim.offsets)),
                                               anim.offsets, anim.orients,
                                               anim.parents, names):

        if parent < 0:
            pm.select(d=True)
        else:
            pm.select(joints[parent])

        joint = pm.joint(n=name, p=offset, relative=True, radius=radius)
        joint.setOrientation([orient[1], orient[2], orient[3], orient[0]])

        curvex = pm.nodetypes.AnimCurveTA(n=name + "_rotateX")
        curvey = pm.nodetypes.AnimCurveTA(n=name + "_rotateY")
        curvez = pm.nodetypes.AnimCurveTA(n=name + "_rotateZ")

        jrotations = (-Quaternions(orient[np.newaxis]) *
                      anim.rotations[:, i]).euler()
        curvex.addKeys(frames, jrotations[:, 0])
        curvey.addKeys(frames, jrotations[:, 1])
        curvez.addKeys(frames, jrotations[:, 2])

        pm.connectAttr(curvex.output, joint.rotateX)
        pm.connectAttr(curvey.output, joint.rotateY)
        pm.connectAttr(curvez.output, joint.rotateZ)

        offsetx = pm.nodetypes.AnimCurveTU(n=name + "_translateX")
        offsety = pm.nodetypes.AnimCurveTU(n=name + "_translateY")
        offsetz = pm.nodetypes.AnimCurveTU(n=name + "_translateZ")

        offsetx.addKeys(frames, anim.positions[:, i, 0])
        offsety.addKeys(frames, anim.positions[:, i, 1])
        offsetz.addKeys(frames, anim.positions[:, i, 2])

        pm.connectAttr(offsetx.output, joint.translateX)
        pm.connectAttr(offsety.output, joint.translateY)
        pm.connectAttr(offsetz.output, joint.translateZ)

        joints.append(joint)

    return joints
Пример #8
0
def test_mixamo(model, path, device, max_steps=None, testset='nkn'):
    suffix = ''
    if max_steps:
        suffix += "max{}frame".format(max_steps)
    else:
        suffix += "fullseq"
    suffix += testset

    min_steps = 120
    if testset == 'paper':
        min_steps = 0

    with open('./datasets/mixamoquatdirect_train_large.bin', 'rb') as binary:
        b = pickle.load(binary)

    f_np = EasyDict(b['f'])
    local_mean = f_np.local.mean
    local_std = f_np.local.std
    rtj_mean = f_np.rtj.mean
    rtj_std = f_np.rtj.std

    f = EasyDict({
        'local': {
            'mean': torch.from_numpy(local_mean).float().to(device),
            'std': torch.from_numpy(local_std).float().to(device),
        },
        'rtj': {
            'mean': torch.from_numpy(rtj_mean).float().to(device),
            'std': torch.from_numpy(rtj_std).float().to(device),
        },
    })
    diff_worlds, diff_locals, diff_rtjs, vels, \
    labels, bl_diffs, blratio_diffs \
        = list(), list(), list(), list(), list(), list(), list()

    (inpjoints, inpanims, inpquats, inplocals, inprtjs, inpskels, from_names,
     tgtjoints, tgtanims, tgtquats, tgtlocals, tgtrtjs, tgtskels, to_names,
     gtanims) = \
        load_testdata_root(min_steps, max_steps, b['scale'], testset)

    gt_world_pos, keys = list(), list()
    inp_heights = get_skel_height_np(np.asarray(inpskels))
    gt_heights = get_skel_height_np(np.asarray(tgtskels))
    for i in range(len(tgtlocals)):
        gt = put_in_world(tgtlocals[i].copy(), tgtrtjs[i].copy(),
                          tgtanims[i][0].rotations[:, 0])

        km = from_names[i].split("_")[0:2]
        from_ = from_names[i][:sum([len(l) for l in km]) + 1]
        kc = to_names[i].split("_")[0:2]
        to_ = to_names[i][:sum([len(l) for l in kc]) + 1]
        key = from_ + "/" + to_

        gt_world_pos.append(gt)
        keys.append(key)

    n_inpskels, n_tgtskels = list(), list()
    for i in range(len(inplocals)):
        inplocals[i] = (inplocals[i] - local_mean) / local_std
        inprtjs[i] = (inprtjs[i] - rtj_mean) / rtj_std
        n_inpskels.append((inpskels[i] - local_mean) / local_std)
        n_tgtskels.append((tgtskels[i] - local_mean) / local_std)

    results_dir = os.path.join(path, "test_{}".format(suffix))

    with trange(len(inplocals)) as tq:
        for i in tq:
            tq.set_description('Mixamo Testing')
            steps = inplocals[i].shape[0]
            tq.set_postfix(frame=steps)

            if not os.path.exists(results_dir):
                os.makedirs(results_dir)

            quatA = torch.tensor(inpquats[i],
                                 dtype=torch.float32,
                                 device=device).view([1, steps, 22, 4])
            rtjA = torch.tensor(inprtjs[i], dtype=torch.float32,
                                device=device).view(1, steps, 3)
            skelA = np.asarray(n_inpskels[i])[0:1]
            skelA = torch.tensor(skelA, dtype=torch.float32,
                                 device=device).view(1, 1, 22, 3)
            skelB = np.asarray(n_tgtskels[i])[0:1]
            skelB = torch.tensor(skelB, dtype=torch.float32,
                                 device=device).view(1, 1, 22, 3)

            dlocalB = torch.tensor(tgtlocals[i],
                                   dtype=torch.float32,
                                   device=device)
            drtjB = torch.tensor(tgtrtjs[i],
                                 dtype=torch.float32,
                                 device=device).view(1, steps, 3)

            with torch.no_grad():
                _, (clocalB, cdlocalB, crtjB, cquatB,
                    _) = model(quatA, rtjA, skelA, skelB)
                cdrtjB = crtjB * f.rtj.std + f.rtj.mean

                init_diff = drtjB[:, 0:1] - cdrtjB[:, 0:1]
                cdrtjB = cdrtjB + init_diff

                diff_local = ((cdlocalB -
                               dlocalB)**2).sum(dim=-1).cpu().numpy()[0]
                diff_local = 1. / gt_heights[i] * diff_local

                diff_rtj = (cdrtjB - drtjB)**2
                diff_rtj = diff_rtj.sum(dim=-1).cpu().numpy()[0]

                outputB = put_in_world_batch(cdlocalB, cdrtjB,
                                             cquatB[:, :, 0]).cpu().numpy()[0]
                diff_world = 1. / gt_heights[i] * (
                    (outputB - gt_world_pos[i])**2).sum(axis=-1)

                variance = np.std(gt_world_pos[i], axis=0)**2
                variance = 1. / gt_heights[i] * variance

                tgtbls = get_bonelengths(tgtskels[i])
                inpbls = get_bonelengths(inpskels[i])
                bl_diff, blratio_diff = compare_bls(tgtbls, inpbls)

                labels.append(keys[i])
                diff_worlds.append(diff_world)
                diff_locals.append(diff_local)
                diff_rtjs.append(diff_rtj)
                vels.append(variance)
                bl_diffs.append(bl_diff)
                blratio_diffs.append(blratio_diff)

                cdlocalB = cdlocalB.cpu().numpy()[0]
                cdrtjB = cdrtjB.cpu().numpy()[0]
                cquatB = cquatB.cpu().numpy()[0]

            # create bvh path
            if "Big_Vegas" in from_names[i]:
                from_bvh = from_names[i].replace("Big_Vegas", "Vegas")
            else:
                from_bvh = from_names[i]

            if "Warrok_W_Kurniawan" in to_names[i]:
                to_bvh = to_names[i].replace("Warrok_W_Kurniawan", "Warrok")
            else:
                to_bvh = to_names[i]

            bvh_path = os.path.join(path, 'blender_files_{}'.format(suffix),
                                    to_bvh.split("_")[-1])
            if not os.path.exists(bvh_path):
                os.makedirs(bvh_path)
            bvh_path += "/{0:05d}".format(i)

            # save input sequence
            inpanim, inpnames, inpftime = inpanims[i]
            BVH.save(
                bvh_path + "_from=" + from_bvh + "_to=" + to_bvh + "_inp.bvh",
                inpanim, inpnames, inpftime)

            # save ground truth
            gtanim, gtnames, gtftime = gtanims[i]
            BVH.save(
                bvh_path + "_from=" + from_bvh + "_to=" + to_bvh + "_gt.bvh",
                gtanim, gtnames, gtftime)

            # save the retargeted result
            tgtanim, tgtnames, tgtftime = tgtanims[i]
            """Exclude angles in exclude_list as they will rotate non-existent
               children During training."""
            exclude_list = [5, 17, 21, 9, 13]
            anim_joints = []
            quat_joints = []
            for l in range(len(tgtjoints[i])):
                if l not in exclude_list:
                    anim_joints.append(
                        tgtjoints[i]
                        [l])  # excluded joint index w.r.t all joints
                    quat_joints.append(l)  # excluded joint index

            root_rotB = Quaternions(cquatB[:, 0])

            worldB = put_in_world(cdlocalB, cdrtjB, root_rotB)

            tgtanim.positions[:, 0] = worldB[:, 0].copy()
            excluded_quatB = cquatB[:, quat_joints].copy()
            excluded_quatB[:, 0, :] = root_rotB.qs
            tgtanim.rotations.qs[:, anim_joints] = excluded_quatB
            BVH.save(bvh_path + "_from=" + from_bvh + "_to=" + to_bvh + ".bvh",
                     tgtanim, tgtnames, tgtftime)

    if testset == 'nkn':
        print("Create report to {}...".format(results_dir))
        create_report(diff_worlds, diff_locals, diff_rtjs, vels, labels,
                      bl_diffs, blratio_diffs, inp_heights, gt_heights, suffix,
                      results_dir)
        print("Done.")