Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 252 additions & 0 deletions docs/tracking/elm-rats/ELM_tracking.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "fc7f8679",
"metadata": {},
"source": [
"Tracking some rats for now... (data from new session, not already in gcloud)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "50048038",
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "48f7f39a",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from pathlib import Path\n",
"\n",
"# Import Environment Variables\n",
"from dotenv import load_dotenv\n",
"\n",
"# Import Utility Functions\n",
"from collab_env.data.file_utils import expand_path, get_project_root\n",
"from collab_env.data.gcs_utils import GCSClient\n",
"\n",
"# Import Custom Scripts\n",
"from collab_env.tracking.alignment_gui import align_videos\n",
"from collab_env.tracking.model.local_model_inference import infer_with_yolo\n",
"from collab_env.tracking.model.local_model_tracking import (\n",
" output_tracked_bboxes_csv,\n",
" overlay_tracks_on_video,\n",
" plot_tracks_at_frame_bbox_from_video,\n",
" run_tracking,\n",
" visualize_detections_from_video,\n",
")\n",
"from collab_env.tracking.thermal_processing import (\n",
" process_directory,\n",
" validate_session_structure,\n",
")\n",
"import shutil\n",
"import cv2\n",
"import numpy as np\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee16be3b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Session directory /Users/emily/Downloads/2025_07_17-session_0001 already exists. Skipping...\n",
"Session directory /Users/emily/Downloads/2025_07_17-session_0002 already exists. Skipping...\n",
"Session directory /Users/emily/Downloads/2025_07_17-session_0003 already exists. Skipping...\n",
"Moving /Users/emily/Downloads/2025_07_17/Thermal_1/20250717202910847.csq to /Users/emily/Downloads/2025_07_17-session_0004/thermal_1/20250717202910847.csq\n",
"Found 1 .csq files in /Users/emily/Downloads/2025_07_17-session_0004/thermal_1\n",
"\n",
"Processing [0] in thermal_1: 20250717202910847.csq\n",
"Auto-detecting vmin/vmax...\n",
"→ Using vmin=26.0, vmax=35.0\n",
"🖼️ Total frames in video: 2482\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"🔄 Writing frames: 100%|██████████| 2482/2482 [10:18<00:00, 4.01frame/s] \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"✅ Exported 2482 frames to: /Users/emily/Downloads/2025_07_17-session_0004/processed/thermal_1/thermal_26_35.mp4\n",
"⏱ Approx. duration: 82.73 seconds at 30 fps\n",
"⚠️ Folder thermal_2 does not exist in /Users/emily/Downloads/2025_07_17-session_0004. Skipping...\n",
"Moving /Users/emily/Downloads/2025_07_17/Thermal_1/20250717210946836.csq to /Users/emily/Downloads/2025_07_17-session_0005/thermal_1/20250717210946836.csq\n",
"Found 1 .csq files in /Users/emily/Downloads/2025_07_17-session_0005/thermal_1\n",
"\n",
"Processing [0] in thermal_1: 20250717210946836.csq\n",
"Auto-detecting vmin/vmax...\n",
"→ Using vmin=26.0, vmax=36.0\n",
"🖼️ Total frames in video: 42989\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"🔄 Writing frames: 0%| | 92/42989 [00:26<5:50:32, 2.04frame/s]"
]
}
],
"source": [
"# split raw folder into session folders, and convert to mp4, and compute max projection image\n",
"BASE_DIR = '/Users/emily/Downloads/'\n",
"DATE_STR = '2025_07_17'\n",
"RAW_DIR = os.path.join(BASE_DIR, DATE_STR)\n",
"csq_dir = os.path.join(RAW_DIR, \"Thermal_1\")\n",
"csq_files = list(Path(csq_dir).glob(\"*.csq\"))\n",
"for idx, csq in enumerate(csq_files, start=1):\n",
" # Create session directory\n",
" session_dir = os.path.join(BASE_DIR, f\"{DATE_STR}-session_{idx:04d}\")\n",
" # check if session directory already exists\n",
" if os.path.exists(session_dir):\n",
" print(f\"Session directory {session_dir} already exists. Skipping...\")\n",
" continue\n",
" os.makedirs(session_dir, exist_ok=True)\n",
" os.makedirs(os.path.join(session_dir, \"thermal_1\"), exist_ok=True)\n",
" print(f\"Moving {csq} to {os.path.join(session_dir, 'thermal_1', csq.name)}\")\n",
" shutil.copy(csq, os.path.join(session_dir, \"thermal_1\", csq.name))\n",
"\n",
" # Process each session directory\n",
" process_directory(\n",
" folder_path=os.path.join(session_dir),\n",
" out_path=os.path.join(session_dir, \"processed\"),\n",
" color=\"magma\", # 'Grays_r'\n",
" preview=False,\n",
" # max_frames=10,\n",
" fps=30,\n",
" )\n",
"\n",
"\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "cfc1bddd",
"metadata": {},
"outputs": [],
"source": [
"def max_projection_from_video(video_path, out_path):\n",
" \"\"\"\n",
" Compute the maximum projection image from a video file.\n",
" \n",
" Args:\n",
" video_path (str): Path to the input video file.\n",
" out_path (str): Path to save the maximum projection image.\n",
" \"\"\"\n",
" cap = cv2.VideoCapture(video_path)\n",
" ok, frame = cap.read()\n",
" acc = frame.astype(np.uint16)\n",
" while ok:\n",
" acc = np.maximum(acc, frame)\n",
" ok, frame = cap.read()\n",
" cap.release()\n",
" cv2.imwrite(out_path, np.clip(acc, 0, 255).astype(np.uint8))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "10159f4f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0007-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0007-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0004-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0004-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0002-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0002-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0001\n",
"Max projection image saved to /Users/emily/Downloads/2025_07_17-session_0001/processed/max_projection.png\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0001-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0001-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0008\n",
"Max projection image saved to /Users/emily/Downloads/2025_07_17-session_0008/processed/max_projection.png\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0003-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0003-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0008-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0008-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0005-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0005-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0003\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0003/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0006-max_projection.png\n",
"No mp4 files found in /Users/emily/Downloads/2025_07_17-session_0006-max_projection.png/processed/thermal_1\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0004\n",
"Max projection image saved to /Users/emily/Downloads/2025_07_17-session_0004/processed/max_projection.png\n",
"Processing session directory: /Users/emily/Downloads/2025_07_17-session_0002\n",
"Max projection image saved to /Users/emily/Downloads/2025_07_17-session_0002/processed/max_projection.png\n"
]
}
],
"source": [
"# compute max projection image for each session\n",
"\n",
"sessions_list = list(Path(BASE_DIR).glob(f\"{DATE_STR}-session_*\"))\n",
"for session_dir in sessions_list:\n",
" print(f\"Processing session directory: {session_dir}\")\n",
" max_proj_path = os.path.join(session_dir, \"processed\", \"max_projection.png\")\n",
" # find the video file in the processed directory\n",
" mp4_files = list(Path(os.path.join(session_dir, \"processed\", \"thermal_1\")).glob(\"*.mp4\"))\n",
" # check if there are any mp4 files\n",
" if not mp4_files:\n",
" print(f\"No mp4 files found in {os.path.join(session_dir, 'processed', 'thermal_1')}\")\n",
" continue\n",
" video_path = mp4_files[0] \n",
" max_projection_from_video(video_path, max_proj_path)\n",
" # get just the folder name from the session directory\n",
" session_str = os.path.basename(session_dir)\n",
" max_projection_from_video(video_path, os.path.join(BASE_DIR, f'{session_str}-max_projection.png'))\n",
" print(f\"Max projection image saved to {max_proj_path}\")\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "collab-environment",
"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.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading