<jupyter_start><jupyter_text>Merging Capacitive Images with OptiTrack Ground TruthThis script performs a simple merge of all data sources: front, back, side, and the OptiTrack timestamps. The result are pickle files with each row representing the capacitive image and the marker positions at one point in time.<jupyter_code>import os
import pandas as pd
import numpy as np
import scipy.interpolate as interp

from skimage import measure
from skimage.measure import find_contours, approximate_polygon, \
    subdivide_polygon, EllipseModel, LineModelND
    
from datetime import datetime

%run py/labeling_names.py
DATA_PATH_TIMESTAMPS = "./data/timestamps/"
DATA_PATH_FRONT = "./data/front/"
DATA_PATH_BACK = "./data/back/"
DATA_PATH_SIDE = "./data/side/"

PREFIX_TIMESTAMPS = "timestamps_"
PREFIX_FRONT = "front_"
PREFIX_BACK  = "back_"
PREFIX_SIDE  = "side_"

df = ""
dfTimestamp = ""
def transform_to_matrix(s):
    matrix = s.replace("\n", "")
    matrix = matrix.split(",")

    if (len(matrix) != 408):
        return -1, -1
    
    matrix = matrix[:407]
    
    # determine timestamp
    timestamp = str(matrix[0]) + str(matrix[1][:3])
    timestamp = int(timestamp)
    
    matrix = np.array(matrix[2:]).reshape(27, 15)
    
    matrix[matrix==''] = '0'
    matrix[matrix=='-'] = '0'
    
    try:
        matrix = matrix.astype(int)
    except ValueError:
        return -1, -1
    
    return matrix, timestamp

def getMatrixLeft(x):
    if (type(x) is int):
        return -1
    else: 
        return x[:16]

def getMatrixBottom(x):
    if (type(x) is int):
        return -1
    else: 
        return x[16:21]

def getMatrixRight(x):
    if (type(x) is int):
        return -1
    else: 
        return x[21:]
def log(s):
    with open("status_PY02_preprocessing.txt", "a") as myfile:
        myfile.write("[" + str(datetime.now()) + "] " + s + "\n")
    print("[" + str(datetime.now()) + "] " + s)
df = ""
dfTimestamp = ""
    
for optitrack_filename in os.listdir("./data/transformed_optitrack/"):
    if optitrack_filename.endswith(".pkl"):
        current_participant = optitrack_filename.split("_")[1].split(".")[0]
        
        if os.path.isfile("./data/pickles/raw_data_" + str(current_participant) + ".pkl") :
            log(current_participant + " is already available. Skipped.")
            continue
        
        log("Reading matrices of " + current_participant)
        df_temp = pd.read_csv(DATA_PATH_FRONT + PREFIX_FRONT + current_participant + ".txt", header=None, sep=";", names=["Participant", "Source", "Capstr"])
        df_temp['Timestamp'] = df_temp.Capstr.apply(lambda x : transform_to_matrix(x)[1])
        df_temp['Matrix'] = df_temp.Capstr.apply(lambda x : transform_to_matrix(x)[0])
        df_temp = df_temp.drop(['Capstr'], axis=1)
        df_temp = df_temp[~(df_temp.Timestamp == -1)]
        df = df_temp
        
        df_temp = pd.read_csv(DATA_PATH_BACK + PREFIX_BACK + current_participant + ".txt", header=None, sep=";", names=["Participant", "Source", "Capstr"])
        df_temp['Timestamp'] = df_temp.Capstr.apply(lambda x : transform_to_matrix(x)[1])
        df_temp['Matrix'] = df_temp.Capstr.apply(lambda x : transform_to_matrix(x)[0])
        df_temp = df_temp.drop(['Capstr'], axis=1)
        df_temp = df_temp[~(df_temp.Timestamp == -1)]
        df = df.append(df_temp)
        
        df_temp = pd.read_csv(DATA_PATH_SIDE + PREFIX_SIDE + current_participant + ".txt", header=None, sep=";", names=["Participant", "Source", "Timestamp", "Matrix"])
        df_temp['Matrix'] = df_temp.Matrix.apply(lambda x : np.fromstring(x, sep=","))
        df_temp = df_temp[~(df_temp.Timestamp == -1)]
        df = df.append(df_temp)
        
        df_temp = pd.read_csv(DATA_PATH_TIMESTAMPS + PREFIX_TIMESTAMPS + current_participant + ".txt", header=None, sep=",", names=["Front", "Back", "Side", "OptiTrack"])
        dfTimestamp = df_temp
        
        log("Reading OptiTrack data of " + current_participant)
        dfOpti = pd.read_pickle("./data/transformed_optitrack/" + optitrack_filename)
        
        # replace participant IDs
        df.Participant = df.Participant.replace(PARTICIPANT_ID_REPLACES)

        df_back = df[df.Source == "BACK"].copy(deep=True).sort_values(by=['Timestamp']).rename(columns={'Timestamp': 'Back_Timestamp'})
        df_front = df[df.Source == "FRONT"].copy(deep=True).sort_values(by=['Timestamp']).rename(columns={'Timestamp': 'Front_Timestamp'})
        df_side = df[df.Source == "SIDE"].copy(deep=True).sort_values(by=['Timestamp']).rename(columns={'Timestamp': 'Side_Timestamp'})

        dfOpti.Time = dfOpti.Time.astype(np.int64)
        dfOpti = dfOpti.rename(columns={'Time': 'OptiTrack_Timestamp'})
        dfOpti = dfOpti.sort_values(by=['OptiTrack_Timestamp'])

        dfTimestamp = dfTimestamp.rename(columns={"Front": "Front_Timestamp", "Back": "Back_Timestamp", "Side": "Side_Timestamp", "OptiTrack": "OptiTrack_Timestamp"})

        ##########
        ## FRONT TIMESTAMP
        ##########
        dfSynced = pd.merge_asof(dfTimestamp.sort_values(by=['Front_Timestamp']), df_front, on='Front_Timestamp', direction='nearest')

        # Leave some of the columns for sanity checks
        dfSynced = dfSynced.drop(['Participant'], axis=1)
        dfSynced = dfSynced.drop(['Source'], axis=1)
        dfSynced = dfSynced.rename(columns={'Matrix': 'MatrixFront'})

        ##########
        ## BACK TIMESTAMP
        ##########
        dfSynced = dfSynced.sort_values(by=['Back_Timestamp'])
        dfSynced = pd.merge_asof(dfSynced, df_back, on='Back_Timestamp', direction='nearest')

        # Leave some of the columns for sanity checks
        dfSynced = dfSynced.drop(['Participant'], axis=1)
        dfSynced = dfSynced.drop(['Source'], axis=1)
        dfSynced = dfSynced.rename(columns={'Matrix': 'MatrixBack'})

        ##########
        ## SIDE TIMESTAMP
        ##########
        dfSynced = dfSynced.sort_values(by=['Side_Timestamp'])
        dfSynced = pd.merge_asof(dfSynced, df_side, on='Side_Timestamp', direction='nearest')

        # Leave some of the columns for sanity checks
        dfSynced = dfSynced.drop(['Participant'], axis=1)
        dfSynced = dfSynced.drop(['Source'], axis=1)
        dfSynced = dfSynced.rename(columns={'Matrix': 'MatrixSide'})

        ##########
        ## OPTITRACK DATA
        ##########
        dfSynced = dfSynced.sort_values(by=['OptiTrack_Timestamp'])
        dfSynced = pd.merge_asof(dfOpti, dfSynced, on='OptiTrack_Timestamp', direction='nearest')

        log("Splitting side into left, bottom and right for " + current_participant)
        dfSynced['MatrixLeft'] = dfSynced.MatrixSide.apply(lambda x : getMatrixLeft(x))
        dfSynced['MatrixBottom'] = dfSynced.MatrixSide.apply(lambda x :getMatrixBottom(x))
        dfSynced['MatrixRight'] = dfSynced.MatrixSide.apply(lambda x : getMatrixRight(x))

        log("Creating merged matrix for " + current_participant)
        merged = []
        for index, d in dfSynced.iterrows():
            if (not type(d.MatrixFront) is int and 
                not type(d.MatrixBack) is int and
                not type(d.MatrixLeft) is int and
                not type(d.MatrixRight) is int and
                not type(d.MatrixBottom) is int):

                rear_img = np.fliplr(d.MatrixBack)
                front_img = d.MatrixFront
                left_img = d.MatrixLeft.T
                right_img = d.MatrixRight
                right_img = np.insert(right_img, 0, 0, axis=0)
                right_img = right_img.T
                bot_img = d.MatrixBottom
                front_back_merged = rear_img
                new_size = 27

                # Interpolate left, right and bottom edges
                left_interp = interp.interp1d(np.arange(left_img.size), left_img)
                left_stretch = left_interp(np.linspace(0, left_img.size - 1, new_size))
                left_stretch = left_stretch.reshape(27, 1)

                right_interp = interp.interp1d(np.arange(right_img.size), right_img)
                right_stretch = right_interp(np.linspace(0, right_img.size - 1, new_size))
                right_stretch = right_stretch.reshape(27, 1)

                bot_interp = interp.interp1d(np.arange(bot_img.size), bot_img)
                bot_stretch = bot_interp(np.linspace(0, bot_img.size - 1, 15))
                bot_stretch = np.insert(bot_stretch, 0, 0) # a zero at the left corner
                bot_stretch = np.insert(bot_stretch, bot_stretch.size, 0) # zero at the right corner

                # merge back image with interpolated left, right and bottom edges
                merged_img = np.hstack((left_stretch, front_back_merged))
                merged_img = np.hstack((merged_img, right_stretch))
                merged_img = np.vstack((merged_img.reshape(-1, 17), bot_stretch.T))
                
                # also merge with front image on the left side
                front_extended = np.vstack((front_img, (np.zeros(15)))) 
                merged_img = np.hstack((merged_img, front_extended))
                
                merged.append(merged_img)
            else:
                merged.append(-1)

        dfSynced['MatrixMerged'] = merged

        log("Saving " + current_participant)
        pd.to_pickle(dfSynced, "./data/pickles/" + "raw_data_" + current_participant + ".pkl")<jupyter_output>[2018-07-13 11:31:51.517632] P16 is already available. Skipped.
[2018-07-13 11:31:51.519097] P18 is already available. Skipped.
[2018-07-13 11:31:51.519356] P17 is already available. Skipped.
[2018-07-13 11:31:51.519608] P6 is already available. Skipped.
[2018-07-13 11:31:51.519861] P19 is already available. Skipped.
[2018-07-13 11:31:51.520109] P13 is already available. Skipped.
[2018-07-13 11:31:51.520355] P4 is already available. Skipped.
[2018-07-13 11:31:51.520599] P10 is already available. Skipped.
[2018-07-13 11:31:51.520886] P21 is already available. Skipped.
[2018-07-13 11:31:51.521144] P8 is already available. Skipped.
[2018-07-13 11:31:51.521423] P3 is already available. Skipped.
[2018-07-13 11:31:51.521680] P2 is already available. Skipped.
[2018-07-13 11:31:51.522014] P22 is already available. Skipped.
[2018-07-13 11:31:51.522329] P12 is already available. Skipped.
[2018-07-13 11:31:51.522598] P5 is already available. Skipped.
[2018-07-13 11:31:51.522859] P9 is already ava[...]
{'fraction_non_alphanumeric': 0.13842597052307098, 'fraction_numerical': 0.041229168673538194, 'mean_word_length': 2.891304347826087, 'pattern_counts': {'":': 4, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '480853', 'license': 'MIT', 'n_tokens_mistral': 3767, 'n_tokens_neox': 3380, 'n_words': 705, 'path': 'Python/02 - Data Merging.ipynb', 'repo_name': 'interactionlab/InfiniTouch', 'size': '10381'}