{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":52950,"databundleVersionId":5973250,"sourceType":"competition"}],"dockerImageVersionId":31012,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:07.221334Z","iopub.execute_input":"2025-05-04T15:03:07.221783Z","iopub.status.idle":"2025-05-04T15:03:07.804083Z","shell.execute_reply.started":"2025-05-04T15:03:07.221757Z","shell.execute_reply":"2025-05-04T15:03:07.802853Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install mediapipe","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:12.801449Z","iopub.execute_input":"2025-05-04T15:03:12.801915Z","iopub.status.idle":"2025-05-04T15:03:16.679584Z","shell.execute_reply.started":"2025-05-04T15:03:12.801892Z","shell.execute_reply":"2025-05-04T15:03:16.678344Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pyarrow.parquet as pq\nfrom mediapipe.framework.formats import landmark_pb2\nimport matplotlib.pyplot as plt\nfrom pathlib import Path\nimport mediapipe\nfrom mediapipe.framework.formats import landmark_pb2\nfrom tqdm.notebook import tqdm\nimport matplotlib\nmatplotlib.rcParams['animation.embed_limit'] = 2**128\nmatplotlib.rcParams['savefig.pad_inches'] = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:26.466534Z","iopub.execute_input":"2025-05-04T15:03:26.466964Z","iopub.status.idle":"2025-05-04T15:03:31.238309Z","shell.execute_reply.started":"2025-05-04T15:03:26.466935Z","shell.execute_reply":"2025-05-04T15:03:31.237512Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_dir = Path('/kaggle/input/asl-fingerspelling/')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:31.245418Z","iopub.execute_input":"2025-05-04T15:03:31.246003Z","iopub.status.idle":"2025-05-04T15:03:31.269706Z","shell.execute_reply.started":"2025-05-04T15:03:31.245974Z","shell.execute_reply":"2025-05-04T15:03:31.268898Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from matplotlib import animation, rc\nrc('animation', html='jshtml')\n\ndef create_animation(images):\n    fig = plt.figure(figsize=(6, 9))\n    ax = plt.Axes(fig, [0., 0., 1., 1.])\n    ax.set_axis_off()\n    fig.add_axes(ax)\n    im=ax.imshow(images[0], cmap=\"gray\")\n    plt.close(fig)\n    \n    def animate_func(i):\n        im.set_array(images[i])\n        return [im]\n\n    return animation.FuncAnimation(fig, animate_func, frames=len(images), interval=1000/10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:32.769253Z","iopub.execute_input":"2025-05-04T15:03:32.769933Z","iopub.status.idle":"2025-05-04T15:03:32.780359Z","shell.execute_reply.started":"2025-05-04T15:03:32.769896Z","shell.execute_reply":"2025-05-04T15:03:32.77933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv(base_dir / 'train.csv')\ntrain_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:35.352846Z","iopub.execute_input":"2025-05-04T15:03:35.353197Z","iopub.status.idle":"2025-05-04T15:03:35.539482Z","shell.execute_reply.started":"2025-05-04T15:03:35.353174Z","shell.execute_reply":"2025-05-04T15:03:35.538743Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_random_sequence(phrase_idx=None):\n    if phrase_idx == None:\n        phrase_idx = np.random.randint(len(train_df))\n\n    selected_row = train_df.iloc[phrase_idx]\n    file_id = selected_row['file_id']\n    sequence_id = selected_row['sequence_id']\n    phrase = selected_row['phrase']\n    \n    parquet_file = pq.ParquetFile(base_dir / 'train_landmarks' / f\"{str(file_id)}.parquet\")\n    \n    dataset = pq.read_table(\n        base_dir / 'train_landmarks' / f\"{str(file_id)}.parquet\",\n        filters=[\n            [('sequence_id', '=', sequence_id)],\n        ]\n    )\n    \n    sequence_df = dataset.to_pandas()\n    return phrase_idx, phrase, sequence_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:38.383648Z","iopub.execute_input":"2025-05-04T15:03:38.384293Z","iopub.status.idle":"2025-05-04T15:03:38.391252Z","shell.execute_reply.started":"2025-05-04T15:03:38.384253Z","shell.execute_reply":"2025-05-04T15:03:38.390039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"phrase_idx = 3\nselected_row = train_df.iloc[phrase_idx]\nfile_id = selected_row['file_id']\nsequence_id = selected_row['sequence_id']\nphrase = selected_row['phrase']\nprint(f\"row: {selected_row.head()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:40.560947Z","iopub.execute_input":"2025-05-04T15:03:40.561636Z","iopub.status.idle":"2025-05-04T15:03:40.567841Z","shell.execute_reply.started":"2025-05-04T15:03:40.56161Z","shell.execute_reply":"2025-05-04T15:03:40.56689Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"parquet_file = pq.ParquetFile(base_dir / 'train_landmarks' / f\"{str(file_id)}.parquet\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:42.525149Z","iopub.execute_input":"2025-05-04T15:03:42.525839Z","iopub.status.idle":"2025-05-04T15:03:42.555388Z","shell.execute_reply.started":"2025-05-04T15:03:42.525811Z","shell.execute_reply":"2025-05-04T15:03:42.554364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = pq.read_table(\n    base_dir / 'train_landmarks' / f\"{str(file_id)}.parquet\",\n    filters=[\n        [('sequence_id', '=', sequence_id)],\n    ]\n)\nsequence_df=dataset.to_pandas()\nsequence_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:53.591134Z","iopub.execute_input":"2025-05-04T15:03:53.591504Z","iopub.status.idle":"2025-05-04T15:03:54.823035Z","shell.execute_reply.started":"2025-05-04T15:03:53.591483Z","shell.execute_reply":"2025-05-04T15:03:54.821995Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mp_pose = mediapipe.solutions.pose\nmp_hands = mediapipe.solutions.hands\nmp_face_mesh = mediapipe.solutions.face_mesh\nmp_drawing = mediapipe.solutions.drawing_utils \nmp_drawing_styles = mediapipe.solutions.drawing_styles","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:03:57.329464Z","iopub.execute_input":"2025-05-04T15:03:57.330191Z","iopub.status.idle":"2025-05-04T15:03:57.334934Z","shell.execute_reply.started":"2025-05-04T15:03:57.330158Z","shell.execute_reply":"2025-05-04T15:03:57.333717Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_hands(seq_df):\n    images = []\n    all_hand_landmarks = []\n    for seq_idx in range(len(seq_df)):\n        x_pose = seq_df.iloc[seq_idx].filter(regex=\"x_right_hand.*\").values\n        y_pose = seq_df.iloc[seq_idx].filter(regex=\"y_right_hand.*\").values\n        z_pose = seq_df.iloc[seq_idx].filter(regex=\"z_right_hand.*\").values\n         \n        right_hand_image = np.zeros((900, 600, 3))\n\n        right_hand_landmarks = landmark_pb2.NormalizedLandmarkList()\n        for x, y, z in zip(x_pose, y_pose, z_pose):\n            right_hand_landmarks.landmark.add(x=x, y=y, z=z)\n        \n        mp_drawing.draw_landmarks(\n                right_hand_image,\n                right_hand_landmarks,\n                mp_hands.HAND_CONNECTIONS,\n                landmark_drawing_spec=mp_drawing_styles.get_default_hand_landmarks_style())\n        \n        x_pose = seq_df.iloc[seq_idx].filter(regex=\"x_left_hand.*\").values\n        y_pose = seq_df.iloc[seq_idx].filter(regex=\"y_left_hand.*\").values\n        z_pose = seq_df.iloc[seq_idx].filter(regex=\"z_left_hand.*\").values\n        \n        left_hand_image = np.zeros((900, 600, 3))\n        \n        left_hand_landmarks = landmark_pb2.NormalizedLandmarkList()\n        for x, y, z in zip(x_pose, y_pose, z_pose):\n            left_hand_landmarks.landmark.add(x=x, y=y, z=z)\n\n        mp_drawing.draw_landmarks(\n                left_hand_image,\n                left_hand_landmarks,\n                mp_hands.HAND_CONNECTIONS,\n                landmark_drawing_spec=mp_drawing_styles.get_default_hand_landmarks_style())\n        \n        images.append([right_hand_image.astype(np.uint8), left_hand_image.astype(np.uint8)])\n        all_hand_landmarks.append([right_hand_landmarks, left_hand_landmarks])\n    return images, all_hand_landmarks","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:04:00.939418Z","iopub.execute_input":"2025-05-04T15:04:00.940597Z","iopub.status.idle":"2025-05-04T15:04:00.949043Z","shell.execute_reply.started":"2025-05-04T15:04:00.940531Z","shell.execute_reply":"2025-05-04T15:04:00.948059Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"hand_images, hand_landmarks = get_hands(sequence_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:04:06.879195Z","iopub.execute_input":"2025-05-04T15:04:06.879428Z","iopub.status.idle":"2025-05-04T15:04:09.478143Z","shell.execute_reply.started":"2025-05-04T15:04:06.879412Z","shell.execute_reply":"2025-05-04T15:04:09.477146Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"create_animation(np.array(hand_images)[:, 0])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:04:50.534303Z","iopub.execute_input":"2025-05-04T15:04:50.535034Z","iopub.status.idle":"2025-05-04T15:04:58.620715Z","shell.execute_reply.started":"2025-05-04T15:04:50.535007Z","shell.execute_reply":"2025-05-04T15:04:58.61968Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"create_animation(np.array(hand_images)[:, 1])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T14:01:42.766774Z","iopub.execute_input":"2025-05-04T14:01:42.767505Z","iopub.status.idle":"2025-05-04T14:01:50.631672Z","shell.execute_reply.started":"2025-05-04T14:01:42.767478Z","shell.execute_reply":"2025-05-04T14:01:50.630732Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"***EXPLAIN***","metadata":{}},{"cell_type":"code","source":"x_pose = sequence_df.iloc[0].filter(regex=\"x_right_hand.*\").values\ny_pose = sequence_df.iloc[0].filter(regex=\"y_right_hand.*\").values\nz_pose = sequence_df.iloc[0].filter(regex=\"z_right_hand.*\").values\n\nright_hand_image = np.zeros((900, 600, 3))\n\nright_hand_landmarks = landmark_pb2.NormalizedLandmarkList()\nfor x, y, z in zip(x_pose, y_pose, z_pose):\n    print(x)\n    print(y)\n    print(z)\n    right_hand_landmarks.landmark.add(x=x, y=y, z=z)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:07:12.327812Z","iopub.execute_input":"2025-05-04T15:07:12.328196Z","iopub.status.idle":"2025-05-04T15:07:12.344217Z","shell.execute_reply.started":"2025-05-04T15:07:12.328174Z","shell.execute_reply":"2025-05-04T15:07:12.343342Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Ảnh ban đầu toàn màu đen\nimage = np.zeros((500, 500, 3), dtype=np.uint8)\n\n# Vẽ landmarks tay (giả sử right_hand_landmarks đã được khởi tạo hợp lệ)\nmp_drawing.draw_landmarks(\n    image, right_hand_landmarks, mp_hands.HAND_CONNECTIONS\n)\n\n# Tìm các pixel đã bị vẽ (khác [0, 0, 0])\nnon_zero_pixels = np.argwhere(np.any(image != 0, axis=-1))\n\n# In một vài pixel để kiểm tra\nprint(f\"Số pixel đã vẽ: {len(non_zero_pixels)}\")\nprint(\"Một vài pixel đã được vẽ:\")\nprint(non_zero_pixels[:10])  # in 10 điểm đầu tiên\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:07:26.151017Z","iopub.execute_input":"2025-05-04T15:07:26.151318Z","iopub.status.idle":"2025-05-04T15:07:26.165797Z","shell.execute_reply.started":"2025-05-04T15:07:26.151298Z","shell.execute_reply":"2025-05-04T15:07:26.164805Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**face**","metadata":{}},{"cell_type":"code","source":"def get_face(seq_df):\n    images = []\n    all_face_landmarks = []\n    for seq_idx in range(len(seq_df)):\n        x_face = seq_df.iloc[seq_idx].filter(regex=\"x_face.*\").values\n        y_face = seq_df.iloc[seq_idx].filter(regex=\"y_face.*\").values\n        z_face = seq_df.iloc[seq_idx].filter(regex=\"z_face.*\").values\n\n        annotated_image = np.zeros((900, 600, 3))\n\n        face_landmarks = landmark_pb2.NormalizedLandmarkList()\n        for x, y, z in zip(x_face, y_face, z_face):\n            face_landmarks.landmark.add(x=x, y=y, z=z)\n\n        mp_drawing.draw_landmarks(\n          image=annotated_image,\n          landmark_list=face_landmarks,\n          connections=mp_face_mesh.FACEMESH_TESSELATION,\n          landmark_drawing_spec=None,\n          connection_drawing_spec=mp_drawing_styles\n          .get_default_face_mesh_tesselation_style())\n        mp_drawing.draw_landmarks(\n          image=annotated_image,\n          landmark_list=face_landmarks,\n          connections=mp_face_mesh.FACEMESH_CONTOURS,\n          landmark_drawing_spec=None,\n          connection_drawing_spec=mp_drawing_styles\n          .get_default_face_mesh_contours_style())\n\n        images.append(annotated_image.astype(np.uint8))\n        all_face_landmarks.append(face_landmarks)\n    return images, all_face_landmarks","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:10:18.56397Z","iopub.execute_input":"2025-05-04T15:10:18.564612Z","iopub.status.idle":"2025-05-04T15:10:18.5717Z","shell.execute_reply.started":"2025-05-04T15:10:18.564588Z","shell.execute_reply":"2025-05-04T15:10:18.570709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"face_images, face_landmarks = get_face(sequence_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:10:20.657593Z","iopub.execute_input":"2025-05-04T15:10:20.657908Z","iopub.status.idle":"2025-05-04T15:10:22.637672Z","shell.execute_reply.started":"2025-05-04T15:10:20.657887Z","shell.execute_reply":"2025-05-04T15:10:22.636925Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"create_animation(face_images)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:10:29.352731Z","iopub.execute_input":"2025-05-04T15:10:29.353077Z","iopub.status.idle":"2025-05-04T15:10:38.085899Z","shell.execute_reply.started":"2025-05-04T15:10:29.353043Z","shell.execute_reply":"2025-05-04T15:10:38.084624Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_pose(seq_df):\n    images = []\n    all_pose_landmarks = []\n    for seq_idx in range(len(seq_df)):\n        x_pose = seq_df.iloc[seq_idx].filter(regex=\"x_pose.*\").values\n        y_pose = seq_df.iloc[seq_idx].filter(regex=\"y_pose.*\").values\n        z_pose = seq_df.iloc[seq_idx].filter(regex=\"z_pose.*\").values\n\n        annotated_image = np.zeros((900, 600, 3))\n        \n        data_points = []\n        for x, y, z in zip(x_pose, y_pose, z_pose):\n            data_points.append(np.array([x, y, z]))\n\n        pose_landmarks = landmark_pb2.NormalizedLandmarkList()\n        for row in data_points:\n            pose_landmarks.landmark.add(x=row[0], y=row[1], z=row[2])\n\n        mp_drawing.draw_landmarks(\n                annotated_image,\n                pose_landmarks,\n                mp_pose.POSE_CONNECTIONS,\n                landmark_drawing_spec=mp_drawing_styles.get_default_pose_landmarks_style())\n        images.append(annotated_image.astype(np.uint8))\n        all_pose_landmarks.append(pose_landmarks)\n    return images, all_pose_landmarks","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:43:56.010128Z","iopub.execute_input":"2025-05-04T15:43:56.011489Z","iopub.status.idle":"2025-05-04T15:43:56.019602Z","shell.execute_reply.started":"2025-05-04T15:43:56.011455Z","shell.execute_reply":"2025-05-04T15:43:56.018479Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pose_images, pose_landmarks = get_pose(sequence_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:44:02.169441Z","iopub.execute_input":"2025-05-04T15:44:02.170194Z","iopub.status.idle":"2025-05-04T15:44:03.507049Z","shell.execute_reply.started":"2025-05-04T15:44:02.170166Z","shell.execute_reply":"2025-05-04T15:44:03.506088Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"create_animation(pose_images)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:44:08.718604Z","iopub.execute_input":"2025-05-04T15:44:08.719313Z","iopub.status.idle":"2025-05-04T15:44:16.76712Z","shell.execute_reply.started":"2025-05-04T15:44:08.719288Z","shell.execute_reply":"2025-05-04T15:44:16.76624Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def convert_landmark_to_npy(landmarklist):\n    return np.array([np.array([landmark.x, landmark.y, landmark.z]) for landmark in landmarklist.landmark])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:53:02.943145Z","iopub.execute_input":"2025-05-04T15:53:02.944004Z","iopub.status.idle":"2025-05-04T15:53:02.948688Z","shell.execute_reply.started":"2025-05-04T15:53:02.943973Z","shell.execute_reply":"2025-05-04T15:53:02.947614Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_all_images(seq_df):\n    pose_images, pose_landmarks = get_pose(sequence_df)\n    hand_images, hand_landmarks = get_hands(sequence_df)\n    face_images, face_landmarks = get_face(sequence_df)\n    \n    all_images = []\n    all_landmarks_data = []\n    all_landmarks = []\n    for seq_idx in tqdm(range(len(pose_landmarks))):\n        pose_landmark_np = convert_landmark_to_npy(pose_landmarks[seq_idx])\n        right_hand_landmark_np = convert_landmark_to_npy(hand_landmarks[seq_idx][0])\n        left_hand_landmark_np = convert_landmark_to_npy(hand_landmarks[seq_idx][1])\n        face_landmark_np = convert_landmark_to_npy(face_landmarks[seq_idx])\n        \n        # Pool all landmarks together to find min and max coordinates\n        pooled_landmarks = np.vstack((pose_landmark_np, right_hand_landmark_np, left_hand_landmark_np, face_landmark_np))\n        pooled_min = np.nanmin(pooled_landmarks, axis=0)\n        pooled_max = np.nanmax(pooled_landmarks, axis=0)\n        \n        # Use the max of x and y scaling to proportionally scale the image. We don't need to scale z for 2D image\n        # There is an elegant way to achieve the same result as below with Matrix transformations. Might re-do this if there is interest.\n        scaling_factor = np.nanmax(pooled_max[:2])\n        pooled_scaled_min = np.nanmin(pooled_landmarks / scaling_factor, axis=0)\n\n        pose_landmark_np_normed = (pose_landmark_np / scaling_factor) - pooled_scaled_min\n        \n        # Center the image around shoulder and hips. Makes for a better visualization\n        x_shift = ((1-(pose_landmark_np_normed[23]+pose_landmark_np_normed[24]))/2)[0]\n        axis_shift = np.array([x_shift, 0, 0])\n        \n        pose_landmark_np_normed = pose_landmark_np_normed + axis_shift\n        right_hand_landmark_np_normed = (right_hand_landmark_np / scaling_factor) - pooled_scaled_min + axis_shift\n        left_hand_landmark_np_normed = (left_hand_landmark_np / scaling_factor) - pooled_scaled_min  + axis_shift\n        face_landmark_np_normed = (face_landmark_np / scaling_factor) - pooled_scaled_min + axis_shift\n        \n        # Now that we have scaled and shifted the landmarks to fit into a [0, 1] range, we can start plotting them using mediapipe APIs\n        # BG image with zeros\n        image = np.zeros((900, 600, 3))\n        \n        # Pose\n        pose_landmark_np_normed_z = landmark_pb2.LandmarkList()\n        for row in pose_landmark_np_normed:\n            pose_landmark_np_normed_z.landmark.add(x=row[0], y=row[1], z=row[2])\n\n        mp_drawing.draw_landmarks(\n                    image,\n                    pose_landmark_np_normed_z,\n                    mp_pose.POSE_CONNECTIONS,\n                    landmark_drawing_spec=mp_drawing_styles.get_default_pose_landmarks_style())\n\n        # Right hand\n        right_hand_landmark_np_normed_z = landmark_pb2.LandmarkList()\n        for row in right_hand_landmark_np_normed:\n            right_hand_landmark_np_normed_z.landmark.add(x=row[0], y=row[1], z=row[2])\n\n        mp_drawing.draw_landmarks(\n                    image,\n                    right_hand_landmark_np_normed_z,\n                    mp_hands.HAND_CONNECTIONS,\n                    landmark_drawing_spec=mp_drawing_styles.get_default_hand_landmarks_style())\n        \n        # Left hand\n        left_hand_landmark_np_normed_z = landmark_pb2.LandmarkList()\n        for row in left_hand_landmark_np_normed:\n            left_hand_landmark_np_normed_z.landmark.add(x=row[0], y=row[1], z=row[2])\n\n        mp_drawing.draw_landmarks(\n                    image,\n                    left_hand_landmark_np_normed_z,\n                    mp_hands.HAND_CONNECTIONS,\n                    landmark_drawing_spec=mp_drawing_styles.get_default_hand_landmarks_style())\n        \n        # Face\n        face_landmark_np_normed_z = landmark_pb2.LandmarkList()\n        for row in face_landmark_np_normed:\n            face_landmark_np_normed_z.landmark.add(x=row[0], y=row[1], z=row[2])\n\n        mp_drawing.draw_landmarks(\n            image=image,\n            landmark_list=face_landmark_np_normed_z,\n            connections=mp_face_mesh.FACEMESH_TESSELATION,\n            landmark_drawing_spec=None,\n            connection_drawing_spec=mp_drawing_styles\n            .get_default_face_mesh_tesselation_style())\n        \n        mp_drawing.draw_landmarks(\n            image=image,\n            landmark_list=face_landmark_np_normed_z,\n            connections=mp_face_mesh.FACEMESH_CONTOURS,\n            landmark_drawing_spec=None,\n            connection_drawing_spec=mp_drawing_styles\n            .get_default_face_mesh_contours_style())\n        \n        # Iris data not available. So ignoring the iris visualization.\n        \n        all_images.append(image.astype(np.uint8))\n        all_landmarks_data.append([pose_landmark_np_normed, right_hand_landmark_np_normed_z, left_hand_landmark_np_normed_z, face_landmark_np_normed_z])\n        all_landmarks.append([pose_landmark_np_normed_z, right_hand_landmark_np_normed_z, left_hand_landmark_np_normed_z, face_landmark_np_normed_z])\n    return all_images, all_landmarks_data, all_landmarks","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:53:05.593985Z","iopub.execute_input":"2025-05-04T15:53:05.594322Z","iopub.status.idle":"2025-05-04T15:53:05.607616Z","shell.execute_reply.started":"2025-05-04T15:53:05.594298Z","shell.execute_reply":"2025-05-04T15:53:05.606574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"phrase_idx, phrase, sequence_df = get_random_sequence(0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:53:10.685418Z","iopub.execute_input":"2025-05-04T15:53:10.686262Z","iopub.status.idle":"2025-05-04T15:53:12.136833Z","shell.execute_reply.started":"2025-05-04T15:53:10.686237Z","shell.execute_reply":"2025-05-04T15:53:12.135792Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"{phrase_idx}: {phrase}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:53:14.649814Z","iopub.execute_input":"2025-05-04T15:53:14.650164Z","iopub.status.idle":"2025-05-04T15:53:14.655469Z","shell.execute_reply.started":"2025-05-04T15:53:14.650137Z","shell.execute_reply":"2025-05-04T15:53:14.654229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"all_images, all_landmarks_data, all_landmarks = get_all_images(sequence_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:53:16.640664Z","iopub.execute_input":"2025-05-04T15:53:16.641335Z","iopub.status.idle":"2025-05-04T15:53:24.365796Z","shell.execute_reply.started":"2025-05-04T15:53:16.641309Z","shell.execute_reply":"2025-05-04T15:53:24.364737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"create_animation(all_images)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T15:53:33.429696Z","iopub.execute_input":"2025-05-04T15:53:33.430075Z","iopub.status.idle":"2025-05-04T15:53:43.790784Z","shell.execute_reply.started":"2025-05-04T15:53:33.430051Z","shell.execute_reply":"2025-05-04T15:53:43.789197Z"}},"outputs":[],"execution_count":null}]}