Esempio n. 1
0
def list_of_vectors_of_concatenated_active_joint_gradients(vid, active_joints):
    grad = skvp.gradient(vid)
    lst = []
    for frame in grad.frames:
        vec = []
        for j in active_joints:
            vec.extend(frame[j])
        lst.append(np.array(vec))

    return lst
Esempio n. 2
0
def detect_rest_sequences(vid, active_joints, exponent=-1.5):
    der = skvp.median(skvp.gradient(vid))
    rest_index_counter = {}
    for joint in active_joints:
        stats = [np.linalg.norm(f[joint])**exponent for f in der.frames]
        stats_mean = np.mean(stats)
        rest_indices = [i for i, val in enumerate(stats) if val > stats_mean]
        margin = int(round(len(der) * 0.075))
        rest_indices = [
            val for val in rest_indices
            if val > margin and val < len(der) - margin
        ]
        for ri in rest_indices:
            if ri not in rest_index_counter:
                rest_index_counter[ri] = 0
            rest_index_counter[ri] += 1
    thresh = int(len(active_joints) * 0.3)
    rest_indices = sorted(
        [ri for ri in rest_index_counter if rest_index_counter[ri] > thresh])
    sequences = []
    first = None
    last = None
    for ind in rest_indices:
        if first == None:
            first = ind
            last = ind
            continue
        if ind - last > len(der) * 0.1:
            sequences.append((first, last))
            first = ind
        last = ind
    if last != None:
        sequences.append((first, last))

    index_trans_func = lambda x: x + 1

    return sequences, index_trans_func
Esempio n. 3
0
def train(input_dir, output_file, warp_mode, output_ref_vid):
    vid_files = [
        os.path.join(input_dir, fname) for fname in os.listdir(input_dir)
    ]
    print('Loading training videos...')
    vids = [skvp.load(path) for path in vid_files]
    print('Normalizing training videos...')
    vids = [skvp.project_to_body_plane(vid, 0, 4, 8) for vid in vids]
    connections_mean_lengths = get_connection_mean_lengths(vids)
    vids = [
        skvp.scaled_connections(vid, connections_mean_lengths) for vid in vids
    ]
    vids_original_lengths_before_filters = [len(vid) for vid in vids]
    vids_mean_len_before_filters = int(
        round(np.mean(vids_original_lengths_before_filters)))
    print('Scaling training videos to have the same length')
    vids = [
        skvp.create_length_scaled_video(
            vid, num_frames=vids_mean_len_before_filters) for vid in vids
    ]
    print('Applying filters')
    vids = [skvp.median(vid) for vid in vids]
    vid_pyramids = [skvp.pyramid(vid, [3, 3, 3], [1, 1, 1]) for vid in vids]
    vids = [pyr.get_level(1) for pyr in vid_pyramids]
    vids_new_len = len(vids[0])
    # Saving original videos before tempora alignment
    vids_nowrap = [vid[:] for vid in vids]
    print('Applying temporal alignment')
    ref_vid_index, vids, active_joints, num_rests_in_motion, ref_vid_warping_indices, all_vids_warping_sequences = our_warping_function(
        vids)
    if warp_mode == 'none':
        vids = vids_nowrap
    if warp_mode == 'dtw':
        vids = warp_using_dtw(vids_nowrap, ref_vid_index, active_joints)
    if output_ref_vid != None:
        skvp.dump(vids_nowrap[ref_vid_index], output_ref_vid)
    # Computing discrete temporal gradients
    ders = [skvp.gradient(vid) for vid in vids]
    connections = skvp.distinct_connections(vids[0])
    # Writing motion metadata into output model file
    f = open(output_file, 'w')
    f.write('ActiveJoints={0}\n'.format(str(active_joints)))
    f.write('VidLength={0:d}\n'.format(vids_mean_len_before_filters))
    f.write('NumRests={0:d}\n'.format(num_rests_in_motion))
    f.write('WarpIndices={0}\n'.format(ref_vid_warping_indices))
    f.write('ConnectionLengths={0}\n'.format(str(connections_mean_lengths)))
    f.write('--stats--\n')
    print('Calculating stats and writing to output file...')
    # Computing and writing time-related statistics - original video lengths and aligned sequence original lengths
    mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
        vids_original_lengths_before_filters)
    data_unit = {
        'mean': mean,
        'dist_mean': dist_mean,
        'dist_std': dist_std,
        'type': 'video_length_frames_raw'
    }
    f.write('{0}\n'.format(str(data_unit)))
    for i in range(len(all_vids_warping_sequences[0]) + 1):
        if i == 0:
            seq_lengths = [v[0] + 1 for v in all_vids_warping_sequences]
        elif i < len(all_vids_warping_sequences[0]):
            seq_lengths = [
                v[i] - v[i - 1] + 1 for v in all_vids_warping_sequences
            ]
        else:
            seq_lengths = [
                vids_new_len - v[i - 1] + 1 for v in all_vids_warping_sequences
            ]
        mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
            seq_lengths)
        data_unit = {
            'mean': mean,
            'dist_mean': dist_mean,
            'dist_std': dist_std,
            'type': 'sequence_length',
            'sequence_num': i
        }
        f.write('{0}\n'.format(str(data_unit)))
    # Computing and writing joint-related statistics
    for frame_num in range(vids_new_len):
        for joint in range(vids[0].get_num_joints()):
            points = [vid.frames[frame_num][joint] for vid in vids]
            xs = [p[0] for p in points]
            ys = [p[1] for p in points]
            zs = [p[2] for p in points]
            mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(xs)
            data_unit = {
                'frame': frame_num,
                'joint': joint,
                'mean': mean,
                'dist_mean': dist_mean,
                'dist_std': dist_std,
                'type': 'location_x'
            }
            f.write('{0}\n'.format(str(data_unit)))
            mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(ys)
            data_unit = {
                'frame': frame_num,
                'joint': joint,
                'mean': mean,
                'dist_mean': dist_mean,
                'dist_std': dist_std,
                'type': 'location_y'
            }
            f.write('{0}\n'.format(str(data_unit)))
            mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(zs)
            data_unit = {
                'frame': frame_num,
                'joint': joint,
                'mean': mean,
                'dist_mean': dist_mean,
                'dist_std': dist_std,
                'type': 'location_z'
            }
            f.write('{0}\n'.format(str(data_unit)))
            if frame_num < vids_new_len - 1:  # We have one frame less in the gradient
                der_points = [vid.frames[frame_num][joint] for vid in ders]
                xs = [p[0] for p in der_points]
                ys = [p[1] for p in der_points]
                zs = [p[2] for p in der_points]
                mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
                    xs)
                data_unit = {
                    'frame': frame_num,
                    'joint': joint,
                    'mean': mean,
                    'dist_mean': dist_mean,
                    'dist_std': dist_std,
                    'type': 'gradient_x'
                }
                f.write('{0}\n'.format(str(data_unit)))
                mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
                    ys)
                data_unit = {
                    'frame': frame_num,
                    'joint': joint,
                    'mean': mean,
                    'dist_mean': dist_mean,
                    'dist_std': dist_std,
                    'type': 'gradient_y'
                }
                f.write('{0}\n'.format(str(data_unit)))
                mean, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
                    zs)
                data_unit = {
                    'frame': frame_num,
                    'joint': joint,
                    'mean': mean,
                    'dist_mean': dist_mean,
                    'dist_std': dist_std,
                    'type': 'gradient_z'
                }
                f.write('{0}\n'.format(str(data_unit)))
        for joint_i in range(vids[0].get_num_joints()):
            for joint_j in range(joint_i + 1, vids[0].get_num_joints()):
                if (joint_i, joint_j) in connections:
                    # Skipping neighbors!!
                    continue
                dists = [
                    np.linalg.norm(vid.frames[frame_num][joint_i] -
                                   vid.frames[frame_num][joint_j])
                    for vid in vids
                ]
                centroid, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
                    dists)
                data_unit = {
                    'frame': frame_num,
                    'joint_i': joint_i,
                    'joint_j': joint_j,
                    'mean': float(centroid),
                    'dist_mean': dist_mean,
                    'dist_std': dist_std,
                    'type': 'joint_distance'
                }
                f.write('{0}\n'.format(str(data_unit)))
        for lower_joint_index, join_index, higher_joint_index in find_all_joint_trios(
                vids[0].get_connections()):
            angles = []
            for vid in vids:
                vec_1 = vid.frames[frame_num][lower_joint_index] - vid.frames[
                    frame_num][join_index]
                vec_2 = vid.frames[frame_num][higher_joint_index] - vid.frames[
                    frame_num][join_index]
                theta = np.arccos(
                    vec_1.dot(vec_2) /
                    (np.linalg.norm(vec_1) * np.linalg.norm(vec_2)))
                angles.append(theta)
            centroid, dist_mean, dist_std = get_centroid_dist_mean_and_dist_std(
                angles)
            data_unit = {
                'frame': frame_num,
                'joint_trio':
                [lower_joint_index, join_index, higher_joint_index],
                'mean': float(centroid),
                'dist_mean': dist_mean,
                'dist_std': dist_std,
                'type': 'joint_angles'
            }
            f.write('{0}\n'.format(str(data_unit)))
    f.close()
Esempio n. 4
0
def test(model_file, input_video_file, warp_mode, ablation, ref_vid_path):
    vid = skvp.load(input_video_file)
    vid = skvp.project_to_body_plane(vid, 0, 4, 8)
    orig_vid_len_frames = len(vid)
    vid_len, active_joints, num_rests, warp_indices, connection_lengths, stats = parse_model_file(
        model_file)
    vid = skvp.scaled_connections(vid, connection_lengths)
    vid = skvp.create_length_scaled_video(vid, num_frames=vid_len)
    vid = skvp.median(vid)
    pyr = skvp.pyramid(vid, [3, 3, 3], [1, 1, 1])
    vid = pyr.get_level(1)
    rest_sequences = []
    exponent = -1.5
    ignore_subsequence_lengths = False
    while len(rest_sequences) < num_rests:
        exponent *= 0.9
        if exponent > -0.5:
            rest_sequences = [(warp_indices[i - 1], warp_indices[i])
                              for i in range(len(warp_indices)) if i % 2 == 1]
            index_transform_function = lambda x: x + 1
            ignore_subsequence_lengths = True
            break
        rest_sequences, index_transform_function = detect_rest_sequences(
            vid, active_joints, exponent)
    vec = []
    for sq in rest_sequences:
        if sq[0] == sq[1]:
            sq = (sq[0] - 1, sq[1] + 1)
        vec.extend(sq)
    vec = [index_transform_function(val) for val in vec]
    if warp_mode in ('our'):
        vid = warp_video(vid, vec, warp_indices)
    elif warp_mode == 'dtw':
        refvid = skvp.load(ref_vid_path)
        ref_vals = list_of_vectors_of_concatenated_active_joint_gradients(
            refvid, active_joints)
        vid_vals = list_of_vectors_of_concatenated_active_joint_gradients(
            vid, active_joints)
        matches, cost, mapping_1, mapping_2, matrix = simpledtw.dtw(
            ref_vals, vid_vals)
        warped = vid[:1]  # Starting from one frame, as grad has n-1 frames
        for mapped_indices in mapping_1:
            warped.add_frame(vid.frames[mapped_indices[-1]])
        vid = warped
    der = skvp.gradient(vid)
    costs = []
    group_weights = {'ActiveJoint': 0.73, 'NonActiveJoint': 0.02, 'Time': 0.25}
    if 'active' in ablation:
        group_weights = {
            'ActiveJoint': 0.15,
            'NonActiveJoint': 0.6,
            'Time': 0.25
        }
    if 'time' in ablation:
        group_weights['ActiveJoint'] /= (1.0 - group_weights['Time'])
        group_weights['NonActiveJoint'] /= (1.0 - group_weights['Time'])
        group_weights['Time'] = 0
    for stat in stats:
        if stat['type'] == 'sequence_length':
            stat['start_frame'] = (vec[stat['sequence_num'] - 1] +
                                   1) if stat['sequence_num'] > 0 else 0
            stat['end_frame'] = vec[
                stat['sequence_num']] if stat['sequence_num'] < len(
                    vec) else len(vid) - 1
        if ignore_subsequence_lengths and stat['type'] == 'sequence_length':
            print('Ignoring seq lengths')
            continue
        if 'joint' in stat or 'joint_trio' in stat:
            stat['type_group'] = 'NonActiveJoint'
        elif 'joint_i' in stat:
            stat[
                'type_group'] = 'NoGroupIgnoreMe' if 'active' not in ablation else 'NonActiveJoint'
        else:
            stat['type_group'] = 'Time'
        if 'joint' in stat and stat['joint'] in active_joints:
            stat['type_group'] = 'ActiveJoint'
        if 'joint_i' in stat and stat[
                'joint_i'] in active_joints and 'joint_j' in stat and stat[
                    'joint_j'] in active_joints:
            stat['type_group'] = 'ActiveJoint'
        if 'joint_trio' in stat:
            for j in stat['joint_trio']:
                if j in active_joints:
                    stat['type_group'] = 'ActiveJoint'
        if stat['type'] == 'location_x':
            val = vid.frames[stat['frame']][stat['joint']][0]
        elif stat['type'] == 'location_y':
            val = vid.frames[stat['frame']][stat['joint']][1]
        elif stat['type'] == 'location_z':
            val = vid.frames[stat['frame']][stat['joint']][2]
        elif stat['type'] == 'gradient_x':
            val = der.frames[stat['frame']][stat['joint']][0]
        elif stat['type'] == 'gradient_y':
            val = der.frames[stat['frame']][stat['joint']][1]
        elif stat['type'] == 'gradient_z':
            val = der.frames[stat['frame']][stat['joint']][2]
        elif stat['type'] == 'joint_distance':
            val = np.linalg.norm(vid.frames[stat['frame']][stat['joint_i']] -
                                 vid.frames[stat['frame']][stat['joint_j']])
        elif stat['type'] == 'joint_angles':
            joint_trio = stat['joint_trio']
            vec_1 = vid.frames[stat['frame']][joint_trio[0]] - vid.frames[
                stat['frame']][joint_trio[1]]
            vec_2 = vid.frames[stat['frame']][joint_trio[2]] - vid.frames[
                stat['frame']][joint_trio[1]]
            val = np.arccos(
                vec_1.dot(vec_2) /
                (np.linalg.norm(vec_1) * np.linalg.norm(vec_2)))
        elif stat['type'] == 'video_length_frames_raw':
            val = orig_vid_len_frames
        elif stat['type'] == 'sequence_length':
            if stat['sequence_num'] == 0:
                val = vec[0] + 1
            elif stat['sequence_num'] < len(vec):
                val = vec[stat['sequence_num']] - vec[stat['sequence_num'] -
                                                      1] + 1
            else:
                val = len(vid) - vec[stat['sequence_num'] - 1] + 1
        else:
            continue
        # Avoiding division by 0 when we normalize the distance
        val = round(val, 7)
        stat['mean'] = round(stat['mean'], 7)
        stat['dist_std'] = round(stat['dist_std'], 7)
        stat['dist_mean'] = round(stat['dist_mean'], 7)
        try:
            dist = abs(val - stat['mean'])
        except:
            print('stat is: {0}'.format(str(stat)))
            print('val is: {0}'.format(str(val)))
            print('mean is: {0}'.format(str(stat['mean'])))
        if stat['dist_std'] == 0:
            if dist - stat['dist_mean'] == 0:
                dist_in_stds = 0
            else:
                dist_in_stds = np.inf
        else:
            dist_in_stds = (dist - stat['dist_mean']) / stat['dist_std']
        stat['cost'] = dist_in_stds
        stat['test_val'] = val
    costed_stats = [s for s in stats
                    if 'cost' in s]  # and s['type'] == 'joint_angles']
    costed_active_joint_stats = [
        s for s in costed_stats if s['type_group'] == 'ActiveJoint'
    ]
    costed_nonactive_joint_stats = [
        s for s in costed_stats if s['type_group'] == 'NonActiveJoint'
    ]
    costed_time_stats = [s for s in costed_stats if s['type_group'] == 'Time']
    lambdaa = 2
    group_to_stats = {
        'Time': costed_time_stats,
        'ActiveJoint': costed_active_joint_stats,
        'NonActiveJoint': costed_nonactive_joint_stats
    }

    feedback_items, avg_active_bad_segment_length, avg_param_num_active_segments, avg_param_num_nonactive_segments = produce_feedback(
        costed_stats, group_weights, ablation)

    scorelambda = 2.9
    scorelambdatime = 7.5

    for item in feedback_items:
        # Here we duplicate the weight manipulation, just to be able to sort the feedbacks
        # The same manupulation will be applied on real items (depending on ablation settings) - we don't apply ablation on feedback
        item['cost'] *= group_weights[item['type_group']]
        item['cost'] /= (scorelambdatime
                         if item['type_group'] == 'Time' else scorelambda)
        item['cost'] /= len(
            [s['cost'] for s in group_to_stats[item['type_group']]])
        if item['type_group'] == 'ActiveJoint':
            item['cost'] *= (0.75**avg_param_num_active_segments)
    feedback_items.sort(key=lambda x: x['cost'], reverse=True)

    if len(feedback_items) > 5:
        feedback_items = feedback_items[:5]
    last_cost = None
    for i, fi in enumerate(feedback_items):
        if last_cost == None or last_cost < 2 * fi['cost']:
            last_cost = fi['cost']
            continue
        # Removing irrelevant feedback
        feedback_items = feedback_items[:i]
        break
    feedback_items = [generate_feedback_text(fi, 15) for fi in feedback_items]
    if len(feedback_items) == 0:
        print('FEEDBACK: empty! congrats :)')
    for feedback_item in feedback_items:
        print('FEEDBACK: ' + str(feedback_item))

    if 'diminish' not in ablation and 'active' not in ablation:
        for s in costed_active_joint_stats:
            s['cost'] *= (0.75**avg_param_num_active_segments)

    #Vector scores
    active_joint_score = max(
        0, 1.0 - abs(
            sum(s['cost']
                for s in costed_active_joint_stats if s['cost'] > 0) /
            (scorelambda * len([s['cost']
                                for s in costed_active_joint_stats]))))
    nonactive_joint_score = max(
        0, 1.0 - abs(
            sum(s['cost']
                for s in costed_nonactive_joint_stats if s['cost'] > 0) /
            (scorelambda *
             len([s['cost'] for s in costed_nonactive_joint_stats]))))
    time_score = max(
        0, 1.0 - abs(
            sum(s['cost'] for s in costed_time_stats if s['cost'] > 2.5) /
            (scorelambdatime * len([s['cost'] for s in costed_time_stats]))))

    print('Scores: Active: {0:f}, NonActive: {1:f}, Time: {2:f}'.format(
        active_joint_score, nonactive_joint_score, time_score))
    final_score = active_joint_score * group_weights[
        'ActiveJoint'] + nonactive_joint_score * group_weights[
            'NonActiveJoint'] + time_score * group_weights['Time']

    print('Score: {0:f}'.format(final_score))