{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":71885,"databundleVersionId":8069805,"sourceType":"competition"}],"dockerImageVersionId":30673,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## In this notebook we show how to convert the rotations to different representations and visualize them in an interactive way.\n\n## 📝Table of Contents\n* [Import and first glance](#import)\n* [Conversions](#conversions)\n* [EDA of features](#EDA)\n* [Interactive Plots](#inter)","metadata":{}},{"cell_type":"code","source":"# packages\n\n# standard\nimport numpy as np\nimport pandas as pd\n\n# plots\nimport matplotlib.pyplot as plt\nimport plotly.express as px\nimport seaborn as sns","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-17T15:46:23.386791Z","iopub.execute_input":"2024-04-17T15:46:23.387934Z","iopub.status.idle":"2024-04-17T15:46:26.278562Z","shell.execute_reply.started":"2024-04-17T15:46:23.387884Z","shell.execute_reply":"2024-04-17T15:46:26.277646Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Using specific scipy package for transformations/rotations, see here: https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html","metadata":{}},{"cell_type":"code","source":"# import rotation package\nfrom scipy.spatial.transform import Rotation as R","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.280345Z","iopub.execute_input":"2024-04-17T15:46:26.280838Z","iopub.status.idle":"2024-04-17T15:46:26.285464Z","shell.execute_reply.started":"2024-04-17T15:46:26.280810Z","shell.execute_reply":"2024-04-17T15:46:26.284447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# configs\npd.set_option('display.max_columns', None) # we want to display all columns in this notebook\npd.set_option('display.max_colwidth', None) # columns can be as wide as necessary to show full content\n\n# aesthetics\ndefault_color_1 = 'darkblue'\ndefault_color_2 = 'darkgreen'\ndefault_color_3 = 'darkred'","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.286542Z","iopub.execute_input":"2024-04-17T15:46:26.286883Z","iopub.status.idle":"2024-04-17T15:46:26.303866Z","shell.execute_reply.started":"2024-04-17T15:46:26.286856Z","shell.execute_reply":"2024-04-17T15:46:26.302367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='import'></a>\n# Import and first glance","metadata":{}},{"cell_type":"code","source":"# load training data table\ndf_train = pd.read_csv('../input/image-matching-challenge-2024/train/train_labels.csv')\ndf_train.head()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.307998Z","iopub.execute_input":"2024-04-17T15:46:26.308384Z","iopub.status.idle":"2024-04-17T15:46:26.375674Z","shell.execute_reply.started":"2024-04-17T15:46:26.308353Z","shell.execute_reply":"2024-04-17T15:46:26.374675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# image names are NOT unique\ndf_train.image_name.value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.377271Z","iopub.execute_input":"2024-04-17T15:46:26.377624Z","iopub.status.idle":"2024-04-17T15:46:26.391847Z","shell.execute_reply.started":"2024-04-17T15:46:26.377594Z","shell.execute_reply":"2024-04-17T15:46:26.390863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# example:\ndf_train[df_train.image_name=='00011.png']","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.393792Z","iopub.execute_input":"2024-04-17T15:46:26.394178Z","iopub.status.idle":"2024-04-17T15:46:26.410621Z","shell.execute_reply.started":"2024-04-17T15:46:26.394149Z","shell.execute_reply":"2024-04-17T15:46:26.409458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# crosstab of dataset and scene\npd.crosstab(df_train.dataset, df_train.scene)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.412004Z","iopub.execute_input":"2024-04-17T15:46:26.412748Z","iopub.status.idle":"2024-04-17T15:46:26.448493Z","shell.execute_reply.started":"2024-04-17T15:46:26.412709Z","shell.execute_reply":"2024-04-17T15:46:26.447680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Features \"dataset\" and \"scene\" are identical here.","metadata":{}},{"cell_type":"markdown","source":"<a id='conversions'></a>\n# Conversions","metadata":{}},{"cell_type":"code","source":"# convert input string to matrix\ndef get_rotation_matrix_from_string(i_matrix_string):\n    # replace semicolon by comma\n    my_string = i_matrix_string.replace(';',',')\n    # split to list\n    my_list = my_string.split(',')\n    # convert each element from string to double\n    my_list = [float(s) for s in my_list]\n    # convert list to array\n    my_array = np.array(my_list)\n    # convert array to 3x3-matrix\n    rot_matrix = np.asmatrix(my_array.reshape(3,3))\n    return rot_matrix","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.449596Z","iopub.execute_input":"2024-04-17T15:46:26.450391Z","iopub.status.idle":"2024-04-17T15:46:26.455507Z","shell.execute_reply.started":"2024-04-17T15:46:26.450362Z","shell.execute_reply":"2024-04-17T15:46:26.454424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# convert input string to vector\ndef get_translation_from_string(i_vector_string):\n    # replace semicolon by comma\n    my_string = i_vector_string.replace(';',',')\n    # split to list\n    my_list = my_string.split(',')\n    # convert each element from string to double\n    my_list = [float(s) for s in my_list]\n    # convert list to array\n    my_array = np.array(my_list)\n    return my_array","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.456608Z","iopub.execute_input":"2024-04-17T15:46:26.457355Z","iopub.status.idle":"2024-04-17T15:46:26.466493Z","shell.execute_reply.started":"2024-04-17T15:46:26.457327Z","shell.execute_reply":"2024-04-17T15:46:26.465591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# convert matrix (in string representation) to rotation vector\ndef get_rotation_vector(i_matrix_string): \n    mat = get_rotation_matrix_from_string(i_matrix_string)\n    rot = R.from_matrix(mat)\n    vec = rot.as_rotvec()\n    return vec","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.470683Z","iopub.execute_input":"2024-04-17T15:46:26.471454Z","iopub.status.idle":"2024-04-17T15:46:26.477426Z","shell.execute_reply.started":"2024-04-17T15:46:26.471396Z","shell.execute_reply":"2024-04-17T15:46:26.476473Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# convert matrix (in string representation) to Euler angles\ndef get_rotation_angles(i_matrix_string): \n    mat = get_rotation_matrix_from_string(i_matrix_string)\n    rot = R.from_matrix(mat)\n    vec = rot.as_euler('zyx', degrees=True)\n    return vec","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.478504Z","iopub.execute_input":"2024-04-17T15:46:26.478963Z","iopub.status.idle":"2024-04-17T15:46:26.490235Z","shell.execute_reply.started":"2024-04-17T15:46:26.478938Z","shell.execute_reply":"2024-04-17T15:46:26.489194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# convert matrix (in string representation) to quaternion\ndef get_rotation_quaternion(i_matrix_string): \n    mat = get_rotation_matrix_from_string(i_matrix_string)\n    rot = R.from_matrix(mat)\n    vec = rot.as_quat()\n    return vec","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.491333Z","iopub.execute_input":"2024-04-17T15:46:26.492036Z","iopub.status.idle":"2024-04-17T15:46:26.501208Z","shell.execute_reply.started":"2024-04-17T15:46:26.492008Z","shell.execute_reply":"2024-04-17T15:46:26.500022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# example\n\n# matrix\nmy_index = 7\nmy_example_mat = df_train.rotation_matrix[my_index]\nprint('Rotation matrix:')\nprint(get_rotation_matrix_from_string(my_example_mat))\nprint()\nprint('Converted to rotation vector:')\nprint(get_rotation_vector(my_example_mat))\nprint()\nprint('Converted to Euler angles:')\nprint(get_rotation_angles(my_example_mat))\nprint()\nprint('Converted to quaternion:')\nprint(get_rotation_quaternion(my_example_mat))\n\n# translation vector\nmy_example_trans = df_train.translation_vector[my_index]\nprint()\nprint('Translation vector:')\nprint(get_translation_from_string(my_example_trans))","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.502531Z","iopub.execute_input":"2024-04-17T15:46:26.503139Z","iopub.status.idle":"2024-04-17T15:46:26.521163Z","shell.execute_reply.started":"2024-04-17T15:46:26.503108Z","shell.execute_reply":"2024-04-17T15:46:26.519995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# component projection functions\ndef get_rotation_vector_x(i_matrix_string):\n    vec = get_rotation_vector(i_matrix_string)\n    return vec[0]\n\ndef get_rotation_vector_y(i_matrix_string):\n    vec = get_rotation_vector(i_matrix_string)\n    return vec[1]\n\ndef get_rotation_vector_z(i_matrix_string):\n    vec = get_rotation_vector(i_matrix_string)\n    return vec[2]\n\ndef get_rotation_angle_1(i_matrix_string):\n    vec = get_rotation_angles(i_matrix_string)\n    return vec[0]\n\ndef get_rotation_angle_2(i_matrix_string):\n    vec = get_rotation_angles(i_matrix_string)\n    return vec[1]\n\ndef get_rotation_angle_3(i_matrix_string):\n    vec = get_rotation_angles(i_matrix_string)\n    return vec[2]\n\ndef get_translation_x(i_vector_string):\n    vec = get_translation_from_string(i_vector_string)\n    return vec[0]\n\ndef get_translation_y(i_vector_string):\n    vec = get_translation_from_string(i_vector_string)\n    return vec[1]\n\ndef get_translation_z(i_vector_string):\n    vec = get_translation_from_string(i_vector_string)\n    return vec[2]","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.522376Z","iopub.execute_input":"2024-04-17T15:46:26.522823Z","iopub.status.idle":"2024-04-17T15:46:26.531444Z","shell.execute_reply.started":"2024-04-17T15:46:26.522794Z","shell.execute_reply":"2024-04-17T15:46:26.529846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# add rotation vector components and norm to data frame\ndf_train['rot_x'] = df_train.rotation_matrix.apply(get_rotation_vector_x)\ndf_train['rot_y'] = df_train.rotation_matrix.apply(get_rotation_vector_y)\ndf_train['rot_z'] = df_train.rotation_matrix.apply(get_rotation_vector_z)\ndf_train['rot_norm'] = np.sqrt(df_train.rot_x**2 + df_train.rot_y**2 + df_train.rot_z**2)\n\n# add Euler angles (in degrees)\ndf_train['angle_1'] = df_train.rotation_matrix.apply(get_rotation_angle_1)\ndf_train['angle_2'] = df_train.rotation_matrix.apply(get_rotation_angle_2)\ndf_train['angle_3'] = df_train.rotation_matrix.apply(get_rotation_angle_3)\n\n# add translation vector components\ndf_train['trans_x'] = df_train.translation_vector.apply(get_translation_x)\ndf_train['trans_y'] = df_train.translation_vector.apply(get_translation_y)\ndf_train['trans_z'] = df_train.translation_vector.apply(get_translation_z)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:26.532824Z","iopub.execute_input":"2024-04-17T15:46:26.533798Z","iopub.status.idle":"2024-04-17T15:46:26.964669Z","shell.execute_reply.started":"2024-04-17T15:46:26.533687Z","shell.execute_reply":"2024-04-17T15:46:26.963387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='EDA'></a>\n# EDA of features","metadata":{}},{"cell_type":"code","source":"# statistics\nfeatures = ['rot_x','rot_y','rot_z','rot_norm',\n            'angle_1', 'angle_2', 'angle_3',\n            'trans_x', 'trans_y', 'trans_z']\n\ndf_train[features].describe()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:47:05.619074Z","iopub.execute_input":"2024-04-17T15:47:05.619500Z","iopub.status.idle":"2024-04-17T15:47:05.658657Z","shell.execute_reply.started":"2024-04-17T15:47:05.619469Z","shell.execute_reply":"2024-04-17T15:47:05.657292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# distributions\nfor f in features:\n    plt.figure(figsize=(8,3))\n    df_train[f].plot(kind='hist', bins=50, color=default_color_1)\n    plt.title(f)\n    plt.grid()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:27.005398Z","iopub.execute_input":"2024-04-17T15:46:27.005768Z","iopub.status.idle":"2024-04-17T15:46:30.300847Z","shell.execute_reply.started":"2024-04-17T15:46:27.005738Z","shell.execute_reply":"2024-04-17T15:46:30.299534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Correlation of features","metadata":{}},{"cell_type":"code","source":"corr_pearson = df_train[features].corr(method='pearson')\ncorr_spearman = df_train[features].corr(method='spearman')\n\nplt.figure(figsize=(15,5))\nax1 = plt.subplot(1,2,1)\nsns.heatmap(corr_pearson, annot=True, cmap='RdYlGn', vmin=-1, vmax=+1,\n            fmt='.2f', linecolor='black', linewidths=0.5)\nplt.title('Pearson Correlation')\n\nax2 = plt.subplot(1,2,2, sharex=ax1)\nsns.heatmap(corr_spearman, annot=True, cmap='RdYlGn', vmin=-1, vmax=+1,\n            fmt='.2f', linecolor='black', linewidths=0.5)\nplt.title('Spearman Correlation')\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:47:21.631510Z","iopub.execute_input":"2024-04-17T15:47:21.631905Z","iopub.status.idle":"2024-04-17T15:47:22.835793Z","shell.execute_reply.started":"2024-04-17T15:47:21.631876Z","shell.execute_reply":"2024-04-17T15:47:22.834682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# mean of features by dataset\nfeature_means = df_train.groupby(by='dataset')[features].mean()\nfeature_means","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:47:49.378936Z","iopub.execute_input":"2024-04-17T15:47:49.380092Z","iopub.status.idle":"2024-04-17T15:47:49.402599Z","shell.execute_reply.started":"2024-04-17T15:47:49.380045Z","shell.execute_reply":"2024-04-17T15:47:49.401458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='inter'></a>\n# Interactive Plots","metadata":{}},{"cell_type":"code","source":"# interactive 3d plot of rotation vectors\nfig = px.scatter_3d(df_train, \n                    x='rot_x', y='rot_y', z='rot_z',\n                    color='dataset',\n                    hover_data=['image_name'],\n                    opacity=0.5)\nfig.update_traces(marker_size = 4)\nfig.update_layout(title='Rotation Vectors')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:47:52.389033Z","iopub.execute_input":"2024-04-17T15:47:52.389667Z","iopub.status.idle":"2024-04-17T15:47:52.500530Z","shell.execute_reply.started":"2024-04-17T15:47:52.389614Z","shell.execute_reply":"2024-04-17T15:47:52.499485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# interactive 3d plot of Euler angles\nfig = px.scatter_3d(df_train, \n                    x='angle_1', y='angle_2', z='angle_3',\n                    color='dataset',\n                    hover_data=['image_name'],\n                    opacity=0.5)\nfig.update_traces(marker_size = 4)\nfig.update_layout(title='Euler angles')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:33.626306Z","iopub.execute_input":"2024-04-17T15:46:33.626819Z","iopub.status.idle":"2024-04-17T15:46:33.746485Z","shell.execute_reply.started":"2024-04-17T15:46:33.626774Z","shell.execute_reply":"2024-04-17T15:46:33.745355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# interactive 3d plot of translation vectors\nfig = px.scatter_3d(df_train, \n                    x='trans_x', y='trans_y', z='trans_z',\n                    color='dataset',\n                    hover_data=['image_name'],\n                    opacity=0.5)\nfig.update_traces(marker_size = 4)\nfig.update_layout(title='Translation vectors')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T15:46:33.748101Z","iopub.execute_input":"2024-04-17T15:46:33.748624Z","iopub.status.idle":"2024-04-17T15:46:33.868364Z","shell.execute_reply.started":"2024-04-17T15:46:33.748580Z","shell.execute_reply":"2024-04-17T15:46:33.867367Z"},"trusted":true},"execution_count":null,"outputs":[]}]}