From a5270169901a2ad601febe7bb560d6a03769a5fb Mon Sep 17 00:00:00 2001 From: Caspar Addyman Date: Sun, 3 May 2020 14:29:57 +0100 Subject: [PATCH] save cleaned data to a dataframe --- Step0.GettingStarted.ipynb | 22 ++- Step1.ProcessVideo.ipynb | 13 +- Step2.OrganiseData.ipynb | 307 ++++++++++++++++++++++++------------- multiindexdataframe.png | Bin 0 -> 18903 bytes 4 files changed, 229 insertions(+), 113 deletions(-) create mode 100644 multiindexdataframe.png diff --git a/Step0.GettingStarted.ipynb b/Step0.GettingStarted.ipynb index c9f151b..73c49d4 100644 --- a/Step0.GettingStarted.ipynb +++ b/Step0.GettingStarted.ipynb @@ -53,14 +53,14 @@ "source": [ "### 0.2 - Load python libraries\n", "\n", - "There are a handful of python libraries that we use for things like image manipulation, file operations, maths and stats. Many are probably already installed by default such as `os, math, numpy, matplotlib`. Others need adding to our python environment. \n", + "There are a handful of python libraries that we use for things like image manipulation, file operations, maths and stats. Many are probably already installed by default such as `os, math, numpy, pandas, matplotlib`. Others need adding to our python environment. \n", "\n", "**If you are using conda then run the following command to install all the main libraries.**\n", "```\n", - "conda install glob2 opencv \n", + "conda install glob2 opencv pyarrow \n", "```\n", "#### Troubleshooting\n", - "If when you run the code in Steps 1, 2 & 3 you might ee an error like `ModuleNotFoundError: No module named 'glob'` this is because that python module needs to be installed on your computer. If you use Anaconda, the missing module can usually be installed with the command `conda install glob`." + "If when you run the code in Steps 1, 2 & 3 you might see an error like `ModuleNotFoundError: No module named 'glob'` this is because that python module needs to be installed on your computer. If you use Anaconda, the missing module can usually be installed with the command `conda install glob`." ] }, { @@ -91,7 +91,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 0.4 - Using Jupyter with network drives\n", + "## 0.4 SyncPy \n", + "\n", + "The data analysis in Step 3 uses the SyncPy library. This needs to be installed as source code in it's own directory in the same folder and at same level as the current VASC project. So if VASC was installed in your 'Projects' folder, SyncPy should go there too. \n", + "```\n", + "/Caspar/Projects/VASC\n", + "/Caspar/Projects/SyncPy\n", + "```\n", + "https://github.com/infantlab/syncpy " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 0.5 - Using Jupyter with network drives\n", "\n", "By default Jupyter launched from Anaconda Navigator will open it in your home directory. It then might not be possible to access files on a network drive you need to first launch a command window for the correct Jupyter environment. Then use command to launch Jupyter itself. \n", "\n", diff --git a/Step1.ProcessVideo.ipynb b/Step1.ProcessVideo.ipynb index c99395f..a3621cb 100644 --- a/Step1.ProcessVideo.ipynb +++ b/Step1.ProcessVideo.ipynb @@ -101,12 +101,13 @@ "outputs": [], "source": [ "# where's the project folder? (with trailing slash)\n", - "# projectpath = os.getcwd() + \"\\\\..\\\\lookit\\\\\"\n", - "projectpath = \"U:\\\\Caspar\\\\\"\n", + "projectpath = os.getcwd() + \"\\\\..\\\\lookit\\\\\"\n", + "# projectpath = \"U:\\\\Caspar\\\\\"\n", "videos_in = projectpath \n", "\n", "# locations of videos and output\n", - "videos_out = \"E:\\\\SpeakNSign\\\\\" + \"out\"\n", + "# videos_out = \"E:\\\\SpeakNSign\\\\\" + \"out\"\n", + "videos_out = projectpath + \"\\\\out\" \n", "videos_out_openpose = videos_out + \"\\\\openpose\"\n", "videos_out_timeseries = videos_out + \"\\\\timeseries\"\n", "videos_out_analyses = videos_out + \"\\\\analyses\"\n", @@ -321,10 +322,10 @@ "params = dict()\n", "params[\"write_json\"] = videos_out_openpose\n", "# params[\"write_images\"] = videos_out_openpose #for the moment dump images in output file - TODO name subfolder\n", - "params[\"disable_blending\"] = \"true\"\n", + "#params[\"disable_blending\"] = \"false\"\n", "params[\"display\"] = \"1\"\n", "\n", - "createoutputvideo = False #do we get openpose to create a video output?" + "createoutputvideo = True #do we get openpose to create a video output?" ] }, { @@ -564,7 +565,7 @@ " i += 1\n", " #end loop for this video\n", " people = int(max(npeople))\n", - " print(\"Video\", vid, \".\", cam, \"has {0} people detected.\".format(people))\n", + " print(\"Video\", vid, cam, \"has {0} people detected.\".format(people))\n", " videos[vid][cam][\"maxpeople\"] = people\n", " videos[vid][cam][\"v\"] = v #might be useful to have these indices available\n", " videos[vid][cam][\"c\"] = c\n", diff --git a/Step2.OrganiseData.ipynb b/Step2.OrganiseData.ipynb index 3a03650..d0bc144 100644 --- a/Step2.OrganiseData.ipynb +++ b/Step2.OrganiseData.ipynb @@ -30,17 +30,9 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Automatic pdb calling has been turned ON\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "import os #operating system functions\n", "import math #simple math\n", @@ -79,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -97,30 +89,20 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "E:\\SpeakNSign\\out\\openpose\n", - "E:\\SpeakNSign\\out\\timeseries\n", - "E:\\SpeakNSign\\out\\analyses\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# where's the project folder?\n", "jupwd = os.getcwd() + \"\\\\\"\n", - "#projectpath = os.getcwd() + \"\\\\..\\\\lookit\\\\\"\n", - "projectpath = os.getcwd() + \"\\\\\"\n", + "#projectpath = os.getcwd() + \"\\\\..\\\\SpeaknSign\\\\\"\n", + "projectpath = os.getcwd() + \"\\\\..\\\\lookit\\\\\"\n", "\n", "\n", "# locations of videos and output\n", "videos_in = projectpath \n", - "#videos_out = projectpath + \"out\"\n", - "videos_out = \"E:\\\\SpeakNSign\\\\out\"\n", + "videos_out = projectpath + \"out\"\n", + "#videos_out = \"E:\\\\SpeakNSign\\\\out\"\n", "videos_out_openpose = videos_out + \"\\\\openpose\"\n", "videos_out_timeseries = videos_out + \"\\\\timeseries\"\n", "videos_out_analyses = videos_out + \"\\\\analyses\"\n", @@ -132,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -143,28 +125,9 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SS003\n", - "{'shortname': 'SS003.camera1', 'stemname': 'SS003_13314_1', 'fullname': 'SS003_13314_1.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS003\\\\SS003_13314_1.mp4', 'index': 0, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T20:57:56.721680', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS003_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 16760, 'frames': 16760, 'maxpeople': 5, 'v': 0, 'c': 0}\n", - "{'shortname': 'SS003.camera2', 'stemname': 'SS003_13314_2', 'fullname': 'SS003_13314_2.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS003\\\\SS003_13314_2.mp4', 'index': 1, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T21:19:23.117676', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS003_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 16759, 'frames': 13317, 'maxpeople': 6, 'v': 0, 'c': 1}\n", - "{'shortname': 'SS003.camera3', 'stemname': 'SS003_13314_3', 'fullname': 'SS003_13314_3.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS003\\\\SS003_13314_3.mp4', 'index': 2, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T21:36:58.059522', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS003_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 16767, 'frames': 16767, 'maxpeople': 6, 'v': 0, 'c': 2}\n", - "SS010\n", - "{'shortname': 'SS010.camera1', 'stemname': 'PCI_SS010_1', 'fullname': 'PCI_SS010_1.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS010\\\\PCI_SS010_1.mp4', 'index': 3, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T21:53:08.615214', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS010_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 16088, 'frames': 16088, 'maxpeople': 5, 'v': 1, 'c': 0}\n", - "{'shortname': 'SS010.camera2', 'stemname': 'PCI_SS010_2', 'fullname': 'PCI_SS010_2.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS010\\\\PCI_SS010_2.mp4', 'index': 4, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T22:08:39.718074', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS010_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 16107, 'frames': 16107, 'maxpeople': 4, 'v': 1, 'c': 1}\n", - "{'shortname': 'SS010.camera3', 'stemname': 'PCI_SS010_3', 'fullname': 'PCI_SS010_3.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS010\\\\PCI_SS010_3.mp4', 'index': 5, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T22:28:53.638164', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS010_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 16091, 'frames': 8168, 'maxpeople': 4, 'v': 1, 'c': 2}\n", - "SS033\n", - "{'shortname': 'SS033.camera1', 'stemname': 'CAM3_20140918-125924', 'fullname': 'CAM3_20140918-125924.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS033\\\\CAM3_20140918-125924.mp4', 'index': 6, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T22:55:22.151757', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS033_output.avi'}, 'height': 576, 'width': 720, 'fps': 24, 'n_frames': 17932, 'frames': 17932, 'maxpeople': 8, 'v': 2, 'c': 0}\n", - "{'shortname': 'SS033.camera2', 'stemname': 'CAM1_20140918-125924', 'fullname': 'CAM1_20140918-125924.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS033\\\\CAM1_20140918-125924.mp4', 'index': 7, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T23:35:08.924992', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS033_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 17933, 'frames': 17932, 'maxpeople': 5, 'v': 2, 'c': 1}\n", - "{'shortname': 'SS033.camera3', 'stemname': 'CAM2_20140918-125924', 'fullname': 'CAM2_20140918-125924.mp4', 'fullpath': 'U:\\\\Toddler_videos\\\\SS033\\\\CAM2_20140918-125924.mp4', 'index': 8, 'format': '.mp4', 'openpose': {'exitcode': 0, 'when': '2020-04-10T23:51:52.771170', 'out': 'E:\\\\SpeakNSign\\\\out\\\\openpose\\\\SS033_output.avi'}, 'height': 576, 'width': 720, 'fps': 25, 'n_frames': 17933, 'frames': 17933, 'maxpeople': 8, 'v': 2, 'c': 2}\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "#optional - check the json\n", "for vid in videos: \n", @@ -175,33 +138,14 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#can reload the values without recomputing\n", "reloaded = np.load(videos_out_timeseries + '\\\\allframedata.npz')\n", "keypoints_original = reloaded[\"keypoints_array\"] #the unprocessed data\n", - "keypoints_array = np.copy(keypoints_original) #an array where we clean the data." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(3, 3, 17933, 8, 75)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ + "keypoints_array = np.copy(keypoints_original) #an array where we clean the data.\n", "keypoints_array.shape" ] }, @@ -230,9 +174,7 @@ "source": [ "### Step 2.3.1: Which is best camera angle?\n", "\n", - "If we have just one camera then use that. If there are multiple angles, pick the best one and swap it to be \"camera1\". \n", - "\n", - "In " + "If we have just one camera then use that. If there are multiple angles, pick the best one and swap it to be \"camera1\". \n" ] }, { @@ -247,7 +189,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -309,24 +251,9 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "43ec49d2f67d4981aa90b5bb704d8a03", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "canvas = Canvas(width=800, height=600)\n", "\n", @@ -574,7 +501,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 2.7: Save the data!\n", + "## Step 2.7: Save the numpy data!\n", "\n", "Saving the data at this stage so we don't have to repeat these steps again if we reorganise or reanalyse the data.\n", "\n", @@ -589,7 +516,33 @@ "metadata": {}, "outputs": [], "source": [ - "(Not yet implemented.) " + "#update the json file in the video out directory\n", + "with open(videos_out + '\\\\clean.json', 'w') as outfile:\n", + " json.dump(videos, outfile)\n", + "\n", + "# in the time series folder we save the data file. \n", + "#in a compressed format as it has a lot of empty values\n", + "np.savez_compressed(videos_out_timeseries + '\\\\cleandata.npz', keypoints_array=keypoints_array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2.8: Save a pandas dataframe version too.\n", + "\n", + "Most of our analysis will be done with SyncPy which uses pandas dataframes as its main data format. So let's build a multiindex dataframe containing just the data we need. \n", + "\n", + "The rows will have three levels of hierarchy (video x person x BODY25-coordinate). The rows are the individual frames. So a single column will contain the complete time-series of a single dimension of a single point of one person. So in this example: \n", + "```\n", + "rows 0-411 represent the 412 frames of data.\n", + "\n", + "col 0 is x-coordinate of point 0 (nose) of infant in video 'lookit.01'\n", + "col 1 is y-coordinate of point 0 (nose) of infant in video 'lookit.01'\n", + "col 2 is openpose confidence score for how well it identified that point.\n", + "```\n", + "\n", + "\"multiindex\"\n" ] }, { @@ -598,16 +551,164 @@ "metadata": {}, "outputs": [], "source": [ - "#update the json file in the video out directory\n", - "with open(videos_out + '\\\\videos.json', 'w') as outfile:\n", - " json.dump(videos, outfile)\n", + "#optional\n", + "#can reload the clean values without recomputing steps above\n", + "reloaded = np.load(videos_out_timeseries + '\\\\cleandata.npz')\n", + "keypoints_array = reloaded[\"keypoints_array\"] #the unprocessed data\n", + "keypoints_array.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#delete all cameras except 0 \n", + "keypoints_array = np.delete(keypoints_array,np.s_[1:],1)\n", + "#delete all people except 0 & 1\n", + "keypoints_array = np.delete(keypoints_array,np.s_[2:],3)\n", + "shp = keypoints_array.shape\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "first create an empty dataframe with right shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#first list the three levels of row hierarchy\n", + "toplevel = videos.keys()\n", + "participants = [\"infant\",\"parent\"]\n", + "coords = list(range(3*vasc.nPoints)) #we have 3 x 25 coordinates to store\n", "\n", - "# in the time series folder we save the data file. \n", - "#in a compressed format as it has a lot of empty values\n", - "np.savez_compressed(videos_out_timeseries + '\\\\cleandata.npz', keypoints_array=keypoints_array)\n", + "#columns are frames\n", + "timeseries = list(range(shp[2])) #how big is third dimension of the array?\n", + "\n", + "row_names = ['video','person','coord']\n", + "col_names = ['frames']\n", + "\n", + "row_index = pd.MultiIndex.from_product([toplevel,participants,coords], names=row_names)\n", + "\n", + "cleandf = pd.DataFrame(index=row_index, columns=timeseries)\n", + "cleandf.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#first list the three levels of row hierarchy\n", + "toplevel = videos.keys()\n", + "participants = [\"infant\",\"parent\"]\n", + "coords = list(range(3*vasc.nPoints)) #we have 3 x 25 coordinates to store\n", + "\n", + "#columns are frames\n", + "timeseries = list(range(shp[2])) #how big is third dimension of the array?\n", + "\n", + "col_names = ['video','person','coord']\n", + "#row_names = ['frames']\n", + "\n", + "col_index = pd.MultiIndex.from_product([toplevel,participants,coords], names=col_names)\n", + "\n", + "cleandfT = pd.DataFrame(columns=col_index, index = timeseries)\n", + "cleandfT.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then populate the dataframe row by row." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for vid in videos:\n", + " for p in range(2) :\n", + " v = videos[vid][\"camera1\"][\"v\"]\n", + " part = participants[p]\n", + " for r in range(3*vasc.nPoints):\n", + " cleandf.loc[(vid, part, r), :] = keypoints_array[v,0,:,p,r]\n", + " \n", + "cleandf.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for vid in videos:\n", + " for p in range(2) :\n", + " v = videos[vid][\"camera1\"][\"v\"]\n", + " part = participants[p]\n", + " for r in range(3*vasc.nPoints):\n", + " cleandfT[(vid, part, r)] = keypoints_array[v,0,:,p,r]\n", + " \n", + "cleandfT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally save this to a compressed file.\n", + "\n", + "We use the fast `parquet` format with library `pyarrow` in order to preserve our hierarchical index in a compressed format. We save into the timeseries sub-folder. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pyarrow.parquet as pq\n", + "\n", + "pq.write_table(pa.Table.from_pandas(cleandf), videos_out_timeseries + '\\\\cleandata.parquet')\n", "\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('reading parquet file:')\n", + "pqdf = pq.read_table(videos_out_timeseries + '\\\\cleandata.parquet').to_pandas()\n", + "print(pqdf.head())\n" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/multiindexdataframe.png b/multiindexdataframe.png new file mode 100644 index 0000000000000000000000000000000000000000..a20e4185341aa5e07f021262697cdc53c8f0aedb GIT binary patch literal 18903 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 literal 0 HcmV?d00001