{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "objc[67861]: Class CaptureDelegate is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_videoio.3.4.16.dylib (0x104544860) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e480). One of the two will be used. Which one is undefined.\n", "objc[67861]: Class CVWindow is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_highgui.3.4.16.dylib (0x103324a68) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e4d0). One of the two will be used. Which one is undefined.\n", "objc[67861]: Class CVView is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_highgui.3.4.16.dylib (0x103324a90) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e4f8). One of the two will be used. Which one is undefined.\n", "objc[67861]: Class CVSlider is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_highgui.3.4.16.dylib (0x103324ab8) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e520). One of the two will be used. Which one is undefined.\n" ] } ], "source": [ "import mediapipe as mp\n", "import cv2\n", "import numpy as np\n", "import pandas as pd\n", "import seaborn as sns\n", "\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "# Drawing helpers\n", "mp_drawing = mp.solutions.drawing_utils\n", "mp_pose = mp.solutions.pose" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. Make some pose detections (Test if Everything works correctly)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(\"../data/plank/20221011_202153.mp4\")\n", "\n", "with mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) as pose:\n", " while cap.isOpened():\n", " ret, image = cap.read()\n", " image = cv2.flip(image, 1)\n", "\n", " if not ret:\n", " break\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n", " image.flags.writeable = False\n", "\n", " results = pose.process(image)\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image.flags.writeable = True\n", " image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n", "\n", " # Draw landmarks and connections\n", " mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, mp_drawing.DrawingSpec(color=(244, 117, 66), thickness=2, circle_radius=4), mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2))\n", "\n", " cv2.imshow(\"CV2\", image)\n", "\n", " # Press Q to close cv2 window\n", " if cv2.waitKey(1) & 0xFF == ord('q'):\n", " break\n", "\n", " cap.release()\n", " cv2.destroyAllWindows()\n", "\n", " # (Optional)Fix bugs cannot close windows in MacOS (https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv)\n", " for i in range (1, 5):\n", " cv2.waitKey(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. Build dataset from collected videos and picture from Kaggle to .csv file for dataset" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import csv\n", "import os" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1 Determine important keypoints and set up important functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are 3 stages that I try to classify for Plank Exercise Correction:\n", "\n", "- Correct: \"C\"\n", "- Back is too low: \"L\"\n", "- Back is too high: \"H\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Determine important landmarks for plank\n", "IMPORTANT_LMS = [\n", " \"NOSE\",\n", " \"LEFT_SHOULDER\",\n", " \"RIGHT_SHOULDER\",\n", " \"LEFT_ELBOW\",\n", " \"RIGHT_ELBOW\",\n", " \"LEFT_WRIST\",\n", " \"RIGHT_WRIST\",\n", " \"LEFT_HIP\",\n", " \"RIGHT_HIP\",\n", " \"LEFT_KNEE\",\n", " \"RIGHT_KNEE\",\n", " \"LEFT_ANKLE\",\n", " \"RIGHT_ANKLE\",\n", " \"LEFT_HEEL\",\n", " \"RIGHT_HEEL\",\n", " \"LEFT_FOOT_INDEX\",\n", " \"RIGHT_FOOT_INDEX\",\n", "]\n", "\n", "# Generate all columns of the data frame\n", "\n", "HEADERS = [\"label\"] # Label column\n", "\n", "for lm in IMPORTANT_LMS:\n", " HEADERS += [f\"{lm.lower()}_x\", f\"{lm.lower()}_y\", f\"{lm.lower()}_z\", f\"{lm.lower()}_v\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Set up important functions*" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def rescale_frame(frame, percent=50):\n", " '''\n", " Rescale a frame to a certain percentage compare to its original frame\n", " '''\n", " width = int(frame.shape[1] * percent/ 100)\n", " height = int(frame.shape[0] * percent/ 100)\n", " dim = (width, height)\n", " return cv2.resize(frame, dim, interpolation = cv2.INTER_AREA)\n", " \n", "\n", "def init_csv(dataset_path: str):\n", " '''\n", " Create a blank csv file with just columns\n", " '''\n", "\n", " # Ignore if file is already exist\n", " if os.path.exists(dataset_path):\n", " return\n", "\n", " # Write all the columns to a empaty file\n", " with open(dataset_path, mode=\"w\", newline=\"\") as f:\n", " csv_writer = csv.writer(f, delimiter=\",\", quotechar='\"', quoting=csv.QUOTE_MINIMAL)\n", " csv_writer.writerow(HEADERS)\n", "\n", "\n", "def export_landmark_to_csv(dataset_path: str, results, action: str) -> None:\n", " '''\n", " Export Labeled Data from detected landmark to csv\n", " '''\n", " landmarks = results.pose_landmarks.landmark\n", " keypoints = []\n", "\n", " try:\n", " # Extract coordinate of important landmarks\n", " for lm in IMPORTANT_LMS:\n", " keypoint = landmarks[mp_pose.PoseLandmark[lm].value]\n", " keypoints.append([keypoint.x, keypoint.y, keypoint.z, keypoint.visibility])\n", " \n", " keypoints = list(np.array(keypoints).flatten())\n", "\n", " # Insert action as the label (first column)\n", " keypoints.insert(0, action)\n", "\n", " # Append new row to .csv file\n", " with open(dataset_path, mode=\"a\", newline=\"\") as f:\n", " csv_writer = csv.writer(f, delimiter=\",\", quotechar='\"', quoting=csv.QUOTE_MINIMAL)\n", " csv_writer.writerow(keypoints)\n", " \n", "\n", " except Exception as e:\n", " print(e)\n", " pass\n", "\n", "\n", "def describe_dataset(dataset_path: str):\n", " '''\n", " Describe dataset\n", " '''\n", "\n", " data = pd.read_csv(dataset_path)\n", " print(f\"Headers: {list(data.columns.values)}\")\n", " print(f'Number of rows: {data.shape[0]} \\nNumber of columns: {data.shape[1]}\\n')\n", " print(f\"Labels: \\n{data['label'].value_counts()}\\n\")\n", " print(f\"Missing values: {data.isnull().values.any()}\\n\")\n", " \n", " duplicate = data[data.duplicated()]\n", " print(f\"Duplicate Rows : {len(duplicate.sum(axis=1))}\")\n", "\n", " return data\n", "\n", "\n", "def remove_duplicate_rows(dataset_path: str):\n", " '''\n", " Remove duplicated data from the dataset then save it to another files\n", " '''\n", " \n", " df = pd.read_csv(dataset_path)\n", " df.drop_duplicates(keep=\"first\", inplace=True)\n", " df.to_csv(f\"cleaned_train.csv\", sep=',', encoding='utf-8', index=False)\n", " \n", "\n", "def concat_csv_files_with_same_headers(file_paths: list, saved_path: str):\n", " '''\n", " Concat different csv files\n", " '''\n", " all_df = []\n", " for path in file_paths:\n", " df = pd.read_csv(path, index_col=None, header=0)\n", " all_df.append(df)\n", " \n", " results = pd.concat(all_df, axis=0, ignore_index=True)\n", " results.to_csv(saved_path, sep=',', encoding='utf-8', index=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2 Extract from video\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO: Created TensorFlow Lite XNNPACK delegate for CPU.\n" ] } ], "source": [ "DATASET_PATH = \"train.csv\"\n", "\n", "cap = cv2.VideoCapture(\"../data/plank/bad/plank_bad_high_4.mp4\")\n", "save_counts = 0\n", "\n", "# init_csv(DATASET_PATH)\n", "\n", "with mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) as pose:\n", " while cap.isOpened():\n", " ret, image = cap.read()\n", "\n", " if not ret:\n", " break\n", "\n", " # Reduce size of a frame\n", " image = rescale_frame(image, 60)\n", " image = cv2.flip(image, 1)\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n", " image.flags.writeable = False\n", "\n", " results = pose.process(image)\n", "\n", " if not results.pose_landmarks: continue\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image.flags.writeable = True\n", " image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n", "\n", " # Draw landmarks and connections\n", " mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, mp_drawing.DrawingSpec(color=(244, 117, 66), thickness=2, circle_radius=4), mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2))\n", "\n", " # Display the saved count\n", " cv2.putText(image, f\"Saved: {save_counts}\", (50, 50), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 0, 0), 2, cv2.LINE_AA)\n", "\n", " cv2.imshow(\"CV2\", image)\n", "\n", " # Pressed key for action\n", " k = cv2.waitKey(1) & 0xFF\n", "\n", " # Press C to save as correct form\n", " if k == ord('c'): \n", " export_landmark_to_csv(DATASET_PATH, results, \"C\")\n", " save_counts += 1\n", " # Press L to save as low back\n", " elif k == ord(\"l\"):\n", " export_landmark_to_csv(DATASET_PATH, results, \"L\")\n", " save_counts += 1\n", " # Press L to save as high back\n", " elif k == ord(\"h\"):\n", " export_landmark_to_csv(DATASET_PATH, results, \"H\")\n", " save_counts += 1\n", "\n", " # Press q to stop\n", " elif k == ord(\"q\"):\n", " break\n", " else: continue\n", "\n", " cap.release()\n", " cv2.destroyAllWindows()\n", "\n", " # (Optional)Fix bugs cannot close windows in MacOS (https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv)\n", " for i in range (1, 5):\n", " cv2.waitKey(1)\n", " " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Headers: ['label', 'nose_x', 'nose_y', 'nose_z', 'nose_v', 'left_shoulder_x', 'left_shoulder_y', 'left_shoulder_z', 'left_shoulder_v', 'right_shoulder_x', 'right_shoulder_y', 'right_shoulder_z', 'right_shoulder_v', 'left_elbow_x', 'left_elbow_y', 'left_elbow_z', 'left_elbow_v', 'right_elbow_x', 'right_elbow_y', 'right_elbow_z', 'right_elbow_v', 'left_wrist_x', 'left_wrist_y', 'left_wrist_z', 'left_wrist_v', 'right_wrist_x', 'right_wrist_y', 'right_wrist_z', 'right_wrist_v', 'left_hip_x', 'left_hip_y', 'left_hip_z', 'left_hip_v', 'right_hip_x', 'right_hip_y', 'right_hip_z', 'right_hip_v', 'left_knee_x', 'left_knee_y', 'left_knee_z', 'left_knee_v', 'right_knee_x', 'right_knee_y', 'right_knee_z', 'right_knee_v', 'left_ankle_x', 'left_ankle_y', 'left_ankle_z', 'left_ankle_v', 'right_ankle_x', 'right_ankle_y', 'right_ankle_z', 'right_ankle_v', 'left_heel_x', 'left_heel_y', 'left_heel_z', 'left_heel_v', 'right_heel_x', 'right_heel_y', 'right_heel_z', 'right_heel_v', 'left_foot_index_x', 'left_foot_index_y', 'left_foot_index_z', 'left_foot_index_v', 'right_foot_index_x', 'right_foot_index_y', 'right_foot_index_z', 'right_foot_index_v']\n", "Number of rows: 28520 \n", "Number of columns: 69\n", "\n", "Labels: \n", "C 9904\n", "L 9546\n", "H 9070\n", "Name: label, dtype: int64\n", "\n", "Missing values: False\n", "\n", "Duplicate Rows : 0\n" ] } ], "source": [ "# csv_files = [os.path.join(\"./\", f) for f in os.listdir(\"./\") if \"csv\" in f]\n", "\n", "# concat_csv_files_with_same_headers(csv_files, \"train.csv\")\n", "\n", "# remove_duplicate_rows(DATASET_PATH)\n", "\n", "df = describe_dataset(DATASET_PATH)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3. Extract from Kaggle dataset ([download here](https://www.kaggle.com/datasets/niharika41298/yoga-poses-dataset))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "FOLDER_PATH = \"../data/kaggle/TRAIN/plank\"\n", "picture_files = [os.path.join(FOLDER_PATH, f) for f in os.listdir(FOLDER_PATH) if os.path.isfile(os.path.join(FOLDER_PATH, f))]\n", "print(f\"Total pictures: {len(picture_files)}\")\n", "\n", "DATASET_PATH = \"./kaggle.csv\"\n", "saved_counts = 0\n", "\n", "init_csv(DATASET_PATH)\n", "\n", "with mp_pose.Pose(min_detection_confidence=0.7, min_tracking_confidence=0.5) as pose:\n", " index = 0\n", " \n", " while True:\n", " if index == len(picture_files):\n", " break\n", " \n", " file_path = picture_files[index]\n", "\n", " image = cv2.imread(file_path)\n", "\n", " # Flip image horizontally for more data\n", " image = cv2.flip(image, 1)\n", "\n", " # get dimensions of image\n", " dimensions = image.shape\n", " \n", " # height, width, number of channels in image\n", " height = image.shape[0]\n", " width = image.shape[1]\n", " channels = image.shape[2]\n", "\n", " # Reduce size of a frame\n", " if width > 1000:\n", " image = rescale_frame(image, 60)\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n", " image.flags.writeable = False\n", "\n", " results = pose.process(image)\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image.flags.writeable = True\n", " image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n", "\n", " # Draw landmarks and connections\n", " mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, mp_drawing.DrawingSpec(color=(244, 117, 66), thickness=2, circle_radius=4), mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2))\n", "\n", " # Display the saved count\n", " cv2.putText(image, f\"Saved: {saved_counts}\", (20, 20), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 0, 0), 2, cv2.LINE_AA)\n", " \n", " cv2.imshow(\"CV2\", image)\n", "\n", " k = cv2.waitKey(1) & 0xFF\n", "\n", " if k == ord('d'): \n", " index += 1\n", "\n", " elif k == ord(\"s\"):\n", " export_landmark_to_csv(DATASET_PATH, results, \"C\")\n", " saved_counts += 1\n", "\n", " elif k == ord(\"f\"):\n", " index += 1\n", " os.remove(file_path)\n", "\n", " elif k == ord(\"q\"):\n", " break\n", "\n", " else:\n", " continue\n", "\n", " # # Press Q to close cv2 window\n", " # if cv2.waitKey(1) & 0xFF == ord('d'):\n", " # index += 1\n", "\n", " # # Press Q to close cv2 window\n", " # if cv2.waitKey(1) & 0xFF == ord('q'):\n", " # break\n", "\n", " # Close cv2 window\n", " cv2.destroyAllWindows()\n", "\n", " # (Optional)Fix bugs cannot close windows in MacOS (https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv)\n", " for i in range (1, 5):\n", " cv2.waitKey(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. Refine Data & Data Visualization" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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d99917oTAACA63Qomvbu3auWlpZ2xz/55BP95je/uealAAAA3OZz/Z6mt956y/nvd955J+zPl7S1tSkQCOhv/uZvOm87AAAAl/hc0fSlL31JHo9HHo/nsk/DxcTE6MUXX+y05QAAANzic0VTTU2NbNvW8OHDVVFRoSFDhjj3RUdHKyEhIey3bAMAAFwvPlc0XfxDuRcuXPhClgEAAHCrDv/tuffee0979+5VfX19u4j6/ve/f82LAQAAuEmHomnz5s36x3/8R8XHx8vn88nj8Tj3eTweogkAAFx3OhRN//zP/6zVq1dr6dKlnb0PAACAK3Xo9zQFg0E99NBDnb0LAACAa3Uomh566CHt2bOns3cBAABwrQ49PXfLLbdoxYoVOnjwoEaNGqU+ffqE3Z+fn98pywEAALhFh6Jp06ZNGjBggMrLy1VeXh52n8fjIZoAAMB1p0PRVFNT09l7AAAAuFqHXtMEAADQ03ToStOsWbOueP8Pf/jDDi0DAADgVh2KpmAwGHa7tbVVR48eVUNDw2X/kC8AAEB316FoKi0tbXfswoULysvL0/Dhw695KQAAALfptNc09erVS9/5zne0bt26zvqUAAAArtGpLwT/n//5H3366aed+SkBAABcoUNPzy1cuDDstm3bqq2t1S9+8QvNnDmzUxYDAABwkw5F05tvvhl2u1evXhoyZIief/75q76zDgAAoDvqUDT9+te/7uw9AAAAXK1D0XTRmTNndPz4cXk8Hv3t3/6thgwZ0ll7AQAAuEqHXgh+/vx5zZo1S0OHDtW9996re+65R0lJSZo9e7Y+/vjjzt4RAAAg4joUTQsXLlR5ebn+4z/+Qw0NDWpoaNDPfvYzlZeXa9GiRZ29IwAAQMR16Om5H//4x/rRj36kiRMnOse+9rWvKSYmRjNmzNCGDRs6az8AAABX6NCVpo8//liJiYntjickJPD0HAAAuC51KJoyMzP1xBNP6JNPPnGONTU16cknn1RmZmanLQcAAOAWHXp6bv369frqV7+qG2+8UXfeeac8Ho+qqqrk9Xq1Z8+ezt4RAAAg4joUTaNGjdL777+v7du3691335Vt23rkkUf06KOPKiYmprN3BAAAiLgORVNRUZESExM1Z86csOM//OEPdebMGS1durRTlgMAAHCLDr2maePGjbr11lvbHb/99tv10ksvXfNSAAAA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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "sns.countplot(x='label', data=df, palette=\"Set1\") " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 5. Extract data for test set" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO: Created TensorFlow Lite XNNPACK delegate for CPU.\n" ] } ], "source": [ "TEST_DATASET_PATH = \"test.csv\"\n", "\n", "cap = cv2.VideoCapture(\"../data/plank/plank_test_4.mp4\")\n", "save_counts = 0\n", "\n", "# init_csv(TEST_DATASET_PATH)\n", "\n", "with mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) as pose:\n", " while cap.isOpened():\n", " ret, image = cap.read()\n", "\n", " if not ret:\n", " break\n", "\n", " # Reduce size of a frame\n", " image = rescale_frame(image, 60)\n", " image = cv2.flip(image, 1)\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n", " image.flags.writeable = False\n", "\n", " results = pose.process(image)\n", "\n", " if not results.pose_landmarks: continue\n", "\n", " # Recolor image from BGR to RGB for mediapipe\n", " image.flags.writeable = True\n", " image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n", "\n", " # Draw landmarks and connections\n", " mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, mp_drawing.DrawingSpec(color=(244, 117, 66), thickness=2, circle_radius=4), mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2))\n", "\n", " # Display the saved count\n", " cv2.putText(image, f\"Saved: {save_counts}\", (50, 50), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 0, 0), 2, cv2.LINE_AA)\n", "\n", " cv2.imshow(\"CV2\", image)\n", "\n", " # Pressed key for action\n", " k = cv2.waitKey(1) & 0xFF\n", "\n", " # Press C to save as correct form\n", " if k == ord('c'): \n", " export_landmark_to_csv(TEST_DATASET_PATH, results, \"C\")\n", " save_counts += 1\n", " # Press L to save as low back\n", " elif k == ord(\"l\"):\n", " export_landmark_to_csv(TEST_DATASET_PATH, results, \"L\")\n", " save_counts += 1\n", " # Press L to save as high back\n", " elif k == ord(\"h\"):\n", " export_landmark_to_csv(TEST_DATASET_PATH, results, \"H\")\n", " save_counts += 1\n", "\n", " # Press q to stop\n", " elif k == ord(\"q\"):\n", " break\n", " else: continue\n", "\n", " cap.release()\n", " cv2.destroyAllWindows()\n", "\n", " # (Optional)Fix bugs cannot close windows in MacOS (https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv)\n", " for i in range (1, 5):\n", " cv2.waitKey(1)\n", " " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Headers: ['label', 'nose_x', 'nose_y', 'nose_z', 'nose_v', 'left_shoulder_x', 'left_shoulder_y', 'left_shoulder_z', 'left_shoulder_v', 'right_shoulder_x', 'right_shoulder_y', 'right_shoulder_z', 'right_shoulder_v', 'left_elbow_x', 'left_elbow_y', 'left_elbow_z', 'left_elbow_v', 'right_elbow_x', 'right_elbow_y', 'right_elbow_z', 'right_elbow_v', 'left_wrist_x', 'left_wrist_y', 'left_wrist_z', 'left_wrist_v', 'right_wrist_x', 'right_wrist_y', 'right_wrist_z', 'right_wrist_v', 'left_hip_x', 'left_hip_y', 'left_hip_z', 'left_hip_v', 'right_hip_x', 'right_hip_y', 'right_hip_z', 'right_hip_v', 'left_knee_x', 'left_knee_y', 'left_knee_z', 'left_knee_v', 'right_knee_x', 'right_knee_y', 'right_knee_z', 'right_knee_v', 'left_ankle_x', 'left_ankle_y', 'left_ankle_z', 'left_ankle_v', 'right_ankle_x', 'right_ankle_y', 'right_ankle_z', 'right_ankle_v', 'left_heel_x', 'left_heel_y', 'left_heel_z', 'left_heel_v', 'right_heel_x', 'right_heel_y', 'right_heel_z', 'right_heel_v', 'left_foot_index_x', 'left_foot_index_y', 'left_foot_index_z', 'left_foot_index_v', 'right_foot_index_x', 'right_foot_index_y', 'right_foot_index_z', 'right_foot_index_v']\n", "Number of rows: 710 \n", "Number of columns: 69\n", "\n", "Labels: \n", "H 241\n", "L 235\n", "C 234\n", "Name: label, dtype: int64\n", "\n", "Missing values: False\n", "\n", "Duplicate Rows : 0\n" ] } ], "source": [ "test_df = describe_dataset(TEST_DATASET_PATH)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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l1psOACAD9OsMzJvvvlm9O3bd4/tW7dubRQ2AACtqVkhM3z48Jg/f37D5d3xcscdd8SIESOaNciECRNi7NixzbotAPDx1KwfLc2aNSvOOeecePHFF2PHjh1x4403xgsvvBBPPvlkLF68uKVnBADYq2adkTnllFPi8ccfj23btsVhhx0Wv//976Nfv37x5JNPxrBhw1p6RgCAvWrWGZmIiCFDhsTcuXNbcpYmq6+vj/r6+obLdXV1ZZkDACivZofMzp0747777osVK1ZEqVSKY445JsaMGROdOzf7Lpts1qxZ8aMf/ajVHwcAaN+aVR3Lly+PMWPGxIYNG+Koo46KiIi//vWv0adPn3jggQdiyJAhLTrkB02fPj2mTp3acLmuri5qa2tb9TEBgPanWSHzne98JwYPHhx//vOfo1evXhER8c4778SECRPi4osvjieffLJFh/ygioqKqKioaNXHAADav2aFzPPPP98oYiIievXqFTNnzozhw4e32HAAAB+mWSFz1FFHxRtvvBGDBw9utH3jxo1x+OGHN3uYzZs3x3PPPddoW+/evWPAgAHNvk8AoONqcsj8+28GXX311XH55ZfHVVddFSeffHJERCxZsiR+/OMfx+zZs5s9zKJFi+KEE05otG38+PFx1113Nfs+AYCOq1QURdGUK3bq1KnRxw/svtnubf9+eefOnS0954eqq6uLqqqqOPN//p/oXHFgmz42AGSy4L/HlXuEBru/f2/evDkqKyubdR9NPiOzcOHCZj0AAEBraXLInH766a05BwDAfvtIf71u27ZtsXbt2ti+fXuj7ccff/xHGgoAoCmaFTJvvvlmfOtb34rf/e53e93f1u+RAQA+npr1oZFTpkyJd955J5YsWRLdu3ePBQsWxNy5c+OII46IBx54oKVnBADYq2adkXn00Ufj17/+dQwfPjw6deoUAwcOjLPOOisqKytj1qxZ8aUvfaml5wQA2EOzzshs3bo1+vbtGxH/+oN1b775ZkT86xOxn3322ZabDgDgQzQrZI466qhYtWpVRER85jOfidtvvz1ee+21uO2226J///4tOiAAwL4060dLU6ZMifXr10dExIwZM+Lss8+On/3sZ9G1a9eYO3duiw4IALAvzQqZCy+8sOHfJ5xwQqxZsyZWrlwZAwYMiEMOOaTFhgMA+DBNDpmpU6c2+U6vv/76Zg0DALA/mhwyS5cubdL1/v3zmAAAWpPPWgIA0mrWby0BALQHQgYASEvIAABpCRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWkIGAEhLyAAAaQkZACAtIQMApCVkAIC0hAwAkJaQAQDSEjIAQFpCBgBIS8gAAGkJGQAgLSEDAKQlZACAtIQMAJCWkAEA0hIyAEBaQgYASEvIAABpCRkAIC0hAwCk1bncA7Ske//X/4jKyspyjwEAtBFnZACAtIQMAJCWkAEA0hIyAEBaQgYASEvIAABpCRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWkIGAEhLyAAAaQkZACAtIQMApCVkAIC0hAwAkJaQAQDSEjIAQFpCBgBIS8gAAGkJGQAgLSEDAKTVudwDtKRvz/tWdOnepdxjAECH8YtvzCv3CB/KGRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWkIGAEhLyAAAaQkZACAtIQMApCVkAIC0hAwAkJaQAQDSEjIAQFpCBgBIS8gAAGkJGQAgLSEDAKQlZACAtIQMAJCWkAEA0hIyAEBaQgYASEvIAABpCRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWkIGAEhLyAAAaQkZACAtIQMApCVkAIC0hAwAkJaQAQDSEjIAQFpCBgBIS8gAAGkJGQAgLSEDAKQlZACAtIQMAJCWkAEA0ipryEyYMCHGjh27x/ZFixZFqVSKTZs2tflMAEAezsgAAGl1LvcAzVFfXx/19fUNl+vq6so4DQBQLinPyMyaNSuqqqoavmpra8s9EgBQBmU/I/Ob3/wmPvGJTzTatnPnzg+9zfTp02Pq1KkNl+vq6sQMAHwMlT1kzjjjjLj11lsbbfvTn/4UX//61/d5m4qKiqioqGjt0QCAdq7sIdOjR484/PDDG2179dVXyzQNAJBJyvfIAABECBkAIDEhAwCkVdb3yNx111173T5y5MgoiqJthwEA0nFGBgBIS8gAAGkJGQAgLSEDAKQlZACAtIQMAJCWkAEA0hIyAEBaQgYASEvIAABpCRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWkIGAEhLyAAAaQkZACAtIQMApCVkAIC0hAwAkJaQAQDSEjIAQFpCBgBIS8gAAGkJGQAgLSEDAKQlZACAtIQMAJCWkAEA0hIyAEBaQgYASEvIAABpCRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWkIGAEirc7kHaEl3fvWnUVlZWe4xAIA24owMAJCWkAEA0hIyAEBaQgYASEvIAABpCRkAIC0hAwCkJWQAgLSEDACQlpABANISMgBAWh3is5aKooiIiLq6ujJPAgA01e7v27u/jzdHhwiZt956KyIiamtryzwJALC/tmzZElVVVc26bYcImd69e0dExNq1a5v9QvDR1dXVRW1tbaxbt86nkJeRdWgfrEP7YB3ah32tQ1EUsWXLlqipqWn2fXeIkOnU6V9v9amqqvIftR2orKy0Du2AdWgfrEP7YB3ah72tw0c9AeHNvgBAWkIGAEirQ4RMRUVFzJgxIyoqKso9yseadWgfrEP7YB3aB+vQPrTmOpSKj/I7TwAAZdQhzsgAAB9PQgYASEvIAABpCRkAIK30IXPLLbfEoEGDolu3bjFs2LD44x//WO6ROrSrrroqSqVSo6/q6uqG/UVRxFVXXRU1NTXRvXv3GDlyZLzwwgtlnLhj+MMf/hDnn39+1NTURKlUivvvv7/R/qa87vX19TF58uQ45JBDokePHvHlL385Xn311TZ8Fvn9p3WYMGHCHsfHySef3Og61uGjmTVrVgwfPjx69uwZffv2jbFjx8aqVasaXcfx0Pqasg5tdTykDpl77rknpkyZEj/4wQ9i6dKl8fnPfz7OPffcWLt2bblH69AGDx4c69evb/hatmxZw75rr702rr/++pgzZ048/fTTUV1dHWeddVZs2bKljBPnt3Xr1hg6dGjMmTNnr/ub8rpPmTIl7rvvvpg3b1489thj8e6778Z5550XO3fubKunkd5/WoeIiHPOOafR8fHb3/620X7r8NEsXrw4LrvssliyZEk89NBDsWPHjhg9enRs3bq14TqOh9bXlHWIaKPjoUjspJNOKi655JJG244++uji+9//fpkm6vhmzJhRDB06dK/7du3aVVRXVxfXXHNNw7Z//vOfRVVVVXHbbbe10YQdX0QU9913X8PlprzumzZtKrp06VLMmzev4TqvvfZa0alTp2LBggVtNntH8sF1KIqiGD9+fDFmzJh93sY6tLyNGzcWEVEsXry4KArHQ7l8cB2Kou2Oh7RnZLZv3x7PPPNMjB49utH20aNHxxNPPFGmqT4eVq9eHTU1NTFo0KD46le/Gi+//HJERLzyyiuxYcOGRmtSUVERp59+ujVpRU153Z955pl4//33G12npqYmjjvuOGvTwhYtWhR9+/aNI488Mr773e/Gxo0bG/ZZh5a3efPmiPj/Hx7seCiPD67Dbm1xPKQNmX/84x+xc+fO6NevX6Pt/fr1iw0bNpRpqo7vc5/7XNx9993x4IMPxh133BEbNmyIU045Jd56662G192atK2mvO4bNmyIrl27Rq9evfZ5HT66c889N37+85/Ho48+Gtddd108/fTTMWrUqKivr48I69DSiqKIqVOnxmmnnRbHHXdcRDgeymFv6xDRdsdD+k+/LpVKjS4XRbHHNlrOueee2/DvIUOGxIgRI+Kwww6LuXPnNryJy5qUR3Ned2vTssaNG9fw7+OOOy5OPPHEGDhwYMyfPz8uuOCCfd7OOjTPpEmT4i9/+Us89thje+xzPLSdfa1DWx0Pac/IHHLIIXHAAQfsUW0bN27co8RpPT169IghQ4bE6tWrG357yZq0raa87tXV1bF9+/Z455139nkdWl7//v1j4MCBsXr16oiwDi1p8uTJ8cADD8TChQvj0EMPbdjueGhb+1qHvWmt4yFtyHTt2jWGDRsWDz30UKPtDz30UJxyyillmurjp76+PlasWBH9+/ePQYMGRXV1daM12b59eyxevNiatKKmvO7Dhg2LLl26NLrO+vXrY/ny5damFb311luxbt266N+/f0RYh5ZQFEVMmjQp7r333nj00Udj0KBBjfY7HtrGf1qHvWm146HJbwtuh+bNm1d06dKluPPOO4sXX3yxmDJlStGjR49izZo15R6tw5o2bVqxaNGi4uWXXy6WLFlSnHfeeUXPnj0bXvNrrrmmqKqqKu69995i2bJlxde+9rWif//+RV1dXZknz23Lli3F0qVLi6VLlxYRUVx//fXF0qVLi7///e9FUTTtdb/kkkuKQw89tHj44YeLZ599thg1alQxdOjQYseOHeV6Wul82Dps2bKlmDZtWvHEE08Ur7zySrFw4cJixIgRxSc/+Unr0IIuvfTSoqqqqli0aFGxfv36hq9t27Y1XMfx0Pr+0zq05fGQOmSKoihuvvnmYuDAgUXXrl2Lz372s41+9YuWN27cuKJ///5Fly5dipqamuKCCy4oXnjhhYb9u3btKmbMmFFUV1cXFRUVxX/9138Vy5YtK+PEHcPChQuLiNjja/z48UVRNO11f++994pJkyYVvXv3Lrp3716cd955xdq1a8vwbPL6sHXYtm1bMXr06KJPnz5Fly5digEDBhTjx4/f4zW2Dh/N3l7/iCh++tOfNlzH8dD6/tM6tOXxUPp/AwEApJP2PTIAAEIGAEhLyAAAaQkZACAtIQMApCVkAIC0hAwAkJaQAQDSEjIAQFpCBuiw1qxZE6VSKZ577rlyjwK0EiEDAKQlZIBWs2vXrpg9e3YcfvjhUVFREQMGDIiZM2dGRMSyZcti1KhR0b179zj44IPj4osvjnfffbfhtiNHjowpU6Y0ur+xY8fGhAkTGi5/6lOfiquvvjouuuii6NmzZwwYMCB+8pOfNOwfNGhQRESccMIJUSqVYuTIka32XIHyEDJAq5k+fXrMnj07rrzyynjxxRfjF7/4RfTr1y+2bdsW55xzTvTq1Suefvrp+OUvfxkPP/xwTJo0ab8f47rrrosTTzwxli5dGhMnToxLL700Vq5cGRERTz31VEREPPzww7F+/fq49957W/T5AeXXudwDAB3Tli1b4sYbb4w5c+bE+PHjIyLisMMOi9NOOy3uuOOOeO+99+Luu++OHj16RETEnDlz4vzzz4/Zs2dHv379mvw4X/ziF2PixIkREXHFFVfEDTfcEIsWLYqjjz46+vTpExERBx98cFRXV7fwMwTaA2dkgFaxYsWKqK+vjzPPPHOv+4YOHdoQMRERp556auzatStWrVq1X49z/PHHN/y7VCpFdXV1bNy4sfmDA6kIGaBVdO/efZ/7iqKIUqm01327t3fq1CmKomi07/3339/j+l26dNnj9rt27drfcYGkhAzQKo444ojo3r17PPLII3vsO/bYY+O5556LrVu3Nmx7/PHHo1OnTnHkkUdGRESfPn1i/fr1Dft37twZy5cv368Zunbt2nBboGMSMkCr6NatW1xxxRXxve99L+6+++546aWXYsmSJXHnnXfGhRdeGN26dYvx48fH8uXLY+HChTF58uT4xje+0fD+mFGjRsX8+fNj/vz5sXLlypg4cWJs2rRpv2bo27dvdO/ePRYsWBBvvPFGbN68uRWeKVBOQgZoNVdeeWVMmzYtfvjDH8YxxxwT48aNi40bN8aBBx4YDz74YLz99tsxfPjw+MpXvhJnnnlmzJkzp+G2F110UYwfPz6++c1vxumnnx6DBg2KM844Y78ev3PnznHTTTfF7bffHjU1NTFmzJiWfopAmZWKD/4QGgAgCWdkAIC0hAwAkJaQAQDSEjIAQFpCBgBIS8gAAGkJGQAgLSEDAKQlZACAtIQMAJCWkAEA0vq/E3SBUUeHU6kAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "sns.countplot(y='label', data=test_df, palette=\"Set1\") " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.13 (conda)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "9260f401923fb5c4108c543a7d176de9733d378b3752e49535ad7c43c2271b65" } } }, "nbformat": 4, "nbformat_minor": 2 }