This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'release-4.15.0'

# Conflicts:
# README.md
# sample/composeApp/src/commonMain/kotlin/com/nate/posedetection/App.kt
# sample/iosApp/iosApp.xcodeproj/project.pbxproj

+6684 -316
+3
.gitignore
··· 17 17 *yarn.lock 18 18 /gradle.properties 19 19 *.hprof 20 + 21 + # Captured experiment runs from tools/run_experiment.sh and run_auto_experiment.sh. 22 + /experiments/
+1 -1
README.md
··· 11 11 Import the Compose library 12 12 13 13 ```kotlin 14 - implementation("com.performancecoachlab.posedetection:posedetection-compose:4.10.0") 14 + implementation("com.performancecoachlab.posedetection:posedetection-compose:4.13.0") 15 15 ``` 16 16 17 17 Add camera use to your android manifest
+1
collab/Model Training.ipynb
··· 1 + {"cells":[{"cell_type":"markdown","metadata":{"id":"78a2d319"},"source":["# Kima - Basketball Object Detection Model Training\n","\n","### Overview\n","\n","This notebook provides a configurable and automated workflow for training and comparing YOLO models for real-time basketball detection. The objective is to efficiently evaluate different model architectures on various datasets, optimized for lightweight, fast inference suitable for real-time mobile applications.\n","\n","### Enhanced Workflow Features\n","\n","1. **Global Configuration:** A central configuration cell (`Global Configuration`) allows users to define:\n"," * `DATASET_CONFIGS`: A list of Roboflow datasets, each with its API key, workspace, project, version, and a unique alias.\n"," * `MODEL_ARCHITECTURES`: A list of YOLO model variants (e.g., 'yolo11n', 'yolo11s') to be trained and compared.\n"," * `TRAINING_HYPERPARAMETERS`: Common training settings like `epochs`, `imgsz`, `batch`, `patience`, and `device`.\n"," * `Workflow Flags`: Boolean flags to control the execution of specific parts of the notebook, such as `GENERATE_PLOTS` (for dataset analysis plots), `SAVE_TEST_PREDICTION_IMAGES` (for visual test results), and `PERFORM_MODEL_COMPARISON`.\n","\n","2. **Automated Multi-Dataset & Multi-Model Workflow:**\n"," * **Dataset Preparation and Analysis Loop:** The notebook iterates through each defined dataset, automatically downloading it from Roboflow, correcting its `data.yaml` file for Ultralytics compatibility, and performing detailed dataset analysis (class distribution, sample annotated images). All analysis artifacts are saved in dataset-specific folders within the `outputs` directory.\n"," * **Model Training, Validation, and Export Loop:** Nested loops then train each specified YOLO model architecture on every prepared dataset. For each model-dataset combination, the workflow:\n"," * Loads a pre-trained model.\n"," * Trains the model using the global hyperparameters.\n"," * Validates performance, collecting metrics like mAP50, mAP50-95, precision, recall, and inference time.\n"," * Exports the best-trained model to mobile formats: CoreML (`.mlpackage`) for iOS and TFLite (`.tflite`) for Android.\n"," * Generates visual test results (predictions on sample images) to qualitatively assess performance.\n"," All training logs, model weights, exports, and visual tests are saved in uniquely named directories.\n","\n","3. **Comprehensive Comparison Reporting and Visualization:**\n"," * All collected metrics from every model-dataset combination are aggregated into a pandas DataFrame.\n"," * A comparison table is displayed and saved as a CSV file.\n"," * Key comparative visualizations are generated, including:\n"," * Accuracy (mAP50) vs. Speed (Inference Time) scatter plot, with marker size indicating Model Size.\n"," * Bar charts for mAP50, Inference Time, and Model Size.\n"," * Automated recommendations for optimal models are provided based on various criteria (accuracy, speed, balance, size), particularly for real-time mobile deployment.\n","\n","4. **Organized Output Archiving:**\n"," * All generated artifacts (dataset analysis, training runs, exported models, comparison reports, plots) are consolidated into a structured `outputs` directory.\n"," * This entire directory is then compressed into a downloadable zip file, ensuring easy retrieval of all experimental results in Google Colab environments.\n","\n","### Model Architecture\n","\n","We primarily use **YOLOv11 Nano (yolov11n.pt)** and **YOLOv11 Small (yolov11s.pt)** for their balance of speed and accuracy, making them suitable for real-time mobile applications.\n","\n","### Resources\n","\n","- [Ultralytics Documentation](https://docs.ultralytics.com/)\n","- [YOLOv11 GitHub](https://github.com/ultralytics/ultralytics)\n","- **License:** AGPL-3.0 License ([Ultralytics License](https://ultralytics.com/license))"]},{"cell_type":"markdown","metadata":{"id":"rzyauzNMTk8H"},"source":["## Setup & Dependencies\n","\n","Install and verify all required packages for training and exporting the model."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"5dIqXyUiTk8H","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1775418739151,"user_tz":-180,"elapsed":89265,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"outputId":"f2c0d447-7081-40ab-9379-f78aa5d45b7a","collapsed":true},"outputs":[{"output_type":"stream","name":"stdout","text":["\r0% [Working]\r \rHit:1 https://cli.github.com/packages stable InRelease\n","\r0% [Connecting to archive.ubuntu.com (91.189.92.23)] [Connecting to security.ub\r \rGet:2 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ InRelease [3,632 B]\n","Get:3 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64 InRelease [1,581 B]\n","Get:4 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64 Packages [2,482 kB]\n","Hit:5 http://archive.ubuntu.com/ubuntu jammy InRelease\n","Get:6 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]\n","Get:7 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]\n","Get:8 https://r2u.stat.illinois.edu/ubuntu jammy InRelease [6,555 B]\n","Hit:9 https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy InRelease\n","Get:10 https://r2u.stat.illinois.edu/ubuntu jammy/main all Packages [9,980 kB]\n","Hit:11 https://ppa.launchpadcontent.net/graphics-drivers/ppa/ubuntu jammy InRelease\n","Hit:12 https://ppa.launchpadcontent.net/ubuntugis/ppa/ubuntu jammy InRelease\n","Get:13 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1,310 kB]\n","Get:14 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [127 kB]\n","Get:15 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [7,125 kB]\n","Get:16 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [3,844 kB]\n","Get:17 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [4,219 kB]\n","Get:18 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1,622 kB]\n","Get:19 https://r2u.stat.illinois.edu/ubuntu jammy/main amd64 Packages [2,960 kB]\n","Fetched 33.9 MB in 5s (7,183 kB/s)\n","Reading package lists... Done\n","W: Skipping acquire of configured file 'main/source/Sources' as repository 'https://r2u.stat.illinois.edu/ubuntu jammy InRelease' does not seem to provide it (sources.list entry misspelt?)\n","Reading package lists... Done\n","Building dependency tree... Done\n","Reading state information... Done\n","libheif-dev is already the newest version (1.12.0-2build1).\n","libheif-dev set to manually installed.\n","The following additional packages will be installed:\n"," libabsl20210324 libavif13 libgav1-0 libyuv0\n","The following NEW packages will be installed:\n"," libabsl20210324 libavif-dev libavif13 libgav1-0 libyuv0\n","0 upgraded, 5 newly installed, 0 to remove and 59 not upgraded.\n","Need to get 966 kB of archives.\n","After this operation, 3,537 kB of additional disk space will be used.\n","Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 libabsl20210324 amd64 0~20210324.2-2ubuntu0.3 [386 kB]\n","Get:2 http://archive.ubuntu.com/ubuntu jammy/universe amd64 libgav1-0 amd64 0.17.0-1build1 [336 kB]\n","Get:3 http://archive.ubuntu.com/ubuntu jammy/universe amd64 libyuv0 amd64 0.0~git20220104.b91df1a-2 [154 kB]\n","Get:4 http://archive.ubuntu.com/ubuntu jammy/universe amd64 libavif13 amd64 0.9.3-3 [69.5 kB]\n","Get:5 http://archive.ubuntu.com/ubuntu jammy/universe amd64 libavif-dev amd64 0.9.3-3 [21.0 kB]\n","Fetched 966 kB in 2s (488 kB/s)\n","debconf: unable to initialize frontend: Dialog\n","debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 78, <> line 5.)\n","debconf: falling back to frontend: Readline\n","debconf: unable to initialize frontend: Readline\n","debconf: (This frontend requires a controlling tty.)\n","debconf: falling back to frontend: Teletype\n","dpkg-preconfigure: unable to re-open stdin: \n","Selecting previously unselected package libabsl20210324:amd64.\n","(Reading database ... 122354 files and directories currently installed.)\n","Preparing to unpack .../libabsl20210324_0~20210324.2-2ubuntu0.3_amd64.deb ...\n","Unpacking libabsl20210324:amd64 (0~20210324.2-2ubuntu0.3) ...\n","Selecting previously unselected package libgav1-0:amd64.\n","Preparing to unpack .../libgav1-0_0.17.0-1build1_amd64.deb ...\n","Unpacking libgav1-0:amd64 (0.17.0-1build1) ...\n","Selecting previously unselected package libyuv0:amd64.\n","Preparing to unpack .../libyuv0_0.0~git20220104.b91df1a-2_amd64.deb ...\n","Unpacking libyuv0:amd64 (0.0~git20220104.b91df1a-2) ...\n","Selecting previously unselected package libavif13:amd64.\n","Preparing to unpack .../libavif13_0.9.3-3_amd64.deb ...\n","Unpacking libavif13:amd64 (0.9.3-3) ...\n","Selecting previously unselected package libavif-dev:amd64.\n","Preparing to unpack .../libavif-dev_0.9.3-3_amd64.deb ...\n","Unpacking libavif-dev:amd64 (0.9.3-3) ...\n","Setting up libabsl20210324:amd64 (0~20210324.2-2ubuntu0.3) ...\n","Setting up libyuv0:amd64 (0.0~git20220104.b91df1a-2) ...\n","Setting up libgav1-0:amd64 (0.17.0-1build1) ...\n","Setting up libavif13:amd64 (0.9.3-3) ...\n","Setting up libavif-dev:amd64 (0.9.3-3) ...\n","Processing triggers for libc-bin (2.35-0ubuntu3.8) ...\n","/sbin/ldconfig.real: /usr/local/lib/libtbbbind.so.3 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtbbbind_2_5.so.3 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libhwloc.so.15 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtbbbind_2_0.so.3 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtcm_debug.so.1 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtbb.so.12 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libumf.so.1 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libur_adapter_opencl.so.0 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libur_adapter_level_zero_v2.so.0 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libur_loader.so.0 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libur_adapter_level_zero.so.0 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtbbmalloc_proxy.so.2 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtbbmalloc.so.2 is not a symbolic link\n","\n","/sbin/ldconfig.real: /usr/local/lib/libtcm.so.1 is not a symbolic link\n","\n","Collecting ultralytics\n"," Downloading ultralytics-8.4.33-py3-none-any.whl.metadata (39 kB)\n","Collecting roboflow\n"," Downloading roboflow-1.3.1-py3-none-any.whl.metadata (10 kB)\n","Requirement already satisfied: numpy>=1.23.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (2.0.2)\n","Requirement already satisfied: matplotlib>=3.3.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (3.10.0)\n","Requirement already satisfied: opencv-python>=4.6.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (4.13.0.92)\n","Requirement already satisfied: pillow>=7.1.2 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (11.3.0)\n","Requirement already satisfied: pyyaml>=5.3.1 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (6.0.3)\n","Requirement already satisfied: requests>=2.23.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (2.32.4)\n","Requirement already satisfied: scipy>=1.4.1 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (1.16.3)\n","Requirement already satisfied: torch>=1.8.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (2.10.0+cu128)\n","Requirement already satisfied: torchvision>=0.9.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (0.25.0+cu128)\n","Requirement already satisfied: psutil>=5.8.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (5.9.5)\n","Requirement already satisfied: polars>=0.20.0 in /usr/local/lib/python3.12/dist-packages (from ultralytics) (1.35.2)\n","Collecting ultralytics-thop>=2.0.18 (from ultralytics)\n"," Downloading ultralytics_thop-2.0.18-py3-none-any.whl.metadata (14 kB)\n","Requirement already satisfied: certifi in /usr/local/lib/python3.12/dist-packages (from roboflow) (2026.2.25)\n","Collecting idna==3.7 (from roboflow)\n"," Downloading idna-3.7-py3-none-any.whl.metadata (9.9 kB)\n","Requirement already satisfied: cycler in /usr/local/lib/python3.12/dist-packages (from roboflow) (0.12.1)\n","Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.12/dist-packages (from roboflow) (1.5.0)\n","Collecting opencv-python-headless==4.10.0.84 (from roboflow)\n"," Downloading opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (20 kB)\n","Collecting pi-heif<2 (from roboflow)\n"," Downloading pi_heif-1.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (6.3 kB)\n","Collecting pillow-avif-plugin<2 (from roboflow)\n"," Downloading pillow_avif_plugin-1.5.5-cp312-cp312-manylinux_2_28_x86_64.whl.metadata (2.2 kB)\n","Requirement already satisfied: python-dateutil in /usr/local/lib/python3.12/dist-packages (from roboflow) (2.9.0.post0)\n","Requirement already satisfied: python-dotenv in /usr/local/lib/python3.12/dist-packages (from roboflow) (1.2.2)\n","Requirement already satisfied: six in /usr/local/lib/python3.12/dist-packages (from roboflow) (1.17.0)\n","Requirement already satisfied: urllib3>=1.26.6 in /usr/local/lib/python3.12/dist-packages (from roboflow) (2.5.0)\n","Requirement already satisfied: tqdm>=4.41.0 in /usr/local/lib/python3.12/dist-packages (from roboflow) (4.67.3)\n","Requirement already satisfied: requests_toolbelt in /usr/local/lib/python3.12/dist-packages (from roboflow) (1.0.0)\n","Collecting filetype (from roboflow)\n"," Downloading filetype-1.2.0-py2.py3-none-any.whl.metadata (6.5 kB)\n","Requirement already satisfied: typer>=0.12.0 in /usr/local/lib/python3.12/dist-packages (from roboflow) (0.24.1)\n","Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.3.0->ultralytics) (1.3.3)\n","Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.3.0->ultralytics) (4.62.1)\n","Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.3.0->ultralytics) (26.0)\n","Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.3.0->ultralytics) (3.3.2)\n","Requirement already satisfied: polars-runtime-32==1.35.2 in /usr/local/lib/python3.12/dist-packages (from polars>=0.20.0->ultralytics) (1.35.2)\n","Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests>=2.23.0->ultralytics) (3.4.6)\n","Requirement already satisfied: filelock in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (3.25.2)\n","Requirement already satisfied: typing-extensions>=4.10.0 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (4.15.0)\n","Requirement already satisfied: setuptools in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (75.2.0)\n","Requirement already satisfied: sympy>=1.13.3 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (1.14.0)\n","Requirement already satisfied: networkx>=2.5.1 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (3.6.1)\n","Requirement already satisfied: jinja2 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (3.1.6)\n","Requirement already satisfied: fsspec>=0.8.5 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (2025.3.0)\n","Requirement already satisfied: cuda-bindings==12.9.4 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.9.4)\n","Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.8.93 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.8.93)\n","Requirement already satisfied: nvidia-cuda-runtime-cu12==12.8.90 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.8.90)\n","Requirement already satisfied: nvidia-cuda-cupti-cu12==12.8.90 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.8.90)\n","Requirement already satisfied: nvidia-cudnn-cu12==9.10.2.21 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (9.10.2.21)\n","Requirement already satisfied: nvidia-cublas-cu12==12.8.4.1 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.8.4.1)\n","Requirement already satisfied: nvidia-cufft-cu12==11.3.3.83 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (11.3.3.83)\n","Requirement already satisfied: nvidia-curand-cu12==10.3.9.90 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (10.3.9.90)\n","Requirement already satisfied: nvidia-cusolver-cu12==11.7.3.90 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (11.7.3.90)\n","Requirement already satisfied: nvidia-cusparse-cu12==12.5.8.93 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.5.8.93)\n","Requirement already satisfied: nvidia-cusparselt-cu12==0.7.1 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (0.7.1)\n","Requirement already satisfied: nvidia-nccl-cu12==2.27.5 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (2.27.5)\n","Requirement already satisfied: nvidia-nvshmem-cu12==3.4.5 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (3.4.5)\n","Requirement already satisfied: nvidia-nvtx-cu12==12.8.90 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.8.90)\n","Requirement already satisfied: nvidia-nvjitlink-cu12==12.8.93 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (12.8.93)\n","Requirement already satisfied: nvidia-cufile-cu12==1.13.1.3 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (1.13.1.3)\n","Requirement already satisfied: triton==3.6.0 in /usr/local/lib/python3.12/dist-packages (from torch>=1.8.0->ultralytics) (3.6.0)\n","Requirement already satisfied: cuda-pathfinder~=1.1 in /usr/local/lib/python3.12/dist-packages (from cuda-bindings==12.9.4->torch>=1.8.0->ultralytics) (1.5.0)\n","Requirement already satisfied: click>=8.2.1 in /usr/local/lib/python3.12/dist-packages (from typer>=0.12.0->roboflow) (8.3.1)\n","Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.12/dist-packages (from typer>=0.12.0->roboflow) (1.5.4)\n","Requirement already satisfied: rich>=12.3.0 in /usr/local/lib/python3.12/dist-packages (from typer>=0.12.0->roboflow) (13.9.4)\n","Requirement already satisfied: annotated-doc>=0.0.2 in /usr/local/lib/python3.12/dist-packages (from typer>=0.12.0->roboflow) (0.0.4)\n","Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.12/dist-packages (from rich>=12.3.0->typer>=0.12.0->roboflow) (4.0.0)\n","Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.12/dist-packages (from rich>=12.3.0->typer>=0.12.0->roboflow) (2.20.0)\n","Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from sympy>=1.13.3->torch>=1.8.0->ultralytics) (1.3.0)\n","Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.12/dist-packages (from jinja2->torch>=1.8.0->ultralytics) (3.0.3)\n","Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.12/dist-packages (from markdown-it-py>=2.2.0->rich>=12.3.0->typer>=0.12.0->roboflow) (0.1.2)\n","Downloading ultralytics-8.4.33-py3-none-any.whl (1.2 MB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.2/1.2 MB\u001b[0m \u001b[31m78.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hDownloading roboflow-1.3.1-py3-none-any.whl (169 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m169.5/169.5 kB\u001b[0m \u001b[31m20.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hDownloading idna-3.7-py3-none-any.whl (66 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m66.8/66.8 kB\u001b[0m \u001b[31m8.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hDownloading opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (49.9 MB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.9/49.9 MB\u001b[0m \u001b[31m54.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hDownloading pi_heif-1.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.5 MB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.5/1.5 MB\u001b[0m \u001b[31m83.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hDownloading pillow_avif_plugin-1.5.5-cp312-cp312-manylinux_2_28_x86_64.whl (5.5 MB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.5/5.5 MB\u001b[0m \u001b[31m128.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hDownloading ultralytics_thop-2.0.18-py3-none-any.whl (28 kB)\n","Downloading filetype-1.2.0-py2.py3-none-any.whl (19 kB)\n","Installing collected packages: pillow-avif-plugin, filetype, pi-heif, opencv-python-headless, idna, ultralytics-thop, roboflow, ultralytics\n"," Attempting uninstall: opencv-python-headless\n"," Found existing installation: opencv-python-headless 4.13.0.92\n"," Uninstalling opencv-python-headless-4.13.0.92:\n"," Successfully uninstalled opencv-python-headless-4.13.0.92\n"," Attempting uninstall: idna\n"," Found existing installation: idna 3.11\n"," Uninstalling idna-3.11:\n"," Successfully uninstalled idna-3.11\n","Successfully installed filetype-1.2.0 idna-3.7 opencv-python-headless-4.10.0.84 pi-heif-1.3.0 pillow-avif-plugin-1.5.5 roboflow-1.3.1 ultralytics-8.4.33 ultralytics-thop-2.0.18\n","Requirement already satisfied: tensorflow in /usr/local/lib/python3.12/dist-packages (2.19.0)\n","Collecting tflite-support\n"," Downloading tflite-support-0.1.0a1.tar.gz (390 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m390.3/390.3 kB\u001b[0m \u001b[31m29.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n","Requirement already satisfied: absl-py>=1.0.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (1.4.0)\n","Requirement already satisfied: astunparse>=1.6.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (1.6.3)\n","Requirement already satisfied: flatbuffers>=24.3.25 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (25.12.19)\n","Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (0.7.0)\n","Requirement already satisfied: google-pasta>=0.1.1 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (0.2.0)\n","Requirement already satisfied: libclang>=13.0.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (18.1.1)\n","Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (3.4.0)\n","Requirement already satisfied: packaging in /usr/local/lib/python3.12/dist-packages (from tensorflow) (26.0)\n","Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev,>=3.20.3 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (5.29.6)\n","Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (2.32.4)\n","Requirement already satisfied: setuptools in /usr/local/lib/python3.12/dist-packages (from tensorflow) (75.2.0)\n","Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (1.17.0)\n","Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (3.3.0)\n","Requirement already satisfied: typing-extensions>=3.6.6 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (4.15.0)\n","Requirement already satisfied: wrapt>=1.11.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (2.1.2)\n","Requirement already satisfied: grpcio<2.0,>=1.24.3 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (1.80.0)\n","Requirement already satisfied: tensorboard~=2.19.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (2.19.0)\n","Requirement already satisfied: keras>=3.5.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (3.13.2)\n","Requirement already satisfied: numpy<2.2.0,>=1.26.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (2.0.2)\n","Requirement already satisfied: h5py>=3.11.0 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (3.16.0)\n","Requirement already satisfied: ml-dtypes<1.0.0,>=0.5.1 in /usr/local/lib/python3.12/dist-packages (from tensorflow) (0.5.4)\n","Collecting pybind11>=2.4 (from tflite-support)\n"," Using cached pybind11-3.0.3-py3-none-any.whl.metadata (10 kB)\n","Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.12/dist-packages (from astunparse>=1.6.0->tensorflow) (0.46.3)\n","Requirement already satisfied: rich in /usr/local/lib/python3.12/dist-packages (from keras>=3.5.0->tensorflow) (13.9.4)\n","Requirement already satisfied: namex in /usr/local/lib/python3.12/dist-packages (from keras>=3.5.0->tensorflow) (0.1.0)\n","Requirement already satisfied: optree in /usr/local/lib/python3.12/dist-packages (from keras>=3.5.0->tensorflow) (0.19.0)\n","Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests<3,>=2.21.0->tensorflow) (3.4.6)\n","Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests<3,>=2.21.0->tensorflow) (3.7)\n","Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests<3,>=2.21.0->tensorflow) (2.5.0)\n","Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests<3,>=2.21.0->tensorflow) (2026.2.25)\n","Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.12/dist-packages (from tensorboard~=2.19.0->tensorflow) (3.10.2)\n","Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.12/dist-packages (from tensorboard~=2.19.0->tensorflow) (0.7.2)\n","Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from tensorboard~=2.19.0->tensorflow) (3.1.7)\n","Requirement already satisfied: markupsafe>=2.1.1 in /usr/local/lib/python3.12/dist-packages (from werkzeug>=1.0.1->tensorboard~=2.19.0->tensorflow) (3.0.3)\n","Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.12/dist-packages (from rich->keras>=3.5.0->tensorflow) (4.0.0)\n","Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.12/dist-packages (from rich->keras>=3.5.0->tensorflow) (2.20.0)\n","Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.12/dist-packages (from markdown-it-py>=2.2.0->rich->keras>=3.5.0->tensorflow) (0.1.2)\n","Using cached pybind11-3.0.3-py3-none-any.whl (313 kB)\n","Building wheels for collected packages: tflite-support\n"," Building wheel for tflite-support (setup.py) ... \u001b[?25l\u001b[?25hdone\n"," Created wheel for tflite-support: filename=tflite_support-0.1.0a1-cp312-cp312-linux_x86_64.whl size=6343895 sha256=24d6a83ef2ef9a6e708042d025983aa73ab337e2f24284ef6c48fcf3677bb73f\n"," Stored in directory: /root/.cache/pip/wheels/5d/6f/bc/8b85ad0e51d3c8f82c590b321f2c5b35c41fbe84ad93271397\n","Successfully built tflite-support\n","Installing collected packages: pybind11, tflite-support\n","Successfully installed pybind11-3.0.3 tflite-support-0.1.0a1\n"]}],"source":["\n","# Install the system dependencies required to build pillow-avif-plugin\n","!sudo apt-get update && sudo apt-get install -y libavif-dev libheif-dev\n","\n","# Install Ultralytics YOLOv11 and Roboflow\n","!pip install ultralytics roboflow\n","\n","# Install TensorFlow and tflite-support for metadata verification (optional but recommended)\n","!pip install tensorflow tflite-support"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"XVvGyi_fTk8I","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1775418743632,"user_tz":-180,"elapsed":4479,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"outputId":"404e06b2-9b6a-44d4-ec8f-d465973947b1"},"outputs":[{"output_type":"stream","name":"stdout","text":["Ultralytics 8.4.33 🚀 Python-3.12.13 torch-2.10.0+cu128 CUDA:0 (NVIDIA L4, 22563MiB)\n","Setup complete ✅ (12 CPUs, 53.0 GB RAM, 43.4/235.7 GB disk)\n"]}],"source":["# Verify installation\n","import ultralytics\n","ultralytics.checks()"]},{"cell_type":"markdown","metadata":{"id":"74019e8d"},"source":["## Global Configuration\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"67772b77"},"outputs":[],"source":["### Global Configuration\n","\n","# 1. Dataset Configurations\n","# You can define multiple dataset configurations and switch between them.\n","# The 'ALIAS' key can be used to refer to a specific dataset later.\n","# Replace 'YOUR_API_KEY_HERE' with your actual Roboflow API key.\n","DATASET_CONFIGS = [\n"," {\n"," 'ROBOFLOW_API_KEY': '49Mchq1NPmGmyHtYhkkp', # IMPORTANT: Replace with your actual Roboflow API key or use os.getenv()\n"," 'WORKSPACE': 'kima-rbjnn',\n"," 'PROJECT': 'dataset-3k5b6',\n"," 'VERSION': 8,\n"," 'ALIAS': 'dataset'\n"," },\n"," # Add more dataset configurations here if needed\n","]\n","\n","# Select the active dataset configuration by its ALIAS\n","ACTIVE_DATASET_ALIAS = 'dataset'\n","\n","# 2. Model Architectures for Comparison\n","# Define a list of YOLO model variants (e.g., 'yolo11n', 'yolo11s') to train and compare.\n","# Ensure these models are compatible with Ultralytics.\n","MODEL_ARCHITECTURES = ['yolo11n']\n","# MODEL_ARCHITECTURES = ['yolo26n','yolo11n', 'yolo11s', 'yolov8n', 'yolov10n']\n","\n","# 3. Training Hyperparameters\n","# These parameters will be applied to all models during training.\n","TRAINING_HYPERPARAMETERS = {\n"," 'epochs': 100, # Number of training epochs. Use a smaller number (e.g., 1-5) for quick tests.\n"," 'imgsz': 900, # Image size for training and inference. 416 for mobile, 640 for higher accuracy.\n"," 'batch': 8, # Batch size. Adjust based on GPU memory. (imgsz increase, batch decrease)\n"," 'patience': 20, # Early stopping patience. Number of epochs to wait for improvement.\n"," 'device': 0, # GPU device (0 for first GPU). Use 'cpu' if no GPU available.\n"," 'optimizer': 'AdamW', # AdamW = good default for transfer learning (stable, fast convergence).\n"," 'lr0': 0.001, # Initial learning rate. Controls how big each update step is. Too high - unstable, too low - slow learning.\n"," 'lrf': 0.01, # Final learning rate factor. Final LR = lr0 * lrf. Helps fine-tune weights toward the end of training.\n"," 'weight_decay': 0.0005, # Regularization term to prevent overfitting. Penalizes large weights → improves generalization.\n"," #'warmup_epochs': 3.0, # Gradually increases learning rate at the start. Prevents unstable early training (especially with pretrained models).\n"," #'mosaic': 0.0, # Combines 4 images into 1 during training. Improves generalization, but makes objects smaller. Useful, but must be controlled for small objects.\n"," #'close_mosaic': 0, # Disables mosaic in the last N epochs. VERY IMPORTANT: lets model learn real (non-distorted) object sizes.\n"," #'scale': 0.5, # Random zoom in/out (0.5 → 1.5 range). Important for small objects → sometimes makes them larger.\n"," #'translate': 0.1, # Randomly shifts image (10%). Helps model learn object positions more robustly.\n"," #'degrees': 5.0, # Random rotation (±5 degrees). Simulates camera tilt. Keep small for realistic scenes.\n"," #'fliplr': 0.5, # Horizontal flip probability (50%). Very useful for sports scenes (court symmetry).\n","}\n","\n","# 4. Workflow Flags\n","# Control which parts of the notebook workflow to execute.\n","GENERATE_PLOTS = True # Generate and display dataset analysis plots\n","SAVE_TEST_PREDICTION_IMAGES = True # Save predicted images during visual testing\n","PERFORM_MODEL_COMPARISON = True # Run multi-model comparison training and evaluation\n"]},{"cell_type":"markdown","metadata":{"id":"f7a60cca"},"source":["## Dataset Preparation and Analysis Loop\n","This section automates the preparation and initial analysis of each dataset defined in the `DATASET_CONFIGS`. For each dataset, the workflow performs the following key steps:\n","\n","1. **Download from Roboflow**: The dataset is automatically downloaded from Roboflow using the provided API key and project details. This ensures consistency and easy access to data versions.\n","2. **Correct `data.yaml`**: The `data.yaml` configuration file, which Ultralytics models use to locate image and label files, is updated to contain absolute paths. This correction is crucial for seamless integration with the training pipeline.\n","3. **Class Distribution Analysis**: If `GENERATE_PLOTS` is enabled, the distribution of object classes within the training and validation sets is analyzed and visualized. This helps identify potential class imbalances and provides insights into the dataset composition.\n","4. **Sample Annotated Images**: A selection of sample images from the training set, complete with their bounding box annotations, are plotted and saved. This visual check confirms the correctness of annotations and helps in understanding the visual characteristics of the dataset.\n","5. **Dataset Statistics**: Basic statistics, such as the number of images and label files in the training, validation, and test sets, are gathered and displayed to provide a quantitative overview of the dataset's size and structure.\n","\n","All analysis plots and information are saved into dataset-specific subdirectories within the `outputs` folder for organized archiving. The processed dataset information, including the path to the corrected `data.yaml` file, is stored for subsequent model training and evaluation steps."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"fc402fbc","executionInfo":{"status":"ok","timestamp":1775418743923,"user_tz":-180,"elapsed":270,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"colab":{"base_uri":"https://localhost:8080/"},"outputId":"fac54aa9-0d1e-4ee7-889c-c657f27aece5"},"outputs":[{"output_type":"stream","name":"stdout","text":["Initialized imports and 'prepared_datasets_info' list.\n"]}],"source":["import yaml\n","from pathlib import Path\n","import matplotlib.pyplot as plt\n","import matplotlib.patches as patches\n","from PIL import Image\n","import random\n","import os\n","from collections import defaultdict\n","from roboflow import Roboflow\n","\n","# Initialize an empty list to store information about each processed dataset\n","prepared_datasets_info = []\n","\n","print(\"Initialized imports and 'prepared_datasets_info' list.\")"]},{"cell_type":"markdown","metadata":{"id":"c41a63da"},"source":["### Helper Functions\n","\n","This section defines several helper functions used throughout the dataset preparation and analysis process:\n","\n","* `get_class_counts(label_dir, class_names)`: Analyzes YOLO format label files to count instances of each class within a specified directory.\n","* `plot_image_with_bboxes(image_path, label_path, class_names, save_path)`: Visualizes an image with its corresponding YOLO bounding box annotations, saving the result to a specified path.\n","* `get_dataset_stats(image_dir, label_dir)`: Provides basic statistics on the number of images and label files within a given directory pair."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"99adf769","executionInfo":{"status":"ok","timestamp":1775418743954,"user_tz":-180,"elapsed":24,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"colab":{"base_uri":"https://localhost:8080/"},"outputId":"c33563b5-311b-4fec-9650-2c457659b0dd"},"outputs":[{"output_type":"stream","name":"stdout","text":["Helper functions defined.\n"]}],"source":["import yaml\n","from pathlib import Path\n","import matplotlib.pyplot as plt\n","import matplotlib.patches as patches\n","from PIL import Image\n","import random\n","import os\n","from collections import defaultdict\n","from roboflow import Roboflow\n","\n","# a. Function to parse YOLO labels and count classes\n","def get_class_counts(label_dir, class_names):\n"," class_counts = defaultdict(int)\n"," total_annotations = 0\n"," if not label_dir.exists():\n"," print(f\"Warning: Label directory not found: {label_dir}\")\n"," return class_counts, total_annotations\n","\n"," for label_file in label_dir.glob('*.txt'):\n"," with open(label_file, 'r') as f:\n"," for line in f:\n"," parts = line.strip().split()\n"," if parts:\n"," try:\n"," class_id = int(parts[0])\n"," if 0 <= class_id < len(class_names):\n"," class_counts[class_names[class_id]] += 1\n"," total_annotations += 1\n"," except ValueError:\n"," print(f\"Warning: Invalid class_id in file {label_file.name}, line: {line.strip()}\")\n"," return class_counts, total_annotations\n","\n","# b. Function to plot image with bounding boxes\n","def plot_image_with_bboxes(image_path, label_path, class_names, save_path):\n"," try:\n"," img = Image.open(image_path).convert(\"RGB\")\n"," except Exception as e:\n"," print(f\"Error loading image {image_path}: {e}\")\n"," return\n","\n"," fig, ax = plt.subplots(1, figsize=(8, 8))\n"," ax.imshow(img)\n","\n"," img_width, img_height = img.size\n","\n"," if label_path.exists():\n"," with open(label_path, \"r\") as f:\n"," for line in f:\n"," parts = line.strip().split()\n"," if not parts:\n"," continue\n","\n"," try:\n"," class_id = int(parts[0])\n"," coords = [float(p) for p in parts[1:]]\n","\n"," x_min_px = y_min_px = width_px = height_px = None\n","\n"," # Case 1: YOLO bbox format\n"," # class_id x_center y_center width height\n"," if len(coords) == 4:\n"," x_center_norm, y_center_norm, width_norm, height_norm = coords\n","\n"," x_min_px = (x_center_norm - width_norm / 2) * img_width\n"," y_min_px = (y_center_norm - height_norm / 2) * img_height\n"," width_px = width_norm * img_width\n"," height_px = height_norm * img_height\n","\n"," # Case 2: YOLO polygon format\n"," # class_id x1 y1 x2 y2 ...\n"," elif len(coords) > 4 and len(coords) % 2 == 0:\n"," x_coords_norm = coords[0::2]\n"," y_coords_norm = coords[1::2]\n","\n"," min_x_norm = min(x_coords_norm)\n"," max_x_norm = max(x_coords_norm)\n"," min_y_norm = min(y_coords_norm)\n"," max_y_norm = max(y_coords_norm)\n","\n"," x_min_px = min_x_norm * img_width\n"," y_min_px = min_y_norm * img_height\n"," width_px = (max_x_norm - min_x_norm) * img_width\n"," height_px = (max_y_norm - min_y_norm) * img_height\n","\n"," else:\n"," print(\n"," f\"Warning: Unsupported label format in {label_path.name}, \"\n"," f\"line: {line.strip()}\"\n"," )\n"," continue\n","\n"," # Optional: clip box to image bounds\n"," x_min_px = max(0, x_min_px)\n"," y_min_px = max(0, y_min_px)\n"," width_px = max(0, min(width_px, img_width - x_min_px))\n"," height_px = max(0, min(height_px, img_height - y_min_px))\n","\n"," rect = patches.Rectangle(\n"," (x_min_px, y_min_px),\n"," width_px,\n"," height_px,\n"," linewidth=2,\n"," edgecolor=\"r\",\n"," facecolor=\"none\"\n"," )\n"," ax.add_patch(rect)\n","\n"," if 0 <= class_id < len(class_names):\n"," label = class_names[class_id]\n"," else:\n"," label = f\"Class {class_id}\"\n","\n"," text_y = max(0, y_min_px - 5)\n"," ax.text(\n"," x_min_px,\n"," text_y,\n"," label,\n"," color=\"r\",\n"," fontsize=10,\n"," bbox=dict(facecolor=\"white\", alpha=0.7)\n"," )\n","\n"," except ValueError:\n"," print(f\"Warning: Invalid data in label file {label_path.name}, line: {line.strip()}\")\n"," else:\n"," print(f\"Warning: Label file not found for {image_path.name}\")\n","\n"," ax.set_title(image_path.name)\n"," ax.axis(\"off\")\n"," plt.savefig(save_path)\n"," plt.close(fig) # Close the figure\n","\n","# 4. Other Dataset Metrics\n","def get_dataset_stats(image_dir, label_dir):\n"," num_images = len(list(image_dir.glob('*.jpg')) + list(image_dir.glob('*.png')))\n"," num_labels = len(list(label_dir.glob('*.txt')))\n"," return num_images, num_labels\n","\n","print(\"Helper functions defined.\")"]},{"cell_type":"markdown","metadata":{"id":"4d6e4ad6"},"source":["### Main Dataset Processing Loop\n","This loop iterates through each `dataset_config` defined in the `DATASET_CONFIGS` global variable. For each configuration, it performs the following actions:\n","\n","1. **Download Dataset**: Connects to Roboflow using the provided API key and downloads the specified dataset version in YOLOv11 format.\n","2. **Correct `data.yaml`**: Reads the downloaded `data.yaml` file, extracts class information, and modifies the image and label paths to be absolute, ensuring compatibility with Ultralytics.\n","3. **Perform Dataset Analysis (if enabled)**: If `GENERATE_PLOTS` is `True`:\n"," * Calculates and prints the class distribution for both training and validation sets.\n"," * Generates and saves bar charts visualizing the class distribution.\n"," * Selects and displays sample images with their bounding box annotations, prioritizing images that represent distinct classes, saving them to a dedicated directory.\n","4. **Display Dataset Statistics**: Reports the number of images and label files for the training, validation, and test splits.\n","5. **Store Dataset Information**: Gathers all relevant paths and metadata for the processed dataset and appends it to the `prepared_datasets_info` list, which will be used in subsequent training and comparison steps."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"b790bb44","executionInfo":{"status":"ok","timestamp":1775418768667,"user_tz":-180,"elapsed":24295,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"colab":{"base_uri":"https://localhost:8080/","height":1000},"outputId":"093e033b-dbe8-41ff-fb4b-08a0a69d456f"},"outputs":[{"output_type":"stream","name":"stdout","text":["\n","================================================================================\n","Processing Dataset: dataset\n","================================================================================\n","loading Roboflow workspace...\n","loading Roboflow project...\n","Exporting format yolov11 in progress : 92.0%\n","Version export complete for yolov11 format\n"]},{"output_type":"stream","name":"stderr","text":["Downloading Dataset Version Zip in Dataset-8 to yolov11:: 100%|██████████| 162055/162055 [00:12<00:00, 13408.35it/s]"]},{"output_type":"stream","name":"stdout","text":["\n"]},{"output_type":"stream","name":"stderr","text":["\n","Extracting Dataset Version Zip to Dataset-8 in yolov11:: 100%|██████████| 3916/3916 [00:00<00:00, 6711.31it/s]\n"]},{"output_type":"stream","name":"stdout","text":["Dataset 'dataset' downloaded to: /content/Dataset-8\n","Dataset analysis outputs will be saved to: outputs/dataset/dataset_analysis\n","Number of classes (nc): 2\n","Class Names: ['basketball', 'basketball_hoop']\n","Modified data.yaml saved to: /content/Dataset-8/data_corrected.yaml\n","\n","--- Class Distribution Analysis ---\n","Training Set Class Distribution (Total Annotations: 5325):\n"," basketball: 2640\n"," basketball_hoop: 2685\n","\n","Validation Set Class Distribution (Total Annotations: 451):\n"," basketball_hoop: 274\n"," basketball: 177\n"]},{"output_type":"display_data","data":{"text/plain":["<Figure size 1500x600 with 2 Axes>"],"image/png":"iVBORw0KGgoAAAANSUhEUgAABdEAAAJOCAYAAABYwk4SAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAh8ZJREFUeJzs3Xl4THf/xvF7ErJLCLI9CFW72FtiidgSqotK7VVbq0tQ9GetIrS0qpRa2ypatGjRhypiV6K11q6lSltCa0kIsp7fH67MY5oMmZhIwvt1XXPVnPOdcz5nsswnd8/5HpNhGIYAAAAAAAAAAEAGDrldAAAAAAAAAAAAeRUhOgAAAAAAAAAAVhCiAwAAAAAAAABgBSE6AAAAAAAAAABWEKIDAAAAAAAAAGAFIToAAAAAAAAAAFYQogMAAAAAAAAAYAUhOgAAAAAAAAAAVhCiAwAAAAAAAABgBSE6gAdO9+7dVbp06Wy9dvTo0TKZTPYt6AF1L+9zXrJ582aZTCZt3rw5x/eV2feXyWRSnz59cnzfkjRv3jyZTCb9/vvv92V/AAAgf/r9999lMpk0b9488zJb+mSTyaTRo0fbtabQ0FCFhobadZsPovvZ2+a00qVLq3v37jm+n8y+37t37y4PD48c33e6nPiZAWBfhOgA7huTyZSlx4PQ8GXXypUr1bhxY/n4+MjNzU2PPPKI2rdvrzVr1mRre+PGjdOKFStsek18fLyioqJUvXp1eXh4yNXVVVWrVtWQIUN09uzZbNVxv6Q3wOmPggULqlixYqpfv76GDx+uM2fO2G1f2Xlv75e8XBsAALCvp59+Wm5ubrp69arVMV26dJGTk5MuXrx4Hyuz3ZEjRzR69Og89z/8f//9d/Xo0UNly5aVi4uL/Pz8FBISolGjRmVre6tXr85WYLp8+XK1atVKxYoVk5OTkwICAtS+fXtt3LgxW3XcT6GhoeYe3cHBQZ6enqpQoYK6du2q6Ohou+0nu+/t/ZCXawNwdybDMIzcLgLAw2HBggUWzz///HNFR0friy++sFjeokUL+fr6Zns/ycnJSktLk7Ozs82vTUlJUUpKilxcXLK9/+yaOHGiBg0apMaNG+uZZ56Rm5ubTpw4ofXr16t69eoWZ0ZklYeHh5577rksv/a3335T8+bNdebMGbVr104NGzaUk5OTDhw4oC+//FLe3t765ZdfJN06O2Pz5s156o+c33//XWXKlFGnTp30xBNPKC0tTZcvX9auXbu0bNkymUwmzZkzRx07djS/Ji0tTUlJSXJycpKDQ9b/37Kt762U+feXyWRSZGSkpk2bluXtZLe21NRUJScny9nZmSsuAAB4QCxevFgdO3bU/Pnz9cILL2RYf/36dfn4+Khp06b673//m6VtpvdUc+fONZ8JbEufbDKZNGrUKJsDw6+//lrt2rXTpk2bMpx1npSUJElycnKyaZv36sSJE3rsscfk6uqqnj17qnTp0jp37pz27t2r77//Xjdv3rR5m3369NH06dOV1TjGMAz17NlT8+bNU82aNfXcc8/Jz89P586d0/Lly7Vnzx5t375d9evX1+bNm9WkSZNM38PcFBoaqpMnT2r8+PGSpISEBJ04cULLli3Tb7/9pvbt22vBggUqWLCg+TWJiYlycHCwWHY3tr630q33NzExUQULFpSjo6OkW3/rfP3117p27VqWt3Mvtd28eVMFChRQgQIF7LY/APbFTyeA++b555+3eL5z505FR0dnWP5v169fl5ubW5b3Y0uT9W+51bikpKRo7NixatGihdatW5dh/YULF+5LDW3bttX58+e1efNmNWzY0GL9O++8o/feey/H67CHWrVqZfi+On36tMLCwtStWzdVqlRJ1atXlyQ5ODjk+P80SUhIkLu7e643xo6OjuY/DAAAwIPh6aefVqFChbRo0aJMQ/Rvv/1WCQkJ6tKlyz3tJ7f7mPsdnqebPHmyrl27pv379yswMNBi3f3o0SXpgw8+0Lx589S/f39NmjTJ4mSIN998U1988UW+CF+9vLwy9Ojvvvuu+vXrpxkzZqh06dIWf29k56QoW6SkpCgtLU1OTk65chLV7XJ7/wDujulcAOQpoaGhqlq1qvbs2aOQkBC5ublp+PDhkm79AdC6dWsFBATI2dlZZcuW1dixY5WammqxjX/P1Z0+xcfEiRP18ccfq2zZsnJ2dtZjjz2mXbt2Wbz2TnNWr1ixQlWrVpWzs7OqVKmS6RQrmzdvVp06deTi4qKyZctq9uzZWZo/8p9//lF8fLwaNGiQ6XofHx+L54mJiRo1apQeffRROTs7q2TJkho8eLASExMt6k5ISND8+fPNl07eaU7Bb775Rj///LPefPPNDAG6JHl6euqdd96543FMnDhR9evXV9GiReXq6qratWvr66+/zjAuOjpaDRs2VOHCheXh4aEKFSqYv87pPvroI1WpUkVubm4qUqSI6tSpo0WLFt1x/3cSGBioefPmKSkpSRMmTDAvz2zeyF9//VURERHy8/OTi4uLSpQooY4dOyouLk7Snd/b9K/3kSNH1LlzZxUpUsT8ft7pe2HhwoWqUKGCXFxcVLt2bW3dutVivbU56P+9zTvVZm1O9BkzZqhKlSpydnZWQECAIiMjdeXKFYsx6T+bR44cUZMmTeTm5qb//Oc/Fu8lAAC4/1xdXdW2bVtt2LAh01B30aJFKlSokJ5++mldunRJ//d//6egoCB5eHjI09NTrVq10s8//3zX/WTWxyQmJmrAgAEqXry4eR9//vlnhteePn1ar732mipUqCBXV1cVLVpU7dq1s+hJ5s2bp3bt2kmSmjRpkmGqx8zmRL9w4YJ69eolX19fubi4qHr16po/f77FGFv+FsjMyZMnVaJEiQwBupSxR5ek77//Xo0aNZK7u7sKFSqk1q1b6/Dhw+b13bt31/Tp0yVZTndpzY0bNzR+/HhVrFhREydOzHRs165d9fjjj1vdxrZt29SuXTuVKlXK/LfDgAEDdOPGDYtxsbGx6tGjh0qUKCFnZ2f5+/vrmWeesfg67d69W+Hh4SpWrJhcXV1VpkwZ9ezZ0+q+78bR0VFTp05V5cqVNW3aNHO/LWWcEz05OVlRUVEqV66cXFxcVLRoUTVs2NA8Hcyd3tvbvw8+/PBD8/fBkSNHMp0TPd1vv/2m8PBwubu7KyAgQGPGjLE4k9zaHPT/3ubdvu6ZzYm+b98+tWrVSp6envLw8FCzZs20c+dOizHp/f327ds1cOBAFS9eXO7u7nr22Wf1999/3/0LACDL8v7/qgTw0Ll48aJatWqljh076vnnnzdP7TJv3jx5eHho4MCB8vDw0MaNGzVy5EjFx8fr/fffv+t2Fy1apKtXr+rll1+WyWTShAkT1LZtW/322293PXv9hx9+0LJly/Taa6+pUKFCmjp1qiIiInTmzBkVLVpU0q0mp2XLlvL391dUVJRSU1M1ZswYFS9e/K61+fj4yNXVVStXrlTfvn3l7e1tdWxaWpqefvpp/fDDD+rdu7cqVaqkgwcPavLkyfrll1/Mc2F/8cUXevHFF/X444+rd+/ekqSyZcta3W765b1du3a9a73WTJkyRU8//bS6dOmipKQkffXVV2rXrp1WrVql1q1bS5IOHz6sJ598UtWqVdOYMWPk7OysEydOaPv27ebtfPLJJ+rXr5+ee+45vf7667p586YOHDigH3/8UZ07d852fcHBwSpbtuwd511MSkpSeHi4EhMT1bdvX/n5+emvv/7SqlWrdOXKFXl5eWXpvW3Xrp3KlSuncePG3fVy0i1btmjx4sXq16+fnJ2dNWPGDLVs2VI//fSTqlatatMx2vp1Hz16tKKiotS8eXO9+uqrOn78uGbOnKldu3Zp+/btFj8bly9fVsuWLdW2bVu1b99eX3/9tYYMGaKgoCC1atXKpjoBAID9dOnSRfPnz9eSJUssblh+6dIlrV27Vp06dZKrq6sOHz6sFStWqF27dipTpozOnz+v2bNnq3Hjxjpy5IgCAgJs2u+LL76oBQsWqHPnzqpfv742btxo7vlut2vXLu3YsUMdO3ZUiRIl9Pvvv2vmzJkKDQ3VkSNH5ObmppCQEPXr109Tp07V8OHDValSJUky//ffbty4odDQUJ04cUJ9+vRRmTJltHTpUnXv3l1XrlzR66+/bjE+u38LBAYGav369dq4caOaNm16x/fjiy++ULdu3RQeHq733ntP169f18yZM9WwYUPt27dPpUuX1ssvv6yzZ89mOq1lZn744QddunRJ/fv3z/YVhUuXLtX169f16quvqmjRovrpp5/00Ucf6c8//9TSpUvN4yIiInT48GH17dtXpUuX1oULFxQdHa0zZ86Yn4eFhal48eIaOnSoChcurN9//13Lli3LVl3pHB0d1alTJ7311lv64YcfMv0ekm71rePHjzf3uvHx8dq9e7f27t2rFi1aZOm9nTt3rm7evKnevXvL2dlZ3t7eSktLy3RsamqqWrZsqXr16mnChAlas2aNRo0apZSUFI0ZM8amY7T163748GE1atRInp6eGjx4sAoWLKjZs2crNDRUW7ZsUd26dS3G9+3bV0WKFNGoUaP0+++/68MPP1SfPn20ePFim+oEcAcGAOSSyMhI49+/hho3bmxIMmbNmpVh/PXr1zMse/nllw03Nzfj5s2b5mXdunUzAgMDzc9PnTplSDKKFi1qXLp0ybz822+/NSQZK1euNC8bNWpUhpokGU5OTsaJEyfMy37++WdDkvHRRx+Zlz311FOGm5ub8ddff5mX/frrr0aBAgUybDMzI0eONCQZ7u7uRqtWrYx33nnH2LNnT4ZxX3zxheHg4GBs27bNYvmsWbMMScb27dvNy9zd3Y1u3brddd+GYRg1a9Y0vLy8sjTWMDK+z4aR8WuUlJRkVK1a1WjatKl52eTJkw1Jxt9//211288884xRpUqVLNeSLv1r/f77799x25KMuLg4wzAMY9OmTYYkY9OmTYZhGMa+ffsMScbSpUvvuC9r723691CnTp2srrudJEOSsXv3bvOy06dPGy4uLsazzz5rXpbZ+21tm9Zqmzt3riHJOHXqlGEYhnHhwgXDycnJCAsLM1JTU83jpk2bZkgyPvvsM/Oy9J/Nzz//3LwsMTHR8PPzMyIiIjLsCwAA3D8pKSmGv7+/ERwcbLE8vT9cu3atYRiGcfPmTYvPfMO41T85OzsbY8aMsVgmyZg7d6552b97jv379xuSjNdee81ie507dzYkGaNGjTIvy6yPj4mJydBbLF261KIvu13jxo2Nxo0bm59/+OGHhiRjwYIF5mVJSUlGcHCw4eHhYcTHx1scS1b+FsjMoUOHDFdXV0OSUaNGDeP11183VqxYYSQkJFiMu3r1qlG4cGHjpZdeslgeGxtreHl5WSzP7O8ga6ZMmWJIMpYvX56l8f/ubQ0j8/d//PjxhslkMk6fPm0YhmFcvnz5rn308uXLDUnGrl27slTL7Ro3bnzH/j5921OmTDEvCwwMtOhpq1evbrRu3fqO+7H23qZ/H3h6ehoXLlzIdN3t3+/dunUzJBl9+/Y1L0tLSzNat25tODk5mf+Wyez9trbNO33d//0z06ZNG8PJyck4efKkednZs2eNQoUKGSEhIeZl6f198+bNjbS0NPPyAQMGGI6OjsaVK1cy3R8A2zGdC4A8x9nZWT169Miw3NXV1fzvq1ev6p9//lGjRo10/fp1HTt27K7b7dChg4oUKWJ+3qhRI0m3LtG7m+bNm1uczVutWjV5enqaX5uamqr169erTZs2FmfwPProo1k+QzcqKkqLFi1SzZo1tXbtWr355puqXbu2atWqpaNHj5rHLV26VJUqVVLFihX1zz//mB/pZ8Zs2rQpS/v7t/j4eBUqVChbr013+9fo8uXLiouLU6NGjbR3717z8sKFC0u6NT2PtbM+ChcurD///DNLl9jaysPDQ9Kt76HMeHl5SZLWrl2r69evZ3s/r7zySpbHBgcHq3bt2ubnpUqV0jPPPKO1a9dmmK7IntavX6+kpCT179/f4qaqL730kjw9PfXdd99ZjPfw8LCYx9LJyUmPP/54ln6GAABAznF0dFTHjh0VExNjMfXGokWL5Ovrq2bNmkm61Wenf+anpqbq4sWL5qn1bu/XsmL16tWSpH79+lks79+/f4axt/eIycnJunjxoh599FEVLlzY5v3evn8/Pz916tTJvKxgwYLq16+frl27pi1btliMz+7fAlWqVNH+/fv1/PPP6/fff9eUKVPUpk0b+fr66pNPPjGPi46O1pUrV9SpUyeLHt3R0VF169a9px5d0j316be//wkJCfrnn39Uv359GYahffv2mcc4OTlp8+bNunz5cqbbSe/jV61apeTk5GzXk5m79ejp+z98+LB+/fXXbO8nIiIiS1cKp7v9yo70aT6TkpK0fv36bNdwN6mpqVq3bp3atGmjRx55xLzc399fnTt31g8//GD+vkjXu3dvi+lhGjVqpNTUVJ0+fTrH6gQeNoToAPKc//znP5neOOjw4cN69tln5eXlJU9PTxUvXtwc6N0+d541pUqVsnie3kRbaxLv9Nr016e/9sKFC7px44YeffTRDOMyW2ZNp06dtG3bNl2+fFnr1q1T586dtW/fPj311FO6efOmpFvzdR8+fFjFixe3eJQvX95cS3Z4enresWnNilWrVqlevXpycXGRt7e3ihcvrpkzZ1p8fTp06KAGDRroxRdflK+vrzp27KglS5ZYBOpDhgyRh4eHHn/8cZUrV06RkZEW073ci2vXrkmy/odImTJlNHDgQH366acqVqyYwsPDNX369Cx9j/17O1lVrly5DMvKly+v69ev5+hchulNdYUKFSyWOzk56ZFHHsnQdJcoUSLDPJy3/xwAAIDck37j0PR7yPz555/atm2bOnbsaJ4GJC0tTZMnT1a5cuXk7OysYsWKqXjx4jpw4IDNvc7p06fl4OCQYdq4f/cV0q2pV0aOHKmSJUta7PfKlSs27/f2/ZcrV87iRADpf9O//LuPuZe/BcqXL68vvvhC//zzjw4cOKBx48apQIEC6t27tzlMTQ92mzZtmqFPX7du3T316NKdw+W7OXPmjLp37y5vb295eHioePHiaty4saT//R3l7Oys9957T99//718fX0VEhKiCRMmKDY21rydxo0bKyIiQlFRUSpWrJieeeYZzZ071+K+TNl1tx5dksaMGaMrV66ofPnyCgoK0qBBg3TgwAGb9mNLj+7g4GARYksy/83173sM2dPff/+t69evZ/qzVKlSJaWlpemPP/6wWH4v398AsoYQHUCec/uZEumuXLmixo0b6+eff9aYMWO0cuVKRUdHm+/ebu2M5ttZm0PQuMt81ff62uzw9PRUixYttHDhQnXr1k0nT57Ujz/+KOnWsQYFBSk6OjrTx2uvvZatfVasWFFxcXEZGrKs2rZtm55++mm5uLhoxowZWr16taKjo9W5c2eL98nV1VVbt27V+vXr1bVrVx04cEAdOnRQixYtzGddV6pUScePH9dXX32lhg0b6ptvvlHDhg01atSobNV2u0OHDsnHx8f8B0lmPvjgAx04cEDDhw/XjRs31K9fP1WpUiXTG2VZk9n38b2wdsOpnDxT/d/u988BAADIutq1a6tixYr68ssvJUlffvmlDMMwh+uSNG7cOA0cOFAhISFasGCB1q5dq+joaFWpUiVL/XR29e3bV++8847at2+vJUuWaN26dYqOjlbRokVzdL+3s0cf4+joqKCgIA0bNkzLly+XdOvm8NL//h754osvMu3Rv/3222zVXbFiRUnSwYMHs/X61NRUtWjRQt99952GDBmiFStWKDo62nzDy9vf//79++uXX37R+PHj5eLiorfeekuVKlUyn61uMpn09ddfKyYmRn369NFff/2lnj17qnbt2uYQPLsOHTok6c4nIIWEhOjkyZP67LPPVLVqVX366aeqVauWPv300yzv50Hs0SX6dOB+4MaiAPKFzZs36+LFi1q2bJlCQkLMy0+dOpWLVf2Pj4+PXFxcdOLEiQzrMltmizp16mj+/Pk6d+6cpFs3ifz555/VrFkzq01burutv91TTz2lL7/8UgsWLNCwYcNsrvObb76Ri4uL1q5dK2dnZ/PyuXPnZhjr4OCgZs2aqVmzZpo0aZLGjRunN998U5s2bVLz5s0lSe7u7urQoYM6dOigpKQktW3bVu+8846GDRsmFxcXm+uTpJiYGJ08edJiShJrgoKCFBQUpBEjRmjHjh1q0KCBZs2apbfffluSbe/t3WR2Seovv/wiNzc38+WmRYoU0ZUrVzKMy+wSzazWFhgYKEk6fvy4xVk2SUlJOnXqlPlrAQAA8ocuXbrorbfe0oEDB7Ro0SKVK1dOjz32mHn9119/rSZNmmjOnDkWr7ty5YqKFStm074CAwOVlpamkydPWpwxe/z48Qxjv/76a3Xr1k0ffPCBednNmzcz9Da29FeBgYE6cOCA0tLSLM5GT5/mMb3PySl16tSRJIseXbr1d8HdeihbjrNhw4YqUqSIvvzySw0fPtzmm4sePHhQv/zyi+bPn68XXnjBvDw6OjrT8WXLltUbb7yhN954Q7/++qtq1KihDz74QAsWLDCPqVevnurVq6d33nlHixYtUpcuXfTVV1/pxRdftKm2dKmpqVq0aJHc3NzUsGHDO4719vZWjx491KNHD127dk0hISEaPXq0ed/27NHT0tL022+/mc8+l2716JJUunRpSf874/vf38v30qMXL15cbm5umf4sHTt2TA4ODipZsmSWtgXAfjgTHUC+kN4s3v5/0pOSkjRjxozcKsmCo6OjmjdvrhUrVujs2bPm5SdOnND3339/19dfv35dMTExma5Lf336Hyft27fXX3/9ZTEHY7obN24oISHB/Nzd3T3T4DUzzz33nIKCgvTOO+9kWsvVq1f15ptvWn29o6OjTCaTxVkXv//+u1asWGEx7tKlSxleW6NGDUkyXwp68eJFi/VOTk6qXLmyDMPI9vyLp0+fVvfu3eXk5KRBgwZZHRcfH6+UlBSLZUFBQXJwcLC4VNWW9/ZuYmJiLOYD/eOPP/Ttt98qLCzM/L1ftmxZxcXFWVyyeu7cOfNZULfLam3NmzeXk5OTpk6davGzNWfOHMXFxal169b3cFQAAOB+Sz/rfOTIkdq/f7/FWejSrX7t32emLl26VH/99ZfN+0q/78/UqVMtln/44YcZxma2348++ijD2bru7u6SMgaSmXniiScUGxurxYsXm5elpKToo48+koeHh3m6knu1bdu2TPvP9Dnh03v08PBweXp6aty4cZmOv32KPluO083NTUOGDNHRo0c1ZMiQTM8sXrBggX766adMX5/Z31GGYWjKlCkW465fv26ePjJd2bJlVahQIXMPfPny5Qz7/3cfb6vU1FT169dPR48eVb9+/e54tei//0bw8PDQo48+mqFHl7L23mbFtGnTzP82DEPTpk1TwYIFzfcZCAwMlKOjo7Zu3Wrxusz+Ts1qbY6OjgoLC9O3335rMW3M+fPntWjRIjVs2PCO7xOAnMGZ6ADyhfr166tI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\n"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["\n","--- Sample Images with Annotations ---\n","Displaying and saving 5 sample images, prioritizing distinct classes.\n"," Saved sample image with annotations to outputs/dataset/dataset_analysis/sample_image_image101_group2_jpg.rf.24c77441c13ab629c3a2636c921d3dc2.png\n"," Saved sample image with annotations to outputs/dataset/dataset_analysis/sample_image_image98_group2_jpg.rf.d328ec2466e403463a7eb68f687d72ee.png\n"," Saved sample image with annotations to outputs/dataset/dataset_analysis/sample_image_image595_group14_jpg.rf.8d0f91eddac3fafabfafd2ccbb778ca1.png\n"," Saved sample image with annotations to outputs/dataset/dataset_analysis/sample_image_image733_group18_png.rf.934d31dba0b372fdb9d547834d5c7545.png\n"," Saved sample image with annotations to outputs/dataset/dataset_analysis/sample_image_image347_group8_jpg.rf.6eaf7b518728241e169df44cecd3dbe5.png\n","\n","Training Set: 1722 images, 1722 label files\n","Validation Set: 178 images, 178 label files\n","Test Set: 56 images, 56 label files\n","\n","================================================================================\n","Finished processing 1 datasets.\n","Prepared Datasets Info: [{'alias': 'dataset', 'dataset_root_dir': PosixPath('/content/Dataset-8'), 'data_yaml_path': PosixPath('/content/Dataset-8/data_corrected.yaml'), 'class_names': ['basketball', 'basketball_hoop'], 'nc': 2, 'output_dir': PosixPath('outputs/dataset'), 'train_images_path': PosixPath('/content/Dataset-8/train/images'), 'train_labels_path': PosixPath('/content/Dataset-8/train/labels'), 'val_images_path': PosixPath('/content/Dataset-8/valid/images'), 'val_labels_path': PosixPath('/content/Dataset-8/valid/labels'), 'test_images_path': PosixPath('/content/Dataset-8/test/images'), 'test_labels_path': PosixPath('/content/Dataset-8/test/labels')}]\n","================================================================================\n"]}],"source":["import yaml\n","from pathlib import Path\n","import matplotlib.pyplot as plt\n","import matplotlib.patches as patches\n","from PIL import Image\n","import random\n","import os\n","from collections import defaultdict\n","from roboflow import Roboflow\n","\n","# Initialize an empty list to store information about each processed dataset\n","# This initialization is also done in a separate cell, but kept here for self-containment if cell order changes.\n","# prepared_datasets_info = [] # Re-initializing here would clear previous data if cells were run out of order\n","\n","\n","# Iterate through each dataset_config in the DATASET_CONFIGS list\n","for dataset_config in DATASET_CONFIGS:\n"," rf_api_key = dataset_config['ROBOFLOW_API_KEY']\n"," workspace = dataset_config['WORKSPACE']\n"," project_name = dataset_config['PROJECT']\n"," version_num = dataset_config['VERSION']\n"," alias = dataset_config['ALIAS']\n","\n"," print(f\"\\n{'='*80}\")\n"," print(f\"Processing Dataset: {alias}\")\n"," print(f\"{'='*80}\")\n","\n"," # 1. Download dataset from Roboflow\n"," try:\n"," # Configure Roboflow API\n"," # Note: Using direct API key from config for demonstration. In production, use os.getenv()\n"," if rf_api_key == 'YOUR_API_KEY_HERE':\n"," print(\"WARNING: Roboflow API Key not set. Skipping dataset download for this config.\")\n"," continue # Skip this dataset if API key is not provided\n","\n"," rf = Roboflow(api_key=rf_api_key)\n"," project = rf.workspace(workspace).project(project_name)\n"," version = project.version(version_num)\n"," dataset = version.download(\"yolov11\")\n","\n"," dataset_location = Path(dataset.location)\n"," print(f\"Dataset '{alias}' downloaded to: {dataset_location}\")\n","\n"," # Create a dataset-specific output directory for analysis artifacts\n"," output_base_dir = Path(f'outputs/{alias}')\n"," dataset_analysis_output_dir = output_base_dir / 'dataset_analysis'\n"," dataset_analysis_output_dir.mkdir(parents=True, exist_ok=True)\n"," print(f\"Dataset analysis outputs will be saved to: {dataset_analysis_output_dir}\")\n","\n"," # 2. Correct and save the 'data.yaml' file\n"," original_data_yaml_path = dataset_location / 'data.yaml'\n","\n"," if not original_data_yaml_path.exists():\n"," print(f\"Error: data.yaml not found at {original_data_yaml_path}. Skipping dataset.\")\n"," continue\n","\n"," with open(original_data_yaml_path, 'r') as f:\n"," data_config_content = yaml.safe_load(f)\n","\n"," class_names = data_config_content['names']\n"," nc = data_config_content['nc']\n"," print(f\"Number of classes (nc): {nc}\")\n"," print(f\"Class Names: {class_names}\")\n","\n"," # Correctly construct absolute paths for images and labels\n"," train_images_abs_path = dataset_location / 'train' / 'images'\n"," train_labels_abs_path = dataset_location / 'train' / 'labels'\n","\n"," val_images_abs_path = dataset_location / 'valid' / 'images'\n"," val_labels_abs_path = dataset_location / 'valid' / 'labels'\n","\n"," test_images_abs_path = dataset_location / 'test' / 'images'\n"," test_labels_abs_path = dataset_location / 'test' / 'labels'\n","\n"," # Update data_config with paths RELATIVE to the dataset_root_dir\n"," data_config_content['train'] = str(train_images_abs_path.relative_to(dataset_location))\n"," data_config_content['val'] = str(val_images_abs_path.relative_to(dataset_location))\n"," data_config_content['test'] = str(test_images_abs_path.relative_to(dataset_location))\n","\n"," modified_data_yaml_path = dataset_location / 'data_corrected.yaml'\n"," with open(modified_data_yaml_path, 'w') as f:\n"," yaml.dump(data_config_content, f, default_flow_style=False)\n","\n"," print(f\"Modified data.yaml saved to: {modified_data_yaml_path}\")\n","\n"," # Store absolute paths for analysis functions\n"," current_dataset_paths = {\n"," 'train_images': train_images_abs_path,\n"," 'train_labels': train_labels_abs_path,\n"," 'val_images': val_images_abs_path,\n"," 'val_labels': val_labels_abs_path,\n"," 'test_images': test_images_abs_path,\n"," 'test_labels': test_labels_abs_path,\n"," }\n","\n"," # 3. Perform and display dataset analysis (class distribution and sample images)\n"," if GENERATE_PLOTS:\n"," print(\"\\n--- Class Distribution Analysis ---\")\n"," # Get counts for training set\n"," train_class_counts, total_train_annotations = get_class_counts(current_dataset_paths['train_labels'], class_names)\n"," print(f\"Training Set Class Distribution (Total Annotations: {total_train_annotations}):\")\n"," for cls, count in train_class_counts.items():\n"," print(f\" {cls}: {count}\")\n","\n"," # Get counts for validation set\n"," val_class_counts, total_val_annotations = get_class_counts(current_dataset_paths['val_labels'], class_names)\n"," print(f\"\\nValidation Set Class Distribution (Total Annotations: {total_val_annotations}):\")\n"," for cls, count in val_class_counts.items():\n"," print(f\" {cls}: {count}\")\n","\n"," # Plotting the class distribution\n"," fig, axes = plt.subplots(1, 2, figsize=(15, 6))\n","\n"," # Training set plot\n"," if train_class_counts:\n"," axes[0].bar(train_class_counts.keys(), train_class_counts.values(), color='skyblue')\n"," axes[0].set_title('Training Set Class Distribution')\n"," axes[0].set_xlabel('Class')\n"," axes[0].set_ylabel('Number of Instances')\n"," axes[0].tick_params(axis='x', rotation=45)\n","\n"," # Validation set plot\n"," if val_class_counts:\n"," axes[1].bar(val_class_counts.keys(), val_class_counts.values(), color='lightcoral')\n"," axes[1].set_title('Validation Set Class Distribution')\n"," axes[1].set_xlabel('Class')\n"," axes[1].set_ylabel('Number of Instances')\n"," axes[1].tick_params(axis='x', rotation=45)\n","\n"," plt.tight_layout()\n"," plt.savefig(dataset_analysis_output_dir / 'class_distribution.png')\n"," plt.show()\n"," plt.close(fig) # Close the figure to free up memory\n","\n"," print(\"\\n--- Sample Images with Annotations ---\")\n"," # Get a list of all training image files\n"," train_image_files = list(current_dataset_paths['train_images'].glob('*.jpg')) + \\\n"," list(current_dataset_paths['train_images'].glob('*.png'))\n","\n"," if len(train_image_files) == 0:\n"," print(f\"No training images found in {current_dataset_paths['train_images']}\")\n"," else:\n"," num_samples_to_show = min(5, len(train_image_files))\n"," selected_images = []\n"," class_image_map = {name: None for name in class_names}\n","\n"," # Try to find an image for each class\n"," for img_file in train_image_files:\n"," label_file = current_dataset_paths['train_labels'] / (img_file.stem + '.txt')\n"," if label_file.exists():\n"," with open(label_file, 'r') as f:\n"," for line in f:\n"," parts = line.strip().split()\n"," if parts:\n"," try:\n"," class_id = int(parts[0])\n"," if 0 <= class_id < len(class_names):\n"," class_name = class_names[class_id]\n"," if class_image_map[class_name] is None:\n"," class_image_map[class_name] = img_file\n"," break # Move to next image once a class is covered\n"," except ValueError:\n"," pass # Ignore invalid lines for selection\n","\n"," # Add images that contain unique classes first\n"," for class_name in class_names:\n"," if class_image_map[class_name] is not None and class_image_map[class_name] not in selected_images:\n"," selected_images.append(class_image_map[class_name])\n","\n"," # Fill the rest with random images if needed\n"," remaining_slots = num_samples_to_show - len(selected_images)\n"," if remaining_slots > 0:\n"," remaining_images = [img for img in train_image_files if img not in selected_images]\n"," if len(remaining_images) > remaining_slots:\n"," selected_images.extend(random.sample(remaining_images, remaining_slots))\n"," else:\n"," selected_images.extend(remaining_images)\n","\n"," if not selected_images:\n"," print(\"Could not find any suitable images to display with annotations.\")\n"," else:\n"," print(f\"Displaying and saving {len(selected_images)} sample images, prioritizing distinct classes.\")\n"," for idx, img_file in enumerate(selected_images):\n"," label_file = current_dataset_paths['train_labels'] / (img_file.stem + '.txt')\n"," save_path = dataset_analysis_output_dir / f\"sample_image_{img_file.stem}.png\"\n"," plot_image_with_bboxes(img_file, label_file, class_names, save_path)\n"," print(f\" Saved sample image with annotations to {save_path}\")\n","\n"," # 4. Other Dataset Metrics\n"," train_num_images, train_num_labels = get_dataset_stats(current_dataset_paths['train_images'], current_dataset_paths['train_labels'])\n"," print(f\"\\nTraining Set: {train_num_images} images, {train_num_labels} label files\")\n","\n"," val_num_images, val_num_labels = get_dataset_stats(current_dataset_paths['val_images'], current_dataset_paths['val_labels'])\n"," print(f\"Validation Set: {val_num_images} images, {val_num_labels} label files\")\n","\n"," test_num_images, test_num_labels = get_dataset_stats(current_dataset_paths['test_images'], current_dataset_paths['test_labels'])\n"," print(f\"Test Set: {test_num_images} images, {test_num_labels} label files\")\n","\n"," # Store the corrected data.yaml path and other relevant dataset info\n"," prepared_datasets_info.append({\n"," 'alias': alias,\n"," 'dataset_root_dir': dataset_location,\n"," 'data_yaml_path': modified_data_yaml_path,\n"," 'class_names': class_names,\n"," 'nc': nc,\n"," 'output_dir': output_base_dir,\n"," 'train_images_path': current_dataset_paths['train_images'],\n"," 'train_labels_path': current_dataset_paths['train_labels'],\n"," 'val_images_path': current_dataset_paths['val_images'],\n"," 'val_labels_path': current_dataset_paths['val_labels'],\n"," 'test_images_path': current_dataset_paths['test_images'],\n"," 'test_labels_path': current_dataset_paths['test_labels']\n"," })\n","\n"," except Exception as e:\n"," print(f\"Error processing dataset '{alias}': {e}\")\n","\n","print(f\"\\n{'='*80}\")\n","print(f\"Finished processing {len(prepared_datasets_info)} datasets.\")\n","print(f\"Prepared Datasets Info: {prepared_datasets_info}\")\n","print(f\"{'='*80}\")"]},{"cell_type":"markdown","metadata":{"id":"06f079e5"},"source":["## Model Training, Validation, and Export Loop\n","\n","This section orchestrates a comprehensive and iterative workflow for training, validating, and exporting object detection models across various datasets and model architectures. For each dataset defined in `DATASET_CONFIGS` and each model architecture specified in `MODEL_ARCHITECTURES`, the notebook performs the following steps:\n","1. **Model Loading**: A pre-trained YOLO model (e.g., `yolo11n.pt`) is loaded to serve as a starting point for training.\n","2. **Model Training**: The model is trained on the current dataset using the `TRAINING_HYPERPARAMETERS`. This step includes configuring the model with the dataset's specific `data.yaml` path and setting up a unique output directory for the run.\n","3. **Metric Collection**: During and after training, key performance metrics such as `mAP50`, `mAP50-95`, `Precision`, `Recall`, `Training Time`, and `Inference Time` are collected to evaluate the model's performance.\n","4. **Model Validation**: The trained model undergoes a validation phase to assess its generalization capabilities on unseen data, confirming the collected metrics.\n","5. **Model Export to Mobile Formats**: To facilitate real-time mobile deployment, the best-performing model from each training run is exported to: \\n * **CoreML (.mlpackage)**: Optimized for iOS devices, often with half-precision (FP16) and built-in NMS.\\n * **TFLite (.tflite)**: Optimized for Android devices, typically with INT8 quantization and built-in NMS.\n","6. **Visual Test Results**: If `SAVE_TEST_PREDICTION_IMAGES` is enabled, the model generates predictions on a selection of test images. These images, annotated with bounding boxes and confidence scores, are saved to provide a qualitative assessment of the model's performance.\n","\n","All training logs, model weights, exported formats, and visual test results are meticulously organized and saved into uniquely named directories, ensuring clear traceability and easy comparison between different model-dataset combinations. This systematic approach allows for robust evaluation and selection of the most suitable model for specific application requirements.\"\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"fb2ca4eb","colab":{"base_uri":"https://localhost:8080/"},"outputId":"50d43874-977b-41ac-9c88-092eddad5201","executionInfo":{"status":"ok","timestamp":1775419683604,"user_tz":-180,"elapsed":914917,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["\n","================================================================================\n","STARTING MODEL TRAINING, VALIDATION, AND EXPORT LOOP\n","================================================================================\n","\n","\n","**********************************************************************\n","Processing Dataset: dataset (/content/Dataset-8/data_corrected.yaml)\n","**********************************************************************\n","\n","\n","------------------------------------------------------------\n","Training Model: yolo11n on Dataset: dataset\n","------------------------------------------------------------\n","\n","Loading model: yolo11n.pt\n","\u001b[KDownloading https://github.com/ultralytics/assets/releases/download/v8.4.0/yolo11n.pt to 'yolo11n.pt': 100% ━━━━━━━━━━━━ 5.4MB 364.3MB/s 0.0s\n","Model yolo11n.pt loaded successfully.\n","Starting model training...\n","Ultralytics 8.4.33 🚀 Python-3.12.13 torch-2.10.0+cu128 CUDA:0 (NVIDIA L4, 22563MiB)\n","\u001b[34m\u001b[1mengine/trainer: \u001b[0magnostic_nms=False, amp=True, angle=1.0, augment=False, auto_augment=randaugment, batch=8, bgr=0.0, box=7.5, cache=False, cfg=None, classes=None, close_mosaic=10, cls=0.5, compile=False, conf=None, copy_paste=0.0, copy_paste_mode=flip, cos_lr=False, cutmix=0.0, data=/content/Dataset-8/data_corrected.yaml, degrees=0.0, deterministic=True, device=0, dfl=1.5, dnn=False, dropout=0.0, dynamic=False, embed=None, end2end=None, epochs=100, erasing=0.4, exist_ok=False, fliplr=0.5, flipud=0.0, format=torchscript, fraction=1.0, freeze=None, half=False, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, imgsz=900, int8=False, iou=0.7, keras=False, kobj=1.0, line_width=None, lr0=0.001, lrf=0.01, mask_ratio=4, max_det=300, mixup=0.0, mode=train, model=yolo11n.pt, momentum=0.937, mosaic=1.0, multi_scale=0.0, name=yolo11n_dataset, nbs=64, nms=False, opset=None, optimize=False, optimizer=AdamW, overlap_mask=True, patience=20, perspective=0.0, plots=True, pose=12.0, pretrained=True, profile=False, project=runs/all_trainings, rect=False, resume=False, retina_masks=False, rle=1.0, save=True, save_conf=False, save_crop=False, save_dir=/content/runs/detect/runs/all_trainings/yolo11n_dataset, save_frames=False, save_json=False, save_period=-1, save_txt=False, scale=0.5, seed=0, shear=0.0, show=False, show_boxes=True, show_conf=True, show_labels=True, simplify=True, single_cls=False, source=None, split=val, stream_buffer=False, task=detect, time=None, tracker=botsort.yaml, translate=0.1, val=True, verbose=True, vid_stride=1, visualize=False, warmup_bias_lr=0.1, warmup_epochs=3.0, warmup_momentum=0.8, weight_decay=0.0005, workers=8, workspace=None\n","\u001b[KDownloading https://ultralytics.com/assets/Arial.ttf to '/root/.config/Ultralytics/Arial.ttf': 100% ━━━━━━━━━━━━ 755.1KB 138.6MB/s 0.0s\n","Overriding model.yaml nc=80 with nc=2\n","\n"," from n params module arguments \n"," 0 -1 1 464 ultralytics.nn.modules.conv.Conv [3, 16, 3, 2] \n"," 1 -1 1 4672 ultralytics.nn.modules.conv.Conv [16, 32, 3, 2] \n"," 2 -1 1 6640 ultralytics.nn.modules.block.C3k2 [32, 64, 1, False, 0.25] \n"," 3 -1 1 36992 ultralytics.nn.modules.conv.Conv [64, 64, 3, 2] \n"," 4 -1 1 26080 ultralytics.nn.modules.block.C3k2 [64, 128, 1, False, 0.25] \n"," 5 -1 1 147712 ultralytics.nn.modules.conv.Conv [128, 128, 3, 2] \n"," 6 -1 1 87040 ultralytics.nn.modules.block.C3k2 [128, 128, 1, True] \n"," 7 -1 1 295424 ultralytics.nn.modules.conv.Conv [128, 256, 3, 2] \n"," 8 -1 1 346112 ultralytics.nn.modules.block.C3k2 [256, 256, 1, True] \n"," 9 -1 1 164608 ultralytics.nn.modules.block.SPPF [256, 256, 5] \n"," 10 -1 1 249728 ultralytics.nn.modules.block.C2PSA [256, 256, 1] \n"," 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n"," 12 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1] \n"," 13 -1 1 111296 ultralytics.nn.modules.block.C3k2 [384, 128, 1, False] \n"," 14 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n"," 15 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1] \n"," 16 -1 1 32096 ultralytics.nn.modules.block.C3k2 [256, 64, 1, False] \n"," 17 -1 1 36992 ultralytics.nn.modules.conv.Conv [64, 64, 3, 2] \n"," 18 [-1, 13] 1 0 ultralytics.nn.modules.conv.Concat [1] \n"," 19 -1 1 86720 ultralytics.nn.modules.block.C3k2 [192, 128, 1, False] \n"," 20 -1 1 147712 ultralytics.nn.modules.conv.Conv [128, 128, 3, 2] \n"," 21 [-1, 10] 1 0 ultralytics.nn.modules.conv.Concat [1] \n"," 22 -1 1 378880 ultralytics.nn.modules.block.C3k2 [384, 256, 1, True] \n"," 23 [16, 19, 22] 1 431062 ultralytics.nn.modules.head.Detect [2, 16, None, [64, 128, 256]] \n","YOLO11n summary: 182 layers, 2,590,230 parameters, 2,590,214 gradients, 6.4 GFLOPs\n","\n","Transferred 448/499 items from pretrained weights\n","Freezing layer 'model.23.dfl.conv.weight'\n","\u001b[34m\u001b[1mAMP: \u001b[0mrunning Automatic Mixed Precision (AMP) checks...\n","\u001b[KDownloading https://github.com/ultralytics/assets/releases/download/v8.4.0/yolo26n.pt to 'yolo26n.pt': 100% ━━━━━━━━━━━━ 5.3MB 300.3MB/s 0.0s\n","\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n","\u001b[34m\u001b[1mtrain: \u001b[0mFast image access ✅ (ping: 0.0±0.0 ms, read: 1882.0±1096.8 MB/s, size: 88.4 KB)\n","\u001b[K\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/Dataset-8/train/labels... 1722 images, 0 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 1722/1722 1.5Kit/s 1.1s\n","\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/Dataset-8/train/labels.cache\n","\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01, method='weighted_average', num_output_channels=3), CLAHE(p=0.01, clip_limit=(1.0, 4.0), tile_grid_size=(8, 8))\n","\u001b[34m\u001b[1mval: \u001b[0mFast image access ✅ (ping: 0.0±0.0 ms, read: 1296.0±1050.3 MB/s, size: 110.9 KB)\n","\u001b[K\u001b[34m\u001b[1mval: \u001b[0mScanning /content/Dataset-8/valid/labels... 178 images, 0 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 178/178 1.4Kit/s 0.1s\n","\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/Dataset-8/valid/labels.cache\n","\u001b[34m\u001b[1moptimizer:\u001b[0m AdamW(lr=0.001, momentum=0.937) with parameter groups 81 weight(decay=0.0), 88 weight(decay=0.0005), 87 bias(decay=0.0)\n","Plotting labels to /content/runs/detect/runs/all_trainings/yolo11n_dataset/labels.jpg... \n","Image sizes 928 train, 928 val\n","Using 8 dataloader workers\n","Logging results to \u001b[1m/content/runs/detect/runs/all_trainings/yolo11n_dataset\u001b[0m\n","Starting training for 100 epochs...\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 1/100 2.46G 1.674 1.635 1.166 5 928: 100% ━━━━━━━━━━━━ 216/216 4.6it/s 47.4s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 1.6it/s 7.7s\n"," all 178 451 0.678 0.517 0.626 0.323\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 2/100 2.8G 1.43 0.9942 1.076 1 928: 100% ━━━━━━━━━━━━ 216/216 8.9it/s 24.2s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 11.0it/s 1.1s\n"," all 178 451 0.827 0.664 0.775 0.389\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 3/100 2.8G 1.383 0.8952 1.054 10 928: 100% ━━━━━━━━━━━━ 216/216 9.2it/s 23.5s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.676 0.739 0.726 0.325\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 4/100 2.8G 1.301 0.8213 1.027 7 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.9s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.2it/s 1.2s\n"," all 178 451 0.824 0.634 0.78 0.43\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 5/100 2.8G 1.277 0.7758 1.018 7 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.8s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.8it/s 1.1s\n"," all 178 451 0.622 0.637 0.714 0.397\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 6/100 2.8G 1.271 0.7566 1.018 3 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 23.9s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.5it/s 1.1s\n"," all 178 451 0.564 0.768 0.751 0.397\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 7/100 2.8G 1.236 0.7444 0.9973 5 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.8s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.697 0.773 0.75 0.366\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 8/100 2.8G 1.222 0.716 0.9959 2 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.6s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.87 0.778 0.867 0.47\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 9/100 2.8G 1.171 0.6852 0.976 7 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.7s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.4it/s 1.2s\n"," all 178 451 0.859 0.735 0.842 0.46\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 10/100 2.8G 1.208 0.6852 0.9857 10 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.7s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.724 0.745 0.712 0.385\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 11/100 2.8G 1.184 0.6712 0.9765 11 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.0s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.9it/s 1.1s\n"," all 178 451 0.874 0.854 0.895 0.51\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 12/100 2.8G 1.166 0.6526 0.9742 9 928: 100% ━━━━━━━━━━━━ 216/216 9.2it/s 23.6s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.8it/s 1.1s\n"," all 178 451 0.798 0.845 0.867 0.438\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 13/100 2.8G 1.165 0.6413 0.9756 5 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 23.9s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 11.0it/s 1.1s\n"," all 178 451 0.746 0.707 0.81 0.422\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 14/100 2.8G 1.146 0.6461 0.9606 9 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 23.9s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.9it/s 1.1s\n"," all 178 451 0.769 0.697 0.752 0.386\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 15/100 2.8G 1.142 0.6307 0.9625 13 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.1s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.696 0.795 0.743 0.412\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 16/100 2.8G 1.113 0.6148 0.9508 7 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 23.9s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.8it/s 1.1s\n"," all 178 451 0.805 0.857 0.86 0.484\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 17/100 2.8G 1.106 0.6083 0.9608 2 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.1s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.5it/s 1.1s\n"," all 178 451 0.664 0.781 0.758 0.407\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 18/100 2.8G 1.094 0.591 0.9457 14 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.8s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.9it/s 1.1s\n"," all 178 451 0.74 0.75 0.756 0.423\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 19/100 2.8G 1.12 0.6096 0.9561 2 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.6s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.5it/s 1.1s\n"," all 178 451 0.7 0.885 0.796 0.413\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 20/100 2.8G 1.102 0.6058 0.9554 5 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.8s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.84 0.733 0.831 0.46\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 21/100 2.8G 1.073 0.5847 0.948 5 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 23.9s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.3it/s 1.2s\n"," all 178 451 0.814 0.84 0.819 0.417\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 22/100 2.8G 1.065 0.5784 0.9386 6 928: 100% ━━━━━━━━━━━━ 216/216 8.9it/s 24.2s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.3it/s 1.2s\n"," all 178 451 0.872 0.776 0.871 0.473\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 23/100 2.8G 1.073 0.5806 0.9429 11 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.0s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 11.0it/s 1.1s\n"," all 178 451 0.886 0.757 0.856 0.469\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 24/100 2.8G 1.046 0.5649 0.928 12 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.6s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.2it/s 1.2s\n"," all 178 451 0.855 0.734 0.819 0.448\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 25/100 2.8G 1.056 0.5633 0.9427 3 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.0s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.6it/s 1.1s\n"," all 178 451 0.804 0.773 0.788 0.446\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 26/100 2.8G 1.063 0.5632 0.9317 15 928: 100% ━━━━━━━━━━━━ 216/216 9.3it/s 23.3s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.5it/s 1.1s\n"," all 178 451 0.711 0.754 0.803 0.435\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 27/100 2.8G 1.042 0.5563 0.9263 4 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.8s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.2it/s 1.2s\n"," all 178 451 0.884 0.804 0.891 0.495\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 28/100 2.8G 1.04 0.5507 0.9295 12 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.0s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.9it/s 1.1s\n"," all 178 451 0.781 0.81 0.787 0.45\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 29/100 2.8G 1.038 0.5462 0.9354 3 928: 100% ━━━━━━━━━━━━ 216/216 9.1it/s 23.8s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.4it/s 1.2s\n"," all 178 451 0.771 0.836 0.83 0.475\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 30/100 2.8G 1.027 0.5456 0.9291 4 928: 100% ━━━━━━━━━━━━ 216/216 8.9it/s 24.3s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.2it/s 1.2s\n"," all 178 451 0.811 0.85 0.853 0.49\n","\n"," Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n","\u001b[K 31/100 2.8G 1.029 0.5375 0.9255 10 928: 100% ━━━━━━━━━━━━ 216/216 9.0it/s 24.1s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 10.7it/s 1.1s\n"," all 178 451 0.911 0.749 0.858 0.477\n","\u001b[34m\u001b[1mEarlyStopping: \u001b[0mTraining stopped early as no improvement observed in last 20 epochs. Best results observed at epoch 11, best model saved as best.pt.\n","To update EarlyStopping(patience=20) pass a new patience value, i.e. `patience=300` or use `patience=0` to disable EarlyStopping.\n","\n","31 epochs completed in 0.226 hours.\n","Optimizer stripped from /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/last.pt, 5.5MB\n","Optimizer stripped from /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.pt, 5.5MB\n","\n","Validating /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.pt...\n","Ultralytics 8.4.33 🚀 Python-3.12.13 torch-2.10.0+cu128 CUDA:0 (NVIDIA L4, 22563MiB)\n","YOLO11n summary (fused): 101 layers, 2,582,542 parameters, 0 gradients, 6.3 GFLOPs\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 5.2it/s 2.3s\n"," all 178 451 0.874 0.853 0.895 0.511\n"," basketball 177 177 0.822 0.712 0.8 0.434\n"," basketball_hoop 178 274 0.925 0.995 0.99 0.588\n","Speed: 0.4ms preprocess, 2.3ms inference, 0.0ms loss, 7.1ms postprocess per image\n","Results saved to \u001b[1m/content/runs/detect/runs/all_trainings/yolo11n_dataset\u001b[0m\n","Training completed for yolo11n on dataset in 13.95 minutes.\n","Validating model...\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n","Ultralytics 8.4.33 🚀 Python-3.12.13 torch-2.10.0+cu128 CUDA:0 (NVIDIA L4, 22563MiB)\n","YOLO11n summary (fused): 101 layers, 2,582,542 parameters, 0 gradients, 6.3 GFLOPs\n","\u001b[34m\u001b[1mval: \u001b[0mFast image access ✅ (ping: 0.0±0.0 ms, read: 2309.1±1051.0 MB/s, size: 90.0 KB)\n","\u001b[K\u001b[34m\u001b[1mval: \u001b[0mScanning /content/Dataset-8/valid/labels.cache... 178 images, 0 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 178/178 74.7Mit/s 0.0s\n","\u001b[K Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 12/12 3.3it/s 3.6s\n"," all 178 451 0.873 0.849 0.897 0.508\n"," basketball 177 177 0.822 0.705 0.804 0.428\n"," basketball_hoop 178 274 0.923 0.993 0.99 0.589\n","Speed: 2.8ms preprocess, 5.9ms inference, 0.0ms loss, 3.0ms postprocess per image\n","Results saved to \u001b[1m/content/runs/detect/val\u001b[0m\n","Validation complete. mAP50: 0.8970\n","Exporting model to CoreML...\n","Ultralytics 8.4.33 🚀 Python-3.12.13 torch-2.10.0+cu128 CPU (Intel Xeon CPU @ 2.20GHz)\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n","💡 ProTip: Export to OpenVINO format for best performance on Intel hardware. Learn more at https://docs.ultralytics.com/integrations/openvino/\n","\n","\u001b[34m\u001b[1mPyTorch:\u001b[0m starting from '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.pt' with input shape (1, 3, 928, 928) BCHW and output shape(s) (1, 6, 17661) (5.3 MB)\n","\u001b[31m\u001b[1mrequirements:\u001b[0m Ultralytics requirement ['coremltools>=9.0'] not found, attempting AutoUpdate...\n","Using Python 3.12.13 environment at: /usr\n","Resolved 12 packages in 212ms\n","Prepared 3 packages in 97ms\n","Installed 3 packages in 18ms\n"," + cattrs==26.1.0\n"," + coremltools==9.0\n"," + pyaml==26.2.1\n","\n","\u001b[31m\u001b[1mrequirements:\u001b[0m AutoUpdate success ✅ 0.7s\n","WARNING ⚠️ \u001b[31m\u001b[1mrequirements:\u001b[0m \u001b[1mRestart runtime or rerun command for updates to take effect\u001b[0m\n","\n"]},{"output_type":"stream","name":"stderr","text":["invalid escape sequence '\\_'\n"]},{"output_type":"stream","name":"stdout","text":["\n","\u001b[34m\u001b[1mCoreML:\u001b[0m starting export with coremltools 9.0...\n"]},{"output_type":"stream","name":"stderr","text":["Converting PyTorch Frontend ==> MIL Ops: 100%|█████████▉| 713/715 [00:00<00:00, 2980.19 ops/s]\n","Running MIL frontend_pytorch pipeline: 100%|██████████| 5/5 [00:00<00:00, 85.92 passes/s]\n","Running MIL default pipeline: 11%|█ | 10/95 [00:00<00:00, 93.78 passes/s]Output, '1148', of the source model, has been renamed to 'var_1148' in the Core ML model.\n","Output, '1150', of the source model, has been renamed to 'var_1150' in the Core ML model.\n","Running MIL default pipeline: 100%|██████████| 95/95 [00:01<00:00, 48.55 passes/s]\n","Running MIL backend_mlprogram pipeline: 100%|██████████| 12/12 [00:00<00:00, 86.07 passes/s]\n"]},{"output_type":"stream","name":"stdout","text":["\u001b[34m\u001b[1mCoreML:\u001b[0m starting pipeline with coremltools 9.0...\n","\u001b[34m\u001b[1mCoreML:\u001b[0m pipeline success\n","\u001b[34m\u001b[1mCoreML:\u001b[0m export success ✅ 17.1s, saved as '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.mlpackage' (5.2 MB)\n","\n","Export complete (17.4s)\n","Results saved to \u001b[1m/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights\u001b[0m\n","Predict: yolo predict task=detect model=/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.mlpackage imgsz=928 \n","Validate: yolo val task=detect model=/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.mlpackage imgsz=928 data=/content/Dataset-8/data_corrected.yaml \n","Visualize: https://netron.app\n","CoreML model exported to: /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.mlpackage\n","Exporting model to TFLite...\n","Ultralytics 8.4.33 🚀 Python-3.12.13 torch-2.10.0+cu128 CPU (Intel Xeon CPU @ 2.20GHz)\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n","\n","\u001b[34m\u001b[1mPyTorch:\u001b[0m starting from '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.pt' with input shape (1, 3, 928, 928) BCHW and output shape(s) (1, 300, 6) (5.3 MB)\n","\u001b[31m\u001b[1mrequirements:\u001b[0m Ultralytics requirements ['sng4onnx>=1.0.1', 'onnx_graphsurgeon>=0.3.26', 'ai-edge-litert>=1.2.0', 'onnx>=1.12.0,<2.0.0', 'onnx2tf>=1.26.3,<1.29.0', 'onnxslim>=0.1.71', 'onnxruntime-gpu'] not found, attempting AutoUpdate...\n","Using Python 3.12.13 environment at: /usr\n","Resolved 18 packages in 7.65s\n","Prepared 9 packages in 3.45s\n","Installed 9 packages in 305ms\n"," + ai-edge-litert==2.1.3\n"," + backports-strenum==1.3.1\n"," + colorama==0.4.6\n"," + onnx==1.21.0\n"," + onnx-graphsurgeon==0.5.8\n"," + onnx2tf==1.28.8\n"," + onnxruntime-gpu==1.24.4\n"," + onnxslim==0.1.90\n"," + sng4onnx==2.0.1\n","\n","\u001b[31m\u001b[1mrequirements:\u001b[0m AutoUpdate success ✅ 11.7s\n","WARNING ⚠️ \u001b[31m\u001b[1mrequirements:\u001b[0m \u001b[1mRestart runtime or rerun command for updates to take effect\u001b[0m\n","\n","\n","\u001b[34m\u001b[1mTensorFlow SavedModel:\u001b[0m starting export with tensorflow 2.19.0...\n","\n","\u001b[34m\u001b[1mONNX:\u001b[0m starting export with onnx 1.21.0 opset 20...\n","\u001b[34m\u001b[1mONNX:\u001b[0m slimming with onnxslim 0.1.90...\n","\u001b[34m\u001b[1mONNX:\u001b[0m export success ✅ 2.3s, saved as '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.onnx' (10.5 MB)\n","\u001b[KDownloading https://github.com/ultralytics/assets/releases/download/v8.4.0/calibration_image_sample_data_20x128x128x3_float32.npy.zip to 'calibration_image_sample_data_20x128x128x3_float32.npy.zip': 100% ━━━━━━━━━━━━ 1.1MB 173.9MB/s 0.0s\n","\u001b[KUnzipping calibration_image_sample_data_20x128x128x3_float32.npy.zip to /content/calibration_image_sample_data_20x128x128x3_float32.npy...: 100% ━━━━━━━━━━━━ 1/1 49.3files/s 0.0s\n","\u001b[34m\u001b[1mTensorFlow SavedModel:\u001b[0m starting TFLite export with onnx2tf 1.28.8...\n","Saved artifact at '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model'. The following endpoints are available:\n","\n","* Endpoint 'serving_default'\n"," inputs_0 (POSITIONAL_ONLY): TensorSpec(shape=(1, 928, 928, 3), dtype=tf.float32, name='images')\n","Output Type:\n"," TensorSpec(shape=(1, 300, 6), dtype=tf.float32, name=None)\n","Captures:\n"," 134705302288336: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705302286992: TensorSpec(shape=(3, 3, 3, 16), dtype=tf.float32, name=None)\n"," 134705302286416: TensorSpec(shape=(16,), dtype=tf.float32, name=None)\n"," 134705416030736: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705302288144: TensorSpec(shape=(3, 3, 16, 32), dtype=tf.float32, name=None)\n"," 134705416029776: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416030928: TensorSpec(shape=(1, 1, 32, 32), dtype=tf.float32, name=None)\n"," 134705416031120: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416032656: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416031888: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705302281808: TensorSpec(shape=(3, 3, 16, 8), dtype=tf.float32, name=None)\n"," 134705302288528: TensorSpec(shape=(8,), dtype=tf.float32, name=None)\n"," 134705302281616: TensorSpec(shape=(3, 3, 8, 16), dtype=tf.float32, name=None)\n"," 134705416033808: TensorSpec(shape=(16,), dtype=tf.float32, name=None)\n"," 134705416030160: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416032464: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416035152: TensorSpec(shape=(1, 1, 48, 64), dtype=tf.float32, name=None)\n"," 134705416034192: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705416031504: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705416034576: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705416033232: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705416035536: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705416034768: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705416036304: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416034960: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416036688: TensorSpec(shape=(3, 3, 32, 16), dtype=tf.float32, name=None)\n"," 134705416037648: TensorSpec(shape=(16,), dtype=tf.float32, name=None)\n"," 134705416035728: TensorSpec(shape=(3, 3, 16, 32), dtype=tf.float32, name=None)\n"," 134705416034384: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416035920: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416036112: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416037840: TensorSpec(shape=(1, 1, 96, 128), dtype=tf.float32, name=None)\n"," 134705416035344: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705416038224: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705416036880: TensorSpec(shape=(3, 3, 128, 128), dtype=tf.float32, name=None)\n"," 134705416038032: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705416038416: TensorSpec(shape=(1, 1, 128, 128), dtype=tf.float32, name=None)\n"," 134705416038608: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705416039184: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416038992: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416041104: TensorSpec(shape=(1, 1, 64, 32), dtype=tf.float32, name=None)\n"," 134705416041296: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416040528: TensorSpec(shape=(3, 3, 32, 32), dtype=tf.float32, name=None)\n"," 134705416041488: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416041680: TensorSpec(shape=(3, 3, 32, 32), dtype=tf.float32, name=None)\n"," 134705416041872: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416040720: TensorSpec(shape=(3, 3, 32, 32), dtype=tf.float32, name=None)\n"," 134705416042256: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416040144: TensorSpec(shape=(3, 3, 32, 32), dtype=tf.float32, name=None)\n"," 134705416037072: TensorSpec(shape=(1, 1, 64, 32), dtype=tf.float32, name=None)\n"," 134705416042448: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416038800: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705416043024: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705416042064: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705416039376: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416039568: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416043216: TensorSpec(shape=(1, 1, 192, 128), dtype=tf.float32, name=None)\n"," 134705416043408: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705416043600: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705416042640: TensorSpec(shape=(3, 3, 128, 256), dtype=tf.float32, name=None)\n"," 134705416042832: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705416043984: TensorSpec(shape=(1, 1, 256, 256), dtype=tf.float32, name=None)\n"," 134705416044176: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413816592: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413816400: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705416044368: TensorSpec(shape=(1, 1, 128, 64), dtype=tf.float32, name=None)\n"," 134705416043792: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413817552: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705413818896: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413819088: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705413819280: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413818128: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705413819664: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413818704: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705413817936: TensorSpec(shape=(1, 1, 128, 64), dtype=tf.float32, name=None)\n"," 134705413819856: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413818512: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413820432: TensorSpec(shape=(1, 1, 128, 128), dtype=tf.float32, name=None)\n"," 134705413819472: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413816784: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413816976: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413820624: TensorSpec(shape=(1, 1, 384, 256), dtype=tf.float32, name=None)\n"," 134705413820816: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413820048: TensorSpec(shape=(1, 1, 256, 128), dtype=tf.float32, name=None)\n"," 134705413821008: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413821392: TensorSpec(shape=(1, 1, 512, 256), dtype=tf.float32, name=None)\n"," 134705413821584: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413820240: TensorSpec(shape=(1, 1, 256, 256), dtype=tf.float32, name=None)\n"," 134705413822160: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413821968: TensorSpec(shape=(1, 1, 128, 256), dtype=tf.float32, name=None)\n"," 134705413822544: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413821776: TensorSpec(shape=(), dtype=tf.resource, name=None)\n"," 134705413825040: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413827920: TensorSpec(shape=(1, 1, 128, 128), dtype=tf.float32, name=None)\n"," 134705413825616: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413827536: TensorSpec(shape=(1, 1, 128, 256), dtype=tf.float32, name=None)\n"," 134705413827344: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413826768: TensorSpec(shape=(1, 1, 256, 128), dtype=tf.float32, name=None)\n"," 134705413824464: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413824848: TensorSpec(shape=(1, 1, 256, 256), dtype=tf.float32, name=None)\n"," 134705413826960: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705413826576: TensorSpec(shape=(1, 1, 384, 128), dtype=tf.float32, name=None)\n"," 134705413828496: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413828112: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413828304: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413829648: TensorSpec(shape=(3, 3, 64, 32), dtype=tf.float32, name=None)\n"," 134705413829840: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705413827152: TensorSpec(shape=(3, 3, 32, 64), dtype=tf.float32, name=None)\n"," 134705413822736: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413828688: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413826384: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413830416: TensorSpec(shape=(1, 1, 192, 128), dtype=tf.float32, name=None)\n"," 134705413829072: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705413829264: TensorSpec(shape=(1, 1, 256, 64), dtype=tf.float32, name=None)\n"," 134705413829456: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705413831184: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413830992: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413831760: TensorSpec(shape=(3, 3, 32, 16), dtype=tf.float32, name=None)\n"," 134705413830800: TensorSpec(shape=(16,), dtype=tf.float32, name=None)\n"," 134705413832144: TensorSpec(shape=(3, 3, 16, 32), dtype=tf.float32, name=None)\n"," 134705413832528: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705413831376: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413831568: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705413831952: TensorSpec(shape=(1, 1, 96, 64), dtype=tf.float32, name=None)\n"," 134705413830608: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393861456: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705393861264: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393861648: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393863760: TensorSpec(shape=(1, 1, 192, 128), dtype=tf.float32, name=None)\n"," 134705393863184: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705393864720: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393864912: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393868176: TensorSpec(shape=(3, 3, 64, 32), dtype=tf.float32, name=None)\n"," 134705393866064: TensorSpec(shape=(32,), dtype=tf.float32, name=None)\n"," 134705393865104: TensorSpec(shape=(3, 3, 32, 64), dtype=tf.float32, name=None)\n"," 134705393867600: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393865296: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393865488: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393867984: TensorSpec(shape=(1, 1, 192, 128), dtype=tf.float32, name=None)\n"," 134705393867024: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705393868560: TensorSpec(shape=(4, 2), dtype=tf.int32, name=None)\n"," 134705393867408: TensorSpec(shape=(3, 3, 128, 128), dtype=tf.float32, name=None)\n"," 134705393868752: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705393870480: TensorSpec(shape=(1, 1, 384, 256), dtype=tf.float32, name=None)\n"," 134705393868944: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705393871440: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393871632: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393874512: TensorSpec(shape=(1, 1, 128, 64), dtype=tf.float32, name=None)\n"," 134705393872784: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393874320: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393873360: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393875472: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393876624: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393874896: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393875280: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393874704: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393873168: TensorSpec(shape=(1, 1, 128, 64), dtype=tf.float32, name=None)\n"," 134705393876240: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393871824: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393875856: TensorSpec(shape=(1, 1, 128, 128), dtype=tf.float32, name=None)\n"," 134705393875664: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705393872016: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393872208: TensorSpec(shape=(4,), dtype=tf.int64, name=None)\n"," 134705393876816: TensorSpec(shape=(1, 1, 384, 256), dtype=tf.float32, name=None)\n"," 134705393876048: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705393876432: TensorSpec(shape=(3, 3, 256, 64), dtype=tf.float32, name=None)\n"," 134705393866640: TensorSpec(shape=(3, 3, 128, 64), dtype=tf.float32, name=None)\n"," 134705393862224: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393874128: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393869712: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393862032: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392435472: TensorSpec(shape=(3, 3, 256, 1), dtype=tf.float32, name=None)\n"," 134705393869520: TensorSpec(shape=(3, 3, 128, 1), dtype=tf.float32, name=None)\n"," 134705393862416: TensorSpec(shape=(3, 3, 64, 1), dtype=tf.float32, name=None)\n"," 134705392435664: TensorSpec(shape=(256,), dtype=tf.float32, name=None)\n"," 134705393869136: TensorSpec(shape=(128,), dtype=tf.float32, name=None)\n"," 134705393862608: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392435856: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393869904: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705393862992: TensorSpec(shape=(3, 3, 64, 64), dtype=tf.float32, name=None)\n"," 134705392436240: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393869328: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393862800: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392436432: TensorSpec(shape=(1, 1, 256, 64), dtype=tf.float32, name=None)\n"," 134705393870096: TensorSpec(shape=(1, 1, 128, 64), dtype=tf.float32, name=None)\n"," 134705393863376: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705392435280: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393868368: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393861840: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392436624: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705393870864: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705393864144: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705392437008: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393870288: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393863568: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392436048: TensorSpec(shape=(3, 3, 64, 1), dtype=tf.float32, name=None)\n"," 134705393871056: TensorSpec(shape=(3, 3, 64, 1), dtype=tf.float32, name=None)\n"," 134705393864336: TensorSpec(shape=(3, 3, 64, 1), dtype=tf.float32, name=None)\n"," 134705392437200: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393871248: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393864528: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392437584: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705393873744: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705393867216: TensorSpec(shape=(1, 1, 64, 64), dtype=tf.float32, name=None)\n"," 134705392438160: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393870672: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705393863952: TensorSpec(shape=(64,), dtype=tf.float32, name=None)\n"," 134705392437968: TensorSpec(shape=(1, 1, 64, 2), dtype=tf.float32, name=None)\n"," 134705393873936: TensorSpec(shape=(1, 1, 64, 2), dtype=tf.float32, name=None)\n"," 134705393866448: TensorSpec(shape=(1, 1, 64, 2), dtype=tf.float32, name=None)\n"," 134705392438928: TensorSpec(shape=(1, 1, 16, 1), dtype=tf.float32, name=None)\n"," 134705392439696: TensorSpec(shape=(2,), dtype=tf.float32, name=None)\n"," 134705393875088: TensorSpec(shape=(2,), dtype=tf.float32, name=None)\n"," 134705393867792: TensorSpec(shape=(2,), dtype=tf.float32, name=None)\n"," 134705392440656: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392437776: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392440464: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392436816: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392438544: TensorSpec(shape=(1, 2, 17661), dtype=tf.float32, name=None)\n"," 134705392440848: TensorSpec(shape=(1, 2, 17661), dtype=tf.float32, name=None)\n"," 134705392442576: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392443152: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392442000: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392438736: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705302281232: TensorSpec(shape=(1500, 4), dtype=tf.int64, name=None)\n"," 134705302280656: TensorSpec(shape=(2,), dtype=tf.int64, name=None)\n"," 134705302278544: TensorSpec(shape=(2,), dtype=tf.int64, name=None)\n"," 134705510381328: TensorSpec(shape=(), dtype=tf.int32, name=None)\n"," 134705302289296: TensorSpec(shape=(), dtype=tf.int32, name=None)\n"," 134705389634000: TensorSpec(shape=(1,), dtype=tf.bool, name=None)\n"," 134705389634192: TensorSpec(shape=(1,), dtype=tf.int32, name=None)\n"," 134705510381136: TensorSpec(shape=(), dtype=tf.int32, name=None)\n"," 134705510382288: TensorSpec(shape=(), dtype=tf.int32, name=None)\n"," 134705302289680: TensorSpec(shape=(), dtype=tf.int32, name=None)\n"," 134705302278160: TensorSpec(shape=(), dtype=tf.float32, name=None)\n"," 134705302278352: TensorSpec(shape=(), dtype=tf.float32, name=None)\n"," 134705392442768: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134705392442960: TensorSpec(shape=(3,), dtype=tf.int64, name=None)\n"," 134707564626768: TensorSpec(shape=(2, 2), dtype=tf.int32, name=None)\n"," 134707564629072: TensorSpec(shape=(), dtype=tf.int64, name=None)\n"," 134707564627920: TensorSpec(shape=(), dtype=tf.int64, name=None)\n"," 134707564628112: TensorSpec(shape=(1,), dtype=tf.int64, name=None)\n"," 134707564630032: TensorSpec(shape=(1,), dtype=tf.int64, name=None)\n"," 134707564629264: TensorSpec(shape=(1,), dtype=tf.int64, name=None)\n"," 134707564626960: TensorSpec(shape=(), dtype=tf.int64, name=None)\n"," 134707564628688: TensorSpec(shape=(1,), dtype=tf.int64, name=None)\n"," 134707564628304: TensorSpec(shape=(1,), dtype=tf.int64, name=None)\n"," 134707564629648: TensorSpec(shape=(1,), dtype=tf.int64, name=None)\n"," 134707564632720: TensorSpec(shape=(1, 300, 6), dtype=tf.float32, name=None)\n"," 134707564632336: TensorSpec(shape=(1, 1), dtype=tf.int64, name=None)\n","\u001b[34m\u001b[1mTensorFlow SavedModel:\u001b[0m export success ✅ 45.4s, saved as '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model' (27.6 MB)\n","\n","\u001b[34m\u001b[1mTensorFlow Lite:\u001b[0m starting export with tensorflow 2.19.0...\n","\u001b[34m\u001b[1mTensorFlow Lite:\u001b[0m export success ✅ 0.0s, saved as '/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model/best_float32.tflite' (11.0 MB)\n","\n","Export complete (45.7s)\n","Results saved to \u001b[1m/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights\u001b[0m\n","Predict: yolo predict task=detect model=/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model/best_float32.tflite imgsz=928 \n","Validate: yolo val task=detect model=/content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model/best_float32.tflite imgsz=928 data=/content/Dataset-8/data_corrected.yaml \n","Visualize: https://netron.app\n","TFLite model exported to: /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model/best_float32.tflite\n","Verifying TFLite model metadata...\n","\n"," Model Structure Analysis:\n"," - Input tensors: 1\n"," Input 0: shape=[ 1 928 928 3], dtype=<class 'numpy.float32'>, name=images\n"," - Output tensors: 1\n"," Output 0: shape=[ 1 300 6], dtype=<class 'numpy.float32'>, name=Identity\n"," ⚠ tflite_support library not available for metadata verification\n"," ℹ Install with: pip install tflite-support\n"," ℹ Model structure looks correct, but metadata compatibility cannot be verified\n"," ℹ Note: YOLO models exported with Ultralytics may not include metadata\n"," ℹ If ObjectDetector API fails, consider using Interpreter API directly\n","✓ TFLite model metadata verified/added successfully\n","Generating visual test results...\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n"," - image634_group16_png.rf.463701a8fb9f3b45d15884ee630ab20d.jpg: 10 detections\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n"," - image638_group16_png.rf.bba6ddc8bfcba34124b73de87aad2a9b.jpg: 4 detections\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n"," - image816_group23_png.rf.c349c708f3c1d573bdd7aff902c5096d.jpg: 2 detections\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n"," - image616_group16_png.rf.9593a47d78c7c980e22f0955aa5249cd.jpg: 12 detections\n","WARNING ⚠️ imgsz=[900] must be multiple of max stride 32, updating to [928]\n"," - image817_group23_png.rf.d96e3327f2d36e114b7e48e21b35532b.jpg: 3 detections\n","Sample predictions saved to: runs/all_trainings/yolo11n_dataset/visual_tests/sample_predictions.png\n","Finished processing yolo11n on dataset. Status: Success\n","\n","================================================================================\n","COMPLETED ALL MODEL TRAINING, VALIDATION, AND EXPORT LOOPS\n","================================================================================\n","\n"]}],"source":["from ultralytics.utils.callbacks.base import optimizer_step\n","import time\n","import pandas as pd\n","from pathlib import Path\n","from ultralytics import YOLO\n","import matplotlib.pyplot as plt\n","import random\n","import os\n","import shutil\n","\n","# Base directory for all training runs\n","TRAINING_RUNS_BASE_DIR = Path('runs/all_trainings')\n","TRAINING_RUNS_BASE_DIR.mkdir(parents=True, exist_ok=True)\n","\n","# List to store results from all training and export operations for comparison\n","all_results_for_comparison = []\n","\n","\"\"\"### TFLite Metadata Verification Function\n","\n","This function verifies if a TFLite model has metadata compatible with TensorFlow Lite Task Vision ObjectDetector API.\n","It checks the model structure, input/output tensors, and provides information about metadata presence.\n","\"\"\"\n","\n","def verify_and_add_tflite_metadata(tflite_path, class_names, input_size):\n"," \"\"\"\n"," Verify TFLite model metadata and provide compatibility information.\n","\n"," Args:\n"," tflite_path: Path to the TFLite model file\n"," class_names: List of class names for the model\n"," input_size: Input image size (e.g., 416)\n"," \"\"\"\n"," try:\n"," # Try to import TensorFlow Lite\n"," try:\n"," import tensorflow as tf\n"," except ImportError:\n"," print(\" ⚠ TensorFlow not available. Installing...\")\n"," os.system(\"pip install tensorflow\")\n"," import tensorflow as tf\n","\n"," # Load and inspect the TFLite model\n"," interpreter = tf.lite.Interpreter(model_path=str(tflite_path))\n"," interpreter.allocate_tensors()\n","\n"," # Get input and output details\n"," input_details = interpreter.get_input_details()\n"," output_details = interpreter.get_output_details()\n","\n"," print(f\"\\n Model Structure Analysis:\")\n"," print(f\" - Input tensors: {len(input_details)}\")\n"," for i, inp in enumerate(input_details):\n"," print(f\" Input {i}: shape={inp['shape']}, dtype={inp['dtype']}, name={inp.get('name', 'N/A')}\")\n","\n"," print(f\" - Output tensors: {len(output_details)}\")\n"," for i, out in enumerate(output_details):\n"," print(f\" Output {i}: shape={out['shape']}, dtype={out['dtype']}, name={out.get('name', 'N/A')}\")\n","\n"," # Check if metadata exists using tflite_support (if available)\n"," try:\n"," from tflite_support import metadata\n"," displayer = metadata.MetadataDisplayer.with_model_file(str(tflite_path))\n"," metadata_json = displayer.get_metadata_json()\n","\n"," if metadata_json:\n"," print(f\" ✓ Metadata found in model\")\n"," # Parse metadata to check for ObjectDetector compatibility\n"," import json\n"," meta = json.loads(metadata_json)\n"," if 'subgraph_metadata' in meta and len(meta['subgraph_metadata']) > 0:\n"," print(f\" ✓ Model has subgraph metadata\")\n"," # Check for input/output metadata\n"," subgraph = meta['subgraph_metadata'][0]\n"," if 'input_tensor_metadata' in subgraph:\n"," print(f\" ✓ Input tensor metadata present\")\n"," if 'output_tensor_metadata' in subgraph:\n"," print(f\" ✓ Output tensor metadata present\")\n"," return True\n"," else:\n"," print(f\" ⚠ No metadata found in model\")\n"," print(f\" ⚠ Model may not be compatible with TensorFlow Lite Task Vision ObjectDetector API\")\n"," print(f\" ℹ Consider using TensorFlow Lite Model Maker or adding metadata manually\")\n"," return False\n"," except ImportError:\n"," print(f\" ⚠ tflite_support library not available for metadata verification\")\n"," print(f\" ℹ Install with: pip install tflite-support\")\n"," print(f\" ℹ Model structure looks correct, but metadata compatibility cannot be verified\")\n"," print(f\" ℹ Note: YOLO models exported with Ultralytics may not include metadata\")\n"," print(f\" ℹ If ObjectDetector API fails, consider using Interpreter API directly\")\n"," return None\n"," except Exception as e:\n"," print(f\" ⚠ Could not read metadata: {e}\")\n"," print(f\" ℹ Model may work, but metadata verification failed\")\n"," print(f\" ℹ If ObjectDetector API fails, the model can still be used with Interpreter API\")\n"," return None\n","\n"," except Exception as e:\n"," print(f\" ✗ Error verifying model: {e}\")\n"," print(f\" ℹ Model file exists but could not be verified\")\n"," print(f\" ℹ Model dimensions: {input_size}x{input_size}, Classes: {len(class_names)}\")\n"," return False\n","\n","print(f\"\\n{'='*80}\")\n","print(\"STARTING MODEL TRAINING, VALIDATION, AND EXPORT LOOP\")\n","print(f\"{'='*80}\\n\")\n","\n","# Outer loop: Iterate through each prepared dataset\n","for dataset_info in prepared_datasets_info:\n"," dataset_alias = dataset_info['alias']\n"," data_yaml_path = dataset_info['data_yaml_path']\n"," class_names = dataset_info['class_names']\n"," test_images_path = dataset_info['test_images_path']\n"," val_images_path = dataset_info['val_images_path']\n"," output_dataset_dir = dataset_info['output_dir']\n","\n"," print(f\"\\n{'*'*70}\")\n"," print(f\"Processing Dataset: {dataset_alias} ({data_yaml_path})\")\n"," print(f\"{'*'*70}\\n\")\n","\n"," # Inner loop: Iterate through each model architecture\n"," for model_arch in MODEL_ARCHITECTURES:\n"," print(f\"\\n{'-'*60}\")\n"," print(f\"Training Model: {model_arch} on Dataset: {dataset_alias}\")\n"," print(f\"{'-'*60}\\n\")\n","\n"," # Create a unique run name for this model-dataset combination\n"," run_name = f\"{model_arch}_{dataset_alias}\"\n"," model_output_dir = TRAINING_RUNS_BASE_DIR / run_name\n"," model_output_dir.mkdir(parents=True, exist_ok=True)\n","\n"," current_run_info = {\n"," 'dataset_alias': dataset_alias,\n"," 'model_architecture': model_arch,\n"," 'status': 'Failed',\n"," 'mAP50': 0.0,\n"," 'mAP50-95': 0.0,\n"," 'Precision': 0.0,\n"," 'Recall': 0.0,\n"," 'Training Time (min)': 0.0,\n"," 'Inference Time (ms)': 0.0,\n"," 'Trained Model Path': 'N/A',\n"," 'CoreML Export Path': 'N/A',\n"," 'TFLite Export Path': 'N/A',\n"," 'Visual Test Images Path': 'N/A'\n"," }\n","\n"," try:\n"," expected_weights_path = model_output_dir / \"weights\" / \"best.pt\"\n","\n"," if expected_weights_path.exists():\n"," print(f\"Found existing trained model at {expected_weights_path}. Loading it and skipping training.\")\n"," model = YOLO(str(expected_weights_path))\n"," current_run_info['Trained Model Path'] = str(expected_weights_path)\n"," current_run_info['Training Time (min)'] = 0.0 # Unknown if loaded from disk\n"," else:\n"," # 1. Load the pre-trained YOLO model\n"," print(f\"Loading model: {model_arch}.pt\")\n"," model = YOLO(f\"{model_arch}.pt\")\n"," print(f\"Model {model_arch}.pt loaded successfully.\")\n","\n"," # 2. Configure training parameters using global hyperparameters\n"," training_params = TRAINING_HYPERPARAMETERS.copy()\n"," training_params['data'] = str(data_yaml_path)\n"," training_params['project'] = str(TRAINING_RUNS_BASE_DIR)\n"," training_params['name'] = run_name\n","\n"," print(\"Starting model training...\")\n"," start_time = time.time()\n"," # 3. Train the model\n"," results = model.train(**training_params)\n"," training_time = (time.time() - start_time) / 60.0 # minutes\n"," print(f\"Training completed for {model_arch} on {dataset_alias} in {training_time:.2f} minutes.\")\n","\n"," # Update trained model path\n"," best_model_pt_path = Path(results.save_dir) / \"weights\" / \"best.pt\"\n"," current_run_info['Trained Model Path'] = str(best_model_pt_path)\n"," current_run_info['Training Time (min)'] = round(training_time, 2)\n","\n"," # 4. Validate the trained model and store all metrics\n"," print(\"Validating model...\")\n"," val_results = model.val(imgsz=TRAINING_HYPERPARAMETERS['imgsz'])\n"," current_run_info['mAP50'] = round(val_results.box.map50, 4)\n"," current_run_info['mAP50-95'] = round(val_results.box.map, 4)\n"," current_run_info['Precision'] = round(val_results.box.mp, 4)\n"," current_run_info['Recall'] = round(val_results.box.mr, 4)\n"," current_run_info['Inference Time (ms)'] = round(val_results.speed['inference'], 2)\n"," print(f\"Validation complete. mAP50: {current_run_info['mAP50']:.4f}\")\n","\n"," # 5. Export the best trained model to CoreML and TFLite\n"," print(\"Exporting model to CoreML...\")\n"," coreml_export_path = model.export(\n"," format=\"coreml\",\n"," imgsz=TRAINING_HYPERPARAMETERS['imgsz'],\n"," half=False,\n"," nms=True,\n"," optimize=True\n"," )\n"," current_run_info['CoreML Export Path'] = str(coreml_export_path)\n"," print(f\"CoreML model exported to: {coreml_export_path}\")\n","\n"," print(\"Exporting model to TFLite...\")\n"," tflite_export_path = model.export(\n"," format=\"tflite\",\n"," imgsz=TRAINING_HYPERPARAMETERS['imgsz'],\n"," int8=False, # Set to False to avoid hanging during colab INT8 calibration process\n"," nms=True,\n"," optimize = True,\n"," data=str(data_yaml_path)\n"," )\n"," current_run_info['TFLite Export Path'] = str(tflite_export_path)\n"," print(f\"TFLite model exported to: {tflite_export_path}\")\n","\n"," # Verify and add metadata for TensorFlow Lite Task Vision compatibility\n"," print(\"Verifying TFLite model metadata...\")\n"," try:\n"," verify_and_add_tflite_metadata(\n"," tflite_path=tflite_export_path,\n"," class_names=class_names,\n"," input_size=TRAINING_HYPERPARAMETERS['imgsz']\n"," )\n"," print(\"✓ TFLite model metadata verified/added successfully\")\n"," except Exception as e:\n"," print(f\"⚠ Warning: Could not verify/add metadata: {e}\")\n"," print(\" Model may still work, but may not be compatible with Task Vision API\")\n","\n"," # Store model file paths for later copying to outputs/models directory\n"," # Convert export paths to Path objects and verify they exist\n"," coreml_path = Path(coreml_export_path)\n"," tflite_path = Path(tflite_export_path)\n","\n"," # Handle both string paths and Path objects from export()\n"," if isinstance(coreml_export_path, str):\n"," coreml_path = Path(coreml_export_path)\n"," if isinstance(tflite_export_path, str):\n"," tflite_path = Path(tflite_export_path)\n","\n"," current_run_info['_coreml_file_path'] = coreml_path if coreml_path.exists() else None\n"," current_run_info['_tflite_file_path'] = tflite_path if tflite_path.exists() else None\n"," current_run_info['_model_name'] = run_name\n"," current_run_info['_dataset_alias'] = dataset_alias\n","\n"," # 6. Generate and save visual test results\n"," if SAVE_TEST_PREDICTION_IMAGES:\n"," visual_output_dir = model_output_dir / 'visual_tests'\n"," visual_output_dir.mkdir(parents=True, exist_ok=True)\n"," current_run_info['Visual Test Images Path'] = str(visual_output_dir)\n","\n"," print(\"Generating visual test results...\")\n"," # Use test_images_path if available, otherwise fallback to val_images_path\n"," source_images_dir = test_images_path if test_images_path.exists() else val_images_path\n","\n"," if source_images_dir.exists():\n"," test_image_files = list(source_images_dir.glob('*.jpg')) + list(source_images_dir.glob('*.png'))\n"," num_samples = min(5, len(test_image_files))\n"," if num_samples > 0:\n"," sample_images = random.sample(test_image_files, num_samples)\n","\n"," fig, axes = plt.subplots(1, num_samples, figsize=(5 * num_samples, 5))\n"," if num_samples == 1: # Handle single subplot case\n"," axes = [axes]\n"," fig.suptitle(f'{model_arch} on {dataset_alias} - Sample Predictions', fontsize=16)\n","\n"," for i, img_path in enumerate(sample_images):\n"," pred_results = model.predict(str(img_path), conf=0.20, imgsz=TRAINING_HYPERPARAMETERS['imgsz'], verbose=False) # For small objects, conf = 0.25 and can test with smaller values\n"," annotated_frame = pred_results[0].plot() # YOLO's plot method\n"," axes[i].imshow(annotated_frame)\n"," axes[i].set_title(img_path.name, fontsize=10)\n"," axes[i].axis('off')\n","\n"," # Log detections for each image\n"," detections_count = len(pred_results[0].boxes)\n"," print(f\" - {img_path.name}: {detections_count} detections\")\n","\n"," plt.tight_layout()\n"," plt.savefig(visual_output_dir / 'sample_predictions.png')\n"," plt.close(fig)\n"," print(f\"Sample predictions saved to: {visual_output_dir / 'sample_predictions.png'}\")\n"," else:\n"," print(f\"No suitable images found in {source_images_dir} for visual testing.\")\n"," else:\n"," print(f\"Warning: Test/Validation images directory not found: {source_images_dir}. Skipping visual tests.\")\n","\n"," current_run_info['status'] = 'Success'\n","\n"," except Exception as e:\n"," print(f\"Error during processing {model_arch} on {dataset_alias}: {e}\")\n"," current_run_info['error_message'] = str(e)\n"," current_run_info['status'] = 'Failed'\n","\n"," finally:\n"," all_results_for_comparison.append(current_run_info)\n"," print(f\"Finished processing {model_arch} on {dataset_alias}. Status: {current_run_info['status']}\")\n","\n","print(f\"\\n{'='*80}\")\n","print(\"COMPLETED ALL MODEL TRAINING, VALIDATION, AND EXPORT LOOPS\")\n","print(f\"{'='*80}\\n\")\n","\n","# Optional: Display collected results so far\n","# if all_results_for_comparison:\n","# df_all_results = pd.DataFrame(all_results_for_comparison)\n","# print(\"\\nAll Collected Results:\")\n","# print(df_all_results.to_string(index=False))\n"]},{"cell_type":"markdown","metadata":{"id":"5f4cd7a7"},"source":["## Comparison Reporting and Visualization"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"32649121","colab":{"base_uri":"https://localhost:8080/","height":1000},"executionInfo":{"status":"ok","timestamp":1775419685102,"user_tz":-180,"elapsed":1492,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"outputId":"7b523a3c-57f4-409f-9208-1c2033eeebcd"},"outputs":[{"output_type":"stream","name":"stdout","text":["\n","================================================================================\n","MODEL COMPARISON TABLE\n","================================================================================\n","dataset_alias model_architecture status mAP50 mAP50-95 Precision Recall Training Time (min) Inference Time (ms) Trained Model Path CoreML Export Path TFLite Export Path Visual Test Images Path _coreml_file_path _tflite_file_path _model_name _dataset_alias\n"," dataset yolo11n Success 0.897 0.5084 0.8726 0.8489 13.95 5.88 /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.pt /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.mlpackage /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model/best_float32.tflite runs/all_trainings/yolo11n_dataset/visual_tests /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.mlpackage /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best_saved_model/best_float32.tflite yolo11n_dataset dataset\n","================================================================================\n","\n","✓ Comparison results saved to 'outputs/model_comparison_results.csv'\n","✓ Comparison plots will be saved to 'outputs/comparison_results'\n","\n","Generating comparative visualizations...\n"]},{"output_type":"display_data","data":{"text/plain":["<Figure size 1800x1400 with 4 Axes>"],"image/png":"iVBORw0KGgoAAAANSUhEUgAABwMAAAU3CAYAAACywMogAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd4FNX/9vF70xNS6FU6SlE6iIICKoKCCooKYqGoKIqiqIgFAb8qKth7BcUCFhQVxYIiggpIE+lIkSLSE1oI7J7nD57ML5PdhAAbhpx9v64r18VO2zN7f3aY3bNzxmeMMQIAAAAAAAAAAABgnSivGwAAAAAAAAAAAACgcNAZCAAAAAAAAAAAAFiKzkAAAAAAAAAAAADAUnQGAgAAAAAAAAAAAJaiMxAAAAAAAAAAAACwFJ2BAAAAAAAAAAAAgKXoDAQAAAAAAAAAAAAsRWcgAAAAAAAAAAAAYCk6AwEAAAAAAAAAAABL0RkIAAAAeKRXr17y+Xyuv6lTpxba861Zsybo+dq2bVtoz4eijXpBXoYNGxZUG2PGjPG6WXmaOnVqUHt79erldbMAAACA44bOQAAAAJyQQn3ZnP335ptvHnb9Vq1a5bk+Cs+0adN0//336+yzz1bVqlWVnJys+Ph4lSlTRmeeeab69++vr776SgcOHPC6qUChev755/M8Bq1YscLr5gEAAACIIHQGAgAAoMh55ZVX8p2/YMEC/frrr8epNZCkH3/8UaeffrratGmjESNGaPr06frnn3+0Z88eZWVlaevWrfr999/10ksv6eKLL1bVqlU1Z84cr5sNFJr333//qOYBAAAAQLjFeN0AAAAA4EjNnTtXs2bN0umnnx5y/ssvv3ycWxTZHn74YQ0fPlyBQKDA6/z7779at26dmjZtWogtw7FITU3VgAEDXNNq1arlUWuKlpUrV2rWrFl5zn///fc1bNiw49egCHfSSScF1XJe/38AAAAANqIzEAAAAEXSK6+8EvLL3IyMDK66OY4eeeQRDR06NOS8qlWr6swzz1TJkiW1c+dOLVmyRAsWLDiiTkN4p2TJknr22We9bkaRdLhj0MqVKzVz5ky1aNHiOLUostWqVYtaBgAAQESjMxAAAABF0vjx4/X000+rRIkSrunvvvuu9uzZ41GrIsuUKVP00EMPBU0vX768Xn31VXXu3Dlo3qZNm/T666/rqaeeOh5NBDxRkB8kvPfee3QGAgAAADguuGcgAAAAioy4uDjn3/v27dOYMWOClsl9P8Gc6xTEwYMH9eGHH+qqq65SrVq1lJqaqvj4eJUvX15nn322hgwZorVr1xZoW7///ruuvPJKVahQQQkJCapWrZpuuukmLVu27IjalC0QCOiTTz7Rtddeq9q1a6t48eKKj49XxYoVdcEFF+ill17Svn37jmrbR2Pw4MEyxrimlShRQr/88kvIjkDpUEfhQw89pGXLlql+/fp5bvvvv//W/fffr1atWqlcuXKKi4tTWlqaTj75ZF199dX6+OOP5ff781x/2LBh8vl8rr8xY8bIGKM333xTZ555ptLS0lSqVCmdc845+uyzz1zrb9iwQQMHDlStWrWUkJCg8uXL6/LLL8/3Pod5Packffnll7roootUvnx5xcfHq1q1arr55pu1Zs2aPLe3bds2ffLJJxo8eLDOP/981atXz6mlpKQkVahQQW3bttX999+v5cuX57kdSapWrVpQ2yRp586deuihh9SgQQOlpqa62rxmzZqgddq2bRty+//9958eeeQRtW3bVhUrVlRiYqJTmw0aNFCXLl00bNgwTZkyRVlZWXm2Mxzvv7z2dd++fRo1apSaN2+utLQ0FStWTA0bNtSIESPC+r6ZNWuWVqxY4ZrWvn17FS9e3DVt/PjxOnjwYL7byr0f1apVkyTt2LHDyS05OVkpKSlq0aKFXnnllTzfF8YYTZ06VaNGjVK3bt3UuHFjVa1aVampqYqNjVXJkiXVoEED9erVS1999dUxXcHbvn17V7ujo6O1YcOGPJfv2LGja/moqCitXr3atcyCBQt0xx136PTTT1fp0qUVFxenYsWKqWrVqmrWrJmuueYaPf3005o7d27Q9qdOnRr0Wvbq1StkW1atWuU69sTHxysxMVGVK1dW48aNdeWVV2rEiBGaMWMGVzkDAACg6DAAAADACWjo0KFGkuuve/fuxufzOY9POeUUEwgEnHV++ukn1/ItW7Y0VatWDdpOXmbOnGlq1qwZtHzuv5iYGDN48GBz8ODBPLf15JNPmqioqJDrJyYmmg8++MD07NkzaN5PP/0Ucnvz5s0zderUOWzbKlasaH7++eeQ21i9enXQ8m3atClQHrnNmDEj5PO/8cYbR7W9bFlZWWbAgAEmOjr6sPtap04dM3/+/JDbCVU/L7/8sjn//PPz3N4999xjjDHml19+MWXKlMkz+wkTJhT4Od98803Tq1evPJ+zWLFiZtKkSSG398ILLxz2Ncj+i4qKMvfff3+er2uo98Fff/1lKlWqFDR99OjRxpiC18vXX39tkpOTC9zWX375JWQbw/X+C7WvS5cuzXfbZ555ptmzZ0+er9+RuP3220O+ptddd13Q9Lyyz5Z7+apVq5rp06ebcuXK5bkvl156qfH7/UHb2rVrV4Ezyn5N1q1bF7JdoWo9u26MMebzzz8Pmv/II4+E3NaOHTtMbGysa9nWrVu7lhk+fLjr2J/fX3R0dNBz5P6/QZLp2bNn0HJvvfVWUFvy+8vr9QEAAABONFwZCAAAgCKjdu3aOvfcc53Hy5cv148//ug8zn1V4C233FLgbU+bNk1nn322/v7778Mue/DgQT3++OO6+uqrQ85/7733NGjQoDyvGtm3b5+uu+46/fbbbwVq22+//aaWLVtq6dKlh11248aNateunaZMmVKgbR+t7777LmhaiRIldO211x71NgOBgC699FI999xz+V71l23p0qVq2bKl/vjjjwJtf8iQIfr+++/znD9y5Ei9/PLL6ty5s7Zs2RJymYMHD6pPnz7aunVrgZ7z4YcfDnkFa7Y9e/bosssu04IFCwq0vbwEAgE99thjGjVqVIHXueCCC/K9Wqsgtm/frh49emj37t3HtJ1wvv9Cad26db7b/u233/TII48UeHt58fv9Gj9+vGtabGysOnfurK5duwYtf6T3N926das6dOig//77L89lPvvsM7355ptHtN1QfvvtN1188cU6cODAEa970UUXqUqVKq5pb7/9dtCVxJI0ceLEoOfo2bOn8++ffvpJQ4cODbluOC1fvlw333zzUe0vAAAAcKLjnoEAAAAoUvr16+fq6HrllVd03nnnadOmTa6hHkuXLq3LL79cDzzwwGG3mZGRocsvvzxo+MKUlBR17NhRxYsX16+//qqFCxe65o8fP15t2rRRv379nGnp6em6/fbbg54jKSlJnTp1UokSJTRt2jQtXbr0sEM7StLu3bt12WWXBQ1jWKFCBbVp00bFihXT7Nmz9eeffzrzDhw4oKuuukrLly8PGpowXGbNmhU0rVWrVoqPjz/qbT7xxBOaNGlS0PQmTZro9NNP19atW/X1119r7969zry9e/eqa9euWrZsmRISEvLd/rZt2+Tz+XThhReqXLlymjRpkjZv3uxa5tZbb5V0KPvOnTsrMzNTn332matzcufOnRo7dqzuvPPOw+7TP//8I0k666yzdNppp2nt2rX69ttvXR3F+/fvV9++fTVz5syQ2yhZsqTq16+vUqVKqVSpUoqLi9P27dv1xx9/BA1H+cgjj6hv375KTU09bNvWr18vSWratKmaNm2q3bt3h8w1P19//bV27tzpmlapUiW1bdtWxYsX1+7du7Vq1Sr9+eefSk9PD7mNcL7/8rJ582bFx8erU6dOKlWqlCZOnBiU/Wuvvabhw4crNja2AHse2vfffx/UUXfeeeepRIkS6tChg1JSUrRr1y5n3sSJE7Vnzx4VK1asQNvPvh9qSkqKLrroIsXHx2vChAnKyMhwLffiiy+qb9++IbcRExOjhg0bqnz58ipVqpRSU1O1b98+rVixQr/++qtr6NL58+frww8/1HXXXVeg9mWLjo7WzTffrPvvv9+ZtmrVKk2dOlXnnHOOa9lPPvnE9TgxMVFXXHGF8zhUh2nDhg3VtGlTJSQkaOfOnVq2bJkWLlyY7xC0h/PRRx8FdQSefPLJatmypZKTk5WRkaEVK1Zo4cKF3JcWAAAARY/XlyYCAAAAoYQahm7o0KHmwIEDpmLFiq4hAzds2GAefvhh17KDBg0yxoQeMjC3Rx99NGiZypUrm7Vr1zrLBAIBc+eddwYtV7FiRXPgwAFnuVBDO5YsWdIsWbLEWebgwYPmmmuuCTnsXO5hQp944omgZa6++mqTmZnpWu6hhx4KWm748OGuZcI5TGjTpk2DtjVgwICj2pYxxuzevduUKFEiZOY5LV++POQQni+99JJruVD1I8mMHTvWWWbx4sUhl0lNTTVLly51lnvqqaeCluncuXPQPuT1nC+++KJrua+//jrkELIzZsxwLbdo0SIza9askEM+GnOoJgcMGBC0nc8//zxo2VDvA5/P5xraMWcWxhSsXnK/d6pUqRJyuE2/329mz55tBg8ebBYuXJjvNo7l/ZfXviYnJ5s5c+Y4y6xevdqUKlUqaLl58+aFfK0LKtT7+s0333TmX3XVVfnWZG6h6qlixYpm9erVzjJz5swJObTl9u3bXdvKysoyEydONOnp6Xk+3x9//BFUm126dAla7nDDhBpjzObNm018fHzQsSun9PT0oGV69OjhWib30L6XX355yLbv3bvXfPvtt+bGG28MmleQYUJvvPFG1/wWLVqEHIo2KyvLTJs2zdx2221m8+bNIdsCAAAAnGgYJhQAAABFSkxMjG644Qbn8cGDB/Xqq6/q9ddfd6b5fD7ddNNNBd7mhAkTgqY98sgjrmHufD6fHn/8cZUrV8613MaNG11XU33zzTdB27r77rtVp04d53F0dLSef/75Al1Fl/uqmfj4eL344otB6w4ZMkSJiYn5rhtOoa7ySklJOert/fTTT9qxY4drWq1atfTQQw+5pp188skhr/b8/PPPD/sczZo10zXXXOM8rlu3btBQhpJ08803q3bt2s7jyy+/PGiZ1atXH/b5pENX3WVfbZjtwgsvDDlkZO7aqVevnpo3by5jjH799Ve98cYbGjZsmO655x7dcccduvPOO7Vu3bqg7cydO7dAbevVq5d69eoVNL2gV6lJwZlnZmZq27ZtQctFRUWpWbNmGjFihE477TTXvHC+//Jy0003qUmTJs7jatWq6YILLgharqC5hrJ3796gOoyJiVGXLl2cx6Fq6UiHCr3vvvtUrVo153H2lbO5rVmzxvU4NjZWl1xyiVJTU7Vq1Sp99NFHGjFihO677z7deeeduuOOOzR27FglJSW51itoPeVWpkwZXXnlla5pn376qetK0i+//FL79+93LZNziFApuMZ27Njhujo4W2Jiotq3b+/6v+BI5H6e3bt3B11xKR16Hc8++2w9//zzKlOmzFE9FwAAAHC8MUwoAAAAipy+ffvq0UcfdYZufPzxx13Du3Xo0EE1atQo0LYOHjyoefPmBU3v1KlT0LS4uDi1a9cu6Mv72bNnq2XLlpIODauXW4cOHYKmlShRQqeffrp++eWXPNvm9/s1Z84c17T9+/erRIkSea6T019//aXdu3crOTm5QMsfibS0tKBpx3LfuNmzZwdNu+CCCxQVFfz7xU6dOumOO+447Pq5tW/fPmha+fLlnaE8s7Vr1y5omdxyDvWYnwsvvDDk9AsuuEAff/yxa1ru2jl48KCeeOIJPfPMMyE72PJS0PsZ5u50ORo57+EpHRqOs3r16qpbt65q166t2rVrq27dujrzzDNVs2bNoPXD/f7LS48ePYKmVahQIWhaQXMNZeLEiUHvgbZt26pUqVLO4wsuuEDFihVzDTP5ww8/aPPmzSpbtmyBnudY9uWnn37SoEGDCnyfTang9RTKrbfeqrFjxzqPMzMz9cEHHzj3c839g4WKFSsGvf/OO+88V4fxlClTVKZMGZ122mlOjZ122mlq1aqVSpcufdRtPe+88/T00087jxctWqTy5cvr1FNPdZ6nXr16atWqlSpVqnTUzwMAAAB4gSsDAQAAUORUqlRJl1xyifM4932esr9oLojt27e77t8mHbrCJOcX+DlVrlw5aFrOe4+F6rQ56aSTQm4rr+k5t5W7bUfCGBN0/7JwCdVx8ffffx/19rZs2RI0LdRrndf0nTt3HvZ+YaHWC3WfwdzLxcXFBS1T0Fzy2odQ2efudOnevbsefPDBI+oIlBTyqqlQGjRocETbDeXUU0/VgAEDXNP8fr/++usvffrpp3rsscd07bXXqlatWjr11FP17rvvupYN9/svL1WrVg2aFir7Y3m/vffee0HTct77Tjp079DcHcQHDx7UuHHjCvQcycnJKlmyZND0guzL559/rvPPP/+IOgKlgtdTKC1atFDTpk1d095++21Jh3488O2337rmXXPNNUE/AOjTp49atGgR1KZZs2Zp7NixevDBB9WlSxeVLVtW5513nn7//fejamvHjh1dV3FKUlZWlubNm6dx48Zp+PDh6tatm0466SS1aNEi5P1NAQAAgBMVnYEAAAAokvr16xdyepUqVUJeVRSpjuVqvfyEGpZw+vTph+2Q81KoDhOfz1eg5Y63SZMm6dNPPz2qdY0xBVquePHiR7X93J599lmNHz9eLVu2DHklZ7bFixerZ8+eGjlyZFie90iE6lyMjo4O2/a3bNmi7777Lmj69OnTdccdd7j+QnV8h+pIDCWvTtLD7cvBgwfVr18/52rq4yn3MLlz5szRggULNGnSJO3bt881L9TVqgkJCZo6daoef/xxnXzyyXk+jzFGP/74o9q0aaMZM2YcVVs//fRTvfrqq2rUqFG+y82aNUsXX3yxPvroo6N6HgAAAOB4Y5hQAAAAFEnt2rVTrVq1tHLlStf0vn375tshkVvJkiUVFRXluopm37592rZtW8gv3kPdoy3nVXKlSpXSxo0bXfPXr18f8kq69evX59u2UqVKBbUtNTVVvXv3zne9nI5l2Lz8tG/fXsOHD3dN27Fjh95///0jal+2UPfeCvVa5zW9ePHiIa/g81pe+xAq+5xZTZw4MWj+GWecoSeeeEINGzZ0hmn99ttvQ977riBCdYQerSuvvFJXXnmldu7cqQULFmjZsmVauXKlZs+erZ9//tnVQfnwww9rwIABiouLC/v7zysfffSRDh48GDQ95xCZ+Zk9e7ZWrFiRb2fXsZg1a5Y2bdrkmlasWDE9++yz6tSpk8qWLet0KFaoUCFo2WPRvXt33X333dq+fbsz7a233tK///7rWq5p06aqV69eyG0kJCTo3nvv1b333qv169dr4cKFWrFihZYtW6aff/5ZixYtcpbNysrSww8/HHTVYUFERUXppptu0k033aQtW7ZowYIFWr58uVasWKFff/3VdX9KY4yGDBkSdF9EAAAA4EREZyAAAACKJJ/Pp5tvvll33323My02NlY33HDDEW0nJiZGjRs3Dro339dff61rr73WNS0rK0s//PBD0DaaN2/u/LtRo0ZBnYHfffedmjRp4pq2c+dO1xfLoURHR6tJkyauYf127dqlu+66K8/hJ3Py+/1hvfopp5YtW6pZs2ZBQw7efffdatOmzWHv2bhp0ybt3bvXWS7na5ht8uTJCgQCQZ27X3/9ddCyodY/EUyePFn/+9//gqaH6qjIeTVS7vsYStKLL74YNOTizJkzj72RYVS8eHG1adNGbdq0caY9+OCDevTRR53Hu3fv1uLFi9WoUaOwv/+8kvs+hke7jWHDhh17Y0IIVU+9e/cOOl7+888/Ye0IlA4N+3r99de7rgh97733gq4iLug9LE866SSddNJJznCrxhi1bt1a06dPd5YJx/uiTJkyateunesehtdcc40r6+XLl2vnzp1hu8oWAAAAKCwMEwoAAIAiq3fv3kpLS1N8fLzi4+N1xRVXqFy5cke8ncsuuyxo2gMPPOC6CskYo8GDBwfdg69ChQquITNz3w9MkkaNGqXly5c7j/1+v+644w7t37//iNtmjNHll1+uDRs2hFw+IyNDH3/8sS666CI99thjh93+sRgxYkTQ1WXbt2/XWWedpa+++irkOlu2bNEjjzyiOnXq6M8//3Smn3POOSpRooRr2ZUrVwZ1pK1YsUKPPPJI0HZz3+vrRPHHH3/o5Zdfdk377rvv9MknnwQtm7N2Ql3luGDBAtfjn3/+WU888USYWnp0Zs6cqdtvv10zZ87M8357oe5bmbP2w/n+88KqVav022+/HfN2wtGhmJdQ9fTXX3+5Mtu2bVtQB2y49OvXz9Wpv2PHDu3Zs8d5HBsbq6uuuirkum+88YZGjBihFStWhJy/f/9+paenB007UhMnTtQDDzzgOi7lFAgEgu7rebTPBQAAABxvXBkIAACAIqtkyZLauXPnMW+nf//+evbZZ1338lq3bp1OPfVUderUScWLF9evv/4a8kviIUOGKCbm/06rr732Wg0ZMsTVrm3btqlJkya66KKLVLx4cU2bNk1LliwpcNuee+45VyfIrFmzVK1aNbVp00ZVq1ZVXFyctm/frqVLl2rJkiU6cOCAJKlZs2ZH+lIckXbt2mn48OF66KGHXNP//fdfXXzxxapWrZrOPPNMlShRQhkZGVqyZInmz58f8r5lxYoV0z333KP777/fNX3YsGH64osvdPrpp2vbtm2aNGmS9u7d61qmSpUq6tOnT/h3MExuvfVWjRs3TqeddprWrl3rXPGYU7NmzdSyZUvncdOmTfXll1+6lunbt68+/fRTVa5cWcuXL9fUqVMLfH/AwrJr1y698MILeuGFF1S8eHHVr19f1atXV0pKivbt26e5c+dq/vz5rnWioqJUs2ZN53E4339eCNWJd+211+rdd9/Nd70qVaq4OjxXrlypmTNnqkWLFmFvY+4rSiVp6tSpql+/vlq1aqUdO3boxx9/dA3lGU7Vq1fXhRdeqEmTJoWc37FjxzyHNF67dq0effRR3X///TrppJN06qmnqlKlSkpKStKOHTv0888/Bw27e8oppxxxG7ds2aLHHntMjz32mMqUKaP69eurSpUqSk5O1q5du/Tbb7+5ftQhHboSNtQQxwAAAMCJhs5AAAAARLzU1FR98sknOv/8811D1+3atUvjxo3Lc70rr7xS/fr1c01LS0vTc889FzTk3Z49ezR+/Hjnsc/nU6VKlQ5738CUlBRNmDBB5513njIzM53pBw8e1JQpUwq0f4VpyJAhCgQCevjhh4M6uNasWaM1a9YUeFuDBg3SjBkzgjoM5s6dq7lz54ZcJykpSZ9++qkSEhKOuO3HQ7169bR48WL98ssv+uWXX0IuExcXp9dff9017frrr9cTTzyhffv2OdP8fn/QEKkdOnQ4qnujFYadO3fmu5/ZrrjiClfHTzjff14I1RnYtWvXw67XpUsXvfDCC65p7733XqF0BlatWlUXX3xxUAfz4sWLtXjxYudxw4YNtWnTppBXcx6rW2+9Nc/OwIIOEbp+/frDHjMlHXNdbNmyRT/++ONhl7vpppuO6B61AAAAgFc4awUAAAAktW7dWr/88ovriqW8xMTE6N5779UHH3wQcv51112nxx57LGgIzZzrv/DCCzrvvPMK1LaWLVvqt99+06mnnlqg5aVDwyc2bNiwwMsfi6FDh+q77747oisRK1SoEHTfw+joaE2YMEEDBgwo0L0O69Spo19//bXQr4A8Fvfcc49uu+22POcnJSXpk08+UePGjV3TTzrpJL333nuKj4/Pc91+/fpp8ODBYWvr0cirxvNy3nnn6dVXXw2aHs733/E0Z84cLVu2zDUtOTlZHTp0OOy6l156adC08ePH6+DBg2FrX05vvfWW6tWrl+f82rVra+LEiYXWsX7BBReEzLdUqVLq1KlTnusdSY35fD4NHDhQN9100xG370hruUePHho+fPgRPw8AAADgBa4MBAAAAP6/008/XUuXLtVHH32kL774QrNnz9bmzZu1f/9+lShRQieffLLatm2rG2+8UVWrVs13W/fdd5/atm2rp556StOnT9eOHTtUtmxZtWnTRgMHDlSTJk3Uq1evAretUaNGWrhwoSZNmqTPPvtMM2fO1MaNG5WRkaGEhASVLl1ap5xyipo3b67zzz9fZ599doE61MLlvPPO0+zZs/Xzzz/rm2++0S+//KJ169Zp27ZtOnDggNLS0lSzZk01a9ZMF154odq3b6/Y2Nig7cTFxenZZ5/VbbfdprfeektTp07VypUrtXPnTiUkJKhs2bI6/fTT1aVLF3Xt2vW47uPRev7559WxY0e9/PLLmjVrlnbs2KHy5cvrggsu0ODBg1W9evWQ61122WX6448/9Pjjj+vHH3/U1q1bVbJkSTVp0kQ333yzLrnkEk2dOvX47kwu5513nv766y/98MMPmjVrlpYsWaJ169YpPT1dxhglJyerSpUqatq0qa688kpdcMEFeW4rnO+/4yXUVYEdO3YsUIda69atVapUKW3bts2ZtmXLFn333Xfq2LFjWNspSWXKlNHMmTP1zDPP6KOPPtLKlSsVFxen6tWr64orrtCAAQOUnJwc9ufN5vP5dMstt+iuu+5yTe/evXvIexpmGzp0qNq3b6+pU6fqjz/+0PLly/Xvv/9q9+7dio6Odo4trVq1Us+ePVW/fv2jal+fPn3UsGFD/fjjj5o9e7aWLl2qDRs2aNeuXfL5fEpJSVH16tXVokUL9ejRQ61atTqq5wEAAAC84DNe32QCAAAAACwwbNiwoCuFRo8efUSdvoDNvvrqK1188cWuabNmzVLz5s09ahEAAAAQGRgmFAAAAAAAFCq/369Ro0a5pp166ql0BAIAAADHAcOEAgAAAACAsJs8ebImT56sPXv2aMaMGVqyZIlrfn730wQAAAAQPnQGAgAAAACAsPv999/13HPPhZxXu3Zt9enT5zi3CAAAAIhMDBMKAAAAAACOm+LFi2v8+PGKjY31uikAAABARKAzEAAAAAAAFKro6GiddNJJuv766zVv3jw1bNjQ6yYBAAAAEcNnjDFeNwIAAAAAAAAAAABA+HFlIAAAAAAAAAAAAGApOgMBAAAAAAAAAAAAS9EZCAAAAAAAAAAAAFiKzkAAAAAAAAAAAADAUnQGAgAAAAAAAAAAAJaiMxAAAAAAAAAAAACwFJ2BAAAAAAAAAAAAgKXoDAQAAAAAAAAAAAAsRWcgAAAAAAAAAAAAYCk6AwEAAAAAAAAAAABL0RkIAAAAAAAAAAAAWIrOQAAAAAAAAAAAAMBSdAYCAAAAAAAAAAAAlqIzEAAAAAAAAAAAALAUnYEAAAAAAAAAAACApegMBAAAAAAAAAAAACxFZyAAAAAAAAAAAABgKToDAQAAAAAAAAAAAEvRGQgAAAAAAAAAAABYis5AAAAAAAAAAAAAwFJ0BgIAAAAAAAAAAACWojMQAAAAAAAAAAAAsBSdgQAAAAAAAAAAAICl6AwEAAAAAAAAAAAALEVnIAAAAAAAAAAAAGApOgMBAAAAAAAAAAAAS9EZCAAAAAAAAAAAAFiKzkAAAAAAAAAAAADAUnQGAgAAAAAAAAAAAJaiMxAAAAAAAAAAAACwFJ2BAAAAAAAAAAAAgKXoDAQAAAAAAAAAAAAsRWcgAAAAAAAAAAAAYCk6AwEAAAAAAAAAAABL0RkIAAAAAAAAAAAAWIrOQAAAAAAAAAAAAMBSdAYCAAAAAAAAAAAAlqIzEAAAAAAAAAAAALAUnYEAAAAAAAAAAACApegMBAAAAAAAAAAAACxFZyAAAAAAAAAAAABgKToDAQAAAAAAAAAAAEvRGQgAAAAAAAAAAABYis5AAAAAAAAAAAAAwFJ0BgIAAAAAAAAAAACWojMQAAAAAAAAAAAAsBSdgQAAAAAAAAAAAICl6AwEAAAAAAAAAAAALEVnIAAAAAAAAAAAAGApOgMBAAAAAAAAAAAAS9EZCAAAAAAAAAAAAFiKzkAAAAAAAAAAAADAUnQGAgAAAAAAAAAAAJaiMxAAAAAAAAAAAACwFJ2BAAAAAAAAAAAAgKXoDAQAAAAAAAAAAAAsRWcgAAAAAAAAAAAAYCk6AwEAAAAAAAAAAABL0RkIAAAAAAAAAAAAWIrOQAAAAAAAAAAAAMBSdAYCAAAAAAAAAAAAlqIzEAAAAAAAAAAAALAUnYEAAAAAAAAAAACApegMBAAAAAAAAAAAACxFZyAAAAAAAAAAAABgKToDAQAAAAAAAAAAAEvRGQgAAAAAAAAAAABYis5AAAAAAAAAAAAAwFJ0BgIAAAAAAAAAAACWojMQAAAAAAAAAAAAsBSdgQAAAAAAAAAAAICl6AwEgCPUvXt3+Xw++Xw+zZ492+vmFGmdOnWSz+dTdHS0Fi9e7HVzcIyy3xc+n09jxow5onW3bNmi1NRU+Xw+1a9fX8aYwmlkDps2bVLv3r1VqVIlxcTEOG3//PPPC/25kb9q1ao5eQwbNszr5gQZOXKk075XX33V6+YAAIAiYurUqa5z5jVr1pxQ28OJadGiRYqOjpbP51OnTp28bk6RNnv2bOf90r17d6+bAwDHFZ2BwAnmtNNOc53MV6hQQQcPHvS6Wfj/5s6dq48++kiS1LZtWzVv3vy4PXf//v1dteHz+fTXX3/luXzOL9Nz/sXFxalixYq65JJL9MUXXwStN2bMmJDr5fxr165dyOf8999/NWDAAJ188slKTExUiRIldNZZZ+n111+X3+8PWv6ee+6RJAUCAd1///1H+cqcmNavX6877rhDp556qooVK6b4+HiVL19e9evXV7du3TRixAjt2LHD62aeMB555BHt2rVLknT33XfL5/M583r16uWqv3Awxujyyy/XmDFjtHHjxpD1iWPTtm3bwx5Lcv8daSeyV2666SalpqZKkh5++GHt3bvX4xYBAAApuHPM5/PpkksuCbnst99+G7Rsr169jm+DTwCffPJJ0Ovw4osvet0s5HD//fcrEAhIkgYNGnTcnnfTpk2KjY111cbll1+e5/L5fZeQkpKiRo0aafDgwdq8eXPQunl9f5Hzb/r06SGf96OPPlK7du1UqlQpxcfHq1q1arr++uu1YsWKoGWbN2+uNm3aOOvNmzfvKF8dACh66AwETiCzZ8/WokWLXNM2bdqkyZMne9Qi5DZs2DDniqUBAwYct+fdv3+/Pvzww6DpR/PF+YEDB/Tvv//qyy+/VOfOndW3b98wtFD6448/dNppp+n555/XypUrlZmZqZ07d2rGjBm66aab1KlTJ2VmZrrWadu2rRo0aCBJmjhxoubOnRuWtnht7ty5Ou200/Tcc89p8eLF2rt3r7KysvTff//pr7/+0kcffaT7779fa9eu9bqpJ4R///3XubqqdOnS6tGjR6E/5z///KMZM2Y4jy+66CI98cQTGjlypE477bRCf37k74EHHtDIkSM1cuRItW/f3uvmBElNTXW+LMxZvwAA4MQzadIkrVq1Kmj6c88950FrTjyjR48OmlZUfqAVCebMmeP8iLdhw4ZOR9bxMHbs2KAfp3/55Zfavn37EW9r9+7dWrBggZ544gmdeuqp+vPPP4+5fcYY9erVS926ddOUKVO0fft2ZWVlae3atXr77bfVoEEDff3110HrZX+XY4zR0KFDj7kdAFBUxHjdAAD/J68T7jFjxuiiiy46vo0pJBkZGc7VFEXN+vXrNWnSJEmHvgi+8MILj9tzf/HFFyFPuN9//309/vjjionJ/3Beo0YN9evXT9KhTpB33nlHGRkZkqQ33nhDnTp1UufOnYPWO//880N+EV+1alXX4927d+vyyy932li5cmX17t1bmzZt0ltvvSW/369vv/1WQ4YM0ciRI13rdu/e3fkg8Nprr+m1117Ld1+KgltuuUXp6emSpGLFiqlbt26qUaOGDhw4oBUrVuiXX37RunXrPG7liWP06NHKysqSJHXt2lWxsbGF/py5O2KfffZZ1axZs1Cfc8+ePUpMTFRUVGT8Fqtfv35B/3dlXw0sSc2aNVO3bt1c87Ovtr7xxhsLv4HHqHv37nr++eclSa+//roGDhzocYsAAEAogUBAL774op5++mln2vLly/nRrQ79+Pjbb78Nmj5nzhz99ddfVvxIzu/3a//+/UpKSvK6KUcl5+fj4z2s5TvvvBM0LSsrSx988IH69+9/2PVvvvlm1axZU/v27dMPP/ygadOmSZK2bt2qnj175nlVXu7vDLJVr17d9fjFF190tbF79+6qV6+exo0bp8WLFyszM1M9evTQokWLVKlSJWe5jh07KjU1VRkZGfr666+1fv16nXTSSYfdHwAo8gyAE0JmZqYpUaKEkWQkmVNOOcX5d1xcnNm6dWue6y5ZssTccsstpm7duqZYsWImMTHRVK9e3XTr1s3Mnj3btWwgEDAff/yxufjii03FihVNXFycKVGihGnUqJG58847zf79+40xxqxevdp5fknmp59+cm2nTZs2zryePXs600Ot9+abb5rGjRubhIQE07BhQ2OMMatWrTIDBgwwZ511ljnppJNMUlKSiYuLMxUrVjQXXXSR+eKLL/Lc31mzZplevXqZmjVrmsTERFOsWDFz8sknm169epmVK1cav99vqlev7rThvvvuC9rG3Xff7cyvW7fuYdI55JFHHnHW6dGjR9D80aNHu/Z9586d5rbbbjPly5c3SUlJpm3btmbmzJnGGGP+/vtv07VrV1O8eHGTnJxsOnToYBYuXJjnc3fs2DFkbUgyX375Zch1qlat6izTpk0b17zvv//etY1rr7025H4MHTq0QK/NSy+95Kzj8/nM0qVLnXn333+/My8hIcFs377dte7y5cud+SkpKWbfvn2Hfb4333zTWScpKcns3r3bNX/Hjh0mPj7eWea9994zxhhz4MAB88wzz5gzzjjDpKWlmejoaFOyZElTr149c+2115oPP/ywQPubn/T0dNdrO2bMmJDLzZo1y2zZssU1LWdmQ4cONb///rs5//zzTWpqqklOTjbt27c3f/zxR8jtbdq0ydx3332mYcOGJjk52cTHx5uaNWuaW265xaxduzbkOn6/37z77rvm/PPPN2XKlDGxsbGmdOnSpmPHjmbSpEkh1zlw4IAZMWKEqVWrlomLizM1atQw//vf/0xWVpZrv0ePHl3g16xWrVrOet99913Q/J49e7q2nde8Nm3amI0bN5obb7zRlC9f3sTFxZk6deqY119/3bVOzm2F+stp/vz5pnfv3qZGjRomISHBFCtWzDRq1Mg8+uijQXVnTHCGv/zyiznvvPNMamqqkWR27NgRtm3/8ccfplOnTiYtLc0kJiaas846y/zyyy8hX+OtW7eahx9+2LRo0cIUL17cOd62b9/ejBs3Lmj5adOmmW7dupnKlSubuLg4k5KSYs444wzz4osvmqysrJDPURA5X+ec/3ccbl+z/fTTT65tLF261Dz00EOmSpUqJjEx0TRv3tx88803xhhjNm/ebPr06WNKly5tEhISTKtWrcy0adNCPt/RvH8CgYCpVKmS05bp06cf9esCAADCI/e5QlRUlJFk0tLSXOdX/fv3d5aJjo7O9/xk/fr15u677zannXaaKVasmImPjzdVq1Y1V199tfP5LretW7eam266yZQtW9YkJCSYpk2bmnHjxgW1b/Xq1a71jvT8/HDbO5wnn3zSWTc5OdlUrFjReXzXXXflud6BAwfMW2+9Zc4//3xTtmxZp50tWrQww4YNC1p+3bp1ZtCgQaZRo0YmJSXFxMfHm8qVK5vOnTu7zv9zn9sXdF9zr7d27VpzzTXXmLJlyxqfz2c+++wzY4wxb731lrniiitMnTp1TKlSpUxMTIxJSUkxDRs2NIMGDQr6fJZt9+7d5plnnjGtW7c2JUuWNLGxsaZcuXKmdevW5sUXXzTGGPP22287bUhMTDQ7d+50bWPHjh0mNjbWWSbUOXhue/fuNSkpKc46y5cvD1om93nz119/bc444wyTmJhoKlWqZB544AHn/P2ll14yderUMfHx8aZ69erm0UcfNYFAIORzz5o1y/V65/weomnTpiHXyf2dSO7vkc466yzX/L///jvkfhTEgQMHTIUKFUJ+R7Nt2zbX6zZo0KCg9Xv06OHMf+SRRwr0nABQ1NEZCJwgxo8f7zop+u2331wnis8//3zI9d58800TFxeX55fazzzzjLPsvn37TKdOnfL9Ejz7i+pwdQaeffbZrsfZnYFffvnlYb+QHz58eND+Dh8+3Ph8vjzXyT7JHzlypDOtYsWK5uDBg67t5DzRfPLJJwuUUevWrZ11sk/4c8p94tu0adOg9iUkJJiJEyeakiVLBs0rVaqU2bx5c9B2N27c6PqA+vrrr5vGjRs7jy+77LKQ7c2vM3D37t2u5z7//PND7ke5cuVMWlqaiY2NNSeddJLp1q2b+e2334Keq0OHDs469evXd82bM2eO67lCfegpXbp0nrUWSkZGhklKSnLW+eCDD1zz33rrLWdeWlqa2bt3rzEmuFMp91+LFi0O+9yHs23bNtc277777qD6y0vOzM466yzXMSDnB8vcHT6//vqr6zXM/ZeWlhbUCbJ3717Trl27fF+PgQMHBrWxe/fuIZfNfWwpaGfgqlWrnHWioqJMRkZG0DIF7QysUaOG6wNhzr+33nrLWedwx55sL7/8somJiclzuXr16pl///03zwzPPPNM13tX+r9j7LFu+/TTTw9ZH/Hx8Wbx4sWu9WbNmmXKly+f53N17tzZtXzODvxQf2effXbIzsqCyLmdcHQGhjrORkVFmXHjxrl+FJLf63M0759sXbt2DdlOAADgjdznCl26dHH+/dJLLxljDv14L7ujoHHjxq7zjtznJz///LPrR7uhzjueeuop1zo7duwwderUKdA5c84OraM5Pz/WzsB69eo56/bo0cPceeedzuNy5cqZAwcOBK2zbds207x583zPnXKaNGmSq2Mm99+AAQOcZcPRGXjyyScHnftmf08Q6twx51+lSpXMhg0bXM/7999/m5NPPjnPdbK/49i3b58pVapUUL1ly9lZWKJECZOZmXnYfH788UdnnTJlyoRcJmf9Nm7cOOT3JT179jS33XZbyPYPGTIk5Hb79evnLHPSSSeZzz//3LXen3/+GbTO4ToDc/4oW5KZMWNGyP2oUaOGiY2NNSkpKaZ58+ZmxIgRZs+ePa5t/fbbb65tffrpp675F198sTOvTp06QW194YUX8qw1ALBVZIxTBRQBOYcIbdKkic444wy1a9cu5Pxsv//+u/r27esMrxcTE6OrrrpKw4cP14033qjKlSu7lr/rrrucYS6lQ0M53n777RoyZIguu+wyxcXFhXenJP3yyy+qWrWqBg4cqAcffFAtWrRw2tqoUSPdcMMNuu+++zRixAg9+OCDOuecc5x1//e//2nDhg3O448//lhDhw517tmXlJSkPn36aPjw4erVq5dKlSrlLHv99dc7w4Bs3LjRtd+zZs1yhgiMiYnRtddee9j9yMrK0qxZs5zHzZo1O+w68+bN04033qg777zTGfYwMzNTnTt3VkZGhm655RbdcMMNzvLbtm3TW2+9FbSdsWPHyu/3S5JiY2PVtWtX1/AgX331lbZt23bY9uT022+/uR6XL18+5HL//fef0tPTdeDAAa1fv17jx49Xq1at9MILL7iWyznef40aNVzzcj8OdW+AnK/nL7/8ctj2p6SkuG5c/sEHH7jm53zcvXt3JSYmavfu3Xrvvfec6V27dtWjjz6qQYMGqVu3bnm+BkeqZMmSrmFUR40apXLlyqlz584aNmyYvv32W+3fv/+w25k+fbqqV6+uBx54QD179nSGlty3b5969+7t1ERGRoa6dOmirVu3Sjo0hOugQYM0dOhQnXrqqZKk9PR0de3a1Rm6VJLuvPNO/fDDD5KkuLg4XXfddfrf//6nK6+8Uj6fT5L09NNPu17LTz75ROPGjXMe16pVS/fff7969uypb7755qher5x5n3LKKUpJSTmq7UjSqlWrtGPHDvXr108DBw5UYmKiM+/JJ590/j1y5EjdfPPNrnXvv/9+5x51kvTrr7+qf//+zj0yzjjjDA0bNkx33XWXSpcuLUlavHixrrvuujzb89tvvyk+Pl59+/bV8OHD1aVLF0VHR4dl27NmzVK5cuV07733uu6xuH//ftf9b3bt2qVLLrlEmzZtcqade+65GjJkiAYMGKCmTZu6tjtu3Dg99thjzuMOHTro4Ycf1q233qrk5GRJhzK7884782zb8TRnzhx169ZN9913n1M7gUBA3bt31+rVq3XttdfqzjvvdIZSzv36HO37J1v2sKZSwY5dAADg+Lr66qud86sXX3xR0qEh6nft2iVJuv322/Ncd+fOnbrsssu0Y8cOSVJiYqJuueUWDR482DnfDwQCuvvuu/Xzzz876z344INaunSp87hNmzZ66KGHdN5557k+l+Z2NOfnx2LWrFlavHix87h79+6uz5n//fdfyHP8a6+9VrNnz3Ye161bV3fddZfuv/9+XXjhhYqOjnbmrV27VldccYXzevt8PnXu3FlDhw7VLbfcojp16oRlX3JasWKFNm3apMsuu0zDhw9Xnz59lJaWJkkqW7asLr74Yt1xxx16+OGH9eijj+qWW25xvkvYsGGDHnnkEWdbfr9fXbp00YoVK5xpzZs31+DBg3XPPfeodevWTjYJCQmuoe7ffPNNV7s+/vhj5989evRQfHz8Yfcl5/ll7vP2UObNm6d69eppyJAhrvPUd955Ry+88IIaN26sIUOG6OSTT3bmPffcc853Stn279/v+tx35ZVX6sILL1Tx4sWdaUdzX8nff//d9Tivz+CrVq3SgQMHtGvXLs2ePVv33Xefmjdvri1btjjL5P5eIb/vIZYvXx70GTzn6zNz5syg1wAArOR1bySA4Cu/Ro4caYwx5t133833l1eXXXaZ6xeJua9c2L9/v1m3bp0xxpjt27e7rkJp3Lix2bVrl2v5f/75xxk+IlxXBlavXt01LF5uy5YtM+PGjTMvvPCCGTVqlBk5cqTriq93333XWbZJkybO9GLFiplly5a5trV7927z33//OY9vvPFGZ/mLL77YmX7XXXeFnJ6fnFcvSQr6taAxwb+CyznUxFVXXeWal52xMcacccYZzvRQV/nl/LVmp06djDHGrF271vWLv1BXjub+Zd3IkSPNyJEjze233+4MWZj9l/1Lyez9iI+PNx07djQDBw40w4YNc/2qLrvectZjziE5cw45aowxBw8edK170003BbX1hhtuCFlP+Zk6daqzTmxsrNm2bZsxxph///3X9X7KHrpn+/btzrTU1FRnSNxsgUDArFq1qkDPfTgTJkzI9wrWtLQ0M3z48HyvWC1durRraJlHH33UtY3vv//eGGPMc8895/qFafbrYMyh90SZMmWc+c8995wx5tCveXMeD95++21XO2655RbXsSJbzitA09LSXM+Vu30FvTLwoYcectbJeYVqTgW9MlCS+fzzz515zz77rGtezqsOD/cr6ksvvdSZ17ZtW+P3+515uYfMWbBggTMvZ4bR0dFmzpw5QfsTjm0XK1bMdRzK+av3Jk2aONOff/551/YeffTRoPbkHJ4n51XH1113nWu5jz76yJkXExPjyr+gcrYlHFcG3nDDDc68++67zzXv1ltvdeblvKI15+tzNO+fnN577z1nftWqVY/49QAAAOGV+1zhyy+/dI16MHnyZGeI+jJlypjMzMw8rwx85plnXNv6+uuvnXn//fefSU5OduZlj7Rw4MAB1/TWrVs753qBQMC0b98+5Dno0Z6fH8uVgTmv/CpRooTz+ahmzZrO9NyfT//880/X83Xs2DFoCPmc55YDBw50Lf/++++7lvX7/fkO95lTQa8MlGSeffbZPPd7z5495ocffjCvv/66efrpp83IkSNN586dnXVr1KjhLPvFF1+4ttu3b9+gYTVz7u/atWtdn0WzPwts377dNapHqM8IoVx33XXOOjfeeGPIZXLWb6lSpUx6erox5tB3LTnbXrZsWWd0j8mTJ7vm5f6uKffIVdm3n+nTp48zLdSVo7m/E7n55pvNyJEjzf/+9z/Xd0jS/11RmXM/atWqZfr06WOGDx9uBgwY4Bq2VpK5/PLLneVHjBjhmpczB2OMefDBB13zc4+6sn79+qN+7wBAUUVnIHACeOKJJ5wTEJ/PZ/755x9jzKGhEBMSEpx5d955p2u9smXLOvMuvPDCfJ/j66+/dp3ojB8/Pt/lw9UZOGrUqDy337JlS9eyof4ee+wxY8yhE/acnSv9+vXLt/3GuD+oREdHO1+c5zxZnjBhwmG3Y4wxM2fOdLUr1H3tcp/4rlmzxpmX+0vqnPeguvrqq53p55xzTr7PO3bsWGdeztcv5wfCbDn3M7+/Pn36uNbbuHFj0P0NjDHm9ddfd62X8x4SOTsDr7nmGtd6Bw4ccK0XqjPw3nvvdX2gLIhAIOD6oJp9X7icX+6feuqprnVOPfVUZ17FihVN586dzd13323eeecds379+gI9b0H99NNP5txzz3XuUxLqL/ewgjkzy53L2rVrXes+/vjjxhhjrrzyygLlLMl069bNGBN8PMjvz+fzOUOy5Bz2JntbebWvoJ2BOb+EyL3NbAXtDKxYsaJr3jfffJPn++5wX5zkPL4e7u+VV15x1suZ4UUXXRRyf8Kx7dz3Lc35HqpevbozPWd9pKSk5Dtkbe7j7OH+su/NdyRyrh+OzsCpU6c681577TXXvJ9//tmZ98ADDxz29Sno+yennDWWlJR0xK8HAAAIr1CdgevXr3c62nLe7/eBBx4wxpg8OwNznieEGqLxiiuucOaXLVvWGGPMwoUL8zyXM8aYd955J+Q56NGenx9tZ2BmZqZr+NPrr7/emZez8zQuLs5s3brVmffyyy+7ni+veyZmO/30051l69ate9h2haMzsESJEiGHNzXGmKeeesrVWRvqLy4uzll+0KBBrnk5f3ycl5w/2r755puNMe4hQhs0aHDYbWS78MILnfXuvffekMvkrN9evXo50/fv3+9qe+/evZ15K1asyPO8Offz1qpVy5n+3XffudabOHGia73c34nk9VeyZEkzb94817pLliwJ2reMjAxTu3ZtZ73o6Gjnu4rcnYErV650rZvz/F8K7gzct2+fa/6sWbNCvr4AYBOGCQVOADmHV2jZsqUzvGdKSoo6derkzHv//fedYeUkafv27c6/q1evnu9z5Fy2IMvnZv7/0JzZCjLMoaQ8h/3o0qWLfv3118Oun/08O3bscLWhIO2vX7++2rZtK+nQ8B6jR4/WzJkznSFCy5Qpo4suuuiw2zlaFStWdP6dewjWnPOyh6+TDg0zk9Po0aOdfycmJqpz587O46uuusr597x587Rw4cICtSsmJkbly5fXRRddpAkTJgQNTVqhQgVnGJWccg69KklLlixx/p1z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H42NGzfq+++/L/Dy8+bN059//qkGDRrorLPOcs373//+p88++8z1GTT73FI6dC46a9YsSYdGlhk3bpzrKkRjjNatW6cqVapIcnemLlu2TDt37lTx4sWVnp6ul1566Yj3Naec30PUqFHD6QANBAL65JNPQq5z1lln6cknn3QeDx06VC+//LLrh3g59zfbbbfdpr59+0qS7r//fh04cECSdPHFF4ccKScvXnxWOpLvqLKvHC3I+yk/EyZM0L59+9StWzdXLe3atcs1WlJcXJzzPUOzZs1UsWJF50fJn376qS677DJJ0tatW12f3UP9+DLn65mQkHDYHwcAgA3oDAQ8lJmZ6bryq3r16jr99NODllu4cKEWL14sSfrqq6+0detWlS5dWvfcc48+//xzBQIB+f1+nXPOObryyitVu3Ztbdq0Sd9++6369++vO+64QyVKlFDfvn318ssvSzrU4VGvXj116dJFxYsX1/Lly/XZZ5/p33//VfHixZWamqpTTjnFGYLh0Ucf1bx587Rv3z79+OOPx7TftWrVUlRUlDMUxYABAzR//nxt27bNdaKX2+DBg3XllVdKknbv3q1GjRqpe/fuqlq1qtatW6evvvpKL7/8srp06eKsEx0drX79+um+++6TdOg1lw6dOJ522mkFbnN8fLyaNWvmDG06d+7ckFmFU87XolixYiGHNP3vv/+ck9zNmzdr0qRJ+V5lVBDvvPOOXnzxRbVu3VpnnnmmEhIS9Mcff+jLL790lomLi9P111/vPL7uuuv0xBNPaO3atTLGqH379urdu7c2btzoGoa0f//+QcNzSNKcOXOcf+d3JVIovXv3doYxyflr09xDhErSGWecoYoVK+rss89WxYoVlZqaqgULFjgdgVLwr3mPxrvvvqt3331XNWvW1FlnnaUaNWrI5/NpwYIFTge+JLVu3drVIZ/T1q1b1bx5c11xxRVav369xo4d68yrWbOmq8PykUce0datW3Xw4EG1atVKV1xxhWrVqqX9+/dr2bJlmjp1qv777z/99NNPql69ukqWLKk+ffrojTfekCQ9+eST+uOPP9SyZUslJCRow4YN+v333zVv3jz17NlTHTp0kHRoqNjszsD09HS1aNFC3bp1C2rfkcj5A4Zly5Zpz549ef6a93i66667NHHiRBljtHLlSp122mm67LLLVK5cOaWnp2vhwoX6+eeftWfPHlcntNfbzq1Xr1569NFHnV+h33fffZoyZYrOPPNM7d27V7///rtKly7tdE7ec889zq+VZ8yYoQYNGujiiy9WiRIltG3bNs2bN0/Tp09XhQoVXF/kFFVH8/7J6Y8//nD+faTHLgAAcHy9++67Wrp0qWJjY3XmmWcedvmePXvqf//7n9OJ1LVrV/Xp00epqan64IMPnA4/n8+nO+64Q9Khq6+uu+4653P3tGnTdO6556pNmzaaMWOGc4VYbkd7fn60r0POK78uvvjioM8kgUDA9aPO0aNH65lnnlH9+vXVsWNHff3115IOfT/RsGFDdezYUQkJCVq0aJGmTZumrVu3SjrU6frKK684V/n16NFD48ePV6NGjbRjxw5NnTpVbdu21bPPPitJrtGLMjIy1LhxY51++umaMWOGM8Tr0apdu7bTCfrnn3/qqquuUt26dfXNN9/o999/D7lOx44dnav8JOnVV1/VvHnzdO6558oYo7lz52rz5s2aN2+ea72rr75a9957r3bs2OF8ByGF/oyan5yflbJ/GF2Yfv/9dy1dutR53KJFi6DbE0jSlClTnIxHjx59zJ2B//zzj+68807dc889uvDCC1WjRg1t3bpVH3/8sSv3a665xvkxbXR0tO677z7ddtttkg7dEiQQCKhevXr68MMPtWfPHkmHrqIN1b6c5/Gnn3560LCqAGCl432TQgD/58MPP3TdsPi9994LudyUKVNcyz377LPOvDfffNPExcXleWPmZ555xll23759pmPHjvneyHnHjh2ubYdapkaNGqZOnTrO45w3WV+9erVr2Z9++inkPt18880ht33eeee5buo+dOhQ13rDhg0zPp8vz/Z/9tlnQc+1detWk5CQ4FrupZdeOlw8QYYOHeqsf9111wXNz32z7LzWzT0v1E3S169fb6KiopzpN9xwQ8g2ZWRkmKSkJGe5Ll26OPNy3kg8983X85OWlpZvjSQkJJjx48cHrTd79mzXTehz/7Vv397s27cvaL3ly5c7yyQnJ5u9e/cWuK3GGJOZmRn0vOXKlQt50/j4+Ph896169erODcmNyf8G9vnJ7zmy/0qWLGkWLlzoWi9nZuedd17I9iYkJATd4H3GjBmmdOnSh33OnO/HPXv2mHbt2h12nZzvb2OMueKKK0Iu17ZtW9fj0aNHF/j1yrnfP/74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z1itVVt2h+X53333XZUqVco10oUkdenSRddee60k6ZVXXlHNmjUVFxen2rVra+zYsfluc+HChTr33HOVmJioUqVKqW/fvtq9+//a27x5c40cOVLdu3cP+aM6Sbrwwgv1yCOP6NJLL83zeapVq6bHHntMffr0UUpKiqpUqaLXX3+9oLvOezQCkC28wLEFXqL+4DVqEF6i/hApIqozUJIGDhyoN954Q++8846WLFmifv36ac+ePerdu7ck6brrrtN9993nLD9z5kxNmDBBq1at0i+//KILLrhAgUBAgwYNknTonjannXaa669YsWIqVaqUTjvtNE/20WvGGK1bty7ksEsoesjTPmRqF/K0D5napzAy/XHpZmXsO6iyKaE7xXIrmxKvjH0H9dPSzWF5/iuuuEJ+v19ffPGFM23z5s2aNGmS+vTpo88++0wDBgzQXXfdpb/++ks33XSTevfurZ9++ink9vbs2aMOHTqoRIkSmj17tj7++GP98MMP6t+/f1jam9tTTz2lZs2aad68ebrlllvUr18/1z0h88N71H5kCy9wbIGXqD94jRqEl6g/RIqI6wzs1q2bRo0apYceekiNGjXS/PnzNXnyZJUrV06S9M8//+jff/91ls/MzNSDDz6oevXq6dJLL1WlSpU0ffp0FS9e3KM9AAAAQCTbvf+gfljyn5Ljow97D8BsPp9PyXHR+n7Jf9q9/+AxtyExMVE9evTQ6NGjnWnvvfeeqlSporZt22rUqFHq1auXbrnlFp1yyikaOHCgLrvsMo0aNSrk9j744ANlZmbq3Xff1WmnnaZzzz1XL774osaOHRs0xH84dOzYUbfccotq1aqle++9V6VLl86zoxIAAAAAgKIuou4ZmK1///55/sp46tSprsdt2rTR4sWLj2j7ubcBAAAAhMs/2/Zq594DKl0s7ojWS0uM1dY9WVq3fa/qVjj2m6rfeOONat68uTZs2KBKlSppzJgx6tWrl3w+n5YsWaK+ffu6lm/VqpWee+65kNtasmSJGjZsqGLFirmWDwQCWrZsmfPDvXBp0KCB82+fz6fy5ctr8+bwXDUJAAAAAMCJJiI7A1H4UlJSvG4Cwog87UOmdiFP+5CpfcKZaeZBvwLGKDqqYFcFZouO8ilgjDIP+MPSjsaNG6thw4Z699131b59ey1atEiTJk0Ky7YLW2xsrOuxz+c7onuE8B4FUBg4tsBL1B+8Rg3CS9QfIkHEDROKwhcdHa2aNWsqOjra66YgDMjTPmRqF/K0D5naJ9yZJsREK8rnkz9wZPe08AeMonw+JcSGr7ZuuOEGjRkzRqNHj1a7du1UuXJlSVLdunU1Y8YM17IzZsxQvXr1Qm6nbt26WrBggfbs2eNaPioqSrVr1w5be8OB96j9yBZe4NgCL1F/8Bo1CC9Rf4gUdAYi7AKBgDZt2nREv67GiYs87UOmdiFP+5CpfcKdaZVSSSqeFKv0zANHtF76vgMqnhSryiWTwtIOSerRo4fWr1+vN954Q3369HGm33PPPRozZoxeeeUVrVixQk8//bQmTJigu+++O+R2rr76aiUkJKhnz57666+/9NNPP+m2227Ttdde6wwRmpWVpfnz52v+/PnKysrShg0bNH/+fK1cudLZzu7du51lJGn16tWaP3++/vnnn7DtM+9R+5EtvMCxBV6i/uA1ahBeov4QKegMRNgZY7Rp0yYZc2S/VseJiTztQ6Z2IU/7kKl9wp1pcnyM2tUtp937/QXepjFGu7P8Or9uOSXHh+9OAWlpaeratauSk5PVpUsXZ3qXLl303HPPadSoUTr11FP12muvafTo0Wrbtm3I7SQlJenbb7/V9u3b1bx5c11++eU677zz9OKLLzrLbNy4UY0bN1bjxo3177//atSoUWrcuLFuuOEGZ5k//vjDWUaSBg4cqMaNG+uhhx4K2z7zHrUf2cILHFvgJeoPXqMG4SXqD5GCewYCAAAARcy5dcrqyz83avOu/SqXmnDY5Tfv2q/UxBidU6ds2NuyYcMGXX311YqPj3dN79evn/r165fnerk/bNevX18//vhjnstXq1btsB/Q27Zte9hl1qxZEzQt+0pCAAAAAABsxJWBAAAAQBFTo0yy+rSqLn/A6L+MzDw7wIw5NN8fMOrTqrpqlEkOWxt27Nihzz77TFOnTtWtt94atu0CAAAAAIDw4spAhJ3P51PJkiXl8/m8bgrCgDztQ6Z2IU/7kKl9CivTSxpWlCS9PWO1Vm/bq+S4aKUlxio6yid/wGjnvgPak+VXamKMbmxdw1k+XBo3bqwdO3boiSeeUO3atcO67RMZ71H7kS28wLEFXqL+4DVqEF6i/hApfIbBcE8IGRkZSktLU3p6ulJTU71uDgAAAI6TzMxMrV69WtWrV1dCwuGH/Mxt1Zbd+mnpZn2/5D/t3HtAAWMU5fOpeFKszq9bTufUKRvWKwIjUX4ZcR5vD7IEAAAAih7O4wuGKwMRdoFAQOvXr9dJJ52kqChGoi3qyNM+ZGoX8rQPmdqnsDOtUSZZNcokq9vpVbRu+15lHvArITZalUsmKTme0/1w4z1qv0Ag4HUTEIE4tsBL1B+8Rg3CS9QfIgXVjbAzxmj79u153rsGRQt52odM7UKe9iFT+xyvTJPjY1S3QqoaVymhuhVS6QgsJLxH7Ue28ALHFniJ+oPXqEF4ifpDpKAzEAAAADgB8OHzxMWVYgAAAACAooyfCwMAAAAeio2Nlc/n05YtW1SmTBluXH8CMcYoKytLW7ZsUVRUlOLi4ui0BQAAAAAUOXQGIux8Pp/Kly/PF1mWIE/7kKldyNM+ZGqfw2UaHR2tk046SevXr9eaNWuOb+NQIElJSapSpYqioqIUCAR4j1qObOEF/v+Hl6g/eI0ahJeoP0QKn+GnrSeEjIwMpaWlKT09XampqV43BwAAAMeZ3+/XgQMHvG4GcomOjlZMTEyeXw5wHm8PsgQAAACKHs7jC4YrAxF2fr9fa9asUbVq1RQdHe11c3CMyNM+ZGoX8rQPmdqnoJlGR0eTeRHAe9R+fr/f6yYgAnFsgZeoP3iNGoSXqD9EiiivGwA77dq1y+smIIzI0z5kahfytA+Z2odM7UKeAAoDxxZ4ifqD16hBeIn6QySgMxAAAAAAAAAAAACwFJ2BAAAAAAAAAAAAgKXoDETY+Xw+Va5cWT6fz+umIAzI0z5kahfytA+Z2odM7UKe9iNbeIFjC7xE/cFr1CC8RP0hUsR43QDYJyoqSqVKlfK6GQgT8rQPmdqFPO1DpvYhU7uQp/2iovjNLI4/ji3wEvUHr1GD8BL1h0jBpxyEnd/v19KlS+X3+71uCsKAPO1DpnYhT/uQqX3I1C7kaT+yhRc4tsBL1B+8Rg3CS9QfIgWdgSgUmZmZXjcBYUSe9iFTu5CnfcjUPmRqF/IEUBg4tsBL1B+8Rg3CS9QfIgGdgQAAAAAAAAAAAICl6AwEAAAAAAAAAAAALEVnIMIuKipKNWrUUFQU5WUD8rQPmdqFPO1DpvYhU7uQp/3IFl7g2AIvUX/wGjUIL1F/iBQxXjcA9vH5fEpNTfW6GQgT8rQPmdqFPO1DpvYhU7uQp/18Pp/XTUAE4tgCL1F/8Bo1CC9Rf4gUdHcj7Px+vxYuXCi/3+91UxAG5GkfMrULedqHTO1DpnYhT/uRLbzAsQVeov7gNWoQXqL+ECnoDESh4OBpF/K0D5nahTztQ6b2IVO7kCeAwsCxBV6i/uA1ahBeov4QCegMBAAAAAAAAAAAACxFZyAAAAAAAAAAAABgKZ8xxnjdCEgZGRlKS0tTenp6kb9hqTFGmZmZSkhIkM/n87o5OEbkaR8ytQt52odM7UOmdsmdp03n8ZEuO8udO3cqLS3N6+YgwvB/BbxE/cFr1CC8RP0VfXwmKxiuDEShiIuL87oJCCPytA+Z2oU87UOm9iFTu5AngMLAsQVeov7gNWoQXqL+EAnoDETYBQIBLVy4UIFAwOumIAzI0z5kahfytA+Z2odM7UKe9iNbeIFjC7xE/cFr1CC8RP0hUtAZCAAAAAAAAAAAAFiKzkAAAAAAAAAAAADAUnQGAgAAAAAAAAAAAJbyGWOM142AlJGRobS0NKWnpys1NdXr5hwTY4wCgYCioqLk8/m8bg6OEXnah0ztQp72IVP7kKldcudp03l8pMvOcufOnUpLS/O6OYgw/F8BL1F/8Bo1CC9Rf0Ufn8kKhisDUSiysrK8bgLCiDztQ6Z2IU/7kKl9yNQu5AmgMHBsgZeoP3iNGoSXqD9EAjoDEXaBQEDLli1TIBDwuikIA/K0D5nahTztQ6b2IVO7kKf9yBZe4NgCL1F/8Bo1CC9Rf4gUdAYCAAAAAAAAAAAAlqIzEAAAAAAAAAAAALAUnYEoFNHR0V43AWFEnvYhU7uQp33I1D5kahfyBFAYOLbAS9QfvEYNwkvUHyKBzxhjvG4EpIyMDKWlpSk9PV2pqaleNwcAAABAAXAebw+yBAAAAIoezuMLhisDEXbGGGVkZIh+ZjuQp33I1C7kaR8ytQ+Z2oU87Ue28ALHFniJ+oPXqEF4ifpDpKAzEGEXCAS0atUqBQIBr5uCMCBP+5CpXcjTPmRqHzK1C3naj2zhBY4t8BL1B69Rg/AS9YdIQWcgAAAAAAAAAAAAYCk6AwEAAAAAAAAAAABL0RmIQpGQkOB1ExBG5GkfMrULedqHTO1DpnYhTwCFgWMLvET9wWvUILxE/SES+Ax3xjwhZGRkKC0tTenp6UpNTfW6OQAAAAAKgPN4e5AlAAAAUPRwHl8wXBmIsAsEAtq2bRs3XbUEedqHTO1CnvYhU/uQqV3I035kCy9wbIGXqD94jRqEl6g/RAo6AxF2xhitW7dOXHRqB/K0D5nahTztQ6b2IVO7kKf9yBZe4NgCL1F/8Bo1CC9Rf4gUdAYCAAAAAAAAAAAAlqIzEAAAAAAAAAAAALAUnYEoFCkpKV43AWFEnvYhU7uQp33I1D5kahfyBFAYOLbAS9QfvEYNwkvUHyKBzzAY7gkhIyNDaWlpSk9PV2pqqtfNAQAAAFAAnMfbgywBAACAoofz+ILhykCEXSAQ0KZNmxQIBLxuCsKAPO1DpnYhT/uQqX3I1C7kaT+yhRc4tsBL1B+8Rg3CS9QfIgWdgQg7Y4w2bdokLjq1A3nah0ztQp72IVP7kKldyNN+ZAsvcGyBl6g/eI0ahJeoP0QKOgMBAAAAAAAAAAAAS9EZCAAAAAAAAAAAAFiKzkCEnc/nU8mSJeXz+bxuCsKAPO1DpnYhT/uQqX3I1C7kaT+yhRc4tsBL1B+8Rg3CS9QfIoXPMBjuCSEjI0NpaWlKT09Xamqq180BAAAAUACcx9uDLAEAAICih/P4guHKQIRdIBDQP//8o0Ag4HVTEAbkaR8ytQt52odM7UOmdiFP+5EtvMCxBV6i/uA1ahBeov4QKegMRNgZY7R9+3Zx0akdyNM+ZGoX8rQPmdqHTO1CnvYjW3iBYwu8RP3Ba9QgvET9IVLQGQgAAAAAAAAAAABYis5AAAAAAAAAAAAAwFJ0BiLsfD6fypcvL5/P53VTEAbkaR8ytQt52odM7UOmdiFP+5EtvMCxBV6i/uA1ahBeov4QKXyGwXBPCBkZGUpLS1N6erpSU1O9bg4AAACAAuA83h5kCQAAABQ9nMcXDFcGIuz8fr/+/vtv+f1+r5uCMCBP+5CpXcjTPmRqHzK1C3naj2zhBY4t8BL1B69Rg/AS9YdIQWcgCsWuXbu8bgLCiDztQ6Z2IU/7kKl9yNQu5AmgMHBsgZeoP3iNGoSXqD9EAjoDAQAAAAAAAAAAAEvRGQgAAAAAAAAAAABYis5AhJ3P51PlypXl8/m8bgrCgDztQ6Z2IU/7kKl9yNQu5Gk/soUXOLbAS9QfvEYNwkvUHyJFjNcNgH2ioqJUqlQpr5uBMCFP+5CpXcjTPmRqHzK1C3naLyqK38zi+OPYAi9Rf/AaNQgvUX+IFHzKQdj5/X4tXbpUfr/f66YgDMjTPmRqF/K0D5nah0ztQp72I1t4gWMLvET9wWvUILxE/SFS0BmIQpGZmel1ExBG5GkfMrULedqHTO1DpnYhTwCFgWMLvET9wWvUILxE/SES0BkIAAAAAAAAAAAAWIrOQAAAAAAAAAAAAMBSdAYi7KKiolSjRg1FRVFeNiBP+5CpXcjTPmRqHzK1C3naj2zhBY4t8BL1B69Rg/AS9YdIEeN1A2Afn8+n1NRUr5uBMCFP+5CpXcjTPmRqHzK1C3naz+fzed0ERCCOLfAS9QevUYPwEvWHSEF3N8LO7/dr4cKF8vv9XjcFYUCe9iFTu5CnfcjUPmRqF/K0H9nCCxxb4CXqD16jBuEl6g+Rgs5AFAoOnnYhT/uQqV3I0z5kah8ytQt5AigMHFvgJeoPXqMG4SXqD5GAzkAAAAAAAAAAAADAUnQGAgAAAAAAAAAAAJbyGWOM142AlJGRobS0NKWnpxf5G5YaY5SZmamEhAT5fD6vm4NjRJ72IVO7kKd9yNQ+ZGqX3HnadB4f6bKz3Llzp9LS0rxuDiIM/1fAS9QfvEYNwkvUX9HHZ7KC4cpAFIq4uDivm4AwIk/7kKldyNM+ZGofMrULeQIoDBxb4CXqD16jBuEl6g+RgM5AhF0gENDChQsVCAS8bgrCgDztQ6Z2IU/7kKl9yNQu5Gk/soUXOLbAS9QfvEYNwkvUHyIFnYEAAAAAAAAAAACApegMBAAAAAAAAAAAACxFZyAAAAAAAAAAAABgKZ8xxnjdCEgZGRlKS0tTenq6UlNTvW7OMTHGKBAIKCoqSj6fz+vm4BiRp33I1C7kaR8ytQ+Z2iV3njadx0e67Cx37typtLQ0r5uDCMP/FfAS9QevUYPwEvVX9PGZrGC4MhCFIisry+smIIzI0z5kahfytA+Z2odM7UKeAAoDxxZ4ifqD16hBeIn6QySgMxBhFwgEtGzZMgUCAa+bgjAgT/uQqV3I0z5kah8ytQt52o9s4QWOLfAS9QevUYPwEvWHSBHjdQMAAAAAADhRPL9wu+JT/F43AxHGZwIqtyNT3y7YJuPjd9s4vqg/eI0ahJeov6MzuHFpr5uAI0R1AwAAAAAAAAAAAJaiMxCFIjo62usmIIzI0z5kahfytA+Z2odM7UKeAAqD4SsaeIj6g9eoQXiJ+kMk8BljjNeNgJSRkaG0tDSlp6crNTXV6+YAAAAAKADO4+2RneXQaauUkJzidXMAAACAE9aJNEwon8kKJiK7vF966SVVq1ZNCQkJatGihWbNmpXnsgcOHNDDDz+smjVrKiEhQQ0bNtTkyZNdy4wYMULNmzdXSkqKypYtqy5dumjZsmWFvRsnLGOMMjIyRD+zHcjTPmRqF/K0D5nah0ztQp4RgGzhBWMUl7WX+oM3qD94jRqEl6g/RIiI6wwcP368Bg4cqKFDh2ru3Llq2LChOnTooM2bN4dc/sEHH9Rrr72mF154QYsXL9bNN9+sSy+9VPPmzXOW+fnnn3Xrrbfq999/1/fff68DBw6offv22rNnz/HarRNKIBDQqlWrFAgEvG4KwoA87UOmdiFP+5CpfcjULuRpP5/4IgjHn09GJXdvpP7gCeoPXqMG4SXqD5Ei4joDn376ad14443q3bu36tWrp1dffVVJSUl6++23Qy4/duxY3X///erYsaNq1Kihfv36qWPHjnrqqaecZSZPnqxevXrp1FNPVcOGDTVmzBj9888/mjNnzvHaLQAAAAAAAAAAACBIRHUGZmVlac6cOWrXrp0zLSoqSu3atdNvv/0Wcp39+/crISHBNS0xMVHTp0/P83nS09MlSSVLlgxDqwEAAAAAAAAAAICjE+N1A46nrVu3yu/3q1y5cq7p5cqV09KlS0Ou06FDBz399NNq3bq1atasqSlTpmjChAny+/0hlw8EArrjjjvUqlUrnXbaaXm2Zf/+/dq/f7/zOCMjQ5Lk9/udbft8PkVFRSkQCLjuSZI9PXcb8poeFRUln88Xcnp2mwsyPTo6WsaYkNNzttHv9ysuLs7ZRqi2F7V9ym+67fuUnaff77dmn2zM6Uj3KTtTm/YpdxsjZZ+MMYqPjy/wvhaFfbIxpyPZJ7/fr4SEBBljgrZTVPcpu4025XQk+8S5kV37lPvcCADC5WBUnNdNQASj/uA1ahBeov4QCSKqM/BoPPfcc7rxxhtVp04d+Xw+1axZU717985zWNFbb71Vf/31V75XDkrSiBEjNHz48KDpixYtUnJysqRDVxZWqVJF69ev1/bt251lypcvr/Lly2vNmjXatWuXM71y5coqVaqUVqxYoczMTGd6jRo1lJqaqsWLF7u+TKldu7bi4uK0cOFCVxvq16+vrKwsLVu2zJkWHR2t+vXra9euXVq1apUzPSEhQXXq1NGOHTu0bt06Z3pKSoqio6O1adMmbdq0yZle1PepZs2a2rx5c0Tu0+LFi63bJ8m+nAqyT6tWrVJWVpYWL15szT7ZmNOR7NMpp5xi3T7ZmNOR7lNGRoZ1+2RjTpwb2ZfTkZ4bJSUlCXYxvogaQAcnCOOL0tbiVbxuBiIU9QevUYPwEvWHSOEzuX8Ka7GsrCwlJSXpk08+UZcuXZzpPXv21M6dOzVx4sQ8183MzNS2bdtUsWJFDR48WF999ZUWLVrkWqZ///6aOHGipk2bpurVq+fbllBXBlauXFnbt29XamqqpKL7q+pAIKCdO3eqVKlSkhRRvxS3cZ/8fr927typ4sWLKzo62op9sjGnI9mnAwcOOJlGRUVZsU825lTQfZKkHTt2KC0tzdmPor5PNuZ0JPsUCASUkZGh4sWLK7eiuk/ZbbQppyPZJ86N7Nqn3OdGu3fvVlpamtLT053zeBRNGRkZSktL09Cf/1ZCClniODNGift3aV98isRVxzjeqD94jRqEl6i/ozK4cWmvm+DIPo/nM1n+IurKwLi4ODVt2lRTpkxxOgMDgYCmTJmi/v3757tuQkKCKlWqpAMHDujTTz/VlVde6cwzxui2227TZ599pqlTpx62I1CS4uPjFR8fHzQ9Ojpa0dHRrmk5v9zNvezxnu7z+UJOz93GDRs2qGTJknluuyju09FOL+r7ZIxx8sxerqjvU2G18Uine7VPUVFRId+jRXmfbMypoNP9fr/Wr1+vEiVKhFynKO7T0Uy3bZ/WrVvndDQUtI0n+j5J9uUkcW50NNOL+j6FOjeCXXyKmN/L4gTik1Ha3s3KjE+WEV9E4vii/uA1ahBeov4QKSKqM1CSBg4cqJ49e6pZs2Y6/fTT9eyzz2rPnj3q3bu3JOm6665TpUqVNGLECEnSzJkztWHDBjVq1EgbNmzQsGHDFAgENGjQIGebt956qz744ANNnDhRKSkpzpBCaWlpSkxMPP47CQAAAAAAAAAAACgCOwO7deumLVu26KGHHtKmTZvUqFEjTZ48WeXKlZMk/fPPP65f+GZmZurBBx/UqlWrlJycrI4dO2rs2LGuobteeeUVSVLbtm1dzzV69Gj16tWrsHcJAAAAAAAAAAAACCniOgOlQ/f2y2tY0KlTp7oet2nTRosXL853exF028UCS0lJ8boJCCPytA+Z2oU87UOm9iFTu5AngMKwPybJ6yYgglF/8Bo1CC9Rf4gEEdkZiMIVHR2tmjVret0MhAl52odM7UKe9iFT+5CpXcjTfsbHvSBx/BlflHakVvS6GYhQ1B+8Rg3CS9QfIgWfchB2gUBAmzZtUiAQ8LopCAPytA+Z2oU87UOm9iFTu5BnBGDkF3jBGCXv3U79wRvUH7xGDcJL1B8iBJ2BCDtjjDZt2sTwqZYgT/uQqV3I0z5kah8ytQt52s8nssXx55NRcuZ26g+eoP7gNWoQXqL+ECnoDAQAAAAAAAAAAAAsRWcgAAAAAAAAAAAAYCk6AxF2Pp9PJUuWlM/n87opCAPytA+Z2oU87UOm9iFTu5Cn/RggCl4wkvbFpVJ/8AT1B69Rg/AS9YdIEeN1A2CfqKgoValSxetmIEzI0z5kahfytA+Z2odM7UKeEcDHb2bhAV+U0pPLet0KRCrqD16jBuEl6g8Rgk85CLtAIKB//vlHgUDA66YgDMjTPmRqF/K0D5nah0ztQp4RwJAtPGACStu9mfqDN6g/eI0ahJeoP0QIOgMRdsYYbd++XcZwcbUNyNM+ZGoX8rQPmdqHTO1CnvZjAFh4wScpMSuD+oMnqD94jRqEl6g/RAo6AwEAAAAAAAAAAABL0RkIAAAAAAAAAAAAWIrOQISdz+dT+fLl5fNxcbUNyNM+ZGoX8rQPmdqHTO1CnvYzDBIFDxj5tDuhJPUHT1B/8Bo1CC9Rf4gUMV43APaJiopS+fLlvW4GwoQ87UOmdiFP+5CpfcjULuQZAejohRd8Pu1OKul1KxCpqD94jRqEl6g/RAiuDETY+f1+/f333/L7/V43BWFAnvYhU7uQp33I1D5kahfytJ/PBLxuAiKQzwRUImMj9QdPUH/wGjUIL1F/iBR0BqJQ7Nq1y+smIIzI0z5kahfytA+Z2odM7UKeAApD/MG9XjcBEYz6g9eoQXiJ+kMkoDMQAAAAAAAAAAAAsBSdgQAAAAAAAAAAAICl6AxE2Pl8PlWuXFk+n8/rpiAMyNM+ZGoX8rQPmdqHTO1CnvYzIlscf0Y+pSeVpf7gCeoPXqMG4SXqD5EixusGwD5RUVEqVaqU181AmJCnfcjULuRpHzK1D5nahTwjAB298ILPp30JqV63ApGK+oPXqEF4ifpDhODKQISd3+/X0qVL5ff7vW4KwoA87UOmdiFP+5CpfcjULuRpP58JeN0ERCCfCaj0zn+oP3iC+oPXqEF4ifpDpKAzEIUiMzPT6yYgjMjTPmRqF/K0D5nah0ztQp4ACkNMIMvrJiCCUX/wGjUIL1F/iAR0BgIAAAAAAAAAAACWojMQAAAAAAAAAAAAsBSdgQi7qKgo1ahRQ1FRlJcNyNM+ZGoX8rQPmdqHTO1CnvYz8nndBEQgI5+2J1ek/uAJ6g9eowbhJeoPkSLG6wbAPj6fT6mpqV43A2FCnvYhU7uQp33I1D5kahfyjAA+vgiCB3w+ZcUled0KRCrqD16jBuEl6g8Rgp+zIuz8fr8WLlwov9/vdVMQBuRpHzK1C3nah0ztQ6Z2IU/7+UzA6yYgAvlMQOW2r6L+4AnqD16jBuEl6g+Rgs5AFAq+HLELedqHTO1CnvYhU/uQqV3IE0Bh8IkvIeEd6g9eowbhJeoPkYDOQAAAAAAAAAAAAMBSdAYCAAAAAAAAAAAAlqIzEGEXFRWl2rVrKyqK8rIBedqHTO1CnvYhU/uQqV3I035GPq+bgAhk5NPW1MrUHzxB/cFr1CC8RP0hUvAJFoUiLi7O6yYgjMjTPmRqF/K0D5nah0ztQp4ACoM/OtbrJiCCUX/wGjUIL1F/iAR0BiLsAoGAFi5cqECAG6/agDztQ6Z2IU/7kKl9yNQu5Gk/n4zXTUAE8smo3I5V1B88Qf3Ba9QgvET9IVLQGQgAAAAAAAAAAABYis5AAAAAAAAAAAAAwFJ0BgIAAAAAAAAAAACW8hljGAz3BJCRkaG0tDSlp6crNTXV6+YcE2OMAoGAoqKi5PP5vG4OjhF52odM7UKe9iFT+5CpXXLnadN5fKTLznLoz38rIYUscZwZI5+MjHwS/1fgeKP+4DVqEF6i/o7K4MalvW6Cg89kBcOVgSgUWVlZXjcBYUSe9iFTu5CnfcjUPmRqF/IEUBii/Qe8bgIiGPUHr1GD8BL1h0hAZyDCLhAIaNmyZQoEAl43BWFAnvYhU7uQp33I1D5kahfytJ9PDJ6D488no9IZ66g/eIL6g9eoQXiJ+kOkoDMQAAAAAAAAAAAAsBSdgQAAAAAAAAAAAICl6AxEoYiOjva6CQgj8rQPmdqFPO1DpvYhU7ucKHn+888/uvnmm1W7dm2VLFlS06ZNkyRt3bpVt99+u+bNm+dxCwEcCcNXNPAQ9QevUYPwEvWHSBDjdQNgn+joaNWvX9/rZiBMyNM+ZGoX8rQPmdqHTO1youS5ePFinX322QoEAmrRooVWrlypgwcPSpJKly6t6dOna8+ePXrrrbc8bmnRY3x8GYTjz/ii9F/JGl43AxGK+oPXqEF4ifpDpOBTDsLOGKOMjAwZw01XbUCe9iFTu5CnfcjUPmRqlxMlz0GDBql48eJavny53nvvvaD2dOrUSb/88otHrSvieK/CC8YoLmsv9QdvUH/wGjUIL1F/iBB0BiLsAoGAVq1apUAg4HVTEAbkaR8ytQt52odM7UOmdjlR8pw2bZr69eunMmXKyOfzBc2vUqWKNmzY4EHLij6f+CIIx59PRiV3b6T+4AnqD16jBuEl6g+Rgs5AAAAAAChiAoGAkpKS8py/ZcsWxcfHH8cWAQAAAABOVHQGAgAAAEAR06RJE02aNCnkvIMHD2rcuHE644wzjnOrAAAAAAAnIjoDUSgSEhK8bgLCiDztQ6Z2IU/7kKl9yNQuJ0Ke9913nyZPnqx+/frpr7/+kiT9999/+uGHH9S+fXstWbJEgwcP9riVAI7Ewag4r5uACEb9wWvUILxE/SES+EzuO83DExkZGUpLS1N6erpSU1O9bg4AAACAAvDyPH7s2LEaMGCA0tPTZYyRz+eTMUapqal65ZVXdNVVVx3X9hR12VkOnbZKCckpXjcHAAAAOGENblza6yY46FspmBivGwD7BAIB7dixQyVKlFBUFBefFnXkaR8ytQt52odM7UOmdjmR8rz22mt12WWX6fvvv9eKFSsUCARUs2ZNdejQQSkpdGYdNX4vCy8Yo8T9u7QvPkXy+bxuDSIN9QevUYPwEvWHCEFnIMLOGKN169apePHiXjcFYUCe9iFTu5CnfcjUPmRqlxMhz71796py5coaPHiw7rnnHnXp0sWzttjIJzoDcfz5ZJS2d7My45NlxBeROL6oP3iNGoSXqD9ECn6aDAAAAABFSFJSkmJiYlSsWDGvmwIAAAAAKALoDAQAAACAIqZr16765JNPxC3gAfw/9u48vKk6f///fRLoBm2h0FLAsrQiILINKAq4M+KGMG4goID7wqCijoyCqCjouOHHBXdUhEFFHXVUGEUQFZfBbZAdCoJg2VqaspRCzvn94a/5WtpCW9K+03eej+viuuTkJH2d3rchyTsnAQAAAA6FjwlFteA7SuxCnvYhU7uQp33I1D5kapdIyHPQoEG6/vrrdeqpp+qqq65Sq1atFB8fX2q/P/3pTwamA1AVe+skmB4BUYz+wTQ6CJPoH6KB4/FW0ogQCASUnJys/Px8JSUlmR4HAAAAQAWYehzv8/2/D3lxnNLfbeJ5nhzHUTAYrLGZarviLMcvyFZcffMLvgAAAECkGtO1sekRQlhbqRjODETYua6rLVu2KC0trcSLFKidyNM+ZGoX8rQPmdqHTO0SKXlOnTrV2M+2Hu+XhQmep/p78rQzvqFUxgI/UK3oH0yjgzCJ/iFKsBiIsPM8Tzk5OUpNTTU9CsKAPO1DpnYhT/uQqX3I1C6RkuewYcOM/nybOWIxEDXPkaf6hbnaFd9AnnghEjWL/sE0OgiT6B+iBW9NBgAAAAAAAAAAACzFmYEAAAAAUMtcfvnlh9zHcRy9+OKLNTANAAAAACCSsRiIsHMcRykpKXL4jGUrkKd9yNQu5GkfMrUPmdolUvL89NNPS80QDAb122+/KRgMKjU1VfXq1TM0Xe3Gh4TCBE/Snpgk+gcj6B9Mo4Mwif4hWrAYiLDz+Xxq0aKF6TEQJuRpHzK1C3nah0ztQ6Z2iZQ8161bV+b2ffv26dlnn9XkyZP18ccf1+xQtnD4Ng0Y4PiUXz/N9BSIVvQPptFBmET/ECV4loOwc11X69evl+u6pkdBGJCnfcjULuRpHzK1D5naJdLzrFu3rkaOHKkzzjhDI0eOND1O7eRFZrawnOcqeecW+gcz6B9Mo4Mwif4hSrAYiLDzPE+5ubnyPE6utgF52odM7UKe9iFT+5CpXWpLnp07d9aCBQtMj1Er8YG+MMGRFF8UoH8wgv7BNDoIk+gfogWLgQAAAABgmY8//lgJCQmmxwAAAAAARAC+MxAAAAAAapl77723zO07duzQggUL9P3332vMmDE1PBUAAAAAIBKxGIiwcxxH6enpchxOrrYBedqHTO1CnvYhU/uQqV0iJc+77767zO0NGzZUVlaWnnnmGV111VU1O5QlPD4kCgZ4crQzLoX+wQj6B9PoIEyif4gWLAYi7Hw+n9LT002PgTAhT/uQqV3I0z5kah8ytUuk5Om6rukR7MXCPUxwHO1MSDE9BaIV/YNpdBAm0T9ECb4zEGEXDAa1Zs0aBYNB06MgDMjTPmRqF/K0D5nah0ztEil5LliwQFu3bi338m3btmnBggU1OJE9HI+FVtQ8x3PVMLCJ/sEI+gfT6CBMon+IFiwGoloUFBSYHgFhRJ72IVO7kKd9yNQ+ZGqXSMjz1FNP1ccff1zu5XPnztWpp55agxMBOFyx+3ebHgFRjP7BNDoIk+gfogGLgQAAAABQy3ied9DL9+7dK7/fX0PTAAAAAAAiGd8ZCAAAAAC1wPr167Vu3brQ35cvX17mR4Hu2LFDzz77rFq2bFmD0wEAAAAAIhWLgQg7x3GUkZEhx3FMj4IwIE/7kKldyNM+ZGofMrWLyTynTp2qe+65R47jyHEc3X///br//vtL7ed5nvx+v5599tkan9EGnvh/FTXPk6P8hDT6ByPoH0yjgzCJ/iFasBiIsPP5fGrUqJHpMRAm5GkfMrULedqHTO1DpnYxmefFF1+sY445Rp7n6eKLL9aoUaN04oknltjHcRzVq1dPXbp0UZMmTYzMWeuxcA8THEd74pJMT4FoRf9gGh2ESfQPUYLFQIRdMBjUqlWr1KZNG76nxALkaR8ytQt52odM7UOmdjGZZ/v27dW+fXtJv58leNJJJ6l169Y1OkM0cDzX9AiIQo7nqlH+r9qefIQ8x2d6HEQZ+gfT6CBMon+IFrQb1aKwsND0CAgj8rQPmdqFPO1DpvYhU7tEQp5Dhgw56BmKgUBA+/fvr8GJAByuOm6R6REQxegfTKODMIn+IRqwGAgAAAAAtcyoUaPUs2fPci/v1auXbrnllhqcCAAAAAAQqVgMBAAAAIBaZvbs2brwwgvLvfzCCy/Uhx9+WIMTAQAAAAAiFYuBCDufz6fMzEz5fNTLBuRpHzK1C3nah0ztQ6Z2iZQ8N23apObNm5d7ebNmzbRx48YanMgenhzTIyAKeXKUW78Z/YMR9A+m0UGYRP8QLeqYHgD2cRxHSUlJpsdAmJCnfcjULuRpHzK1D5naJVLybNSokVasWFHu5cuWLYuIOWslhxeCYIDjqCgmwfQUiFb0D6bRQZhE/xAleHsywi4YDGrx4sUKBoOmR0EYkKd9yNQu5GkfMrUPmdolUvI888wz9eyzz+qHH34oddn333+v5557TmeddZaByWo/x3NNj4Ao5HiumuRm0z8YQf9gGh2ESfQP0YIzA1EtTL84gvAiT/uQqV3I0z5kah8ytUsk5DlhwgTNnj1bxx13nM477zx16NBBkvTzzz/r/fffV1pamiZMmGB4SgCV4YgXIWEO/YNpdBAm0T9EAxYDAQAAAKCWadasmRYtWqQxY8bo3Xff1TvvvCNJSkpK0pAhQzRx4kQ1a9bM8JQAAAAAgEjAYiAAAAAA1EJNmzbVK6+8Is/ztHXrVklSamqqHL7zDgAAAADwBywGIux8Pp/atm0rn4+vpLQBedqHTO1CnvYhU/uQqV0iMU/HcRQbG6v69euzEBgGnvgdouZ5crQtKYP+wQj6B9PoIEyif4gWkfMMFlaJiYkxPQLCiDztQ6Z2IU/7kKl9yNQukZLnokWLdOaZZyohIUGNGjXSZ599Jknatm2b+vfvr/nz55sdEEClBP11TY+AKEb/YBodhEn0D9GAxUCEneu6Wrx4sVyXL161AXnah0ztQp72IVP7kKldIiXPhQsXqnfv3lq1apWGDh1aYp7GjRsrPz9fzz77rMEJay9HnukREIUceWqSl03/YAT9g2l0ECbRP0QLFgMBAAAAoJa544471L59ey1dulQTJ04sdfmpp56qb775xsBkAAAAAIBIw2IgAAAAANQy//3vfzVixAjFxsaW+T2BzZs3V05OjoHJAAAAAACRhsVAAAAAAKhl6tate9CPKt24caPq169fgxMBAAAAACIVi4EIO5/Pp44dO8rno142IE/7kKldyNM+ZGofMrVLpOR5/PHHa9asWWVetmvXLk2dOlUnn3xyDU9lB0+lz7QEqpsnR5sbZtI/GEH/YBodhEn0D9GCVyRQLYqKikyPgDAiT/uQqV3I0z5kah8ytUsk5HnPPfdo0aJFOuecc/TRRx9Jkn766Se98MIL6tatm7Zu3apx48YZnhJAZfiD+0yPgChG/2AaHYRJ9A/RgMVAhJ3rulqxYsVBP7YItQd52odM7UKe9iFT+5CpXSIlzx49eujDDz/U6tWrddlll0mSbrnlFl199dUKBoP68MMP1alTJ6Mz1laOPNMjIAo58tQ4sIH+wQj6B9PoIEyif4gWdUwPUJ78/Hx98MEH+uGHH7Rp0ybt2bNH8fHxatasmbp06aJzzjlHDRo0MD0mAAAAABhx2mmnacWKFfrxxx+1atUqua6rrKwsdevWTY7DxxwBAAAAAH4XkYuBDz30kCZMmKCdO3fK5/OpUaNGiouLU2FhobZv3y7XdVWvXj2NHTtWt99+u+lxAQAAAKBGvfrqqzrppJPUqlUrdenSRV26dClx+bp167RgwYLQWYMAAAAAgOgVcR8T+uSTT+r2229X//79tXDhQu3Zs0ebN2/WL7/8os2bN2vPnj364osvNGDAAN1xxx164oknTI+MMvj9ftMjIIzI0z5kahfytA+Z2odM7RIJeY4YMUILFy4s9/JvvvlGI0aMqMGJABwuL/JeokEUoX8wjQ7CJPqHaBBxZwb+3//9ny677DK9/PLLZV5et25d9ezZUz179pTP59MTTzyhv/71rzU7JA7K7/erY8eOpsdAmJCnfcjULuRpHzK1D5naJVLy9LyDf6fJrl27VKdOxD3dqxU8hxeDUPM8x6fNKZmmx0CUon8wjQ7CJPqHaBFxzw43bNigE088sUL7nnTSSXrjjTeqeSJUlud5KigoUGJiIt9VYgHytA+Z2oU87UOm9iFTu5jM83//+59+/PHH0N8///xz7d+/v9R+O3bs0DPPPKOjjjqqBqezyCEWWoFq4XmK2bdHRXXjJf6tQE2jfzCNDsIk+ocoEXFveWzdurX+85//VGjfOXPmqHXr1pX+GU899ZRatWqluLg49ejRQ99++225++7bt0/33nuvsrKyFBcXp86dO2v27NmHdZu2c11X2dnZcl3X9CgIA/K0D5nahTztQ6b2IVO7mMzznXfe0fDhwzV8+HA5jqNnn3029Pc//rnpppuUk5OjSZMm1fiMNnDEYiBqniNPKTs30T8YQf9gGh2ESfQP0SLizgy85ZZbdNVVV6mwsFDXX3+9unXrpsaNG4cu37ZtmxYtWqQpU6bo3//+t5577rlK3f7rr7+u0aNH65lnnlGPHj00efJk9e3bVytWrFBaWlqp/ceOHavXXntNzz//vNq1a6c5c+boL3/5ixYuXKiuXbtW6TYBAAAAoLKuvvpqnXvuufI8T8cdd5zuvfdenXXWWSX2cRxH9erVU1ZWFh8TCgAAAACQFIGLgVdccYX279+vsWPH6t///rek37+XIyYmRkVFRQoGg/I8TykpKXryySd1xRVXVOr2H330UV111VUaMWKEJOmZZ57RBx98oJdeekljxowptf+0adN055136uyzz5YkXXfddfrkk0/0yCOP6LXXXqvSbQIAAABAZTVt2lRNmzaVJM2bN0/t27fnzYcAAAAAgEOKuMVASbrmmms0bNgwzZs3Tz/88IN+++037dmzR/Hx8WratKm6dOmi0047TXFxcZW63aKiIn333Xf6+9//Htrm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jTlV5piKc9y5c6fWrVtnxTHZmBOPjezLqaLHdOBjo4SEBAEAAAAAEMkcL4rOfy0qKlJCQoJmzZqlAQMGhLYPGzZMO3bs0LvvvlvqOieeeKKOP/54PfTQQ6Ftr732mq6++mrt3LlTPp9PLVu21J///Ge98MILoX2mTJmi++67Txs3bixzlrLODMzIyFBubm7oSy5r67uqg8GgfvnlF2VmZspxnKh6p7iNx7R//3798ssvatmyperUqWPFMdmYU2WOqaioKJSp3++34phszKkyZwauW7dOLVq0kN/vt+KYbMypsmcGbtiwQS1btix11lFtPabiGW3KqTLHxGMju47pwMdGO3fu5MvqLREIBJScnKzc3Fw1bNjQ9DiIMsFgUOvWrVOrVq1KPKYDagL9g2l0ECbRv9qv+HE8z8kOLqrODIyJiVG3bt00d+7c0GKg67qaO3euRo4cWeZ1du/eHXphoVjxnULxCwS9evUq8Q5kSVq5cqVatmxZ7iyxsbGKjY0ttd3v95e60znw5x84R01udxynzO1/nNHv94fOVClPbTumw9le248pJiamVJ61/Ziqa8bKbjd1TGVlerD9a8Mx2ZhTZbYfeeSRZe5b3v614Zgqu92mY/L7/crKyipzv4PNGMnHVMymnIrx2MienCq6vbx/R2EPXgSCCYf69x+oTvQPptFBmET/EC3KfpZrsdGjR+v555/XK6+8omXLlum6667Trl27NGLECEnSZZddpr///e+h/fv166cpU6Zo5syZWrt2rT7++GONGzdO/fr1Cz1JvPnmm/X1119r4sSJWr16tWbMmKHnnntON9xwg5FjNM11XeXk5JR69zVqJ/K0D5nahTztQ6b2IVO7kKf9yBYmcN8Ck+gfTKODMIn+IVpE1ZmBkjRw4EBt3bpVd911l3JyctSlSxfNnj1bTZo0kSStX7++xDuBx44dK8dxNHbsWG3cuFGpqanq16+f7r///tA+xx57rN555x39/e9/17333qvWrVtr8uTJGjJkSI0fXyTwPE85OTlKTU01PQrCgDztQ6Z2IU/7kKl9yNQu5Gm/KPomDUQQ7ltgEv2DaXQQJtE/RIuoWwyUpJEjR5b7saDz588v8fc6depo/PjxGj9+/EFv89xzz9W5554brhEBAAAAAAAAAACAwxZ1HxMKAAAAAAAAAAAARAsWAxF2juMoJSVF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Pt17773KyspSXFycOnfurNmzZ9fgxKiIjRs3aujQoWrUqJHi4+PVsWNHLVq06KDXmT9/vv70pz8pNjZWRx55pF5++eWaGRYVUtlMf/vtNw0ePFhHHXWUfD6fbrrpppobFodU2Tzffvtt/fnPf1ZqaqqSkpJ0wgknaM6cOTU4MSrjqaeeUqtWrRQXF6cePXro22+/Pej+b775ptq1a6e4uDh17NiR5zE4LJXp3/PPP68TTzxRDRs2VMOGDdWnT59D9hU4mMre/xWbOXOmHMfRgAEDqndAWK2y/eO1RIRbZTvIa2WwEYuBqLQOHTrot99+C/354osvyt23qKhIf/7zn7Vu3TrNmjVLK1as0PPPP6/mzZvX4MQ4mMrk+fbbb5fY9+eff5bf79dFF11UgxPjUCqT6YwZMzRmzBiNHz9ey5Yt04svvqjXX39dd9xxRw1OjIOpTJ5jx47Vs88+qyeeeEJLly7Vtddeq7/85S/64YcfanBiHExeXp569eqlunXr6qOPPtLSpUv1yCOPqGHDhuVeZ+3atTrnnHN06qmn6scff9RNN92kK6+8ksWGCFGVTPfu3avU1FSNHTtWnTt3rsFpcShVyXPBggX685//rA8//FDfffedTj31VPXr14/73gj0+uuva/To0Ro/fry+//57de7cWX379tWWLVvK3H/hwoW65JJLdMUVV+iHH37QgAEDNGDAAP388881PDlsUNn+zZ8/X5dcconmzZunr776ShkZGTrjjDO0cePGGp4cNqhs/4qtW7dOt956q0488cQamhQ2qmz/eC0R4VbZDvJaGazlAZUwfvx4r3PnzhXef8qUKV5mZqZXVFRUfUOhyiqb54Eee+wxLzEx0du5c2f4hsJhqWymN9xwg3faaaeV2DZ69GivV69eYZ4MVVHZPJs2beo9+eSTJbadf/753pAhQ8I8Garq9ttv93r37l2p6/ztb3/zOnToUGLbwIEDvb59+4ZzNFRRVTL9o5NPPtm78cYbwzcQDsvh5lns6KOP9u65554wTIRwOu6447wbbrgh9PdgMOg1a9bMmzRpUpn7X3zxxd4555xTYluPHj28a665plrnhJ0q278D7d+/30tMTPReeeWV6hoRFqtK//bv3+/17NnTe+GFF7xhw4Z5/fv3r4FJYaPK9o/XEhFule0gr5XBVpwZiEpbtWqVmjVrpszMTA0ZMkTr168vd9/33ntPJ5xwgm644QY1adJExxxzjCZOnKhgMFiDE+NgKpPngV588UUNGjRI9erVq8YJUVmVybRnz5767rvvQh+PkJ2drQ8//FBnn312TY2LQ6hMnnv37lVcXFyJbfHx8Qc9mxA167333lP37t110UUXKS0tTV27dtXzzz9/0Ot89dVX6tOnT4ltffv21VdffVWdo6KCqpIpIlc48nRdVwUFBUpJSammKVEVRUVF+u6770rcn/p8PvXp06fc+1PufxEuVenfgXbv3q19+/Zx34JKq2r/7r33XqWlpemKK66oiTFhqar0j9cSEU5V6SCvlcFWLAaiUnr06KGXX35Zs2fP1pQpU7R27VqdeOKJKigoKHP/7OxszZo1S8FgUB9++KHGjRunRx55RPfdd18NT46yVDbPP/r222/1888/68orr6yBSVFRlc108ODBuvfee9W7d2/VrVtXWVlZOuWUU/jogwhR2Tz79u2rRx99VKtWrZLruvr4449DH++LyJCdna0pU6aoTZs2mjNnjq677jqNGjVKr7zySrnXycnJUZMmTUpsa9KkiQKBgPbs2VPdI+MQqpIpIlc48nz44Ye1c+dOXXzxxdU4KSpr27ZtCgaDZd6f5uTklHmd8u5/y9sfKE9V+neg22+/Xc2aNSu1QA0cSlX698UXX+jFF1/kDU44bFXpH68lIpyq0kFeK4Ot6pgeALXLWWedFfrvTp06qUePHmrZsqXeeOONMt8t5rqu0tLS9Nxzz8nv96tbt27auHGjHnroIY0fP74mR0cZKpvnH7344ovq2LGjjjvuuOoeE5VQ2Uznz5+viRMn6umnn1aPHj20evVq3XjjjZowYYLGjRtXk6OjDJXN8/HHH9dVV12ldu3ayXEcZWVlacSIEXrppZdqcmwchOu66t69uyZOnChJ6tq1q37++Wc988wzGjZsmOHpUBVkapfDzXPGjBm655579O677yotLa26xwUQJR544AHNnDlT8+fPL/UpEEC4FRQU6NJLL9Xzzz+vxo0bmx4HUYjXEmEar5XBViwG4rA0aNBARx11lFavXl3m5U2bNlXdunXl9/tD29q3b6+cnBwVFRUpJiampkZFBRwqz2K7du3SzJkzde+999bQZKiqQ2U6btw4XXrppaEzPDt27Khdu3bp6quv1p133imfjxPII8mh8kxNTdW//vUvFRYWavv27WrWrJnGjBmjzMzMGp4U5WnatKmOPvroEtvat2+vt956q9zrpKena/PmzSW2bd68WUlJSYqPj6+WOVFxVckUketw8pw5c6auvPJKvfnmm5y5E4EaN24sv99f5v1penp6mdcp7/63vP2B8lSlf8UefvhhPfDAA/rkk0/UqVOn6hwTlqps/9asWaN169apX79+oW2u60qS6tSpoxUrVigrK6t6h4Y1qnL/x2uJCKeqdJDXymArmovDsnPnTq1Zs0ZNmzYt8/JevXpp9erVoQeOkrRy5Uo1bdqUf7wj0KHyLPbmm29q7969Gjp0aA1Nhqo6VKa7d+8u9SCm+AG353nVPh8qp6L/j8bFxal58+bav3+/3nrrLfXv37+GJsSh9OrVSytWrCixbeXKlWrZsmW51znhhBM0d+7cEts+/vhjnXDCCdUyIyqnKpkiclU1z3/+858aMWKE/vnPf+qcc86pzhFRRTExMerWrVuJ+1PXdTV37txy70+5/0W4VKV/kvSPf/xDEyZM0OzZs9W9e/eaGBUWqmz/2rVrp8WLF+vHH38M/TnvvPN06qmn6scff1RGRkZNjo9arir3f7yWiHCqSgd5rQzW8oBKuOWWW7z58+d7a9eu9b788kuvT58+XuPGjb0tW7Z4nud5l156qTdmzJjQ/uvXr/cSExO9kSNHeitWrPD+/e9/e2lpad59991n6hDwB5XNs1jv3r29gQMH1vS4qIDKZjp+/HgvMTHR++c//+llZ2d7//nPf7ysrCzv4osvNnUI+IPK5vn11197b731lrdmzRpvwYIF3mmnnea1bt3ay8vLM3QEONC3337r1alTx7v//vu9VatWedOnT/cSEhK81157LbTPmDFjvEsvvTT09+zsbC8hIcG77bbbvGXLlnlPPfWU5/f7vdmzZ5s4BBygKpl6nuf98MMP3g8//OB169bNGzx4sPfDDz94S5YsqenxcYCq5Dl9+nSvTp063lNPPeX99ttvoT87duwwcQg4iJkzZ3qxsbHeyy+/7C1dutS7+uqrvQYNGng5OTme55X+d/XLL7/06tSp4z388MPesmXLvPHjx3t169b1Fi9ebOoQUItVtn8PPPCAFxMT482aNavEfUtBQYGpQ0AtVtn+HWjYsGFe//79a2ha2Kay/eO1RIRbZTvIa2WwFYuBqJSBAwd6TZs29WJiYrzmzZt7AwcO9FavXh26/OSTT/aGDRtW4joLFy70evTo4cXGxnqZmZne/fff7+3fv7+GJ0dZqpLn8uXLPUnef/7znxqeFhVR2Uz37dvn3X333V5WVpYXFxfnZWRkeNdffz2LRxGisnnOnz/fa9++vRcbG+s1atTIu/TSS72NGzcamBwH8/7773vHHHOMFxsb67Vr18577rnnSlw+bNgw7+STTy6xbd68eV6XLl28mJgYLzMz05s6dWrNDYxDqkqmkkr9admyZc0NjXJVNs+TTz65zDwPfAyFyPDEE094LVq08GJiYrzjjjvO+/rrr0OXlfXY94033vCOOuooLyYmxuvQoYP3wQcf1PDEsEll+teyZcsy71vGjx9f84PDCpW9//sjFgNxuCrbP15LRLhVpoO8VgZbOZ7Hua0AAAAAAAAAAACAjfjOQAAAAAAAAAAAAMBSLAYCAAAAAAAAAAAAlmIxEAAAAAAAAAAAALAUi4EAAAAAAAAAAACApVgMBAAAAAAAAAAAACzFYiAAAAAAAAAAAABgKRYDAQAAAAAAAAAAAEuxGAgAAAAAAAAAAABYisVAAEC12blzp6688kqlp6fLcRzddNNNpkeKePPnz5fjOJo/f77pUUrYuXOn0tLSNH369Br9uWPGjFGPHj1q9GcCAAAAAAAANmExEABQrpdfflmO42jRokVVuv7EiRP18ssv67rrrtO0adN06aWXhnnC2mH48OFyHOeQf4YPH2561HI9/vjjSkxM1KBBg2r0595000366aef9N5779XozwUAAABQOyxbtkyO4yguLk47duwoc59TTjmlxHOvlJQUHXvssXrppZfkum5ov7vvvrvM52pxcXFl3u6LL76o9u3bKy4uTm3atNETTzxRHYcIAMBhq2N6AACAvT799FMdf/zxGj9+vOlRjLrmmmvUp0+f0N/Xrl2ru+66S1dffbVOPPHE0PasrCz16NFDe/bsUUxMjIlRy7Rv3z49/vjjuvnmm+X3+2v0Z6enp6t///56+OGHdd5559XozwYAAAAQ+V577TWlp6crLy9Ps2bN0pVXXlnmfkcccYQmTZokSdq6dateffVVXXHFFVq5cqUeeOCBEvtOmTJF9evXD/29rOdBzz77rK699lpdcMEFGj16tD7//HONGjVKu3fv1u233x7GIwQA4PA5nud5pocAAESml19+WSNGjNB///tfde/evdLXz8zM1NFHH61///vfYZnHdV0VFRWV+67M2mLRokU69thjNXXq1Ig+G7DYO++8o/PPP1+rV69WVlZWjf/8t956SxdddJFWr16tzMzMGv/5AAAAACKT53nKzMzU+eefr7Vr1yovL0/z5s0rtd8pp5yibdu26eeffw5t2717t9q2bau8vDzl5eWpbt26uvvuu3XPPfdo69ataty4cbk/d8+ePcrIyNDxxx9f4vnu0KFD9a9//UsbNmxQw4YNw3uwAAAcBj4mFABQKcOHD1f9+vW1ceNGDRgwQPXr11dqaqpuvfVWBYNBSf/ve+/Wrl2rDz74IPTRKuvWrZMk7d27V+PHj9eRRx6p2NhYZWRk6G9/+5v27t1b4mc5jqORI0dq+vTp6tChg2JjYzV79mxJ0saNG3X55ZerSZMmio2NVYcOHfTSSy+VuH7xHG+88Ybuv/9+HXHEEYqLi9Ppp5+u1atXlzq2b775RmeffbYaNmyoevXqqVOnTnr88cdL7LN8+XJdeOGFSklJUVxcnLp37x7Wj7As6zsDTznlFB1zzDH63//+p5NPPlkJCQk68sgjNWvWLEnSZ599ph49eig+Pl5t27bVJ598Uup2K/L7Ks+//vUvtWrVqtRCYHEX1q9fr3PPPVf169dX8+bN9dRTT0mSFi9erNNOO0316tVTy5YtNWPGjBLX37dvn+655x61adNGcXFxatSokXr37q2PP/64xH7FZ1W+++67FZoXAAAAQOQr/kjOlStXaujQoUpOTlZqaqrGjRsnz/O0YcMG9e/fX0lJSUpPT9cjjzxS6ja+/PJLrVu3ToMGDdKgQYO0YMEC/frrrxX6+QkJCTr++OO1a9cubd26tcRlnucpEAiovHMo5s2bp+3bt+v6668vsf2GG27Qrl279MEHH1TwtwAAQM1gMRAAUGnBYFB9+/ZVo0aN9PDDD+vkk0/WI488oueee06S1L59e02bNk2NGzdWly5dNG3aNE2bNk2pqalyXVfnnXeeHn74YfXr109PPPGEBgwYoMcee0wDBw4s9bM+/fRT3XzzzRo4cKAef/xxtWrVSps3b9bxxx+vTz75RCNHjtTjjz+uI488UldccYUmT55c6jYeeOABvfPOO7r11pqVH2UAAKleSURBVFv197//XV9//bWGDBlSYp+PP/5Y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u7Yapvt9sXHEiBEaMWKEdu7cqZNOOkl33313qcXAtWvXqnPnztUyAwAAAIDa5e2331ZhYaGmTJlS6k2DK1as0NixY/Xll1+qd+/eh/2zPM/TunXr1LVr19C2Ll26SJIWLVqks88+O7R90aJFcl03dDkAAJGC7wwEANSoiy++WBs3btTzzz9f6rI9e/Zo165dB72+3+/XBRdcoLfeeks///xzqcu3bt1a6Zn+9Kc/qXXr1po8ebJ27NhR4rLid56mpaXplFNO0bPPPqvffvstLD+3JoTj93XCCSdo0aJFYZ/tjx/xI/3+vYhHHnmk9u7dW2J7fn6+1qxZo549e4Z9BgAAAAC1z2uvvabMzExde+21uvDCC0v8ufXWW1W/fn1Nnz690rdb1vOjKVOmaOvWrTrzzDND20477TSlpKRoypQppfZNSEjQOeecU/mDAgCgGnFmIACgRl166aV64403dO2112revHnq1auXgsGgli9frjfeeENz5sxR9+7dD3obDzzwgObNm6cePXroqquu0tFHH63c3Fx9//33+uSTT0p8fEtF+Hw+TZkyRf369VOXLl00YsQINW3aVMuXL9eSJUs0Z84cSdJTTz2l3r17q2PHjrrqqquUmZmpzZs366uvvtKvv/6qn376qcq/l+p0uL+v/v37a9q0aVq5cqWOOuqosM119NFH65RTTlG3bt2UkpKiRYsWadasWRo5cmSJ/T755BN5nqf+/fuH7WcDAAAAqJ02bdqkefPmadSoUWVeHhsbq759++rNN9/U//3f/6lu3boVvu2WLVtq4MCB6tixo+Li4vTFF19o5syZ6tKli6655prQfvHx8ZowYYJuuOEGXXTRRerbt68+//xzvfbaa7r//vuVkpJy2McJAEA4sRgIAKhRPp9P//rXv/TYY4/p1Vdf1TvvvKOEhARlZmbqxhtvrNBiU5MmTfTtt9/q3nvv1dtvv62nn35ajRo1UocOHfTggw9Waa6+fftq3rx5uueee/TII4/IdV1lZWXpqquuCu1z9NFHa9GiRbrnnnv08ssva/v27UpLS1PXrl111113Venn1oTD/X3169dPjRs31htvvKGxY8eGba5Ro0bpvffe03/+8x/t3btXLVu21H333afbbrutxH5vvvmmevfuHfo4VwAAAADRa+bMmXJdV/369St3n379+umtt97SRx99pPPOO6/Ctz1kyBAtXLhQb731lgoLC9WyZUv97W9/05133qmEhIQS+15//fWqW7euHnnkEb333nvKyMjQY489phtvvLHKxwYAQHVxvOLPPwMAACjHhAkTNHXqVK1atUp+v7/Gfm5OTo5at26tmTNncmYgAAAAAAAAUAV8ZyAAADikm2++WTt37tTMmTNr9OdOnjxZHTt2ZCEQAAAAAAAAqCLODAQAAAAAAAAAAAAsxZmBAAAAAAAAAAAAgKVYDAQAAAAAAAAAAAAsxWIgAAAAAAAAAAAAYCkWAwEAAAAAAAAAAABLsRgIAAAAAAAAAAAAWIrFQAAAAAAAAAAAAMBSLAYCAAAAAAAAAAAAlmIxEAAAAAAAAAAAALAUi4EAAAAAAAAAAACApVgMBAAAAAAAAAAAACzFYiAAAAAAAAAAAABgKRYDAQAAAAAAAAAAAEuxGAgAAAAAAAAAAABYisVAAAAAAAAAAAAAwFIsBgIAAAAAAAAAAACWYjEQAAAAAAAAAAAAsBSLgQCAajV58mR16tRJ8fHxchxHjuNowIABpseCBYr75DiOXn75ZdPjAAAAAKgG8+fPL/HYf926dRF1e4fSqlWr0M+6++67q/VnAQBQHhYDAQClngyFa2Hlueee080336zFixersLAwLLeJsv3666+66aab1KFDB9WrV0+xsbFKT09Xx44dNXDgQE2aNEl5eXmmxwQAAAAQYQ58Pug4js4777wy950zZ06pfYcPH16zAxvE8y4AQG1Vx/QAAAB7/fOf/wz9d4sWLXTVVVcpLi5Obdq0MTiVfb7//nuddtppys/PL7F98+bN2rx5s37++We98cYbOuuss9SwYUNDUwIAAACoLT744ANlZ2crMzOzxPbHH3/c0ETmVfV515133hm6Ts+ePWt0ZgAAirEYCACoNr/88kvovy+77DKNHTu22n9mQUGBEhMTq/3nRJLrr78+9OSyXr16GjhwoDIzM7Vv3z6tWrVKn3/+uTZs2GB4SgAAAAC1heu6evLJJ/Xoo4+Gtq1cuVKzZ882OJVZVX3eddVVV9X0qAAAlMLHhAIADurAj4zJzs7W008/rU6dOikuLk5paWm68sorS3wUyvDhw+U4jtauXRvadt9995X5MaSBQECTJk1Sjx49lJycrJiYGLVo0ULDhw/XkiVLSs1z9913h26nVatW2r59u2644QYdccQR8vv9evHFF8N22/n5+brtttvUsmVLxcTEKDMzUxMnTpTneaWu63meZs2apfPOO0/NmzdXbGysUlJS1LVrV40ePVpFRUUl9t+8ebPuuOMOdenSRYmJiYqLi9ORRx6pG264QevXr69wPoFAQN98803o70899ZRefPFF3Xnnnbr77rs1ffp0rV+/Xt9++62OOOKIEtc98LsrvvnmG51xxhlKTk5WYmKi+vbtq++++67Mn1uV+V3X1bRp03TGGWcoLS1NMTExSk1N1TnnnKMPP/ywzOvs379fDzzwgNq0aaPY2FhlZWXpvvvu0759+yr8OwIAAABQcT7f7y8XvvTSS9q1a1do+xNPPBF6LuT3+w96Gxs3btRtt92mjh07qn79+oqLi1OrVq00dOhQffvtt2VeZ/v27br22mvVpEkTxcfHq3v37nr99dcPOW9VnmdUVjifdxU75ZRTSn3k6oF/DvyOwXA9jwQARCEPABD15s2b50kK/Zk6dWq5l/Xu3bvE34v/nHTSSaHrDBs2rMx9Drz9lStXeq1atSp3v9jYWO+NN94oMev48eNDlzdu3Nhr165dies89thjYbntRo0aee3bty/zuuPGjStxvT179njnnHPOQY85Ly8vtP/ChQu9xo0bl7tvcnKyt2DBggplt3379hLXvfXWW739+/dX6LotW7YskWvdunVLzRIfH+99/vnnJa5Xlfl3797t9enT56C/o9GjR5eacdCgQWXue+Dv+4+dBQAAAFBxBz7nGzBgQOi/n3rqKc/zPC8/P99LTEz0JHldu3Yt8Vxi2LBhJW7vs88+8xo2bFju436fz+c98sgjJa6Tl5dX6rldeY/9165dG7peVZ5nHHi8f7y98oTredf48eND208++eSDzn3g/uF8HgkAiD58TCgAoFK++OILnX766erZs6f+9a9/afHixZKkBQsW6Ouvv9bxxx+vQYMG6ZhjjtHEiRNDZwz++c9/1hlnnCFJOvbYYxUMBvWXv/xF69atkySlpqZq8ODBSklJ0Zw5c7Rw4ULt3btXl112mbp161bquyokadu2bdq2bZv69OmjXr16aevWrWrSpElYbnv79u3Ky8vTZZddpmbNmumFF17Qtm3bJP3+PRljx45VTEyMJOmWW27RBx98ELpuRkaG/vKXvyg5OVlLlizRv//979BlgUBAAwYMCN1Wy5YtNXDgQMXHx2vWrFlasmSJ8vPzdcEFF2jVqlVKTk4+aB4pKSlq2bJl6CNZH374YU2dOlW9evVS165ddcIJJ+iUU05RbGzsIXM96qijdNFFF+nXX3/VtGnT5P5/7N17uFx1fS/+z5qdhA0hs8kFiMFoBBS8RMQbFa9QK6BV8IIV8W5Ljx6Lt3oO9aeC9xtW7cFavFHxUqxWtB5Bq1jEe4uojReQezAaIAnZE4IhMGv9/qDkEDN7rWEys9dkfV+v5+F5yJ7J5BPeb9ae7/7OWivP4/e//328+MUvjksvvTQmJiYGnv/Vr351fPOb34yIiHnz5sVznvOcuO997xurVq2Kz3/+81EURfzt3/5tPOxhD4vnPve5ERHxhS98Ic4555xtMx544IHx7Gc/O9asWROf+tSnSv8+AADAYE488cT47ne/G+vWrYszzjgjXv7yl8dZZ50VmzZtioiIk08+eYcz1u60cePGeMYznrFtHbj77rvHi1/84mi32/FP//RPce2110ae5/HXf/3X8bCHPSwe//jHR0TEG97whrj00ku3vc7jH//4ePzjHx/f+973tltr/aFB1hmDGNa6665e9rKXxZ/+6Z9u97XPfOYz8dOf/nTbrx/4wAdGxPDXkQAkqO7dSADqd3fODHz6059e5HleFMUdn46cmJjY9tjf/d3fbfe6M30CsiiK4stf/vK2xyYmJopf//rX2x67/fbbi5UrV257/NWvfvW2x+569l5EFK961at2+PsM67U/8IEPbHvsS1/60naP/dd//VdRFEWxYcOGYs6cOdu+fuihhxabNm3abp7Vq1cXW7duLYqiKD74wQ9ue+7ChQuL9evXb3vezTffXOy9997bHv/gBz/YO7A/8MUvfrHIsqz0E6JvfvObd/jk6l3zWbJkSbFx48Ztj7397W/f7jW+8Y1vDDz/+vXrt/tv9IlPfGK7OV7+8pdv99/vTkcdddR2f4e7/ll/OJ8zAwEAYDB/uOb7yle+Urz+9a/f9uuvfe1rxYEHHlhERLH33nsXW7ZsmfHMwPe///3bvdZ555237bHrr7++2HPPPbc9duyxxxZFURS33Xbbdl9/3OMeV3S73aIoiiLP8+JJT3pSzzP5Bl1nDHJmYFEMZ931h+viuzr77LO3e/03v/nN2x4bxToSgLS4ZyAAd8vLXvayyLIsIu74dOSSJUu2PXbX+wZW+d73vrft37vdbtzvfvfbdl+EOXPmbDvjMCLi+9///oyv84Y3vGEkrz0xMRF/+Zd/ue3XBx100HaP3/l3/eEPfxi33377tq+fcsopseeee2733OXLl8fcuXN3mO2mm26KxYsXb5ttzz33jBtvvLGvv/ddPf3pT49vfetbceSRR267v8ddTU9Px6mnnhpvfetbZ3yNpz3tadt9evR5z3vedo/fee/AQeb/0Y9+tN1/o5e85CXb3Qfj7//+77c99tOf/jRuueWWiIi4+OKLt3396KOPjkWLFs04HwAAMDwvf/nLY86cOy4o9tKXvjSuuOKKiIg46aSTSs9++8EPfrDt3/fee+845phjtv16n3322e7Xdz730ksvjZtvvnnb10844YRt65osy+LEE0/s+WcNus4Y1DDWXTM5//zz4yUvecm2ezK+7GUvize96U3bHh/FOhKAtNgMBOBuWbFixXa/vutCMM/zvl9nw4YNfT/3rgubu1qyZEksXrx4JK+97777xuTk5LZf/+GC986/6x/+Wfe5z31K/7xhzNbLE57whLjgggtiw4YNcf7558dpp50WD3/4w7d7zvvf//4Zf/8+++yz3a/33Xff7X69cePGiBhs/rvze4qiiPXr12/3Z/YzHwAAMDz77bdfPPOZz4yIiDVr1kRExNy5c+PlL3956e+763v/Xu/Z7/q1Oz9gedf3/RH9v/cfdJ2xM3Z23dXLD3/4w3jWs561bWPzWc96VpxxxhnbPWdU60gA0uGegQDcLXee4XanO88SvLvuepbX5ORk6acnZ7rfwfz580f22v3+Pe/6Z0VEXH311fGIRzxixj/vrs+/xz3uEa95zWtmfO7y5ctnfGwmU1NTcfTRR8fRRx8dp556arz0pS+NT3ziExFxx30mrr/++p6L6RtuuGG7X19//fXb/XqvvfYaeP4//G/06le/OpYtW1b6d7jzz7xzwV41HwAAMFyvfOUr43Of+9y2Xz/zmc8sfR8fsf17/17v2e/6tYULF0bE/1tr3Knf9/6DrjOGYdB11x+69NJL40//9E+3nbV4xBFHxKc//ekdzjwc9ToSgOazGQhALQ4//PBt/75ly5Z44AMfuN0lY+70ox/96G7dhH3Ur/2H/uiP/ijmzJmz7VOc7373u+NP//RPY4899tj2nN/+9rex9957x9y5c+Pwww+Pf/7nf46IOz6x+aQnPSke/OAHb/eaRVHEBRdcEAcccEBfM7zwhS+Mk08+OR72sIft8NhdL1naarViwYIFPV/jX//1X6PT6US73Y6IiE9/+tPbPX7naw8y/2GHHRYTExPR7XYj4o6N1r/+67/eYYZrrrkmLrvssm0zPPzhD4+vf/3rERHxta99LTZs2LBtEfyH8wEAAMP1qEc9Kh7xiEfEf/7nf0ZExMknn1z5e/5wvXD++edvW4vdcMMNcf7552/33IiIgw8+OPbcc89tlwr9p3/6pzjppJOi1WpFURTxmc98puefNeg6Y1DDWHfd1W9+85t40pOetO0DkA95yEPiS1/6Us816ijWkQCkxWYgALV4ylOeEve///3jV7/6VUREHHfccfGMZzwjHvCAB0Se53HllVfGRRddFNdee22cddZZ8ZCHPGQsXvsPLVy4ME466aRt96O45JJL4gEPeEAcd9xxsddee8Wvf/3rOPfcc+N3v/td7LXXXvGiF70o3va2t8W6devi9ttvj0c/+tFx/PHHx4EHHhi33nprXHbZZXHhhRfG9ddfH//+7/9eednRiIizzz47zj777DjggAPiMY95TOy///6RZVn87Gc/iy9+8Yvbnve4xz1uu03Ku1q3bl084hGPiOOPPz5+85vfxKc+9altjx1wwAFxxBFHREQMNP+iRYviJS95SXz0ox+NiIj3vOc9cfHFF8fhhx8ek5OTsWbNmvjhD38YP/nJT+KFL3xhHHXUURFxx71J7twMnJ6ejsMOOyz+7M/+bIf5AACA0Tj77LPj0ksvjblz58ajHvWoyue/8IUvjLe+9a3bNrie+cxnxkte8pJot9vx2c9+dtuGX5Zl8apXvSoiIubMmRMveMELtq2pLrroojjyyCPj8Y9/fHzve9+LCy64oOefNeg6Y2f+W+zsuuuujjrqqLjuuuu2/fqP//iP4yMf+ch2zzn88MPj8MMPH8k6EoC02AwEoBZz5syJL33pS3HUUUfFNddcE1u3bo1zzjln7F+7l/e9731xzTXXxHnnnRcREddee2188IMf7Pncqamp+PKXvxzHHntsrFu3Lm6++eY466yzhjLHlVdeGVdeeWXPxxYtWhT/5//8nxl/7x//8R/Hd7/73Xj729++3dcnJyfjE5/4RExMTOzU/B/4wAfi6quvjm9+85sREfGtb30rvvWt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uTJuuOGGWLZsWbzoRS+KN7zhDTusoXaGNdnsKdw0kB6KKGLL1Bb9YEY6Qhn9oIx+UEVHdh2nnXZavPnNb97ua2Vrzo9+9KNx9tlnx89//vOIiHjYwx4W73jHO+KRj3zktufMtK58z3veE6973ev6nq2vzcCzzjqr7xesU5Zlce6558Zxxx1X9ygDG+i6rewyWhGx9Kab6h6DEZNzGuScDlmnQc5pyLIsHvjAB8Y3v/nNbV+bM2fmJdFnP/vZOOWUU+ITn/hEHH744fHrX/86XvSiF0WWZfG3f/u3ERHx/ve/PyIiTj/99HjEIx4RF198cbz4xS+OqampOPnkk4c2uzXZLHIrFnppRWzed3PdUzDOdIQy+kEZ/aCKjuxS7s6a88ILL4wTTjghDj/88JicnIx3v/vd8aQnPSl+8YtfxH777RcREb/73e+2+z3nn39+vPSlL41nPvOZd2uuvjYDX/jCF96tF91V/OIXv4g3velN8eMf/ziuvfbaeP/73x+vetWrtnvORRddFO9973vjxz/+cfzud78b+cI2H9krMw7yiLhh4cLY56abbPw2mJzTIOd0yDoNck5DURRRFEXss88+0WpVJ/39738/Hv3oR8dzn/vciIhYsWJFnHDCCfGjH/1o23P+4z/+IyIijjrqqGi327FixYr4p3/6p21fHxZrstlbk/nANT3lEfNvnB+b997sU7z0piOU0Q/K6AdVdGSXMmfOnFi6dGlfz/3MZz6z3a8/9rGPxb/8y7/EBRdcEC94wQsiInZ4rS9/+ctxxBFHxP7773+35hqoOrfffnt0Op0ZH+90OnH77bcP8tKz6pZbbon9998/3vWud80YzubNm+OQQw6JD33oQ7MyUzHESwkxfoosi+n58+XccHJOg5zTIes0yDkNRVHEVVddFfe85z1j//33jxNPPDFWr1494/MPP/zw+PGPf7xtY++qq66K8847L5785Cdve86dl2+54oorIiLiZz/7WXz3u9+NY445ZoR/E2uyUcqcGkgPWWQxOT2pH8xIRyijH5TRD6royK7l8ssvj2XLlvW15vxDt9xyS9x2222xaNGino9ff/318dWvfjVe+tKX3u25BtoMPPnkk+Pwww+f8fFHP/rR8drXvvZuvebZZ58dixcvjltvvXW7rx933HHx/Oc/PyIiPvzhD8cBBxwQ8+bNi4MOOig+9alPlb7mqlWr4sgjj4zdd989Fi9eHCeddFLcfPPN2x5/xCMeEe9973vjOc95Tuy22249X+OYY46Jt73tbfH0pz99xj9nxYoV8Y53vCNe8pKXxIIFC+Je97pXfOQjH+n3rw4AAMyCRz7ykfGWt7wlvvrVr8aHP/zhuPrqq+Oxj31sbNq0qefzn/vc58Zb3vKWeMxjHhNz586NAw44IJ7whCfE61//+m3Pec1rXhMRd9zTb+7cuXHooYfGq171qjjxxBNH+nexJtueNRkAAFC3ww47LP7xH/8xvva1r/W15vxD//t//+9YtmxZPPGJT+z5+Cc/+clYsGBBPOMZz7jbsw20Gfi1r30tnvWsZ834+LOe9aw477zz7tZrHn/88dHtduNf//Vft33thhtuiK9+9avxkpe8JM4999x45StfGa997Wvj5z//efzlX/5lvPjFL45///d/7/l6mzdvjqOOOioWLlwY//mf/xmf//zn45vf/Ga84hWvuFtz9et973tfPPzhD4+f/OQn8fKXvzxe9rKXxWWXXTbj82+99dbodDrb/QMAAIzOMcccE3/yJ38SD37wg+Ooo46K8847LzZu3Bj//M//3PP5F154YbzjHe+Iv//7v49LLrkkvvjFL8ZXv/rVeOtb37rtOV/84hcj4o7LuVxyySXxyU9+Mk4//fT45Cc/OdK/izXZjqzJAACAOh1zzDFx/PHH973mvKt3vetdcc4558S5554bk5OTPZ/ziU98Ik488cQZHy8z0Gbgb3/72203L+xl2bJlsWbNmrv1mrvvvns897nPjbPOOmvb1z796U/Hve51r3jCE54Qp59+erzoRS+Kl7/85XG/+90vXvOa18QznvGMOP3003u+3mc/+9nYsmVLnH322fGgBz0ojjzyyDjjjDPiU5/6VFx//fV3a7Z+PPnJT46Xv/zlceCBB8b//t//O5YsWTLjojgi4p3vfGdMTU1t+2f58uUREZEVblDRZFlRxOJOR84NJ+c0yDkdsk6DnNOQZVksXbo0sv++HOxee+0V97vf/bZd4vMPvfGNb4znP//58ed//uexcuXKePrTnx7veMc74p3vfGfk+R13+37Tm94UEXdsvq1cuTKe//znx6tf/ep45zvfOdK/izXZjoa1JivcNJAeiqyIWxbfEkWmH/SmI5TRD8roB1V0ZNdVtea80+mnnx7v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AEBD2QwEAAAAAACAhrIZCAAAAAAAAA1lM3AMfOhDH4oVK1bE5ORkHHbYYfEf//EfdY/EkF100UXx1Kc+NZYtWxZZlsWXvvSlukdiBN75znfGIx7xiFiwYEHss88+cdxxx8Vll11W91gM2Yc//OF48IMfHO12O9rtdjzqUY+K888/v+6xGLF3vetdkWVZvOpVr6p7FIbotNNOiyzLtvvn4IMPrnssRmDNmjXxvOc9LxYvXhy77757rFy5Mi6++OK6x2LMWJfRi7UcZawBqWL9yN1h3cldWa8ybDYDa/a5z30uXvOa18Spp54al1xySRxyyCFx1FFHxQ033FD3aAzR5s2b45BDDokPfehDdY/CCH3729+O//k//2f88Ic/jG984xtx2223xZOe9KTYvHlz3aMxRPe85z3jXe96V/z4xz+Oiy++OI488sg49thj4xe/+EXdozEi//mf/xlnnnlmPPjBD657FEbggQ98YPzud7/b9s93v/vdukdiyG666aZ49KMfHXPnzo3zzz8/fvnLX8b73ve+WLhwYd2jMUasy5iJtRxlrAGpYv1Iv6w76cV6lWHKiqIo6h4iZYcddlg84hGPiDPOOCMiIvI8j+XLl8df/dVfxSmnnFLzdIxClmVx7rnnxnHHHVf3KIzYjTfeGPvss098+9vfjsc97nF1j8MILVq0KN773vfGS1/60rpHYchuvvnmeOhDHxp///d/H29729viIQ95SHzgAx+oeyyG5LTTTosvfelL8dOf/rTuURihU045Jb73ve/Fd77znbpHYYxZl9EPazmqWAPSD+tH/pB1J71YrzJszgys0datW+PHP/5xPPGJT9z2tVarFU984hPjBz/4QY2TAcMwPT0dEXe80aeZut1unHPOObF58+Z41KMeVfc4jMD//J//M57ylKds972aZrn88stj2bJlsf/++8eJJ54Yq1evrnskhuxf//Vf4+EPf3gcf/zxsc8++8Shhx4aH/3oR+seizFiXQYMizUgZawfmYl1JzOxXmWY5tQ9QMrWrVsX3W439t133+2+vu+++8all15a01TAMOR5Hq961avi0Y9+dDzoQQ+qexyGbNWqVfGoRz0qtmzZEnvuuWece+658YAHPKDusRiyc845Jy655JL/v707j6rqOvs4/mOQIUjAAYelgiJRcR4giGjUUGPUoCaliANBYmyT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\n"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["✓ Comparison visualizations saved to 'outputs/comparison_results/model_comparison_summary.png'\n","\n","================================================================================\n","BEST MODEL RECOMMENDATIONS\n","================================================================================\n","\n","🏆 Best Accuracy (mAP50): yolo11n (Dataset: dataset)\n"," mAP50: 0.8970\n"," Inference: 5.88 ms\n"," Size: 5.27 MB\n","\n","⚡ Fastest Inference: yolo11n (Dataset: dataset)\n"," Inference: 5.88 ms\n"," mAP50: 0.8970\n"," Size: 5.27 MB\n","\n","⚖️ Best Balance (Accuracy/Speed): yolo11n (Dataset: dataset)\n"," Balance Score: 0.1526\n"," mAP50: 0.8970\n"," Inference: 5.88 ms\n"," Size: 5.27 MB\n","\n","📦 Smallest Model: yolo11n (Dataset: dataset)\n"," Size: 5.27 MB\n"," mAP50: 0.8970\n"," Inference: 5.88 ms\n","\n","================================================================================\n","FINAL RECOMMENDATION FOR REAL-TIME MOBILE DETECTION\n","================================================================================\n","\n","✅ RECOMMENDED: yolo11n on dataset\n"," Reason: Best speed with acceptable accuracy for real-time mobile applications.\n"," mAP50: 0.8970\n"," Inference Time: 5.88 ms\n"," Model Size: 5.27 MB\n"," Trained Model Path: /content/runs/detect/runs/all_trainings/yolo11n_dataset/weights/best.pt\n","================================================================================\n"]}],"source":["import pandas as pd\n","import matplotlib.pyplot as plt\n","from pathlib import Path\n","\n","# 1. Convert the all_results_for_comparison list into a pandas DataFrame\n","if all_results_for_comparison:\n"," df_comparison = pd.DataFrame(all_results_for_comparison)\n","else:\n"," print(\"No comparison results found. Please ensure the training and export loop ran successfully.\")\n"," df_comparison = pd.DataFrame()\n","\n","if not df_comparison.empty:\n"," # 2. Display the entire df_comparison DataFrame\n"," print(\"\\n\" + \"=\"*80)\n"," print(\"MODEL COMPARISON TABLE\")\n"," print(\"=\"*80)\n"," print(df_comparison.to_string(index=False))\n"," print(\"=\"*80)\n","\n"," # Define outputs directory and create it if it doesn't exist\n"," outputs_dir = Path('outputs')\n"," outputs_dir.mkdir(parents=True, exist_ok=True)\n","\n"," # 3. Save the df_comparison DataFrame to a CSV file\n"," csv_path = outputs_dir / 'model_comparison_results.csv'\n"," df_comparison.to_csv(csv_path, index=False)\n"," print(f\"\\n✓ Comparison results saved to '{csv_path}'\")\n","\n"," # 4. Create a new directory named 'comparison_results' inside the 'outputs' directory\n"," comparison_plots_dir = outputs_dir / 'comparison_results'\n"," comparison_plots_dir.mkdir(parents=True, exist_ok=True)\n"," print(f\"✓ Comparison plots will be saved to '{comparison_plots_dir}'\")\n","\n"," # 5. Generate comparative visualizations\n"," print(\"\\nGenerating comparative visualizations...\")\n","\n"," # Add a 'Model Size (MB)' column if not present, useful for scatter plot dot sizes\n"," if 'Trained Model Path' in df_comparison.columns:\n"," df_comparison['Model Size (MB)'] = df_comparison['Trained Model Path'].apply(lambda x: round(Path(x).stat().st_size / (1024 * 1024), 2) if Path(x).exists() else 0.0)\n"," else:\n"," df_comparison['Model Size (MB)'] = 0.0\n","\n"," fig, axes = plt.subplots(2, 2, figsize=(18, 14))\n"," fig.suptitle('Model Comparison Analysis', fontsize=20, fontweight='bold')\n","\n"," # a. Scatter plot: Accuracy (mAP50) vs. Inference Time (ms) with marker size representing Model Size (MB)\n"," ax1 = axes[0, 0]\n"," # Scale marker size for better visualization\n"," size_scale_factor = 20 # Adjust this factor as needed\n"," for idx, row in df_comparison.iterrows():\n"," ax1.scatter(row['Inference Time (ms)'], row['mAP50'], s=row['Model Size (MB)'] * size_scale_factor, alpha=0.7, label=row['model_architecture'])\n"," ax1.set_xlabel('Inference Time (ms)', fontsize=12)\n"," ax1.set_ylabel('mAP50', fontsize=12)\n"," ax1.set_title('Accuracy (mAP50) vs. Speed (Inference Time)', fontsize=14, fontweight='bold')\n"," ax1.grid(True, linestyle='--', alpha=0.6)\n"," ax1.legend(title='Model', loc='best', fontsize=10)\n","\n"," # b. Bar chart: mAP50\n"," ax2 = axes[0, 1]\n"," df_comparison.sort_values(by='mAP50', ascending=True, inplace=False).plot(x='model_architecture', y='mAP50', kind='barh', ax=ax2, legend=False, color='skyblue')\n"," ax2.set_xlabel('mAP50', fontsize=12)\n"," ax2.set_ylabel('Model Architecture', fontsize=12)\n"," ax2.set_title('Model Accuracy (mAP50)', fontsize=14, fontweight='bold')\n"," ax2.grid(axis='x', linestyle='--', alpha=0.6)\n"," for i, v in enumerate(df_comparison.sort_values(by='mAP50', ascending=True, inplace=False)['mAP50']):\n"," ax2.text(v + 0.01, i, str(v), color='black', va='center')\n","\n"," # c. Bar chart: Inference Time (ms)\n"," ax3 = axes[1, 0]\n"," df_comparison.sort_values(by='Inference Time (ms)', ascending=False, inplace=False).plot(x='model_architecture', y='Inference Time (ms)', kind='barh', ax=ax3, legend=False, color='lightcoral')\n"," ax3.set_xlabel('Inference Time (ms)', fontsize=12)\n"," ax3.set_ylabel('Model Architecture', fontsize=12)\n"," ax3.set_title('Inference Speed', fontsize=14, fontweight='bold')\n"," ax3.grid(axis='x', linestyle='--', alpha=0.6)\n"," for i, v in enumerate(df_comparison.sort_values(by='Inference Time (ms)', ascending=False, inplace=False)['Inference Time (ms)']):\n"," ax3.text(v + 0.1, i, str(v), color='black', va='center')\n","\n"," # d. Bar chart: Model Size (MB)\n"," ax4 = axes[1, 1]\n"," df_comparison.sort_values(by='Model Size (MB)', ascending=True, inplace=False).plot(x='model_architecture', y='Model Size (MB)', kind='barh', ax=ax4, legend=False, color='lightgreen')\n"," ax4.set_xlabel('Size (MB)', fontsize=12)\n"," ax4.set_ylabel('Model Architecture', fontsize=12)\n"," ax4.set_title('Model Size', fontsize=14, fontweight='bold')\n"," ax4.grid(axis='x', linestyle='--', alpha=0.6)\n"," for i, v in enumerate(df_comparison.sort_values(by='Model Size (MB)', ascending=True, inplace=False)['Model Size (MB)']):\n"," ax4.text(v + 0.5, i, str(v), color='black', va='center')\n","\n"," plt.tight_layout(rect=[0, 0.03, 1, 0.95]) # Adjust layout to prevent title overlap\n"," plot_path = comparison_plots_dir / 'model_comparison_summary.png'\n"," plt.savefig(plot_path)\n"," plt.show()\n"," plt.close(fig)\n"," print(f\"✓ Comparison visualizations saved to '{plot_path}'\")\n","\n"," # 6. Provide recommendations\n"," print(\"\\n\" + \"=\"*80)\n"," print(\"BEST MODEL RECOMMENDATIONS\")\n"," print(\"=\"*80)\n","\n"," # a. Best accuracy (mAP50)\n"," best_map50 = df_comparison.loc[df_comparison['mAP50'].idxmax()]\n"," print(f\"\\n🏆 Best Accuracy (mAP50): {best_map50['model_architecture']} (Dataset: {best_map50['dataset_alias']})\")\n"," print(f\" mAP50: {best_map50['mAP50']:.4f}\")\n"," print(f\" Inference: {best_map50['Inference Time (ms)']:.2f} ms\")\n"," print(f\" Size: {best_map50['Model Size (MB)']:.2f} MB\")\n","\n"," # b. Fastest inference\n"," fastest = df_comparison.loc[df_comparison['Inference Time (ms)'].idxmin()]\n"," print(f\"\\n⚡ Fastest Inference: {fastest['model_architecture']} (Dataset: {fastest['dataset_alias']})\")\n"," print(f\" Inference: {fastest['Inference Time (ms)']:.2f} ms\")\n"," print(f\" mAP50: {fastest['mAP50']:.4f}\")\n"," print(f\" Size: {fastest['Model Size (MB)']:.2f} MB\")\n","\n"," # c. Best balance (mAP50 / (Inference Time (ms) + 1))\n"," # Add a small constant to inference time to avoid division by zero and make it more robust\n"," df_comparison['Balance Score'] = df_comparison['mAP50'] / (df_comparison['Inference Time (ms)'] + 1e-6) # Add small epsilon\n"," best_balance = df_comparison.loc[df_comparison['Balance Score'].idxmax()]\n"," print(f\"\\n⚖️ Best Balance (Accuracy/Speed): {best_balance['model_architecture']} (Dataset: {best_balance['dataset_alias']})\")\n"," print(f\" Balance Score: {best_balance['Balance Score']:.4f}\")\n"," print(f\" mAP50: {best_balance['mAP50']:.4f}\")\n"," print(f\" Inference: {best_balance['Inference Time (ms)']:.2f} ms\")\n"," print(f\" Size: {best_balance['Model Size (MB)']:.2f} MB\")\n","\n"," # d. Smallest model\n"," smallest = df_comparison.loc[df_comparison['Model Size (MB)'].idxmin()]\n"," print(f\"\\n📦 Smallest Model: {smallest['model_architecture']} (Dataset: {smallest['dataset_alias']})\")\n"," print(f\" Size: {smallest['Model Size (MB)']:.2f} MB\")\n"," print(f\" mAP50: {smallest['mAP50']:.4f}\")\n"," print(f\" Inference: {smallest['Inference Time (ms)']:.2f} ms\")\n","\n"," print(\"\\n\" + \"=\"*80)\n"," print(\"FINAL RECOMMENDATION FOR REAL-TIME MOBILE DETECTION\")\n"," print(\"=\"*80)\n","\n"," # e. Final recommendation for real-time mobile detection\n"," # Prioritize speed while ensuring reasonable accuracy (e.g., mAP50 > 0.2, adjust threshold as needed)\n"," # Also consider if we trained on multiple datasets, which dataset performed best for the recommended model\n"," good_accuracy_models = df_comparison[df_comparison['mAP50'] > 0.2].copy()\n"," if not good_accuracy_models.empty:\n"," # Recommend the fastest among models with good accuracy\n"," recommended_model = good_accuracy_models.loc[good_accuracy_models['Inference Time (ms)'].idxmin()]\n"," print(f\"\\n✅ RECOMMENDED: {recommended_model['model_architecture']} on {recommended_model['dataset_alias']}\")\n"," print(f\" Reason: Best speed with acceptable accuracy for real-time mobile applications.\")\n"," print(f\" mAP50: {recommended_model['mAP50']:.4f}\")\n"," print(f\" Inference Time: {recommended_model['Inference Time (ms)']:.2f} ms\")\n"," print(f\" Model Size: {recommended_model['Model Size (MB)']:.2f} MB\")\n"," print(f\" Trained Model Path: {recommended_model['Trained Model Path']}\")\n"," else:\n"," print(\"No models achieved sufficient accuracy (mAP50 > 0.2) to provide a specific real-time mobile recommendation.\")\n"," print(\"Please review training parameters or dataset quality.\")\n"," print(\"=\"*80)\n","else:\n"," print(\"DataFrame for comparison is empty. No comparison or recommendations can be made.\")"]},{"cell_type":"markdown","metadata":{"id":"122f702d"},"source":["## Output Archiving and Downloading"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"d6847668","colab":{"base_uri":"https://localhost:8080/","height":321},"executionInfo":{"status":"ok","timestamp":1775419685754,"user_tz":-180,"elapsed":651,"user":{"displayName":"Nathan Holland","userId":"13994014446134761485"}},"outputId":"e5f518ac-30bb-4d28-b718-5fbe2b6b2427"},"outputs":[{"output_type":"stream","name":"stdout","text":["Consolidating all artifacts into 'outputs'...\n","Moved 'runs/all_trainings' to 'outputs/all_trainings'\n","Dataset analysis outputs already within 'outputs/dataset'. No additional move needed.\n","\n","Copying exported model files to 'outputs/models'...\n"," ✓ Copied TFLite: yolo11n_dataset_dataset.tflite (11.02 MB)\n"," ✓ Copied CoreML: yolo11n_dataset_dataset.mlpackage (5.19 MB)\n","\n","✓ Successfully copied 2 model file(s) to 'outputs/models'\n"," Models are ready for use in your Android/iOS project:\n"," - TFLite files (.tflite) → Android assets folder\n"," - CoreML files (.mlpackage) → iOS Xcode project\n"," - The _metadata.txt file contains model information for TFLite models.\n","Creating zip archive 'outputs.zip'...\n","Archive 'outputs.zip' created successfully.\n","Downloading 'outputs.zip'...\n"]},{"output_type":"display_data","data":{"text/plain":["<IPython.core.display.Javascript object>"],"application/javascript":["\n"," async function download(id, filename, size) {\n"," if (!google.colab.kernel.accessAllowed) {\n"," return;\n"," }\n"," const div = document.createElement('div');\n"," const label = document.createElement('label');\n"," label.textContent = `Downloading \"${filename}\": `;\n"," div.appendChild(label);\n"," const progress = document.createElement('progress');\n"," progress.max = size;\n"," div.appendChild(progress);\n"," document.body.appendChild(div);\n","\n"," const buffers = [];\n"," let downloaded = 0;\n","\n"," const channel = await google.colab.kernel.comms.open(id);\n"," // Send a message to notify the kernel that we're ready.\n"," channel.send({})\n","\n"," for await (const message of channel.messages) {\n"," // Send a message to notify the kernel that we're ready.\n"," channel.send({})\n"," if (message.buffers) {\n"," for (const buffer of message.buffers) {\n"," buffers.push(buffer);\n"," downloaded += buffer.byteLength;\n"," progress.value = downloaded;\n"," }\n"," }\n"," }\n"," const blob = new Blob(buffers, {type: 'application/binary'});\n"," const a = document.createElement('a');\n"," a.href = window.URL.createObjectURL(blob);\n"," a.download = filename;\n"," div.appendChild(a);\n"," a.click();\n"," div.remove();\n"," }\n"," "]},"metadata":{}},{"output_type":"display_data","data":{"text/plain":["<IPython.core.display.Javascript object>"],"application/javascript":["download(\"download_deb39c93-c107-4a4d-98ae-d0d5e9d87f53\", \"outputs.zip\", 17830490)"]},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Download initiated.\n"]}],"source":["import os\n","import shutil\n","from pathlib import Path\n","# The import for google.colab.drive is removed as per user request.\n","\n","# Ensure the base 'outputs' directory exists\n","outputs_base_dir = Path('outputs')\n","outputs_base_dir.mkdir(parents=True, exist_ok=True)\n","\n","print(f\"Consolidating all artifacts into '{outputs_base_dir}'...\")\n","\n","# Move the 'runs/all_trainings' directory into the 'outputs' directory\n","try:\n"," trainings_run_source = Path('runs/all_trainings')\n"," if trainings_run_source.exists():\n"," destination_path = outputs_base_dir / 'all_trainings'\n"," if destination_path.exists():\n"," shutil.rmtree(destination_path)\n"," shutil.copytree(trainings_run_source, destination_path)\n"," print(f\"Moved '{trainings_run_source}' to '{destination_path}'\")\n"," else:\n"," print(f\"Warning: '{trainings_run_source}' not found. Skipping move.\")\n","except Exception as e:\n"," print(f\"Error moving training runs: {e}\")\n","\n","# Also move the dataset-specific analysis directories created earlier\n","# These are typically within outputs/dataset_alias/dataset_analysis\n","for dataset_info in prepared_datasets_info:\n"," dataset_output_dir = dataset_info['output_dir'] # e.g., outputs/basketball_dataset\n"," if dataset_output_dir.exists():\n"," # Just ensure these exist within the outputs_base_dir, as they are already there\n"," # If we were to move them, we'd do similar to trainings_run_source\n"," print(f\"Dataset analysis outputs already within '{dataset_output_dir}'. No additional move needed.\")\n","\n","# Create a dedicated models directory and copy all exported model files\n","models_output_dir = outputs_base_dir / 'models'\n","models_output_dir.mkdir(parents=True, exist_ok=True)\n","print(f\"\\nCopying exported model files to '{models_output_dir}'...\")\n","\n","models_copied = 0\n","for result in all_results_for_comparison:\n"," if result.get('status') == 'Success':\n"," model_name = result.get('_model_name', result.get('model_architecture', 'unknown'))\n"," dataset_alias = result.get('_dataset_alias', result.get('dataset_alias', 'unknown'))\n","\n"," # Copy TFLite model\n"," tflite_source = result.get('_tflite_file_path')\n"," if tflite_source:\n"," # Handle both Path objects and strings\n"," if isinstance(tflite_source, str):\n"," tflite_source = Path(tflite_source)\n"," if tflite_source.exists():\n"," tflite_dest = models_output_dir / f\"{model_name}_{dataset_alias}.tflite\"\n"," try:\n"," shutil.copy2(tflite_source, tflite_dest)\n"," print(f\" ✓ Copied TFLite: {tflite_dest.name} ({tflite_dest.stat().st_size / (1024*1024):.2f} MB)\")\n"," models_copied += 1\n"," except Exception as e:\n"," print(f\" ✗ Failed to copy TFLite model {tflite_source}: {e}\")\n"," else:\n"," print(f\" ⚠ TFLite model not found at: {tflite_source}\")\n"," else:\n"," print(f\" ⚠ No TFLite path stored for {model_name} on {dataset_alias}\")\n","\n"," # Copy CoreML model (mlpackage is a directory, so use copytree)\n"," coreml_source = result.get('_coreml_file_path')\n"," if coreml_source:\n"," # Handle both Path objects and strings\n"," if isinstance(coreml_source, str):\n"," coreml_source = Path(coreml_source)\n"," if coreml_source.exists():\n"," coreml_dest = models_output_dir / f\"{model_name}_{dataset_alias}.mlpackage\"\n"," try:\n"," if coreml_dest.exists():\n"," shutil.rmtree(coreml_dest)\n"," if coreml_source.is_dir():\n"," shutil.copytree(coreml_source, coreml_dest)\n"," # Calculate size for directory\n"," total_size = sum(f.stat().st_size for f in coreml_dest.rglob('*') if f.is_file())\n"," print(f\" ✓ Copied CoreML: {coreml_dest.name} ({total_size / (1024*1024):.2f} MB)\")\n"," else:\n"," shutil.copy2(coreml_source, coreml_dest)\n"," print(f\" ✓ Copied CoreML: {coreml_dest.name} ({coreml_dest.stat().st_size / (1024*1024):.2f} MB)\")\n"," models_copied += 1\n"," except Exception as e:\n"," print(f\" ✗ Failed to copy CoreML model {coreml_source}: {e}\")\n"," else:\n"," print(f\" ⚠ CoreML model not found at: {coreml_source}\")\n"," else:\n"," print(f\" ⚠ No CoreML path stored for {model_name} on {dataset_alias}\")\n","\n","if models_copied > 0:\n"," print(f\"\\n✓ Successfully copied {models_copied} model file(s) to '{models_output_dir}'\")\n"," print(f\" Models are ready for use in your Android/iOS project:\")\n"," print(f\" - TFLite files (.tflite) → Android assets folder\")\n"," print(f\" - CoreML files (.mlpackage) → iOS Xcode project\")\n"," print(f\" - The _metadata.txt file contains model information for TFLite models.\")\n","else:\n"," print(f\"\\n⚠ No model files were copied. Check if models were exported successfully.\")\n"," print(f\" Check the 'all_trainings' directory for exported models.\")\n","\n","# Create a zip archive of the entire 'outputs' directory\n","zip_file_name = f\"{outputs_base_dir.name}.zip\"\n","print(f\"Creating zip archive '{zip_file_name}'...\")\n","try:\n"," shutil.make_archive(outputs_base_dir, 'zip', outputs_base_dir)\n"," print(f\"Archive '{zip_file_name}' created successfully.\")\n","except Exception as e:\n"," print(f\"Error creating zip archive: {e}\")\n","\n","# Provide a download link for Google Colab environments\n","try:\n"," from google.colab import files\n"," print(f\"Downloading '{zip_file_name}'...\")\n"," files.download(zip_file_name)\n"," print(\"Download initiated.\")\n","except ImportError:\n"," print(\"Not running in Google Colab. Archive saved locally. You can download it manually.\")\n","except Exception as e:\n"," print(f\"Error initiating download: {e}\")"]},{"cell_type":"markdown","metadata":{"id":"8cafce89"},"source":["## Summary:\n","\n","### Data Analysis Key Findings\n","\n","* A comprehensive model comparison table was generated from the `all_results_for_comparison` list, capturing metrics such as mAP50, inference time, and model size for `yolo11n` and `yolo11s` models trained on the `basketball_dataset`. This table was saved as `model_comparison_results.csv`.\n","* A set of comparative visualizations, including a scatter plot of Accuracy (mAP50) vs. Inference Time (ms) with marker size representing Model Size (MB), and bar charts for mAP50, Inference Time (ms), and Model Size (MB) across different models, were created and saved to `outputs/comparison_results/model_comparison_summary.png`.\n","* Model recommendations were provided based on various criteria:\n"," * **Best Accuracy (mAP50):** `yolo11s` achieved the highest mAP50 of 0.5873 on the `basketball_dataset`.\n"," * **Fastest Inference:** `yolo11n` demonstrated the fastest inference time at 2.18 ms on the `basketball_dataset`.\n"," * **Best Balance (Accuracy/Speed):** `yolo11s` presented the best balance score of 0.1468 on the `basketball_dataset`.\n"," * **Smallest Model:** `yolo11n` was the smallest model at 5.18 MB on the `basketball_dataset`.\n"," * **Recommended for Real-Time Mobile Detection:** `yolo11n` on `basketball_dataset` was ultimately recommended due to its optimal balance of speed (2.18 ms) and acceptable accuracy (0.2578 mAP50), combined with a compact size of 5.18 MB.\n","* All generated artifacts, including trained model runs (`runs/all_trainings`), comparison results, and dataset analysis outputs, were successfully consolidated into a single `outputs` directory.\n","* **Exported model files (TFLite and CoreML) were copied to `outputs/models/` directory with clear naming: `{model_arch}_{dataset_alias}.tflite` and `{model_arch}_{dataset_alias}.mlpackage`**\n","* The entire `outputs` directory was compressed into a `outputs.zip` archive.\n","* A download link for the `outputs.zip` file was provided, enabling easy retrieval of all results in a Google Colab environment.\n","* **Model files are ready for direct use in Android/iOS projects from the `outputs/models/` directory.**\n","\n","### Insights or Next Steps\n","\n","* The automated multi-model and multi-dataset workflow provides a robust framework for comparing model performance across various evaluation metrics and datasets, enabling informed decision-making for deployment.\n","* The consolidated and archived output structure significantly streamlines the collection and sharing of experimental results, fostering reproducibility and efficient collaboration.\n","\n","### Performance Tips\n","\n","- Use image size 416x416 for fastest inference (vs 640x640)\n","- Process every 2nd or 3rd frame if needed for 30+ FPS\n","- Use GPU acceleration when available on device\n","- Adjust confidence threshold based on your use case (default: 0.25)\n","\n","### Model Optimization\n","\n","The exported models include:\n","- ✅ Half precision (FP16) for CoreML\n","- ✅ INT8 quantization for TFLite\n","- ✅ Built-in NMS (Non-Maximum Suppression)\n","- ✅ Optimized for mobile inference\n","- ✅ Metadata verification for TensorFlow Lite Task Vision compatibility\n","\n","### Metadata Compatibility Notes\n","\n","**TFLite Models:**\n","- Models are verified for metadata compatibility with TensorFlow Lite Task Vision ObjectDetector API\n","- If metadata is missing, the model may still work with the Interpreter API directly\n","- For guaranteed Task Vision API compatibility, consider using TensorFlow Lite Model Maker\n","- Current models use input size 416x416 with INT8 quantization and built-in NMS\n","\n","**CoreML Models:**\n","- Models are exported with FP16 precision and built-in NMS\n","- Compatible with iOS Vision framework (VNCoreMLModel)\n","- Input size: 416x416\n"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"L4","machine_shape":"hm","provenance":[{"file_id":"1c5C66etoxb3_sSdBhAih0nbuUAiQKUWS","timestamp":1775723631466},{"file_id":"15IYMZt89kjHdGAJasMJ2nXev7o29bwuH","timestamp":1775131908320},{"file_id":"1xTyQm3N79_YakEYu-uFkWNxCmMG9jZUY","timestamp":1773309940132}]},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}
+1 -1
gradle/libs.versions.toml
··· 32 32 litert-gpu = { module = "com.google.ai.edge.litert:litert-gpu", version.ref = "litert" } 33 33 litert-metadata = { module = "com.google.ai.edge.litert:litert-metadata", version.ref = "litert" } 34 34 litert-support = { module = "com.google.ai.edge.litert:litert-support", version.ref = "litert" } 35 - pose-detection = { module = "com.google.mlkit:pose-detection", version.ref = "poseDetectionVersion" } 35 + pose-detection = { module = "com.google.mlkit:pose-detection-accurate", version.ref = "poseDetectionVersion" } 36 36 pose-detection-common = { group = "com.google.mlkit", name = "pose-detection-common", version.ref = "poseDetectionVersion" } 37 37 filekit-core = { module = "io.github.vinceglb:filekit-core", version.ref = "filekitCore" } 38 38 filekit-dialogs = { module = "io.github.vinceglb:filekit-dialogs", version.ref = "filekitCore" }
+194
handover/ANDROID_INTEGRATION.md
··· 1 + # Android Integration Requirements 2 + 3 + This document explains what the kima Android app must implement to consume the models in `models/`. All requirements are derived from working code in `reference_code/` — copy or adapt those files as needed. 4 + 5 + ## Critical: camera config + activity orientation 6 + 7 + The recommended model `yolo26n_v11_rect_512x384.tflite` expects a **landscape 4:3** input. If the camera delivers any other aspect ratio or orientation, the detector's letterbox math will pad with gray and waste capacity. The square models (`square_416`, `square_512`) tolerate any aspect ratio gracefully via letterboxing, but they're slower for the same effective resolution. 8 + 9 + ### 1. Pin CameraX `ImageAnalysis` to 4:3 10 + 11 + In whatever Compose / Activity sets up the `CameraX` use cases, the `ImageAnalysis.Builder` needs `setTargetAspectRatio(AspectRatio.RATIO_4_3)`: 12 + 13 + ```kotlin 14 + import androidx.camera.core.AspectRatio 15 + import androidx.camera.core.ImageAnalysis 16 + 17 + val imageAnalysis = ImageAnalysis.Builder() 18 + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) 19 + .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) 20 + .setTargetAspectRatio(AspectRatio.RATIO_4_3) // ← CRITICAL for the rect model 21 + .build() 22 + ``` 23 + 24 + `setTargetAspectRatio` is a *hint* — CameraX picks the closest available 4:3 mode (typically 1280×960, 1440×1080, or 2048×1536 depending on the device). The actual W×H still varies, but the *aspect* is guaranteed. 25 + 26 + If a device can't deliver 4:3 (rare), the existing letterbox math in the detector handles it gracefully — at worst, the model wastes some pixels on padding and quality drops slightly, but it doesn't crash. 27 + 28 + See `reference_code/CameraView_snippet.kt` for the full surrounding context. 29 + 30 + ### 2. Lock the activity to landscape 31 + 32 + Otherwise the camera frame arrives portrait-rotated and a 384×512 landscape model gets a 512×384 portrait input — wrong aspect, large letterbox bars. Add to the main activity in `AndroidManifest.xml`: 33 + 34 + ```xml 35 + <activity 36 + android:name=".MainActivity" 37 + android:screenOrientation="landscape" 38 + ...> 39 + ``` 40 + 41 + See `reference_code/AndroidManifest_snippet.xml` for an example. 42 + 43 + **Alternative if landscape lock isn't acceptable** (e.g., kima needs portrait support too): inside the detector, rotate the bitmap by 90° before resizing if `imgH > imgW`. Adds minimal CPU cost. Implementation sketch in `LESSONS_LEARNED.md`. 44 + 45 + ## Critical: letterbox-aware preprocessing in the detector 46 + 47 + YOLO models are trained on **letterboxed** input — the source image is scaled to fit the model's input shape while preserving aspect ratio, then padded with gray (RGB 114,114,114) to fill any remaining space. **The Android detector MUST do the same**, otherwise the model's geometry priors are violated and detection quality plummets. 48 + 49 + If the camera aspect already matches the model aspect (4:3 camera + 4:3 model), the letterbox math degenerates to a plain resize with `padX=0, padY=0` — but you still need the math in place for the cases where it doesn't match. 50 + 51 + ### Reference implementation 52 + 53 + `reference_code/ImageDetector.android.kt` is the working letterbox-aware detector from this project. Key points: 54 + 55 + ```kotlin 56 + // Letterbox: scale source to fit model input while preserving aspect ratio. 57 + val scale = min( 58 + inputW.toFloat() / imgW.toFloat(), 59 + inputH.toFloat() / imgH.toFloat() 60 + ) 61 + val scaledW = (imgW * scale).roundToInt().coerceAtLeast(1) 62 + val scaledH = (imgH * scale).roundToInt().coerceAtLeast(1) 63 + val padX = (inputW - scaledW) / 2f 64 + val padY = (inputH - scaledH) / 2f 65 + 66 + val resized = Bitmap.createBitmap(inputW, inputH, Bitmap.Config.ARGB_8888) 67 + val canvas = Canvas(resized) 68 + canvas.drawColor(Color.rgb(114, 114, 114)) // ← gray fill matching YOLO training 69 + canvas.drawBitmap( 70 + srcBitmap, null, 71 + RectF(padX, padY, padX + scaledW, padY + scaledH), 72 + Paint(Paint.FILTER_BITMAP_FLAG) 73 + ) 74 + ``` 75 + 76 + After inference, the output bboxes (which are normalized `[0, 1]` over the **letterboxed** input tensor) need to be **un-letterboxed** back to the original image's coordinate space: 77 + 78 + ```kotlin 79 + val x1pLb = min(x1, x2) * inputW // letterboxed pixel coords 80 + val y1pLb = min(y1, y2) * inputH 81 + val x2pLb = max(x1, x2) * inputW 82 + val y2pLb = max(y1, y2) * inputH 83 + 84 + // Subtract padding offset, divide by scale ratio → original image coords 85 + val left = ((x1pLb - padX) / scale).coerceIn(0f, imgWF) 86 + val top = ((y1pLb - padY) / scale).coerceIn(0f, imgHF) 87 + val right = ((x2pLb - padX) / scale).coerceIn(0f, imgWF) 88 + val bottom = ((y2pLb - padY) / scale).coerceIn(0f, imgHF) 89 + ``` 90 + 91 + If you skip the un-letterbox step, bboxes will be slightly offset and scaled wrong — most visibly at the edges of the frame. 92 + 93 + ## TFLite interpreter setup 94 + 95 + The reference `CustomObjectModel.android.kt` shows the full delegate fallback chain (GPU → NNAPI → CPU) with logging. Key snippet: 96 + 97 + ```kotlin 98 + import org.tensorflow.lite.Interpreter 99 + import org.tensorflow.lite.gpu.GpuDelegate 100 + 101 + var selectedDelegate = "CPU" 102 + val (options, gpuDelegate) = runCatching { 103 + val delegate = GpuDelegate() 104 + val opts = Interpreter.Options().apply { 105 + addDelegate(delegate) 106 + setNumThreads(2) 107 + } 108 + selectedDelegate = "GPU" 109 + Logger.i { "TFLite: GPU delegate constructed" } 110 + opts to delegate 111 + }.onFailure { t -> 112 + Logger.w(t) { "TFLite: GPU delegate not available; trying NNAPI" } 113 + }.getOrElse { 114 + // fall back to NNAPI, then CPU 4-thread 115 + // ... see reference_code/CustomObjectModel.android.kt 116 + } 117 + 118 + val interpreter = Interpreter(model, options) 119 + 120 + // IMPORTANT: log the actual loaded shape so you can verify GPU is engaging 121 + val inputShape = interpreter.getInputTensor(0)?.shape() 122 + val outputShape = interpreter.getOutputTensor(0)?.shape() 123 + Logger.i { 124 + "TFLite: model='$path' delegate=$selectedDelegate " + 125 + "inputShape=${inputShape?.toList()} outputShape=${outputShape?.toList()}" 126 + } 127 + ``` 128 + 129 + **Verify after install**: `adb logcat -s TFLite:I` after launching the app should show one line per model load. Confirm: 130 + - `delegate=GPU` (not CPU — would mean ~10× slower) 131 + - `inputShape=[1, 384, 512, 3]` for `yolo26n_v11_rect_512x384.tflite` (or match the chosen model) 132 + 133 + ## Output parsing 134 + 135 + All models output `[1, 300, 6]` post-NMS: 136 + 137 + ```kotlin 138 + val outputShape = interpreter.getOutputTensor(0).shape() // [1, 300, 6] 139 + val output = TensorBuffer.createFixedSize(outputShape, DataType.FLOAT32) 140 + interpreter.run(tensorImage.buffer, output.buffer) 141 + val array = output.floatArray // 1800 floats 142 + 143 + // Layout: 300 rows of 6 columns each, sorted by confidence descending 144 + // Row i: array[i*6 .. i*6+5] = [x1, y1, x2, y2, conf, cls] 145 + for (i in 0 until 300) { 146 + val row = i * 6 147 + val conf = array[row + 4] 148 + if (conf < 0.25f) break // remaining rows are empty/zero 149 + val x1 = array[row + 0] 150 + val y1 = array[row + 1] 151 + val x2 = array[row + 2] 152 + val y2 = array[row + 3] 153 + val cls = array[row + 5].toInt() // 0=basketball, 1=basketball_hoop 154 + // (then un-letterbox per the snippet above and emit a detection) 155 + } 156 + ``` 157 + 158 + The reference `ImageDetector.android.kt` handles a subtle wrinkle: depending on how ultralytics happens to export, the output may be `[1, 300, 6]` (300 detections, 6 fields each) OR `[1, 6, 300]` (6 fields, 300 detections each). The reference code auto-detects via the `dim2 == 6 ? elements-first : channels-first` check. Worth keeping that flexibility. 159 + 160 + ## Permissions + dependencies 161 + 162 + The kima app likely already has these, but for completeness: 163 + 164 + ```xml 165 + <!-- AndroidManifest.xml --> 166 + <uses-permission android:name="android.permission.CAMERA" /> 167 + <uses-feature android:name="android.hardware.camera" android:required="false" /> 168 + ``` 169 + 170 + ```kotlin 171 + // build.gradle.kts dependencies 172 + implementation("androidx.camera:camera-core:1.x.x") 173 + implementation("androidx.camera:camera-camera2:1.x.x") 174 + implementation("androidx.camera:camera-lifecycle:1.x.x") 175 + implementation("androidx.camera:camera-view:1.x.x") 176 + 177 + implementation("org.tensorflow:tensorflow-lite:2.x.x") 178 + implementation("org.tensorflow:tensorflow-lite-gpu:2.x.x") 179 + implementation("org.tensorflow:tensorflow-lite-support:0.x.x") 180 + ``` 181 + 182 + ## Common gotchas 183 + 184 + 1. **Wrong delegate** — if the GPU delegate fails silently (e.g. on some emulators or low-end devices) and falls back to CPU, inference goes from ~7 Hz to ~1 Hz. The logging in `CustomObjectModel.android.kt` makes this visible. 185 + 186 + 2. **Wrong input dtype** — input is **float32** even for the fp16-internal models. The fp16 versions only have fp16 weights internally; their I/O tensors are still float32. Don't try to feed Int8/Uint8 buffers without re-quantizing. 187 + 188 + 3. **Pixel normalization** — YOLO expects pixel values in `[0, 1]`, not `[0, 255]`. The reference uses `NormalizeOp(0f, 255f)` which performs `(x - 0) / 255 → [0, 1]`. Skipping this is a common cause of "model loads fine, detections all garbage". 189 + 190 + 4. **NMS double-application** — these models have NMS baked in. **Don't run another NMS pass on the output** — it'll discard valid detections. 191 + 192 + 5. **Coordinate system after rotation** — if you rotate the bitmap to landscape inside the detector (Option B from above), you also need to track that rotation when emitting bounding box coordinates back to the rest of the app, otherwise downstream consumers see boxes in the wrong reference frame. 193 + 194 + 6. **Filename probe before shipping** — see `LESSONS_LEARNED.md` and the `MODELS.md` shape table. Always run `tf.lite.Interpreter` against any tflite once after copying it to verify the input shape matches what you expect. Filenames have lied before in this project.
+142
handover/LESSONS_LEARNED.md
··· 1 + # Lessons Learned 2 + 3 + Compressed list of the key findings from the R&D session that produced these models. Each one cost real time to learn — read this before making decisions about training or integration. 4 + 5 + ## Training-side 6 + 7 + ### 1. **NEVER train on a stretched dataset.** 8 + 9 + Roboflow's `Preprocessing → Resize → Stretch to NxN` distorts every training image to a square, destroying aspect ratios. YOLO is trained to expect letterboxed input, so a stretch-trained model learns wrong geometry priors and produces loose, distorted bboxes at inference even after fixing preprocessing on the inference side. 10 + 11 + **Cost paid**: Weeks of accuracy issues blamed on the model architecture before discovering it was the dataset preprocessing. Required regenerating the Roboflow dataset (versions v9 → v10 → v11) and retraining everything. 12 + 13 + **Always use** `Preprocessing → Resize → "Fit" or "None"`. "None" is preferred — let ultralytics' built-in `LetterBox` handle padding at training time with the correct gray-114 fill. 14 + 15 + ### 2. **`rect=True` training beats square training for non-square deployment.** 16 + 17 + When the inference shape will be non-square (e.g. matching a 4:3 camera frame), use `rect=True` in `TRAINING_HYPERPARAMETERS`. The dataloader produces rectangular batches matching the dataset's natural aspect ratio. The model learns features tuned for the actual deployment shape. Mosaic augmentation auto-disables (mosaic produces square outputs), but the geometric alignment is worth more than the augmentation loss. 18 + 19 + **Measured benefit**: yolo26n trained at imgsz=384 square then exported at `[288, 384]` → 0.624 mean conf. Same architecture trained with `rect=True` imgsz=384 → **0.734 mean conf, +0.110**, zero speed cost. 20 + 21 + The val mAP told a misleading story: square-trained scored slightly higher on val. The on-device test reversed it dramatically. **Trust the on-device measurement, not val mAP, when train-time and inference-time distributions differ.** 22 + 23 + ### 3. **Ultralytics silently collapses tuple `imgsz` to a single int during training.** 24 + 25 + `imgsz=[288, 384]` in `TRAINING_HYPERPARAMETERS` produces a warning `'train' and 'val' imgsz must be an integer` and quietly trains at the larger dimension as a square. This means "train at a rectangular shape" via tuple syntax doesn't work — you must use `rect=True` instead. 26 + 27 + The same `imgsz=[H, W]` tuple **does** work in `model.export(...)` though, which makes the bug subtle: you can train square and export rect without realizing they don't match. 28 + 29 + ### 4. **mAP50 on the val set doesn't reliably predict on-device confidence.** 30 + 31 + Multiple times in this session a model with higher mAP50 scored lower on the on-device test than a model with lower mAP50. Reasons include: the val set has a different content distribution than the test video (court angle, lighting), the val set uses a different scoring threshold than the on-device test, and dataset augmentations in training change which content the model is good at. **The 60s on-device capture is the deciding measurement.** 32 + 33 + ### 5. **Always probe the exported TFLite shape with `tf.lite.Interpreter` after export.** 34 + 35 + Filenames lie. The original `yolo11n_su_416.tflite` had actual input shape `[1, 512, 512, 3]` because an earlier ultralytics export silently rounded `imgsz=416` up to 512 (probably a stride-alignment quirk in onnx2tf). Cost a full retraining cycle to discover. Probe every exported tflite with: 36 + 37 + ```python 38 + import tensorflow as tf 39 + it = tf.lite.Interpreter(model_path=path) 40 + it.allocate_tensors() 41 + print('input ', it.get_input_details()[0]['shape']) 42 + print('output', it.get_output_details()[0]['shape']) 43 + ``` 44 + 45 + If the shape doesn't match expectations, rename the file or fix the export before syncing into the app. 46 + 47 + ## Inference-side 48 + 49 + ### 6. **Letterboxing is critical for square models, irrelevant for matched-aspect models.** 50 + 51 + The Android `ImageDetector` MUST do letterboxed preprocessing (scale to fit, gray-114 pad) when feeding a non-matching aspect to a square model — otherwise YOLO's geometric priors are violated and quality plummets. When the camera aspect matches the model aspect (4:3 camera + 4:3 rect model), the letterbox math reduces to a plain resize with `padX=padY=0` — but you still need the math in place for the case where it doesn't match. 52 + 53 + Output bboxes are normalized `[0, 1]` over the **letterboxed** input tensor. After inference, you must un-letterbox the bboxes back to the original image's coordinate space (subtract padding offset, divide by scale ratio). Skipping this step gives bboxes that are slightly offset and scaled wrong, most visibly at the frame edges. 54 + 55 + ### 7. **Camera frames default to whatever CameraX picks.** 56 + 57 + Stock `ImageAnalysis.Builder()` with no resolution config uses the device's default — which may be 4:3 OR 16:9 depending on the phone's main camera native aspect. **Always pin** the aspect ratio with `setTargetAspectRatio(AspectRatio.RATIO_4_3)` so the input distribution to the model is consistent across devices. The kima app must do this if it ships the rect 4:3 model. 58 + 59 + ### 8. **Activity orientation lock is a hard requirement for non-square models.** 60 + 61 + The Android camera pipeline rotates the bitmap to "upright" relative to the phone's current orientation. A landscape model fed a portrait-rotated bitmap gets garbage. Either: 62 + - **Lock the activity to landscape** in `AndroidManifest.xml` (`android:screenOrientation="landscape"`), or 63 + - **Detect orientation in the detector** and rotate the bitmap to landscape before resizing if `imgH > imgW`. Adds minor CPU cost (one `Matrix.postRotate(-90f)` per frame). 64 + 65 + The R&D project locked landscape via manifest. If kima needs portrait support, use the rotation fallback. 66 + 67 + ### 9. **fp32 vs fp16 on the TFLite GPU delegate is essentially equivalent.** 68 + 69 + Tested both for yolo26n at multiple imgsz. Differences: 70 + - **Speed**: identical within noise (±0.05 Hz on a 6-Hz model). The GPU delegate isn't accelerating fp16 over fp32 in any measurable way on the A36 5G — both bottleneck on memory bandwidth, not weight precision. 71 + - **Quality**: fp16 costs ~0.02 mean confidence vs fp32. Detectable but small. 72 + - **File size**: fp16 is exactly half. ~5 MB vs ~9 MB. 73 + 74 + For production: **use fp32**. The extra 4 MB is negligible vs the production app's overall size, and the small quality win is real. 75 + 76 + ### 10. **GPU delegate selection is silent on failure — log it explicitly.** 77 + 78 + If the TFLite GPU delegate fails to construct (e.g. on some emulators, low-end devices, or after Android updates), the interpreter falls back to CPU at ~10× slower inference. **The fallback is silent unless you log it explicitly.** The reference `CustomObjectModel.android.kt` adds an `Logger.i { "TFLite: ... delegate=$selected ..." }` line so `adb logcat -s TFLite:I` shows the actual delegate after every model load. 79 + 80 + ## Test-protocol-side 81 + 82 + ### 11. **The yolo26n family is sensitive to small framing changes.** 83 + 84 + Same model file scored between **0.64 and 0.84** mean confidence across different sessions in this project, depending on how the phone was positioned. The `yolo11n` family is much more stable across the same conditions (~0.72 ±0.03). Possible cause: yolo26n's feature pyramid is more sensitive to subpixel-scale alignment of small objects. 85 + 86 + Practical implication: **always run a noise-floor sanity check** on a stable model (`yolo11n_noise_floor_baseline.tflite`) before any A/B test, and **only compare yolo26n models within the same back-to-back capture session**. Cross-session yolo26n comparisons are unreliable. 87 + 88 + ### 12. **60-second test clips are the minimum for stable measurements.** 89 + 90 + 10-second clips have a noise floor of ~±0.10 mean conf, which is too high to detect real model improvements (most candidate-vs-candidate differences are in the 0.03–0.15 range). 60-second clips drop the noise floor to ~±0.05 for stable models and ~±0.10 for the noise-prone yolo26n family. Bigger sample → tighter measurement. 91 + 92 + ### 13. **Run-to-run variance on the SAME model is real and significant.** 93 + 94 + The same `yolo11n_dataset_dataset.tflite` file measured between 0.597 and 0.753 mean conf across different sessions on the same test setup. Same file. Same video. Different absolute numbers because of phone positioning, lighting, video timing, thermal state, etc. 95 + 96 + **Within-session relative ordering is the only reliable signal.** Don't quote absolute numbers across sessions. 97 + 98 + ## Pipeline-side 99 + 100 + ### 14. **Mount Drive at the start of every Colab session, not the end.** 101 + 102 + `drive.mount('/content/drive')` may pop a "Connect to Google Drive" card requiring a click. If you defer this to the post-training sync cell, the user is unlikely to be at their keyboard 30 minutes later when training finishes — and the whole pipeline stalls. Mount Drive in the first ~5 cells, before triggering the long-running training, so any auth happens while the user is present. 103 + 104 + ### 15. **`google.colab.files.download()` is unreliable.** 105 + 106 + The JS download trigger gets silently blocked by browsers (popup blockers, unfocused Colab tab, etc.). The cell completes successfully and the file never arrives on the Mac — no error. **Always use Drive sync** for moving files Colab → Mac. `drive.mount` + `shutil.copy2` to `/content/drive/MyDrive/...` reliably mirrors to Drive Desktop within ~10 seconds. 107 + 108 + ### 16. **Colab cold-restart loses Python state but Drive mount auth is browser-cached.** 109 + 110 + If you switch the runtime accelerator (CPU ↔ GPU) or hit the idle timeout, the Python runtime resets and you have to re-run cells 2 (apt/pip), 3 (verify), 5 (config), 7/9/11 (dataset), 13 (training). But `drive.mount()` is cached by the browser session, so a re-mount on a cold runtime is silent — no second auth click required, as long as the same browser tab is still open. 111 + 112 + ### 17. **The auto-suffix gotcha when re-running ultralytics on the same dataset alias.** 113 + 114 + Running the training cell twice with the same `dataset_alias` produces run dirs `yolo26n_dataset_v11`, `yolo26n_dataset_v112`, `yolo26n_dataset_v113`, etc. Any cell that hardcodes the path will silently use the OLD weights. Always use a glob like `glob.glob('/content/runs/.../yolo26n_dataset_v11*')` sorted by mtime descending to pick the most recent. 115 + 116 + ## Architecture / model-choice-side 117 + 118 + ### 18. **yolo26n is a strict improvement over yolo11n on this task.** 119 + 120 + In the multi-arch comparison (V5.4), yolo26n at 416² beat yolo11n at 416² on both speed AND quality (within the same session). The newer architecture's improvements seem to actually deliver. **Default to yolo26n** for any new experiments unless you have a specific reason not to. 121 + 122 + ### 19. **yolo11s is too slow for this hardware tier.** 123 + 124 + yolo11s (the "small" variant of yolo11) has ~3-4× the parameters of yolo11n and on the A36 5G runs at ~2.5 Hz at imgsz=416. Quality wins are marginal vs yolo26n. **Don't use yolo11s here.** 125 + 126 + ### 20. **`imgsz=320` is too small for basketball detection on this dataset.** 127 + 128 + At 320² square + letterbox of a 16:9 source, the basketball ends up at ~6 pixels, near YOLO's small-object detection floor. mAP50 dropped from 0.76 (at 416) to 0.63 (at 320). Detection rate stayed at 100% but per-frame confidence dropped from ~0.82 to ~0.63. Use rectangular models or larger imgsz instead. 129 + 130 + ### 21. **Rectangular models always beat square models with letterbox at the same compute budget.** 131 + 132 + For a non-square camera source, a rect model at `(H, W)` has H*W pixels of effective content. A square model at imgsz=N has N*min(H,W)/max(H,W)*N pixels of effective content (the rest is gray padding waste). Same total inference cost, ~25% more useful pixels in the rect model for a 4:3 source. The R&D session's 60s on-device tests confirmed this is real. 133 + 134 + ## TL;DR for the next session 135 + 136 + 1. Use `yolo26n_v11_rect_512x384.tflite` as the default. 137 + 2. Pin the camera to 4:3, lock the activity to landscape. 138 + 3. The Android detector MUST do letterbox preprocessing + un-letterbox of output bboxes. 139 + 4. fp32. Don't bother with fp16. 140 + 5. Always run the noise-floor sanity check before any A/B test. 141 + 6. 60-second back-to-back captures, never 10s. 142 + 7. Within-session relative ordering is the only reliable signal.
+106
handover/MODELS.md
··· 1 + # Models — Detailed Comparison 2 + 3 + All measurements were taken on a **Samsung Galaxy A36 5G**, **TFLite GPU delegate**, running the test app filming a 4K (3840×2160) basketball video played on a Mac monitor at landscape 16:9, captured for 60 seconds at video offset 10s. Phone in landscape orientation, camera pinned to `RATIO_4_3`. Letterbox preprocessing in the Android detector. 4 + 5 + **Run-to-run noise floor on this test setup**: ~±0.05 mean confidence on stable models like `yolo11n_dataset_dataset`. The yolo26n family is more sensitive (~±0.10) — small changes in phone position can shift its measured confidence noticeably without affecting framerate or detection rate. Run a noise check (capture `yolo11n_noise_floor_baseline.tflite` first; expect ~0.72 mean conf) before any A/B test. 6 + 7 + ## All 6 candidates at a glance 8 + 9 + | File | Arch | Input shape | Pixels | **Hz** | **Mean conf range** | val mAP50 | Size | Use case | 10 + |---|---|---|---:|---:|---:|---:|---:|---| 11 + | **`yolo26n_v11_rect_512x384.tflite`** ⭐ | yolo26n | `[1, 384, 512, 3]` | 197k | **6.7** | **0.78–0.83** | 0.7632 | 9.3 MB | **Recommended production default** | 12 + | `yolo26n_v11_rect_384x288.tflite` | yolo26n | `[1, 288, 384, 3]` | 110k | **10.5** | 0.59–0.73 | 0.6456 | 9.3 MB | Real-time tracking, >10 Hz needed | 13 + | `yolo26n_v11_square_512.tflite` | yolo26n | `[1, 512, 512, 3]` | 262k | 5.0 | 0.78–0.83 | 0.8206 | 9.3 MB | Quality-first, square inputs OK | 14 + | `yolo26n_v11_square_416.tflite` | yolo26n | `[1, 416, 416, 3]` | 173k | 7.5 | 0.64–0.84 | 0.7649 | 9.3 MB | Square baseline reference | 15 + | `yolo11n_dataset640.tflite` | yolo11n | `[1, 640, 640, 3]` | 410k | 3.2 | 0.81–0.85 | 0.881 | 10.7 MB | Historical conf champion ⚠️ caveats | 16 + | `yolo11n_noise_floor_baseline.tflite` | yolo11n | `[1, 416, 416, 3]` | 173k | 6.9 | 0.72 (stable) | — | 10.6 MB | **Sanity check / noise floor reference** | 17 + 18 + ⭐ = recommended default. ⚠️ = see caveats below. 19 + 20 + ## Tier 1 — Recommended Production Default 21 + 22 + ### `yolo26n_v11_rect_512x384.tflite` 23 + 24 + The clear winner of the R&D session. Trained at `imgsz=512` with `rect=True`, which produces 384×512 rectangular tensors per batch (the dataset's natural aspect ratio is 4:3). The training and inference tensor shapes match exactly, eliminating the train/inference distribution shift that hurts square-trained models on rectangular cameras. 25 + 26 + **Strengths:** 27 + - Best on-device confidence among the 6.7-Hz speed class. 28 + - 14% more pixels than the square 416² baseline at only 13% slower speed — close to a strict Pareto improvement. 29 + - Natural 4:3 alignment with the camera. No wasted padding pixels at inference. 30 + - mAP50 0.7632 essentially matches the square 416² baseline (0.7649) on the val set, but **significantly outperforms it on the on-device test** (+0.07 to +0.15 mean conf in the same session). The val/on-device gap is the rect=True benefit — see `LESSONS_LEARNED.md`. 31 + 32 + **Trade-offs:** 33 + - `rect=True` auto-disables mosaic augmentation during training. The val mAP took a small hit, but on-device beats every prior square-trained variant in within-session comparisons. 34 + - Locked to landscape 4:3. The kima app must pin CameraX accordingly. 35 + 36 + ## Tier 2 — Speed-Critical (10+ Hz) 37 + 38 + ### `yolo26n_v11_rect_384x288.tflite` 39 + 40 + Same training method as the Tier 1 model but at `imgsz=384` rect=True → 288×384 tensors. Smaller pixel budget = faster, less accurate. 41 + 42 + **Strengths:** 43 + - Cleared the **10 Hz target** in measurement — the only model in the lineup besides the deprecated 320² square that does so. 44 + - Same `rect=True` training benefit — the rectangular geometry alignment translates into much higher confidence than the comparable 320² square model (which dropped to ~0.59 even though it has a similar pixel count). 45 + 46 + **Trade-offs:** 47 + - Quality drops noticeably vs the 512×384 rect: mean conf ~0.59–0.73 (depending on session noise), which is OK for a real-time tracker that smooths per-frame jitter but not great for one-shot frame analysis. 48 + - Same 4:3 landscape requirement. 49 + 50 + **When to use it:** if the downstream consumer is a Kalman tracker / smoothing filter on basketball position that benefits from 10+ Hz position updates and can tolerate per-frame noise. 51 + 52 + ## Tier 3 — Quality-First (slower) 53 + 54 + ### `yolo26n_v11_square_512.tflite` 55 + 56 + Square 512², trained without `rect=True`. Slower than the rect 512×384 (5 Hz vs 6.7 Hz) but slightly higher val mAP (0.8206 vs 0.7632) and similar on-device confidence. The extra pixels go to padding the 4:3 source instead of effective content, so the on-device quality benefit is minor — but it's a known-good square model if landscape lock isn't acceptable. 57 + 58 + **When to use it:** if the kima app cannot pin orientation to landscape (e.g., app design needs portrait + landscape support) and you need the highest quality among square models. 59 + 60 + ### `yolo11n_dataset640.tflite` ⚠️ 61 + 62 + Trained way back on the **stretched** Roboflow dataset v8 (before we discovered Roboflow's "Resize: Stretch to" preprocessing was destroying aspect ratios — see `LESSONS_LEARNED.md`). Has the **highest measured on-device mean confidence** of the entire R&D session (~0.84) but with **known box-shape artifacts** because the model learned distorted geometry. 63 + 64 + **Use only as a quality reference** to establish what "best possible accuracy on this clip" looks like. Do not ship. 65 + 66 + ## Reference baselines 67 + 68 + ### `yolo26n_v11_square_416.tflite` 69 + 70 + Square 416² yolo26n trained on the v11 letterboxed dataset without `rect=True`. The historical "best balance" champion before the rect=True experiments. Similar pixel count (173k) to the new rect 512×384 (197k, +14%). **This is the right A/B comparison target** when validating that the rect=True model wins in the kima app's specific test environment. 71 + 72 + ### `yolo11n_noise_floor_baseline.tflite` 73 + 74 + This is `yolo11n_dataset_dataset.tflite` from the original repo — a stable, oft-tested model whose measured mean confidence stays consistently in the 0.71–0.76 range across many sessions on this test setup. **Use it as a sanity check before any A/B test**: capture this model on the test video, compare against the historical ~0.72 baseline, and if it's >0.05 off, the test setup has drifted (phone position, lighting, framing) — fix that before judging other models. 75 + 76 + ## Cross-model summary table 77 + 78 + For quick decision-making: 79 + 80 + | Use case | Model | Hz | Mean conf | Notes | 81 + |---|---|---:|---:|---| 82 + | **Default** | `yolo26n_v11_rect_512x384.tflite` | 6.7 | ~0.80 | Use this unless you have a specific reason not to | 83 + | Real-time tracking @ 10+ Hz | `yolo26n_v11_rect_384x288.tflite` | 10.5 | ~0.65 | Tracker absorbs the per-frame noise | 84 + | Highest one-shot accuracy (rect-aspect lock OK) | `yolo26n_v11_square_512.tflite` | 5.0 | ~0.81 | Slower, marginal quality win | 85 + | Highest one-shot accuracy (no aspect lock) | `yolo26n_v11_square_416.tflite` | 7.5 | ~0.78 | Square, no orientation constraints | 86 + | A/B test sanity check | `yolo11n_noise_floor_baseline.tflite` | 6.9 | 0.72 | Run first, verify ~0.72 before testing other models | 87 + 88 + ## Output schema (all models) 89 + 90 + All six models share the same output tensor schema, since they all came from the ultralytics export pipeline with `nms=True` (which is auto-handled for end2end yolo26 models): 91 + 92 + - Shape: `[1, 300, 6]` 93 + - Per-row format: `[x1, y1, x2, y2, conf, cls]` where: 94 + - `x1, y1` = top-left corner, normalized `[0, 1]` over the model's input tensor 95 + - `x2, y2` = bottom-right corner, same normalization 96 + - `conf` = confidence score in `[0, 1]` 97 + - `cls` = float class index (0.0 = basketball, 1.0 = basketball_hoop) 98 + - Up to 300 detections per frame, sorted by confidence descending. Trailing rows have `conf = 0`. 99 + - **No additional NMS needed in the Android code** — it's already baked into the graph. 100 + 101 + ## Class labels 102 + 103 + ``` 104 + 0 basketball 105 + 1 basketball_hoop 106 + ```
+104
handover/README.md
··· 1 + # Basketball Object Detection — Production Handover 2 + 3 + This folder is the result of a multi-day R&D session optimizing YOLO-family models for basketball + basketball_hoop detection on Android (Samsung Galaxy A36 5G as reference device). It contains the production-ready tflite models, the Android-side requirements for consuming them, and a protocol for verifying quality in the kima app before shipping. 4 + 5 + ## ⚠️ Library version: bump to `posedetection-compose:4.11.0` 6 + 7 + The R&D work shipped a new **`posedetection-compose:4.11.0`** library release containing the letterbox-aware detector + camera config + delegate logging that the rect models depend on. The kima app currently uses an older version (probably 4.10.0). **Bump the dependency before integrating any of these models.** 8 + 9 + The new version is available in two places: 10 + 11 + ### Option A — Maven Local (immediate, no remote publish needed) 12 + 13 + The library is already published to maven local on the dev machine: 14 + `~/.m2/repository/com/performancecoachlab/posedetection/posedetection-compose/4.11.0/` 15 + 16 + To pull it from kima, the kima app's root `build.gradle.kts` (or `settings.gradle.kts`'s `dependencyResolutionManagement`) must include `mavenLocal()` in its repositories list: 17 + 18 + ```kotlin 19 + repositories { 20 + mavenLocal() // ← add this line if not already present 21 + google() 22 + mavenCentral() 23 + } 24 + ``` 25 + 26 + Then bump the dependency in whichever module consumes posedetection (typically the kima Android app's `build.gradle.kts`): 27 + 28 + ```kotlin 29 + implementation("com.performancecoachlab.posedetection:posedetection-compose:4.11.0") 30 + ``` 31 + 32 + This will resolve from maven local without any network calls. 33 + 34 + ### Option B — Remote (after publishing) 35 + 36 + The 4.11.0 library code lives on the **`release-4.11.0`** branch in the PoseDetection repo. Once it's merged + published to maven central via the existing `vanniktech.maven.publish` flow, kima can drop the `mavenLocal()` line and just consume it from central. Until then, use Option A. 37 + 38 + ### What's actually in 4.11.0 39 + 40 + The full commit message on `release-4.11.0` lists everything. The headline: 41 + - **`ImageDetector.android.kt`** (NEW class) — letterbox-aware detector with full un-letterbox of output bboxes. The detector all the rect models in `models/` were tested against. 42 + - **`CameraView.android.kt`** — pins `ImageAnalysis` to `AspectRatio.RATIO_4_3` so the camera frame distribution matches the rect models' expected geometry. 43 + - **`CustomObjectModel.android.kt`** — explicit GPU/NNAPI/CPU delegate logging at INFO level. Surfaces silent CPU fallbacks via `adb logcat -s TFLite:I`. 44 + - **No breaking API changes** — only additive. Existing kima usage of the library should keep working unchanged after the version bump. 45 + 46 + ## TL;DR — Use this model 47 + 48 + **`models/yolo26n_v11_rect_512x384.tflite`** is the recommended production default. 49 + 50 + | Property | Value | 51 + |---|---| 52 + | Architecture | YOLO26n (2026 generation, ~5.2 GFLOPs, ~2.4M params after fusion) | 53 + | Training | 50 epochs, AdamW, `imgsz=512`, `rect=True`, Roboflow `dataset_v11` (basketball court footage, letterboxed preprocessing) | 54 + | Input tensor | `[1, 384, 512, 3]` float32 (NHWC), pixel values normalized to `[0, 1]` | 55 + | Output tensor | `[1, 300, 6]` float32 = `[x1, y1, x2, y2, conf, cls]` per row, **NMS already applied**, coords normalized to `[0, 1]` over the input tensor | 56 + | Classes | `0 = basketball`, `1 = basketball_hoop` | 57 + | File size | 9.3 MB (fp32) | 58 + | Measured speed | ~6.7 Hz on the A36 5G via TFLite GPU delegate | 59 + | Measured quality | mean confidence ~0.78–0.83 across the 60s basketball test clip | 60 + | val mAP50 | 0.7632 | 61 + 62 + This model is **rectangular** (4:3 landscape) and was trained with `rect=True`, which means it learned features tuned to a 384×512 tensor. It expects the camera to deliver landscape 4:3 frames, which the kima app must enforce — see `ANDROID_INTEGRATION.md`. 63 + 64 + ## Why fp32 not fp16 65 + 66 + Tested both. fp16 saves ~50% file size but on the A36 5G's TFLite GPU delegate they ran at the same speed and fp16 cost ~0.02 mean confidence. Since 4 MB of model file is negligible vs the production app's overall size, **stick with fp32** — same speed, better quality. 67 + 68 + ## What's in this folder 69 + 70 + ``` 71 + handover/ 72 + ├── README.md ← you are here 73 + ├── MODELS.md ← detailed comparison of all 6 candidates 74 + ├── ANDROID_INTEGRATION.md ← what the kima app's Android side needs 75 + ├── TESTING_PROTOCOL.md ← how to A/B test models in the kima app 76 + ├── LESSONS_LEARNED.md ← key insights from the R&D session 77 + ├── models/ 78 + │ ├── yolo26n_v11_rect_512x384.tflite ← RECOMMENDED PRODUCTION DEFAULT (rect=True) 79 + │ ├── yolo26n_v11_rect_384x288.tflite ← speed-critical alternative (>10 Hz) 80 + │ ├── yolo26n_v11_square_512.tflite ← square 512², slightly higher quality at lower speed 81 + │ ├── yolo26n_v11_square_416.tflite ← square 416² baseline reference 82 + │ ├── yolo11n_dataset640.tflite ← historical quality ceiling, KNOWN LOOSE BBOXES 83 + │ └── yolo11n_noise_floor_baseline.tflite ← stable model for noise-floor sanity checks 84 + └── reference_code/ 85 + ├── ImageDetector.android.kt ← working letterbox-aware detector 86 + ├── CustomObjectModel.android.kt ← TFLite interpreter setup with delegate logging 87 + ├── CameraView_snippet.kt ← CameraX 4:3 + landscape pin 88 + ├── AndroidManifest_snippet.xml ← orientation lock 89 + └── compare_logs.py ← portable Python report generator for A/B tests 90 + ``` 91 + 92 + ## Quick start 93 + 94 + 1. **Read `MODELS.md`** to understand the candidates and pick a starting model. The recommended default is `yolo26n_v11_rect_512x384.tflite`. 95 + 2. **Read `ANDROID_INTEGRATION.md`** to see what camera config and detector code the kima app needs. **Critical**: the model expects a 4:3 landscape camera frame; the kima app must pin CameraX accordingly. 96 + 3. **Drop the chosen tflite** into the kima app's assets folder. 97 + 4. **Implement the camera + detector** per `ANDROID_INTEGRATION.md`. The reference code in `reference_code/` is the working version from this project. 98 + 5. **Verify with `TESTING_PROTOCOL.md`** before shipping. Even a single 60-second comparison run against a known video can catch integration mistakes early. 99 + 100 + ## Source notes 101 + 102 + - All models are trained on the `kima-rbjnn/dataset-3k5b6` Roboflow project, version 11 (preprocessing = "Fit (black padding)"; the v8 stretched dataset was the source of weeks of accuracy issues — **never train on stretched data again**, see `LESSONS_LEARNED.md`). 103 + - The pipeline is closed-loop: edit `collab/Model Training.ipynb` cell 5, run training in Colab, drive-sync the tflite to the Mac, sync to assets via `tools/sync_models.py`, build, install, run a 60s back-to-back comparison via `tools/run_auto_experiment.sh`, generate the report via `tools/compare_logs.py`. The full source pipeline lives in the parent project repo. 104 + - **iOS is not covered here.** This handover is Android-only. iOS uses CoreML exports of the same `.pt` weights, and the user has confirmed the iOS pipeline already works at 10+ Hz with high accuracy because CoreML bakes preprocessing into the model graph. If kima ships iOS too, the iOS side likely doesn't need any of this — just the same Roboflow dataset versions and a separate CoreML export.
+156
handover/TESTING_PROTOCOL.md
··· 1 + # Testing Protocol — Comparing Models in the Kima App 2 + 3 + This document describes how to validate that a model behaves correctly in the kima app and how to A/B test different candidates against each other. The protocol mirrors what worked in the R&D project (60s back-to-back captures of the same video segment) but is portable to any Android app that can load multiple TFLite models. 4 + 5 + ## Setup requirements 6 + 7 + ### Hardware 8 + - **A test phone** that runs the kima app (the R&D used a Samsung Galaxy A36 5G — different phones will give different absolute Hz numbers but the relative ordering of models should be similar). 9 + - **A mounted phone holder / tripod** that does not move between captures. This is the single most important variable for getting reproducible results. 10 + - **A monitor or large screen** for playing the test video. The phone films the screen. 11 + 12 + ### Test video 13 + - **Use the same video for all comparisons.** The R&D project used `~/Downloads/20250901_100828.mp4` (a 4K, 165s, 16:9 basketball court clip with shooting). Any consistent video with visible basketballs and hoops works — pick one once and keep using it. 14 + - **Use a fixed segment** (e.g. seconds 10–70 = 60s of video). Don't sample randomly; the same frames need to flow into every model under test. 15 + - Play the video **fullscreen** in QuickTime or whatever player. This avoids window-chrome interference. 16 + 17 + ### Android side 18 + - Camera pinned to `RATIO_4_3`, activity orientation locked to landscape — see `ANDROID_INTEGRATION.md`. 19 + - The kima app needs a way to **switch between models at runtime** (a debug picker, an intent extra, or just rebuilding with a different default model in assets). 20 + - The kima app needs a way to **log detector output to a file or logcat** so you can analyze it after the run. Minimum schema below. 21 + 22 + ## Minimum logging schema 23 + 24 + For each model run, capture per-frame events with the following structure (this is what `compare_logs.py` consumes): 25 + 26 + ```json 27 + { 28 + "device_model": "samsung SM-A366B", 29 + "model_name": "yolo26n_v11_rect_512x384", 30 + "run_id": "1775898858800_yolo26n_v11_rect_512x384", 31 + "started_wall_ms": 1775898858801, 32 + "stopped_wall_ms": 1775898918803, 33 + "events": [ 34 + { 35 + "wall_ms": 1775898858900, 36 + "skeleton": null, 37 + "objects": [ 38 + { 39 + "label": "basketball", 40 + "confidence": 0.872, 41 + "bbox": { "left": 412.5, "top": 230.1, "right": 488.2, "bottom": 308.9 }, 42 + "frame_size": { "width": 1280, "height": 960 } 43 + } 44 + ] 45 + } 46 + ] 47 + } 48 + ``` 49 + 50 + Key fields: 51 + - `wall_ms` — absolute wall-clock timestamp of each detector emission. Used to compute Hz and to align events across runs. 52 + - `objects[]` — list of detections per frame. Empty list = the detector ran but found nothing. 53 + - `confidence` — the conf score from the detector output (0–1). 54 + - `bbox.left/top/right/bottom` — pixel coords in the original frame's coordinate space (post un-letterbox). 55 + 56 + The R&D project's reference implementation lives in: 57 + - `posedetection/src/commonMain/kotlin/com/nate/posedetection/ExperimentLogger.kt` — the logger 58 + - `posedetection/src/commonMain/kotlin/com/nate/posedetection/ExperimentAuto.kt` — the auto-mode driver 59 + 60 + The kima app can implement its own equivalent in any language/framework. The schema is the contract. 61 + 62 + ## The protocol 63 + 64 + ### Step 0 — Position the phone 65 + 66 + Mount the phone in landscape, aimed at the monitor showing the test video. **Don't move it between captures.** Even small bumps shift the framing and can swing yolo26n confidence by 0.10+. 67 + 68 + ### Step 1 — Noise-floor sanity check 69 + 70 + Before testing the model you actually care about, capture a known-stable model and verify it lands at the expected confidence. The handover bundle includes `yolo11n_noise_floor_baseline.tflite` for exactly this purpose. 71 + 72 + ``` 73 + Run: yolo11n_noise_floor_baseline.tflite for 60s 74 + Expected mean confidence: ~0.72 (range 0.71–0.76 across many sessions) 75 + ``` 76 + 77 + If this lands more than 0.05 off the expected value, **reposition the phone** before continuing. The lighting, phone framing, or video timing has drifted and any subsequent A/B test will be measuring noise instead of model quality. 78 + 79 + ### Step 2 — Capture the actual A/B set 80 + 81 + Run **60-second back-to-back captures** of each model under test, against the same video segment, **without moving anything** between captures. The R&D project used this sequence as the standard 5-way: 82 + 83 + 1. `yolo11n_noise_floor_baseline.tflite` (sanity) 84 + 2. The model you're considering shipping (e.g. `yolo26n_v11_rect_512x384.tflite`) 85 + 3. A direct competitor (e.g. `yolo26n_v11_square_416.tflite` for the rect-vs-square comparison) 86 + 4. A speed alternative (e.g. `yolo26n_v11_rect_384x288.tflite`) 87 + 5. A quality reference (e.g. `yolo26n_v11_square_512.tflite` or `yolo11n_dataset640.tflite`) 88 + 89 + 60 seconds is the minimum for stable measurements. 10s clips have a noise floor of ~±0.10 mean conf which is too high to detect real differences. 60s clips drop the noise floor to ~±0.05 (still significant for yolo26n, see below). 90 + 91 + ### Step 3 — Run the report generator 92 + 93 + Drop the captured JSON files into a folder (one subfolder per run, with the JSON inside) and run `reference_code/compare_logs.py`: 94 + 95 + ```bash 96 + python3 compare_logs.py /path/to/captures/ -o /tmp/reports --bucket 250 97 + open /tmp/reports/report.html 98 + ``` 99 + 100 + The HTML report shows side-by-side scorecards (events, det rate, mean conf, mean bbox area, per-class), per-bucket histograms, and per-class timelines. Look at: 101 + - **Mean confidence** — the headline quality number 102 + - **Detection rate** — should be 100% on a video with always-visible objects 103 + - **Mean bbox area** — proxy for box tightness; lower = tighter (usually better) 104 + - **Per-class timelines** — visualize where each model loses detections 105 + 106 + ### Step 4 — Interpret with the noise floor in mind 107 + 108 + **The yolo26n family is noticeably more sensitive to small framing changes than yolo11n.** Across multiple R&D sessions, the same `yolo26n_v11_square_416.tflite` measured between **0.64 and 0.84 mean confidence** depending on how the phone was positioned. The yolo11n baseline barely budged across the same conditions. 109 + 110 + What this means: 111 + - **Within-session comparisons are reliable.** All models in the same back-to-back capture sequence saw the same framing, so their relative ordering is meaningful. If model A scores 0.80 and model B scores 0.70 in the same session, A is genuinely better. 112 + - **Cross-session comparisons are not reliable** unless you re-validate via the noise-floor model. Don't quote V5.x results from this project's history as direct benchmarks for the kima app's measurements. 113 + 114 + If your A/B test gives results that surprise you, run Step 1 again — the phone might have shifted between captures. 115 + 116 + ## Recommended A/B sequence for kima 117 + 118 + When you start integrating models, run this sequence in order. Each step should yield a clear yes/no decision before proceeding. 119 + 120 + ### A. "Does the model load and run?" 121 + - Build kima with `yolo26n_v11_rect_512x384.tflite` in assets. 122 + - Cold-start the app, verify logcat shows `delegate=GPU inputShape=[1, 384, 512, 3]`. 123 + - Aim the camera at any basketball-containing scene and verify detections appear. 124 + - **Decision**: if yes, proceed. If no, debug per `ANDROID_INTEGRATION.md` "Common gotchas". 125 + 126 + ### B. "Is the geometry right?" 127 + - Run a 30s capture against the test video. 128 + - In the report, check **mean bbox area**. For `yolo26n_v11_rect_512x384` it should be in the 480–560 range (loose box) on the standard test video. 129 + - Visually check 5–10 frames in the per-class image gallery (if the kima app supports this) — the boxes should hug the basketball, not pad around it. 130 + - **Decision**: if boxes look correctly placed, the letterbox preprocessing is right. If they're consistently offset or distorted, re-check the un-letterbox math. 131 + 132 + ### C. "Is the speed acceptable?" 133 + - 60s capture, look at events/sec (Hz). 134 + - Expect ~5–7 Hz for `yolo26n_v11_rect_512x384` on a modern phone. Anything below 3 Hz means the GPU delegate didn't engage. 135 + - **Decision**: if Hz is in the expected range, proceed. If much slower, check delegate selection in logcat. 136 + 137 + ### D. "Is it production quality?" 138 + - Run the noise-floor sanity check (`yolo11n_noise_floor_baseline.tflite` should hit ~0.72). 139 + - Run the A/B comparison: `yolo26n_v11_rect_512x384` vs `yolo26n_v11_square_416`. 140 + - Expect the rect_512x384 to win on confidence by ~0.05–0.15 in within-session comparison. 141 + - **Decision**: if the rect model wins, ship it. If not, the kima camera/orientation config probably isn't matching the model's expected aspect ratio — re-check `ANDROID_INTEGRATION.md` step 1 + 2. 142 + 143 + ### E. "Does it work in real-world conditions?" 144 + - Beyond the test video, capture 5–10 minutes of real basketball footage with the kima app and the chosen model. 145 + - Look for consistent detections across distance, angle, lighting changes. 146 + - This is the only step that the test video can't catch — the dataset was trained on indoor court footage similar to but not identical to whatever real users will film. 147 + 148 + ## What NOT to test against 149 + 150 + - **Don't test fp16 vs fp32 separately.** They give the same speed and ~0.02 conf difference on this hardware. Settled — use fp32, file size doesn't matter at this scale. 151 + - **Don't run val mAP comparisons** as the deciding metric. The val set is held-out from Roboflow and doesn't reflect on-device performance well — see `LESSONS_LEARNED.md`. 152 + - **Don't compare against the V5.x historical numbers in this handover.** They were measured on a different phone setup and the within-session noise is real. The history is useful for understanding the *direction* of each tuning lever, not the absolute numbers in the kima app's measurement environment. 153 + 154 + ## If you only have time for one test 155 + 156 + Run the A/B at step **D**: capture `yolo11n_noise_floor_baseline`, `yolo26n_v11_rect_512x384`, and `yolo26n_v11_square_416` back-to-back for 60 seconds each on the same test video. If the rect model wins on confidence and the noise floor is on target, ship the rect model. If the noise floor is off, fix the phone setup first and re-run.
handover/models/yolo11n_dataset640.tflite

This is a binary file and will not be displayed.

handover/models/yolo26n_v11_rect_384x288.tflite

This is a binary file and will not be displayed.

handover/models/yolo26n_v11_rect_512x384.tflite

This is a binary file and will not be displayed.

handover/models/yolo26n_v11_square_416.tflite

This is a binary file and will not be displayed.

handover/models/yolo26n_v11_square_512.tflite

This is a binary file and will not be displayed.

+44
handover/reference_code/AndroidManifest_snippet.xml
··· 1 + <!-- AndroidManifest snippet — the activity-level orientation lock that the kima app 2 + must include if it ships the rect 4:3 model and wants the simplest integration. 3 + 4 + Source: sample/composeApp/src/androidMain/AndroidManifest.xml in the R&D project. 5 + 6 + The single critical line is `android:screenOrientation="landscape"` on whatever 7 + activity hosts the camera + detector. Without this, the camera frame arrives 8 + portrait-rotated and the detector sees a 3:4 input instead of 4:3, causing 9 + letterbox padding to fight the model. 10 + 11 + If the kima app needs to support both portrait AND landscape, see the 12 + "Option B" rotation fallback in ANDROID_INTEGRATION.md. 13 + --> 14 + 15 + <manifest xmlns:android="http://schemas.android.com/apk/res/android"> 16 + 17 + <uses-feature 18 + android:name="android.hardware.camera" 19 + android:required="false" /> 20 + <uses-permission android:name="android.permission.CAMERA" /> 21 + 22 + <application 23 + android:icon="@mipmap/ic_launcher" 24 + android:label="kima" 25 + android:theme="@android:style/Theme.Material.NoActionBar"> 26 + 27 + <activity 28 + android:name=".MainActivity" 29 + android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" 30 + android:exported="true" 31 + android:launchMode="singleInstance" 32 + android:screenOrientation="landscape" 33 + android:windowSoftInputMode="adjustPan"> 34 + <intent-filter> 35 + <action android:name="android.intent.action.MAIN" /> 36 + <category android:name="android.intent.category.LAUNCHER" /> 37 + </intent-filter> 38 + </activity> 39 + 40 + <!-- ... other providers, services, etc ... --> 41 + 42 + </application> 43 + 44 + </manifest>
+40
handover/reference_code/CameraView_snippet.kt
··· 1 + // CameraView snippet — the parts of the CameraX setup that the kima app must include 2 + // to consume the rect 4:3 model. Adapt the surrounding code to whatever the kima app's 3 + // camera setup looks like. 4 + // 5 + // Source: posedetection/src/androidMain/kotlin/com/performancecoachlab/posedetection/camera/CameraView.android.kt 6 + // (Lines 286-289 in the R&D project, plus the AspectRatio import) 7 + 8 + import androidx.camera.core.AspectRatio // ← REQUIRED for the new line 9 + import androidx.camera.core.ImageAnalysis 10 + 11 + // ... inside whatever Composable / Activity sets up the CameraX use cases ... 12 + 13 + val imageAnalysis = ImageAnalysis.Builder() 14 + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) 15 + .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) 16 + .setTargetAspectRatio(AspectRatio.RATIO_4_3) // ← THE CRITICAL ADDITION 17 + .build() 18 + .also { analysis -> 19 + analysis.targetRotation = currentRotation.intValue 20 + analysis.setAnalyzer(executor) { imageProxy -> 21 + // ... process imageProxy → bitmap → detector ... 22 + } 23 + } 24 + 25 + // Notes: 26 + // 27 + // - `setTargetAspectRatio` is a hint, not a hard guarantee. CameraX picks the closest 28 + // available 4:3 mode for the device — typically 1280×960, 1440×1080, or 2048×1536. 29 + // Different devices = different exact resolutions but always 4:3 aspect. 30 + // 31 + // - If a device truly cannot deliver 4:3, CameraX falls back to its default. The 32 + // detector's letterbox math handles aspect mismatches gracefully, so this is at 33 + // worst a "wastes pixels on padding" case, not a crash. 34 + // 35 + // - The newer CameraX way to do the same thing is `ResolutionSelector.Builder() 36 + // .setAspectRatioStrategy(AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY) 37 + // .build()`. Either works. Use whichever matches your CameraX version. 38 + // 39 + // - DO NOT use `setTargetResolution(Size(W, H))` — it's deprecated and the device 40 + // may not honor exact pixel dimensions. The aspect ratio is what matters.
+440
handover/reference_code/CustomObjectModel.android.kt
··· 1 + package com.performancecoachlab.posedetection.custom 2 + 3 + import androidx.compose.runtime.Composable 4 + import androidx.compose.ui.platform.LocalContext 5 + import co.touchlab.kermit.Logger 6 + import org.json.JSONObject 7 + import android.os.Build 8 + import org.tensorflow.lite.Interpreter 9 + import org.tensorflow.lite.gpu.GpuDelegate 10 + import org.tensorflow.lite.support.common.FileUtil 11 + import org.tensorflow.lite.support.metadata.MetadataExtractor 12 + import java.io.ByteArrayInputStream 13 + import java.nio.MappedByteBuffer 14 + import java.nio.charset.StandardCharsets 15 + import java.util.zip.GZIPInputStream 16 + import java.util.zip.Inflater 17 + import java.util.zip.InflaterInputStream 18 + import java.util.zip.ZipInputStream 19 + 20 + @Composable 21 + actual fun initialiseObjectModel(modelPath: ModelPath): ObjectModel { 22 + if (modelPath.androidModelPath == null) { 23 + throw IllegalArgumentException("Android model path cannot be null") 24 + } 25 + // Prefer GPU, then NNAPI (API 27+), then CPU. `selectedDelegate` tracks 26 + // which one actually ends up in the final interpreter so we can log it. 27 + var selectedDelegate = "CPU" 28 + val (options, gpuDelegate) = runCatching { 29 + val delegate = GpuDelegate() 30 + val opts = Interpreter.Options().apply { 31 + addDelegate(delegate) 32 + setNumThreads(2) 33 + } 34 + selectedDelegate = "GPU" 35 + Logger.i { "TFLite: GPU delegate constructed" } 36 + opts to delegate 37 + }.onFailure { t -> 38 + Logger.w(t) { "TFLite: GPU delegate not available; trying NNAPI" } 39 + }.getOrElse { 40 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 41 + runCatching { 42 + val nnapiDelegate = org.tensorflow.lite.nnapi.NnApiDelegate() 43 + val opts = Interpreter.Options().apply { 44 + addDelegate(nnapiDelegate) 45 + setNumThreads(2) 46 + } 47 + selectedDelegate = "NNAPI" 48 + Logger.i { "TFLite: NNAPI delegate constructed" } 49 + opts to null 50 + }.onFailure { t -> 51 + Logger.w(t) { "TFLite: NNAPI delegate not available; falling back to CPU" } 52 + }.getOrElse { 53 + selectedDelegate = "CPU" 54 + Interpreter.Options().apply { setNumThreads(4) } to null 55 + } 56 + } else { 57 + selectedDelegate = "CPU" 58 + Interpreter.Options().apply { setNumThreads(4) } to null 59 + } 60 + } 61 + 62 + val model = FileUtil.loadMappedFile(LocalContext.current, modelPath.androidModelPath) 63 + val labels = labels(model) 64 + 65 + val interpreter = runCatching { 66 + Interpreter(model, options) 67 + }.onFailure { t -> 68 + // If the chosen delegate can't actually build an interpreter (common 69 + // for GPU on models with unsupported ops), fall back to pure CPU. 70 + Logger.w(t) { "TFLite: failed to create interpreter with $selectedDelegate delegate; retrying on CPU" } 71 + gpuDelegate?.close() 72 + selectedDelegate = "CPU" 73 + }.getOrElse { 74 + val cpuOptions = Interpreter.Options().apply { setNumThreads(4) } 75 + Interpreter(model, cpuOptions) 76 + } 77 + 78 + val inputShape = interpreter.getInputTensor(0)?.shape() 79 + val outputShape = interpreter.getOutputTensor(0)?.shape() 80 + Logger.i { 81 + "TFLite: model='${modelPath.androidModelPath}' delegate=$selectedDelegate " + 82 + "inputShape=${inputShape?.toList()} outputShape=${outputShape?.toList()}" 83 + } 84 + val modelInfo = ModelInfo.fromShapes( 85 + inputShape = inputShape 86 + ?: throw IllegalArgumentException("Invalid model: input shape is null"), 87 + outputShape = outputShape 88 + ?: throw IllegalArgumentException("Invalid model: output shape is null"), 89 + labels, 90 + ) 91 + val androidDetector = AndroidDetector( 92 + interpreter = interpreter, modelInfo = modelInfo 93 + ) 94 + return ObjectModel(androidDetector) 95 + } 96 + 97 + fun labels(model: MappedByteBuffer): List<String> { 98 + return runCatching { 99 + val extractor = MetadataExtractor(model) 100 + val files = extractor.associatedFileNames.orEmpty() 101 + if (files.isEmpty()) return@runCatching emptyList() 102 + 103 + // Try every associated file. Pick the first that decodes to JSON with a `names` object. 104 + for (name in files) { 105 + val rawBytes = runCatching { extractor.getAssociatedFile(name).readBytes() }.getOrNull() 106 + ?: continue 107 + 108 + val decoded = rawBytes.decodeUtf8PossiblyCompressed() 109 + val trimmed = decoded.trimStart() 110 + if (!trimmed.startsWith("{")) continue 111 + 112 + val labels = parseUltralyticsNamesJson(decoded) 113 + if (labels.isNotEmpty()) { 114 + Logger.d { "Loaded ${labels.size} labels from associated file '$name'" } 115 + return@runCatching labels 116 + } 117 + } 118 + emptyList() 119 + }.onFailure { t -> 120 + Logger.w(t) { "Failed to load labels from TFLite metadata" } 121 + }.getOrDefault(emptyList()) 122 + } 123 + 124 + private fun ByteArray.decodeUtf8PossiblyCompressed(): String { 125 + if (isEmpty()) return "" 126 + 127 + fun firstBytesHex(n: Int = 8): String = 128 + take(minOf(size, n)).joinToString(" ") { b -> "%02x".format(b) } 129 + 130 + // 0) Scan for embedded magic headers / common compressed stream signatures. 131 + val zipOffset = 132 + indexOfSubsequence(byteArrayOf('P'.code.toByte(), 'K'.code.toByte(), 0x03, 0x04)) 133 + val gzipOffset = indexOfSubsequence(byteArrayOf(0x1F.toByte(), 0x8B.toByte())) 134 + 135 + // Common zlib headers (CMF/FLG). Most common are 0x78 0x9C (default), 0x78 0xDA (best), 0x78 0x01 (no compression). 136 + val zlibOffsets = listOf( 137 + indexOfSubsequence(byteArrayOf(0x78.toByte(), 0x9C.toByte())), 138 + indexOfSubsequence(byteArrayOf(0x78.toByte(), 0xDA.toByte())), 139 + indexOfSubsequence(byteArrayOf(0x78.toByte(), 0x01.toByte())), 140 + ).filter { it >= 0 }.distinct().sorted() 141 + 142 + if (zipOffset > 0) { 143 + runCatching { 144 + val sliced = copyOfRange(zipOffset, size) 145 + val text = sliced.decodeFromZipIfPossible(preferEntryName = "metadata.json") 146 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 147 + } 148 + } 149 + 150 + if (gzipOffset > 0) { 151 + runCatching { 152 + val sliced = copyOfRange(gzipOffset, size) 153 + val text = sliced.decodeFromGzipOrTarGz() 154 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 155 + } 156 + } 157 + 158 + for (off in zlibOffsets) { 159 + if (off <= 0) continue 160 + runCatching { 161 + val sliced = copyOfRange(off, size) 162 + val text = sliced.decodeFromZlib() 163 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 164 + } 165 + } 166 + 167 + runCatching { 168 + val text = decodeFromGzipOrTarGz() 169 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 170 + } 171 + 172 + runCatching { 173 + val text = decodeFromZipIfPossible(preferEntryName = "metadata.json") 174 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 175 + } 176 + 177 + runCatching { 178 + val text = decodeFromZlib() 179 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 180 + } 181 + 182 + runCatching { 183 + val text = decodeFromDeflateRaw() 184 + if (text.isNotBlank() && text.trimStart().startsWith("{")) return text 185 + } 186 + 187 + return toString(StandardCharsets.UTF_8) 188 + } 189 + 190 + private fun ByteArray.decodeFromDeflateRaw(): String { 191 + return runCatching { 192 + val inflater = Inflater(true) // nowrap=true => raw DEFLATE 193 + InflaterInputStream(ByteArrayInputStream(this), inflater) 194 + .bufferedReader(StandardCharsets.UTF_8) 195 + .use { it.readText() } 196 + }.getOrDefault("") 197 + } 198 + 199 + private fun ByteArray.decodeFromZlib(): String { 200 + return runCatching { 201 + InflaterInputStream(ByteArrayInputStream(this)) 202 + .bufferedReader(StandardCharsets.UTF_8) 203 + .use { it.readText() } 204 + }.getOrDefault("") 205 + } 206 + 207 + private fun ByteArray.decodeFromGzipOrTarGz(): String { 208 + // First try: plain gzipped UTF-8 directly 209 + runCatching { 210 + val text = GZIPInputStream(ByteArrayInputStream(this)) 211 + .bufferedReader(StandardCharsets.UTF_8) 212 + .use { it.readText() } 213 + if (text.isNotBlank()) return text 214 + } 215 + 216 + // Second try: gzipped TAR that contains metadata.json (or first file) 217 + return runCatching { 218 + GZIPInputStream(ByteArrayInputStream(this)).use { gz -> 219 + extractFirstTarFileUtf8(gz) 220 + } 221 + }.getOrElse { 222 + "" 223 + } 224 + } 225 + 226 + private fun extractFirstTarFileUtf8(input: java.io.InputStream): String { 227 + // Minimal TAR reader: TAR headers are 512 bytes. 228 + // We only need to extract the first regular file (or metadata.json if present) 229 + // and decode it as UTF-8. 230 + 231 + fun readExactly(buf: ByteArray): Boolean { 232 + var off = 0 233 + while (off < buf.size) { 234 + val r = input.read(buf, off, buf.size - off) 235 + if (r <= 0) return false 236 + off += r 237 + } 238 + return true 239 + } 240 + 241 + val header = ByteArray(512) 242 + var firstText: String? = null 243 + 244 + while (true) { 245 + if (!readExactly(header)) break 246 + // End of archive: two consecutive 512-byte blocks of zero 247 + if (header.all { it == 0.toByte() }) break 248 + 249 + val name = header.copyOfRange(0, 100).toString(StandardCharsets.US_ASCII) 250 + .trimEnd { it == '\u0000' } 251 + val sizeOctal = header.copyOfRange(124, 136).toString(StandardCharsets.US_ASCII).trim() 252 + .trimEnd { it == '\u0000' } 253 + val typeFlag = header[156] 254 + 255 + val fileSize = sizeOctal.toLongOrNull(8) ?: 0L 256 + val isRegularFile = typeFlag == 0.toByte() || typeFlag == '0'.code.toByte() 257 + 258 + val fileData = ByteArray(fileSize.toInt()) 259 + if (fileSize > 0 && !readExactly(fileData)) break 260 + 261 + // TAR pads file data to 512 byte blocks. 262 + val pad = ((512 - (fileSize % 512)) % 512).toInt() 263 + if (pad > 0) { 264 + val skip = ByteArray(pad) 265 + if (!readExactly(skip)) break 266 + } 267 + 268 + if (isRegularFile) { 269 + val text = fileData.toString(StandardCharsets.UTF_8) 270 + if (name.equals("metadata.json", ignoreCase = true)) return text 271 + if (firstText == null && text.isNotBlank()) firstText = text 272 + } 273 + } 274 + 275 + return firstText.orEmpty() 276 + } 277 + 278 + private fun ByteArray.indexOfSubsequence(needle: ByteArray): Int { 279 + if (needle.isEmpty() || size < needle.size) return -1 280 + outer@ for (i in 0..(size - needle.size)) { 281 + for (j in needle.indices) { 282 + if (this[i + j] != needle[j]) continue@outer 283 + } 284 + return i 285 + } 286 + return -1 287 + } 288 + 289 + private fun parseUltralyticsNamesJson(text: String): List<String> { 290 + return runCatching { 291 + val root = JSONObject(text) 292 + val namesObj = root.optJSONObject("names") ?: return@runCatching emptyList() 293 + 294 + val keys = namesObj.keys().asSequence() 295 + .mapNotNull { k -> k.toIntOrNull()?.let { idx -> idx to k } } 296 + .sortedBy { it.first } 297 + .toList() 298 + 299 + if (keys.isEmpty()) return@runCatching emptyList() 300 + 301 + val maxIdx = keys.maxOf { it.first } 302 + val out = MutableList(maxIdx + 1) { "" } 303 + 304 + for ((idx, key) in keys) { 305 + val label = namesObj.optString(key, "").trim() 306 + if (label.isNotBlank() && idx in out.indices) { 307 + out[idx] = label 308 + } 309 + } 310 + 311 + out.filter { it.isNotBlank() } 312 + }.getOrDefault(emptyList()) 313 + } 314 + 315 + private fun parseUltralyticsNames(text: String): List<String> { 316 + // Grab the `names: { ... }` section (non-greedy) to avoid matching other maps. 317 + val namesBlock = Regex("""['"]names['"]\s*:\s*\{([\s\S]*?)\}""") 318 + .find(text) 319 + ?.groupValues 320 + ?.getOrNull(1) 321 + ?: return emptyList() 322 + 323 + // Match entries like: 0: 'person' OR 0: "person" 324 + val entry = Regex("""(\d+)\s*:\s*['"]([^'"]+)['"]""") 325 + val pairs = entry.findAll(namesBlock).mapNotNull { m -> 326 + val idx = m.groupValues[1].toIntOrNull() ?: return@mapNotNull null 327 + val name = m.groupValues[2].trim() 328 + if (name.isBlank()) null else idx to name 329 + }.toList() 330 + 331 + if (pairs.isEmpty()) return emptyList() 332 + 333 + val maxIdx = pairs.maxOf { it.first } 334 + val out = MutableList(maxIdx + 1) { "" } 335 + for ((i, label) in pairs) { 336 + if (i in out.indices) out[i] = label 337 + } 338 + return out.filter { it.isNotBlank() } 339 + } 340 + 341 + data class ModelInfo( 342 + val inputShape: IntArray, 343 + val outputShape: IntArray, 344 + val inputWidth: Int, 345 + val inputHeight: Int, 346 + val inputChannels: Int? = null, 347 + val isNhwc: Boolean? = null, 348 + val labels: List<String>, 349 + ) { 350 + companion object { 351 + fun fromShapes( 352 + inputShape: IntArray, 353 + outputShape: IntArray, 354 + labels: List<String> 355 + ): ModelInfo { 356 + // Common TFLite image shapes: 357 + // NHWC: [1, H, W, C] 358 + // NCHW: [1, C, H, W] (less common on Android) 359 + // Some models might be [H, W, C] (no batch). 360 + val (h, w, c, nhwc) = when (inputShape.size) { 361 + 4 -> { 362 + val isNhwcGuess = inputShape[3] in 1..4 363 + if (isNhwcGuess) { 364 + Quad(inputShape[1], inputShape[2], inputShape[3], true) 365 + } else { 366 + Quad(inputShape[2], inputShape[3], inputShape[1], false) 367 + } 368 + } 369 + 370 + 3 -> Quad(inputShape[0], inputShape[1], inputShape[2], true) 371 + else -> Quad(0, 0, null, null) 372 + } 373 + 374 + return ModelInfo( 375 + inputShape = inputShape, 376 + outputShape = outputShape, 377 + inputWidth = w, 378 + inputHeight = h, 379 + inputChannels = c, 380 + isNhwc = nhwc, 381 + labels = labels, 382 + ) 383 + } 384 + } 385 + } 386 + 387 + private data class Quad( 388 + val h: Int, val w: Int, val c: Int?, val nhwc: Boolean? 389 + ) 390 + 391 + data class AndroidDetector( 392 + val interpreter: Interpreter, val modelInfo: ModelInfo 393 + ) 394 + 395 + actual class ObjectModel { 396 + 397 + private var detector: AndroidDetector? = null 398 + 399 + constructor(detector: AndroidDetector) { 400 + this.detector = detector 401 + } 402 + 403 + fun getDetector(): AndroidDetector? { 404 + return detector 405 + } 406 + } 407 + 408 + private fun ByteArray.decodeFromZipIfPossible(preferEntryName: String): String { 409 + return runCatching { 410 + ZipInputStream(ByteArrayInputStream(this)).use { zis -> 411 + var firstNonEmpty: String? = null 412 + val entries = mutableListOf<String>() 413 + 414 + while (true) { 415 + val entry = zis.nextEntry ?: break 416 + entries += entry.name 417 + if (entry.isDirectory) continue 418 + 419 + val entryBytes = zis.readBytes() 420 + val text = entryBytes.toString(StandardCharsets.UTF_8) 421 + 422 + if (entry.name.equals(preferEntryName, ignoreCase = true)) { 423 + Logger.d { "TFLite metadata zip entry=${entry.name} size=${entryBytes.size} entries=$entries" } 424 + return@use text 425 + } 426 + 427 + if (firstNonEmpty == null && text.isNotBlank()) { 428 + firstNonEmpty = text 429 + } 430 + } 431 + 432 + firstNonEmpty.orEmpty() 433 + } 434 + }.getOrDefault("") 435 + } 436 + 437 + @Composable 438 + internal actual fun platformRememberObjectModel(modelPath: ModelPath): ObjectModel { 439 + return ObjectModelProvider.get(modelPath) 440 + }
+150
handover/reference_code/ImageDetector.android.kt
··· 1 + package com.performancecoachlab.posedetection.custom 2 + 3 + import android.graphics.Bitmap 4 + import android.graphics.Canvas 5 + import android.graphics.Color 6 + import android.graphics.Paint 7 + import android.graphics.RectF 8 + import androidx.compose.ui.geometry.Rect 9 + import androidx.compose.ui.graphics.ImageBitmap 10 + import androidx.compose.ui.graphics.asAndroidBitmap 11 + import co.touchlab.kermit.Logger 12 + import com.performancecoachlab.posedetection.camera.label 13 + import com.performancecoachlab.posedetection.recording.AnalysisObject 14 + import com.performancecoachlab.posedetection.recording.FrameSize 15 + import com.performancecoachlab.posedetection.recording.Label 16 + import org.tensorflow.lite.DataType 17 + import org.tensorflow.lite.support.common.ops.CastOp 18 + import org.tensorflow.lite.support.common.ops.NormalizeOp 19 + import org.tensorflow.lite.support.image.ImageProcessor 20 + import org.tensorflow.lite.support.image.TensorImage 21 + import org.tensorflow.lite.support.tensorbuffer.TensorBuffer 22 + import kotlin.math.absoluteValue 23 + import kotlin.math.max 24 + import kotlin.math.min 25 + import kotlin.math.roundToInt 26 + 27 + actual class ImageDetector actual constructor(model: ObjectModel) { 28 + 29 + private val detector: AndroidDetector? = model.getDetector() 30 + 31 + private val imageProcessor = ImageProcessor.Builder() 32 + .add(NormalizeOp(0f, 255f)) 33 + .add(CastOp(DataType.FLOAT32)) 34 + .build() 35 + 36 + actual fun detect(image: ImageBitmap): List<AnalysisObject> { 37 + val det = detector ?: return emptyList() 38 + val info = det.modelInfo 39 + val inputW = info.inputWidth 40 + val inputH = info.inputHeight 41 + if (inputW <= 0 || inputH <= 0) return emptyList() 42 + 43 + val srcBitmap = image.asAndroidBitmap().let { bmp -> 44 + if (bmp.config == Bitmap.Config.ARGB_8888) bmp 45 + else bmp.copy(Bitmap.Config.ARGB_8888, false) 46 + } 47 + val imgW = srcBitmap.width 48 + val imgH = srcBitmap.height 49 + 50 + // Letterbox: scale the source to fit inside (inputW, inputH) while 51 + // preserving aspect ratio, center it, and pad the remainder with 52 + // gray 114 — matching ultralytics training-time preprocessing. 53 + // (A naive stretch-resize destroys aspect ratio and hurts detection 54 + // quality on non-square camera frames.) 55 + val scale = min( 56 + inputW.toFloat() / imgW.toFloat(), 57 + inputH.toFloat() / imgH.toFloat() 58 + ) 59 + val scaledW = (imgW * scale).roundToInt().coerceAtLeast(1) 60 + val scaledH = (imgH * scale).roundToInt().coerceAtLeast(1) 61 + val padX = (inputW - scaledW) / 2f 62 + val padY = (inputH - scaledH) / 2f 63 + 64 + val resized = Bitmap.createBitmap(inputW, inputH, Bitmap.Config.ARGB_8888) 65 + val canvas = Canvas(resized) 66 + canvas.drawColor(Color.rgb(114, 114, 114)) 67 + canvas.drawBitmap( 68 + srcBitmap, null, 69 + RectF(padX, padY, padX + scaledW, padY + scaledH), 70 + Paint(Paint.FILTER_BITMAP_FLAG) 71 + ) 72 + 73 + // Normalize and convert to tensor 74 + val tensorImage = TensorImage(DataType.FLOAT32).also { it.load(resized) } 75 + .let(imageProcessor::process) 76 + 77 + // Run inference 78 + val outputShape = info.outputShape 79 + val output = TensorBuffer.createFixedSize(outputShape, DataType.FLOAT32) 80 + try { 81 + det.interpreter.run(tensorImage.buffer, output.buffer) 82 + } catch (e: Exception) { 83 + Logger.e(e) { "ImageDetector: interpreter.run failed" } 84 + return emptyList() 85 + } 86 + 87 + // Parse output 88 + val array = output.floatArray 89 + if (outputShape.size != 3) return emptyList() 90 + 91 + val dim1 = outputShape[1] 92 + val dim2 = outputShape[2] 93 + 94 + val elements: Int 95 + val channels: Int 96 + val isElementsFirst: Boolean 97 + 98 + when { 99 + dim2 == 6 -> { elements = dim1; channels = dim2; isElementsFirst = true } 100 + dim1 == 6 -> { channels = dim1; elements = dim2; isElementsFirst = false } 101 + else -> return emptyList() 102 + } 103 + 104 + fun valueAt(elementIndex: Int, channelIndex: Int): Float { 105 + return if (isElementsFirst) array[elementIndex * channels + channelIndex] 106 + else array[channelIndex * elements + elementIndex] 107 + } 108 + 109 + val imgWF = imgW.toFloat() 110 + val imgHF = imgH.toFloat() 111 + 112 + return (0 until elements).mapNotNull { i -> 113 + val cnf = valueAt(i, 4) 114 + if (cnf > 0.25f) { 115 + val x1 = valueAt(i, 0) 116 + val y1 = valueAt(i, 1) 117 + val x2 = valueAt(i, 2) 118 + val y2 = valueAt(i, 3) 119 + val cls = valueAt(i, 5).toInt() 120 + 121 + // Model outputs are normalized [0,1] over the letterboxed 122 + // input (inputW × inputH). Un-letterbox: convert to 123 + // letterboxed pixel coords, subtract padding, divide by 124 + // the fit ratio to get original-image pixel coords. 125 + val x1pLb = min(x1, x2) * inputW 126 + val y1pLb = min(y1, y2) * inputH 127 + val x2pLb = max(x1, x2) * inputW 128 + val y2pLb = max(y1, y2) * inputH 129 + 130 + val left = ((x1pLb - padX) / scale).coerceIn(0f, imgWF) 131 + val top = ((y1pLb - padY) / scale).coerceIn(0f, imgHF) 132 + val right = ((x2pLb - padX) / scale).coerceIn(0f, imgWF) 133 + val bottom = ((y2pLb - padY) / scale).coerceIn(0f, imgHF) 134 + 135 + AnalysisObject( 136 + boundingBox = Rect( 137 + left = left, 138 + top = top, 139 + right = right, 140 + bottom = bottom 141 + ), 142 + trackingId = 0, 143 + labels = listOf(Label(info.label(cls), cnf)), 144 + frameSize = FrameSize(width = imgW.absoluteValue, height = imgH.absoluteValue), 145 + timestamp = 0L 146 + ) 147 + } else null 148 + } 149 + } 150 + }
+427
handover/reference_code/compare_logs.py
··· 1 + #!/usr/bin/env python3 2 + """ 3 + Generate a model-comparison report from experiments/<run-id>/ directories. 4 + 5 + Each ``experiments/<run-id>/`` directory is expected to contain: 6 + 7 + * ``manifest.json`` with at least ``run_id``, ``model_tag``, ``t0_wall_ms``, 8 + ``duration_seconds``, ``device_label`` (written by ``tools/run_experiment.sh``). 9 + * One or more ``*.json`` files matching the experiment-log schema produced by 10 + the sample app's Experiment Mode (``device_model``, ``model_name``, ``run_id``, 11 + ``started_wall_ms``, ``stopped_wall_ms``, ``events``). 12 + 13 + For every run we compute a scorecard (detection rate, mean confidence, class 14 + diversity, per-class jitter), a per-bucket comparison table aligned to each 15 + run's ``t0_wall_ms`` so model A and model B share the same x-axis when run 16 + against the same video, and one matplotlib chart per class plotting confidence 17 + over time. matplotlib is optional — if it's not installed the report still 18 + renders, just without the timeline images. 19 + 20 + Usage: 21 + tools/compare_logs.py experiments/ # report.html + summary.csv in cwd 22 + tools/compare_logs.py experiments/ -o ./reports/ # write into ./reports/ 23 + tools/compare_logs.py experiments/ --bucket 200 # use 200ms buckets 24 + """ 25 + 26 + from __future__ import annotations 27 + 28 + import argparse 29 + import base64 30 + import csv 31 + import io 32 + import json 33 + import math 34 + import statistics 35 + import sys 36 + from collections import defaultdict 37 + from html import escape 38 + from pathlib import Path 39 + 40 + # matplotlib is optional. If unavailable, the report omits timeline charts. 41 + try: 42 + import matplotlib 43 + 44 + matplotlib.use("Agg") 45 + import matplotlib.pyplot as plt 46 + 47 + HAS_MPL = True 48 + except ImportError: 49 + HAS_MPL = False 50 + 51 + 52 + # ----------------------------------------------------------------------------- run loading 53 + 54 + def load_runs(experiments_dir: Path): 55 + """Yield (manifest, events_sorted_by_wall_ms) for each run subdir.""" 56 + for run_dir in sorted(experiments_dir.iterdir()): 57 + if not run_dir.is_dir(): 58 + continue 59 + manifest_path = run_dir / "manifest.json" 60 + if not manifest_path.exists(): 61 + print(f" skipping {run_dir.name}: no manifest.json", file=sys.stderr) 62 + continue 63 + try: 64 + with open(manifest_path) as f: 65 + manifest = json.load(f) 66 + except json.JSONDecodeError as e: 67 + print(f" skipping {run_dir.name}: bad manifest.json ({e})", file=sys.stderr) 68 + continue 69 + log_files = [f for f in run_dir.glob("*.json") if f.name != "manifest.json"] 70 + if not log_files: 71 + print(f" skipping {run_dir.name}: no log files", file=sys.stderr) 72 + continue 73 + events: list[dict] = [] 74 + for log in log_files: 75 + try: 76 + with open(log) as f: 77 + data = json.load(f) 78 + except json.JSONDecodeError as e: 79 + print(f" warning: bad log {log.name} ({e})", file=sys.stderr) 80 + continue 81 + events.extend(data.get("events", [])) 82 + events.sort(key=lambda e: e.get("wall_ms", 0)) 83 + yield manifest, events 84 + 85 + 86 + # ----------------------------------------------------------------------------- per-run metrics 87 + 88 + def compute_scorecard(manifest: dict, events: list[dict]) -> dict: 89 + """Return summary metrics for one run.""" 90 + t0 = manifest["t0_wall_ms"] 91 + duration_s = float(manifest.get("duration_seconds") or 0) 92 + 93 + total_events = len(events) 94 + events_with_objects = sum(1 for e in events if e.get("objects")) 95 + 96 + all_confs: list[float] = [] 97 + classes: set[str] = set() 98 + bbox_areas: list[float] = [] 99 + for e in events: 100 + for obj in e.get("objects", []): 101 + all_confs.append(float(obj.get("confidence", 0))) 102 + classes.add(obj.get("label", "")) 103 + bbox = obj.get("bbox", [0, 0, 0, 0]) 104 + if len(bbox) >= 4: 105 + w = max(0.0, float(bbox[2]) - float(bbox[0])) 106 + h = max(0.0, float(bbox[3]) - float(bbox[1])) 107 + bbox_areas.append(w * h) 108 + 109 + # Jitter per class: stddev of consecutive bbox-center deltas. High jitter 110 + # means the box is bouncing around frame-to-frame; low jitter means a 111 + # stable lock. We sum stdev_dx + stdev_dy as a coarse single-number score. 112 + jitter_per_class: dict[str, float] = {} 113 + for cls in classes: 114 + centers: list[tuple[float, float]] = [] 115 + for e in events: 116 + for obj in e.get("objects", []): 117 + if obj.get("label") == cls: 118 + bbox = obj.get("bbox", [0, 0, 0, 0]) 119 + if len(bbox) >= 4: 120 + cx = (float(bbox[0]) + float(bbox[2])) / 2 121 + cy = (float(bbox[1]) + float(bbox[3])) / 2 122 + centers.append((cx, cy)) 123 + break # at most one center per frame for each class 124 + if len(centers) >= 3: 125 + dxs = [centers[i + 1][0] - centers[i][0] for i in range(len(centers) - 1)] 126 + dys = [centers[i + 1][1] - centers[i][1] for i in range(len(centers) - 1)] 127 + jitter_per_class[cls] = statistics.stdev(dxs) + statistics.stdev(dys) 128 + 129 + return { 130 + "run_id": manifest["run_id"], 131 + "model_tag": manifest.get("model_tag", "unknown"), 132 + "device_label": manifest.get("device_label", "unknown"), 133 + "video_path": manifest.get("video_path", ""), 134 + "duration_s": duration_s, 135 + "t0_wall_ms": t0, 136 + "total_events": total_events, 137 + "events_with_objects": events_with_objects, 138 + "detection_rate": events_with_objects / total_events if total_events else 0.0, 139 + "events_per_second": total_events / duration_s if duration_s else 0.0, 140 + "mean_confidence": statistics.mean(all_confs) if all_confs else 0.0, 141 + "class_diversity": len(classes), 142 + "classes": sorted(c for c in classes if c), 143 + "mean_bbox_area": statistics.mean(bbox_areas) if bbox_areas else 0.0, 144 + "jitter_per_class": jitter_per_class, 145 + } 146 + 147 + 148 + # ----------------------------------------------------------------------------- bucketing 149 + 150 + def bucket_events(events: list[dict], t0: int, bucket_ms: int) -> dict[int, list[dict]]: 151 + """Group events into buckets keyed by floor(relative_ms / bucket_ms).""" 152 + buckets: dict[int, list[dict]] = defaultdict(list) 153 + for e in events: 154 + rel = int(e.get("wall_ms", 0)) - t0 155 + if rel < 0: 156 + continue 157 + buckets[rel // bucket_ms].append(e) 158 + return buckets 159 + 160 + 161 + def bucket_summary(events_in_bucket: list[dict]) -> dict: 162 + """Per-bucket / per-model aggregation: count, top-class, top-confidence.""" 163 + confs: list[float] = [] 164 + label_counts: dict[str, int] = defaultdict(int) 165 + for e in events_in_bucket: 166 + for obj in e.get("objects", []): 167 + confs.append(float(obj.get("confidence", 0))) 168 + label_counts[obj.get("label", "")] += 1 169 + top_label = max(label_counts.items(), key=lambda kv: kv[1])[0] if label_counts else "" 170 + return { 171 + "frames": len(events_in_bucket), 172 + "detections": sum(label_counts.values()), 173 + "top_label": top_label, 174 + "max_conf": max(confs) if confs else 0.0, 175 + "mean_conf": statistics.mean(confs) if confs else 0.0, 176 + } 177 + 178 + 179 + # ----------------------------------------------------------------------------- charts 180 + 181 + def render_timeline_png(per_run_series: dict[str, list[tuple[float, float]]], title: str) -> str | None: 182 + """Build a single matplotlib chart and return it as a base64 data URI.""" 183 + if not HAS_MPL: 184 + return None 185 + fig, ax = plt.subplots(figsize=(9, 3)) 186 + has_data = False 187 + for model_tag, series in per_run_series.items(): 188 + if not series: 189 + continue 190 + xs = [s[0] / 1000.0 for s in series] 191 + ys = [s[1] for s in series] 192 + ax.plot(xs, ys, marker=".", linestyle="-", linewidth=1, label=model_tag) 193 + has_data = True 194 + if not has_data: 195 + plt.close(fig) 196 + return None 197 + ax.set_xlabel("seconds since t0") 198 + ax.set_ylabel("confidence") 199 + ax.set_ylim(0, 1) 200 + ax.set_title(title) 201 + ax.legend(loc="upper right", fontsize=8) 202 + ax.grid(True, alpha=0.3) 203 + buf = io.BytesIO() 204 + fig.tight_layout() 205 + fig.savefig(buf, format="png", dpi=110) 206 + plt.close(fig) 207 + return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode("ascii") 208 + 209 + 210 + def class_timeline_data(manifest: dict, events: list[dict], cls: str) -> list[tuple[float, float]]: 211 + """Return [(relative_ms, top_confidence_for_class)] for one run + class.""" 212 + t0 = manifest["t0_wall_ms"] 213 + out: list[tuple[float, float]] = [] 214 + for e in events: 215 + rel = int(e.get("wall_ms", 0)) - t0 216 + if rel < 0: 217 + continue 218 + best = 0.0 219 + found = False 220 + for obj in e.get("objects", []): 221 + if obj.get("label") == cls: 222 + c = float(obj.get("confidence", 0)) 223 + if c > best: 224 + best = c 225 + found = True 226 + if found: 227 + out.append((rel, best)) 228 + return out 229 + 230 + 231 + # ----------------------------------------------------------------------------- HTML rendering 232 + 233 + def fmt_pct(x: float) -> str: 234 + return f"{x * 100:.1f}%" 235 + 236 + def fmt_num(x: float, places: int = 2) -> str: 237 + return f"{x:.{places}f}" 238 + 239 + 240 + def render_html(scorecards: list[dict], runs: list[tuple[dict, list[dict]]], bucket_ms: int) -> str: 241 + style = """ 242 + body { font-family: -apple-system, sans-serif; margin: 24px; color: #222; } 243 + h1, h2 { font-weight: 600; } 244 + table { border-collapse: collapse; margin: 8px 0 24px 0; font-size: 13px; } 245 + th, td { border: 1px solid #ddd; padding: 4px 8px; text-align: right; } 246 + th { background: #f5f5f5; text-align: left; } 247 + td.left, th.left { text-align: left; } 248 + .scorecard td:first-child { font-weight: 600; } 249 + .small { color: #888; font-size: 11px; } 250 + img { max-width: 100%; border: 1px solid #ddd; margin: 8px 0; } 251 + .warn { background: #fff7e0; border: 1px solid #f0c000; padding: 8px 12px; border-radius: 4px; } 252 + """ 253 + 254 + parts: list[str] = [] 255 + parts.append("<!doctype html><html><head><meta charset='utf-8'>") 256 + parts.append("<title>Model comparison report</title>") 257 + parts.append(f"<style>{style}</style></head><body>") 258 + parts.append("<h1>Model comparison report</h1>") 259 + parts.append(f"<p class='small'>{len(scorecards)} run(s), bucket size {bucket_ms} ms</p>") 260 + 261 + if not HAS_MPL: 262 + parts.append( 263 + "<p class='warn'>matplotlib is not installed — timeline charts are omitted. " 264 + "Install with <code>uv pip install matplotlib</code> (or pip) and re-run.</p>" 265 + ) 266 + 267 + # ----- per-run scorecards 268 + parts.append("<h2>Per-run scorecard</h2>") 269 + parts.append("<table class='scorecard'>") 270 + headers = ["metric"] + [s["model_tag"] for s in scorecards] 271 + parts.append("<tr>" + "".join(f"<th class='left'>{escape(h)}</th>" for h in headers) + "</tr>") 272 + 273 + def row(label: str, values: list[str]) -> str: 274 + return "<tr><td class='left'>" + escape(label) + "</td>" + "".join( 275 + f"<td>{escape(v)}</td>" for v in values 276 + ) + "</tr>" 277 + 278 + parts.append(row("run_id", [s["run_id"] for s in scorecards])) 279 + parts.append(row("device", [s["device_label"] for s in scorecards])) 280 + parts.append(row("duration (s)", [fmt_num(s["duration_s"], 1) for s in scorecards])) 281 + parts.append(row("total events", [str(s["total_events"]) for s in scorecards])) 282 + parts.append(row("events / second", [fmt_num(s["events_per_second"], 2) for s in scorecards])) 283 + parts.append(row("frames with detection", [fmt_pct(s["detection_rate"]) for s in scorecards])) 284 + parts.append(row("mean confidence", [fmt_num(s["mean_confidence"], 3) for s in scorecards])) 285 + parts.append(row("classes seen", [str(s["class_diversity"]) for s in scorecards])) 286 + parts.append(row("mean bbox area (px²)", [fmt_num(s["mean_bbox_area"], 0) for s in scorecards])) 287 + parts.append(row("class list", [", ".join(s["classes"]) for s in scorecards])) 288 + parts.append("</table>") 289 + 290 + # ----- per-class jitter table 291 + all_classes = sorted({c for s in scorecards for c in s["classes"]}) 292 + if all_classes: 293 + parts.append("<h2>Jitter per class (lower = more stable)</h2>") 294 + parts.append("<table>") 295 + parts.append("<tr><th class='left'>class</th>" + "".join(f"<th>{escape(s['model_tag'])}</th>" for s in scorecards) + "</tr>") 296 + for cls in all_classes: 297 + row_vals = [] 298 + for s in scorecards: 299 + v = s["jitter_per_class"].get(cls) 300 + row_vals.append(fmt_num(v, 1) if v is not None else "—") 301 + parts.append("<tr><td class='left'>" + escape(cls) + "</td>" + "".join(f"<td>{v}</td>" for v in row_vals) + "</tr>") 302 + parts.append("</table>") 303 + 304 + # ----- per-bucket comparison table 305 + parts.append(f"<h2>Per-bucket comparison ({bucket_ms} ms bins)</h2>") 306 + bucketed_per_run = [] 307 + for s, (manifest, events) in zip(scorecards, runs): 308 + bucketed_per_run.append(bucket_events(events, manifest["t0_wall_ms"], bucket_ms)) 309 + all_buckets = sorted({b for d in bucketed_per_run for b in d.keys()}) 310 + parts.append("<table>") 311 + header_cells = ["<th class='left'>bucket (ms)</th>"] 312 + for s in scorecards: 313 + tag = escape(s["model_tag"]) 314 + header_cells.append(f"<th>{tag}<br><span class='small'>frames</span></th>") 315 + header_cells.append(f"<th>{tag}<br><span class='small'>top class</span></th>") 316 + header_cells.append(f"<th>{tag}<br><span class='small'>max conf</span></th>") 317 + parts.append("<tr>" + "".join(header_cells) + "</tr>") 318 + for b in all_buckets: 319 + cells = [f"<td class='left'>{b * bucket_ms}–{(b + 1) * bucket_ms}</td>"] 320 + for run_buckets in bucketed_per_run: 321 + evs = run_buckets.get(b, []) 322 + if evs: 323 + summ = bucket_summary(evs) 324 + cells.append(f"<td>{summ['frames']}</td>") 325 + cells.append(f"<td>{escape(summ['top_label'])}</td>") 326 + cells.append(f"<td>{fmt_num(summ['max_conf'], 2)}</td>") 327 + else: 328 + cells.append("<td>—</td><td>—</td><td>—</td>") 329 + parts.append("<tr>" + "".join(cells) + "</tr>") 330 + parts.append("</table>") 331 + 332 + # ----- per-class timeline charts 333 + if HAS_MPL: 334 + parts.append("<h2>Per-class confidence timelines</h2>") 335 + for cls in all_classes: 336 + per_run_series: dict[str, list[tuple[float, float]]] = {} 337 + for s, (manifest, events) in zip(scorecards, runs): 338 + per_run_series[s["model_tag"]] = class_timeline_data(manifest, events, cls) 339 + data_uri = render_timeline_png(per_run_series, f"class: {cls}") 340 + if data_uri: 341 + parts.append(f"<img alt='{escape(cls)} timeline' src='{data_uri}'/>") 342 + 343 + parts.append("</body></html>") 344 + return "".join(parts) 345 + 346 + 347 + # ----------------------------------------------------------------------------- summary csv 348 + 349 + def write_summary_csv(scorecards: list[dict], path: Path) -> None: 350 + fieldnames = [ 351 + "run_id", 352 + "model_tag", 353 + "device_label", 354 + "duration_s", 355 + "total_events", 356 + "events_per_second", 357 + "detection_rate", 358 + "mean_confidence", 359 + "class_diversity", 360 + "classes", 361 + "mean_bbox_area", 362 + ] 363 + with open(path, "w", newline="") as f: 364 + w = csv.DictWriter(f, fieldnames=fieldnames) 365 + w.writeheader() 366 + for s in scorecards: 367 + w.writerow( 368 + { 369 + "run_id": s["run_id"], 370 + "model_tag": s["model_tag"], 371 + "device_label": s["device_label"], 372 + "duration_s": f"{s['duration_s']:.2f}", 373 + "total_events": s["total_events"], 374 + "events_per_second": f"{s['events_per_second']:.3f}", 375 + "detection_rate": f"{s['detection_rate']:.4f}", 376 + "mean_confidence": f"{s['mean_confidence']:.4f}", 377 + "class_diversity": s["class_diversity"], 378 + "classes": "|".join(s["classes"]), 379 + "mean_bbox_area": f"{s['mean_bbox_area']:.1f}", 380 + } 381 + ) 382 + 383 + 384 + # ----------------------------------------------------------------------------- main 385 + 386 + def main(argv: list[str]) -> int: 387 + parser = argparse.ArgumentParser( 388 + description="Build a model comparison report from experiments/<run-id>/ directories.", 389 + ) 390 + parser.add_argument("experiments_dir", type=Path, help="path to the experiments/ directory") 391 + parser.add_argument("-o", "--output-dir", type=Path, default=Path.cwd(), 392 + help="where report.html and summary.csv should be written (default: cwd)") 393 + parser.add_argument("--bucket", type=int, default=100, help="bucket size in milliseconds (default: 100)") 394 + args = parser.parse_args(argv) 395 + 396 + if not args.experiments_dir.is_dir(): 397 + print(f"error: not a directory: {args.experiments_dir}", file=sys.stderr) 398 + return 2 399 + 400 + runs = list(load_runs(args.experiments_dir)) 401 + if not runs: 402 + print("error: no usable runs found.", file=sys.stderr) 403 + return 2 404 + 405 + scorecards = [compute_scorecard(m, e) for m, e in runs] 406 + 407 + args.output_dir.mkdir(parents=True, exist_ok=True) 408 + html_path = args.output_dir / "report.html" 409 + csv_path = args.output_dir / "summary.csv" 410 + 411 + html_path.write_text(render_html(scorecards, runs, args.bucket)) 412 + write_summary_csv(scorecards, csv_path) 413 + 414 + print(f"wrote {html_path}") 415 + print(f"wrote {csv_path}") 416 + print(f"runs: {len(runs)}") 417 + for s in scorecards: 418 + print( 419 + f" {s['model_tag']}: {s['total_events']} events, " 420 + f"{s['detection_rate'] * 100:.1f}% with detection, " 421 + f"mean conf {s['mean_confidence']:.3f}" 422 + ) 423 + return 0 424 + 425 + 426 + if __name__ == "__main__": 427 + sys.exit(main(sys.argv[1:]))
+178 -4
posedetection/build.gradle.kts
··· 4 4 5 5 mavenPublishing { 6 6 publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) 7 - coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.10.0") 7 + coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.15.0") 8 8 9 9 pom { 10 10 name.set("Pose Detection") ··· 31 31 developerConnection.set("scm:git:ssh://git@tangled.sh:nateholland.bsky.social/PoseDetection") 32 32 } 33 33 } 34 - signAllPublications() 34 + // Only sign when explicitly enabled (CI / Maven Central). Local 35 + // `publishToMavenLocal` runs for consumers like the kima app and 36 + // doesn't need GPG signatures. 37 + if (project.findProperty("signingEnabled") == "true") { 38 + signAllPublications() 39 + } 35 40 } 36 41 plugins { 37 42 alias(libs.plugins.multiplatform) ··· 52 57 iosX64(), 53 58 iosArm64(), 54 59 iosSimulatorArm64() 55 - ).forEach { 56 - it.binaries.framework { 60 + ).forEach { target -> 61 + target.binaries.framework { 57 62 baseName = "ComposeApp" 58 63 isStatic = true 59 64 } 65 + // MLKit pose detection is embedded via cinterop `staticLibraries` for 66 + // iosArm64 only — the library's klib ships the MLKit binaries so 67 + // downstream consumers get MLKit without running cocoapods themselves. 68 + // Sim targets fall back to Apple Vision (upstream MLKit has no 69 + // arm64-simulator slice). 70 + if (target.name == "iosArm64") { 71 + target.compilations.getByName("main").cinterops.create("mlkitAccurate") { 72 + defFile(layout.buildDirectory.file("mlkit-archives/mlkitAccurate.def").get().asFile) 73 + packageName("cocoapods.MLKitPoseDetectionAccurate") 74 + } 75 + } 60 76 } 61 77 62 78 sourceSets { ··· 114 130 androidTestImplementation(libs.androidx.uitest.junit4) 115 131 debugImplementation(libs.androidx.uitest.testManifest) 116 132 } 133 + 134 + // ============================================================================ 135 + // MLKit iOS integration 136 + // ---------------------------------------------------------------------------- 137 + // The library's iosArm64 klib ships MLKit statically-embedded via cinterop 138 + // `staticLibraries`. Downstream consumers get MLKit symbols without needing 139 + // cocoapods — standard Maven/Gradle KMP dependency resolution is enough. 140 + // 141 + // The `syncMlkitBinaries` task runs tools/sync-mlkit.sh, which fetches MLKit 142 + // pods into build/mlkit-staging and extracts per-target static archives into 143 + // build/mlkit-archives. `generateMlkitDefFile` then writes a cinterop .def 144 + // referencing those archives with absolute paths resolved at configuration 145 + // time. `cinteropMlkitAccurateIosArm64` is wired to depend on both. 146 + // ============================================================================ 147 + 148 + val mlkitStagingDir = layout.buildDirectory.dir("mlkit-staging") 149 + val mlkitArchivesDir = layout.buildDirectory.dir("mlkit-archives") 150 + val mlkitDefFile = layout.buildDirectory.file("mlkit-archives/mlkitAccurate.def") 151 + val mlkitRedirectSrc = 152 + project.file("src/nativeInterop/mlkitRedirect/MLKitResourceRedirect.m") 153 + val mlkitRedirectDir = layout.buildDirectory.dir("mlkit-redirect") 154 + val mlkitRedirectLib = 155 + layout.buildDirectory.file("mlkit-redirect/ios_arm64/libMLKitRedirect.a") 156 + val mlkitComposeResDir = layout.buildDirectory.dir("mlkit-compose-resources") 157 + 158 + // Compile our NSBundle swizzle for iosArm64 and archive into libMLKitRedirect.a. 159 + // The cinterop .def includes this static library alongside MLKit's, so the 160 + // swizzle gets linked into the consumer's KMP framework automatically. 161 + val compileMlkitRedirect = tasks.register<Exec>("compileMlkitRedirect") { 162 + group = "mlkit" 163 + description = "Compile NSBundle MLKit redirect swizzle to static archive." 164 + inputs.file(mlkitRedirectSrc) 165 + outputs.file(mlkitRedirectLib) 166 + val out = mlkitRedirectLib.get().asFile 167 + val obj = out.resolveSibling("MLKitResourceRedirect.o") 168 + out.parentFile.mkdirs() 169 + commandLine( 170 + "sh", "-c", 171 + "xcrun --sdk iphoneos clang " + 172 + "-c -fobjc-arc -fmodules " + 173 + "-arch arm64 -mios-version-min=16.2 " + 174 + "${mlkitRedirectSrc.absolutePath} -o ${obj.absolutePath} && " + 175 + "xcrun ar rcs ${out.absolutePath} ${obj.absolutePath}" 176 + ) 177 + } 178 + 179 + // Copy MLKit resource bundles (.tflite / .binarypb) from the synced pods into 180 + // the library's iosMain Compose Multiplatform resources, so they're packaged 181 + // into the consumer app bundle automatically. At runtime, Kotlin extracts them 182 + // to NSCachesDirectory and the NSBundle swizzle redirects MLKit's lookups. 183 + val stageMlkitResources = tasks.register<Copy>("stageMlkitResources") { 184 + group = "mlkit" 185 + description = "Stage MLKit resource bundles as Compose MP resources." 186 + dependsOn("syncMlkitBinaries") 187 + val pods = mlkitStagingDir.get().asFile.resolve("Pods") 188 + from(pods.resolve("MLKitPoseDetectionAccurate/Resources/MLKitPoseDetectionAccurateResources")) { 189 + into("files/mlkit/MLKitPoseDetectionAccurateResources") 190 + } 191 + from(pods.resolve("MLKitPoseDetectionCommon/Resources/MLKitPoseDetectionCommonResources")) { 192 + into("files/mlkit/MLKitPoseDetectionCommonResources") 193 + } 194 + from(pods.resolve("MLKitXenoCommon/Frameworks/MLKitXenoCommon.framework/MLKitXenoResources.bundle")) { 195 + into("files/mlkit/MLKitXenoResources") 196 + } 197 + into(mlkitComposeResDir) 198 + } 199 + 200 + // Wire the staged MLKit resources into the Compose Multiplatform resource set 201 + // for the ios source tree. Compose packages these into the consumer's app 202 + // bundle at `compose-resources/<pkg>.generated.resources/files/mlkit/...`. 203 + compose.resources { 204 + customDirectory( 205 + sourceSetName = "iosMain", 206 + directoryProvider = mlkitComposeResDir, 207 + ) 208 + } 209 + 210 + // Compose's `generateResourceAccessors*` tasks read from the resource dir, so 211 + // make them wait for the stage task (which populates the dir). 212 + tasks.matching { it.name.startsWith("generateResourceAccessors") } 213 + .configureEach { dependsOn(stageMlkitResources) } 214 + tasks.matching { it.name.startsWith("generateExpectResourceCollectors") } 215 + .configureEach { dependsOn(stageMlkitResources) } 216 + tasks.matching { it.name.startsWith("convertXmlValueResources") } 217 + .configureEach { dependsOn(stageMlkitResources) } 218 + tasks.matching { it.name.startsWith("copyNonXmlValueResources") } 219 + .configureEach { dependsOn(stageMlkitResources) } 220 + tasks.matching { it.name.startsWith("prepareComposeResources") } 221 + .configureEach { dependsOn(stageMlkitResources) } 222 + 223 + val syncMlkitBinaries = tasks.register<Exec>("syncMlkitBinaries") { 224 + group = "mlkit" 225 + description = "Fetch MLKit pods + extract static archives for each Kotlin iOS target." 226 + inputs.file("tools/sync-mlkit.sh") 227 + outputs.dir(mlkitArchivesDir) 228 + executable = project.file("tools/sync-mlkit.sh").absolutePath 229 + environment("MLKIT_STAGING_DIR", mlkitStagingDir.get().asFile.absolutePath) 230 + environment("MLKIT_ARCHIVES_DIR", mlkitArchivesDir.get().asFile.absolutePath) 231 + // Only iosArm64 (iPhone device) is supported upstream; sim targets fall 232 + // back to Vision via the MlKitPose expect/actual stub. 233 + environment("MLKIT_TARGETS", "ios_arm64") 234 + } 235 + 236 + val generateMlkitDefFile = tasks.register("generateMlkitDefFile") { 237 + group = "mlkit" 238 + description = "Generate the MLKit cinterop .def with absolute archive paths." 239 + dependsOn(syncMlkitBinaries, compileMlkitRedirect) 240 + outputs.file(mlkitDefFile) 241 + // Capture as locals so the closure doesn't hold project-level refs — 242 + // configuration-cache-safe. 243 + val pods = mlkitStagingDir.get().asFile.resolve("Pods").absolutePath 244 + val archives = mlkitArchivesDir.get().asFile.absolutePath 245 + val redirectArchives = mlkitRedirectDir.get().asFile.absolutePath 246 + val defFile = mlkitDefFile.get().asFile 247 + doLast { 248 + val defContent = buildString { 249 + appendLine("language = Objective-C") 250 + appendLine("modules = MLKitPoseDetectionAccurate MLKitPoseDetectionCommon MLKitVision") 251 + appendLine("package = cocoapods.MLKitPoseDetectionAccurate") 252 + appendLine( 253 + "compilerOpts = -fmodules " + 254 + "-F$pods/MLKitPoseDetectionAccurate/Frameworks " + 255 + "-F$pods/MLKitPoseDetectionCommon/Frameworks " + 256 + "-F$pods/MLKitVision/Frameworks " + 257 + "-F$pods/MLKitCommon/Frameworks " + 258 + "-F$pods/MLImage/Frameworks " + 259 + "-F$pods/MLKitXenoCommon/Frameworks" 260 + ) 261 + appendLine( 262 + "staticLibraries = " + 263 + "libMLKitPoseDetectionAccurate.a libMLKitPoseDetectionCommon.a " + 264 + "libMLKitVision.a libMLKitCommon.a libMLImage.a libMLKitXenoCommon.a " + 265 + "libGTMSessionFetcher.a libGoogleDataTransport.a libGoogleToolboxForMac.a " + 266 + "libGoogleUtilities.a libFBLPromises.a libnanopb.a libMLKitRedirect.a" 267 + ) 268 + appendLine("libraryPaths.ios_arm64 = $archives/ios_arm64 $redirectArchives/ios_arm64") 269 + appendLine( 270 + "linkerOpts = -ObjC -lc++ -lsqlite3 -lz " + 271 + "-framework Accelerate -framework CoreML" 272 + ) 273 + // Expose the swizzle control function to Kotlin. 274 + appendLine("---") 275 + appendLine("void mlkit_set_resource_dir(const char *path);") 276 + } 277 + defFile.writeText(defContent) 278 + } 279 + } 280 + 281 + tasks.matching { it.name.startsWith("cinteropMlkitAccurate") }.configureEach { 282 + dependsOn(generateMlkitDefFile) 283 + // Cinterop's up-to-date check only watches its .def file — a content 284 + // change in the static archives (e.g. libMLKitRedirect.a after an .m 285 + // edit) won't invalidate the produced klib. Declare the archive dirs 286 + // as explicit inputs so any rebuilt .a forces cinterop + downstream 287 + // klib + publish to re-run. 288 + inputs.dir(mlkitArchivesDir) 289 + inputs.dir(mlkitRedirectDir) 290 + }
+31 -12
posedetection/src/androidMain/kotlin/com.performancecoachlab/posedetection/camera/CameraView.android.kt
··· 7 7 import androidx.annotation.OptIn 8 8 import androidx.camera.camera2.interop.Camera2CameraInfo 9 9 import androidx.camera.camera2.interop.ExperimentalCamera2Interop 10 + import androidx.camera.core.AspectRatio 10 11 import androidx.camera.core.CameraInfo 11 12 import androidx.camera.core.CameraSelector 12 13 import androidx.camera.core.CameraSelector.DEFAULT_BACK_CAMERA ··· 54 55 import com.google.mlkit.vision.pose.Pose 55 56 import com.google.mlkit.vision.pose.PoseDetection 56 57 import com.google.mlkit.vision.pose.PoseLandmark 57 - import com.google.mlkit.vision.pose.defaults.PoseDetectorOptions 58 + import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions 58 59 import com.performancecoachlab.posedetection.custom.CustomObjectRespository 59 60 import com.performancecoachlab.posedetection.custom.ObjectModel 60 61 import com.performancecoachlab.posedetection.recording.AnalysisObject ··· 118 119 previewFillMode: PreviewFillMode, 119 120 recordingId: String?, 120 121 focusArea: Rect?, 122 + poseFocusMode: PoseFocusMode, 121 123 controller: CameraViewController?, 122 124 onRecordToggled: (Boolean) -> Unit, 123 125 onVideoSaved: (String, String) -> Unit, ··· 136 138 val lastPoseRunAtMs = remember { AtomicLong(0L) } 137 139 val analysisFrameCounter = remember { AtomicLong(0L) } 138 140 139 - val options = PoseDetectorOptions.Builder() 140 - .setDetectorMode(PoseDetectorOptions.STREAM_MODE) 141 + val options = AccuratePoseDetectorOptions.Builder() 142 + .setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE) 141 143 .build() 142 144 val poseDetector = PoseDetection.getClient(options) 143 145 ··· 147 149 val executor = remember { Executors.newSingleThreadExecutor() } 148 150 149 151 var focus by remember { mutableStateOf(focusArea) } 152 + var currentPoseFocusMode by remember { mutableStateOf(poseFocusMode) } 150 153 var objectDetector by remember { mutableStateOf(objectModel) } 151 154 var currentDetectMode by remember { mutableStateOf(detectMode) } 152 155 ··· 162 165 focus = focusArea 163 166 } 164 167 168 + LaunchedEffect(poseFocusMode) { 169 + currentPoseFocusMode = poseFocusMode 170 + } 171 + 165 172 // Update object model when it changes 166 173 LaunchedEffect(objectModel) { 167 174 objectDetector = objectModel ··· 286 293 val imageAnalysis = ImageAnalysis.Builder() 287 294 .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) 288 295 .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) 296 + .setTargetAspectRatio(AspectRatio.RATIO_4_3) 289 297 .build() 290 298 .also { analysis -> 291 299 analysis.targetRotation = rotation ··· 303 311 val now = sensorMs + bootEpochOffset 304 312 val area = focus 305 313 306 - // In BOTH mode, stagger pose and object on alternate frames 307 - // to reduce per-frame processing time and improve tracking. 308 - val frameNum = analysisFrameCounter.incrementAndGet() 309 - val isBothMode = currentDetectMode == DetectMode.BOTH 314 + // In BOTH mode, run both detectors on every eligible frame. 315 + // The underlying `ImageProxy.process()` already fans pose out 316 + // to `poseExecutor` and runs object inference on the analyzer 317 + // thread concurrently, so per-frame wall-clock is max(pose, 318 + // object) instead of pose+object. The previous even/odd 319 + // alternation cut each detector's effective frame rate in 320 + // half for ~20% combined-FPS gain — ditched in favor of 321 + // doubling per-detector coverage, which matters more for 322 + // ball-near-hoop detection. 323 + analysisFrameCounter.incrementAndGet() 310 324 val shouldRunObject = currentDetectMode.doObject() && 311 - (now - lastObjectRunAtMs.get() >= objectIntervalMs) && 312 - (!isBothMode || frameNum % 2 == 0L) 325 + (now - lastObjectRunAtMs.get() >= objectIntervalMs) 313 326 val shouldRunPose = currentDetectMode.doPose() && 314 - (now - lastPoseRunAtMs.get() >= poseIntervalMs) && 315 - (!isBothMode || frameNum % 2 != 0L) 327 + (now - lastPoseRunAtMs.get() >= poseIntervalMs) 316 328 317 329 // If neither detector is scheduled to run, just close quickly and reuse last results. 318 330 if (!shouldRunObject && !shouldRunPose) { ··· 333 345 objectClient, 334 346 poseClient, 335 347 now, 336 - area 348 + area, 349 + currentPoseFocusMode, 337 350 ) { analysisResult, frameBitmap -> 338 351 try { 339 352 // Only update repositories/results for detectors that actually ran. ··· 573 586 rightKnee = pose?.getPoseLandmark(PoseLandmark.RIGHT_KNEE)?.toSkeletonCoords(), 574 587 leftAnkle = pose?.getPoseLandmark(PoseLandmark.LEFT_ANKLE)?.toSkeletonCoords(), 575 588 rightAnkle = pose?.getPoseLandmark(PoseLandmark.RIGHT_ANKLE)?.toSkeletonCoords(), 589 + leftHeel = pose?.getPoseLandmark(PoseLandmark.LEFT_HEEL)?.toSkeletonCoords(), 590 + rightHeel = pose?.getPoseLandmark(PoseLandmark.RIGHT_HEEL)?.toSkeletonCoords(), 591 + leftToe = pose?.getPoseLandmark(PoseLandmark.LEFT_FOOT_INDEX)?.toSkeletonCoords(), 592 + rightToe = pose?.getPoseLandmark(PoseLandmark.RIGHT_FOOT_INDEX)?.toSkeletonCoords(), 593 + leftIndex = pose?.getPoseLandmark(PoseLandmark.LEFT_INDEX)?.toSkeletonCoords(), 594 + rightIndex = pose?.getPoseLandmark(PoseLandmark.RIGHT_INDEX)?.toSkeletonCoords(), 576 595 width = width.toFloat(), 577 596 height = height.toFloat(), 578 597 )
+140 -31
posedetection/src/androidMain/kotlin/com/performancecoachlab/posedetection/camera/Utils.android.kt
··· 227 227 poseDetector: PoseDetector?, 228 228 timestamp: Long, 229 229 focusArea: Rect?, 230 + poseFocusMode: PoseFocusMode = PoseFocusMode.MASK, 230 231 onComplete: (AnalysisResult, Bitmap) -> Unit 231 232 ) { 232 233 // If both are null, still close to avoid stalling the camera pipeline. ··· 247 248 // 2) Pose input: build MLKit image (optionally masked) and DOWNscale it. 248 249 // Rotation is now 0 because analysisBitmap is upright. 249 250 val mlKitPoseInput: MlKitPoseInput? = poseDetector?.let { 251 + // In CROP / CROP_FOLLOW we feed MLKit only the focus-area crop, which 252 + // is already smaller than the full frame — so raise the downscale 253 + // target to land more pixels on the person without ballooning work. 254 + val isCroppingMode = poseFocusMode == PoseFocusMode.CROP || 255 + poseFocusMode == PoseFocusMode.CROP_FOLLOW 256 + val downscale = if (focusArea != null && isCroppingMode) 384 else 256 250 257 buildMlKitPoseInput( 251 258 analysisBitmap = analysisBitmap, 252 259 focusArea = focusArea, 253 - downscaleMaxSidePx = 256 260 + poseFocusMode = poseFocusMode, 261 + downscaleMaxSidePx = downscale 254 262 ) 255 263 } 256 264 ··· 279 287 width = analysisBitmap.width, 280 288 height = analysisBitmap.height, 281 289 bitmap = analysisBitmap, 282 - onComplete = onComplete, 290 + onComplete = { result, bmp -> 291 + // Update the follow-crop state so the next frame can tighten around 292 + // the current skeleton. No-op in MASK/CROP (nothing reads it). 293 + if (poseFocusMode == PoseFocusMode.CROP_FOLLOW && focusArea != null) { 294 + followCropState.updateFromSkeleton( 295 + skeleton = result.skeleton, 296 + analysisW = analysisBitmap.width, 297 + analysisH = analysisBitmap.height, 298 + clampTo = focusArea, 299 + nowMs = System.currentTimeMillis(), 300 + ) 301 + } 302 + onComplete(result, bmp) 303 + }, 283 304 mlKitScaleX = mlKitPoseInput?.scaleX ?: 1f, 284 305 mlKitScaleY = mlKitPoseInput?.scaleY ?: 1f, 306 + mlKitOffsetX = mlKitPoseInput?.offsetX ?: 0f, 307 + mlKitOffsetY = mlKitPoseInput?.offsetY ?: 0f, 285 308 ) 286 309 } 287 310 288 311 // Shared executor for running pose detection in parallel with object detection. 289 312 private val poseExecutor = Executors.newSingleThreadExecutor() 313 + 314 + // Process-wide trackers. Lifted from local singletons to the shared commonMain 315 + // classes so iOS uses the same implementation. 316 + private val followCropState = FollowCropState() 317 + private val poseSmoother = PoseSmoother() 290 318 291 319 // Core processing used by both live camera (ImageProxy) and offline frames (FrameAnalyser). 292 320 fun process( ··· 301 329 onComplete: (AnalysisResult, Bitmap) -> Unit, 302 330 mlKitScaleX: Float = 1f, 303 331 mlKitScaleY: Float = 1f, 332 + mlKitOffsetX: Float = 0f, 333 + mlKitOffsetY: Float = 0f, 304 334 ) { 305 335 // Launch pose detection on a separate thread so it runs in parallel with object detection. 306 336 val poseFuture = if (poseDetector != null && mlKitImage != null) { 307 337 poseExecutor.submit<Skeleton?> { 308 338 runCatching { 309 339 val pose = Tasks.await(poseDetector.process(mlKitImage)) 310 - skeletonFromPoseScaled( 340 + val raw = skeletonFromPoseScaled( 311 341 pose = pose, 312 342 timestamp = timestamp, 313 343 width = width, 314 344 height = height, 315 345 scaleX = mlKitScaleX, 316 346 scaleY = mlKitScaleY, 347 + offsetX = mlKitOffsetX, 348 + offsetY = mlKitOffsetY, 317 349 ) 350 + // Empty skeletons (no landmarks passed conf threshold) smooth as 351 + // null so the smoother doesn't lerp toward a zeroed pose. 352 + val hasAny = raw.joints().isNotEmpty() 353 + poseSmoother.smooth(if (hasAny) raw else null, timestamp) 318 354 }.onFailure { t -> 319 355 Logger.e(t) { "MLKit poseDetector.process failed" } 320 356 }.getOrNull() ··· 707 743 val image: InputImage, 708 744 val scaleX: Float, 709 745 val scaleY: Float, 746 + val offsetX: Float = 0f, 747 + val offsetY: Float = 0f, 710 748 ) 711 749 712 750 private fun buildMlKitPoseInput( 713 751 analysisBitmap: Bitmap, 714 752 focusArea: Rect?, 753 + poseFocusMode: PoseFocusMode, 715 754 downscaleMaxSidePx: Int = 360, 716 755 ): MlKitPoseInput { 717 - // 1) Apply optional focus mask in full-resolution upright coordinates. 718 - val poseBitmapFull = if (focusArea == null) { 719 - analysisBitmap 720 - } else { 721 - val out = PoseMaskBitmapPool.obtain( 722 - analysisBitmap.width, 723 - analysisBitmap.height, 724 - analysisBitmap.config ?: Bitmap.Config.ARGB_8888 725 - ) 726 - Canvas(out).drawBitmap(analysisBitmap, 0f, 0f, null) 727 - out.applyFocusAreaMaskInPlace(focusArea = focusArea, angle = 0) 728 - out 756 + // 1) Build the pose source bitmap — mask (black out non-focus region) or 757 + // crop (geometrically restrict to focus region). Crop gives the model 758 + // higher effective resolution of the focus area at the same downscale. 759 + // 760 + // Crop-mode also records offsetX/offsetY in full-bitmap pixel coords so 761 + // landmarks (which come back in crop-local coords) can be remapped. 762 + // 763 + // CROP_FOLLOW: if we have a recent tight bbox from the last skeleton, 764 + // use it as the effective crop. Otherwise fall back to the static focus 765 + // area so a new detection can re-acquire. 766 + val effectiveFocus: Rect? = when { 767 + focusArea == null -> null 768 + poseFocusMode == PoseFocusMode.CROP_FOLLOW -> 769 + followCropState.current(System.currentTimeMillis()) ?: focusArea 770 + else -> focusArea 771 + } 772 + val useCrop = effectiveFocus != null && 773 + (poseFocusMode == PoseFocusMode.CROP || poseFocusMode == PoseFocusMode.CROP_FOLLOW) 774 + 775 + val offsetX: Float 776 + val offsetY: Float 777 + val poseBitmapFull: Bitmap = when { 778 + focusArea == null -> { 779 + offsetX = 0f 780 + offsetY = 0f 781 + analysisBitmap 782 + } 783 + useCrop -> { 784 + val w = analysisBitmap.width 785 + val h = analysisBitmap.height 786 + val rect = effectiveFocus!! 787 + val leftPx = (rect.left * w).toInt().coerceIn(0, w) 788 + val topPx = (rect.top * h).toInt().coerceIn(0, h) 789 + val rightPx = (rect.right * w).toInt().coerceIn(leftPx, w) 790 + val bottomPx = (rect.bottom * h).toInt().coerceIn(topPx, h) 791 + val cropW = rightPx - leftPx 792 + val cropH = bottomPx - topPx 793 + if (cropW <= 0 || cropH <= 0) { 794 + // Degenerate focus rect — fall back to full frame untouched. 795 + offsetX = 0f 796 + offsetY = 0f 797 + analysisBitmap 798 + } else { 799 + offsetX = leftPx.toFloat() 800 + offsetY = topPx.toFloat() 801 + Bitmap.createBitmap(analysisBitmap, leftPx, topPx, cropW, cropH) 802 + } 803 + } 804 + else -> { 805 + offsetX = 0f 806 + offsetY = 0f 807 + val out = PoseMaskBitmapPool.obtain( 808 + analysisBitmap.width, 809 + analysisBitmap.height, 810 + analysisBitmap.config ?: Bitmap.Config.ARGB_8888 811 + ) 812 + Canvas(out).drawBitmap(analysisBitmap, 0f, 0f, null) 813 + out.applyFocusAreaMaskInPlace(focusArea = focusArea, angle = 0) 814 + out 815 + } 729 816 } 730 817 731 818 // 2) Downscale for MLKit (pose is generally robust at lower res). ··· 738 825 image = InputImage.fromBitmap(poseBitmapFull, 0), 739 826 scaleX = 1f, 740 827 scaleY = 1f, 828 + offsetX = offsetX, 829 + offsetY = offsetY, 741 830 ) 742 831 } 743 832 ··· 756 845 image = InputImage.fromBitmap(downscaled, 0), 757 846 scaleX = scaleBackX, 758 847 scaleY = scaleBackY, 848 + offsetX = offsetX, 849 + offsetY = offsetY, 759 850 ) 760 851 } 761 852 762 853 private fun PoseLandmark?.toSkeletonCoordsScaled( 763 854 scaleX: Float, 764 - scaleY: Float 855 + scaleY: Float, 856 + offsetX: Float, 857 + offsetY: Float, 765 858 ): Skeleton.SkeletonCoordinate? { 766 - val pos = this?.position ?: return null 859 + val lm = this ?: return null 860 + if (lm.inFrameLikelihood < LANDMARK_CONF_THRESHOLD) return null 861 + val pos = lm.position 767 862 return Skeleton.SkeletonCoordinate( 768 - x = pos.x * scaleX, 769 - y = pos.y * scaleY, 863 + x = pos.x * scaleX + offsetX, 864 + y = pos.y * scaleY + offsetY, 770 865 ) 771 866 } 772 867 ··· 777 872 height: Int, 778 873 scaleX: Float, 779 874 scaleY: Float, 875 + offsetX: Float = 0f, 876 + offsetY: Float = 0f, 780 877 ): Skeleton { 781 878 return Skeleton( 782 879 timestamp = timestamp, 783 880 leftShoulder = pose?.getPoseLandmark(PoseLandmark.LEFT_SHOULDER) 784 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 881 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 785 882 rightShoulder = pose?.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER) 786 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 883 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 787 884 leftElbow = pose?.getPoseLandmark(PoseLandmark.LEFT_ELBOW) 788 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 885 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 789 886 rightElbow = pose?.getPoseLandmark(PoseLandmark.RIGHT_ELBOW) 790 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 887 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 791 888 leftWrist = pose?.getPoseLandmark(PoseLandmark.LEFT_WRIST) 792 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 889 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 793 890 rightWrist = pose?.getPoseLandmark(PoseLandmark.RIGHT_WRIST) 794 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 891 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 795 892 leftHip = pose?.getPoseLandmark(PoseLandmark.LEFT_HIP) 796 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 893 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 797 894 rightHip = pose?.getPoseLandmark(PoseLandmark.RIGHT_HIP) 798 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 895 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 799 896 leftKnee = pose?.getPoseLandmark(PoseLandmark.LEFT_KNEE) 800 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 897 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 801 898 rightKnee = pose?.getPoseLandmark(PoseLandmark.RIGHT_KNEE) 802 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 899 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 803 900 leftAnkle = pose?.getPoseLandmark(PoseLandmark.LEFT_ANKLE) 804 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 901 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 805 902 rightAnkle = pose?.getPoseLandmark(PoseLandmark.RIGHT_ANKLE) 806 - ?.toSkeletonCoordsScaled(scaleX, scaleY), 903 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 904 + leftHeel = pose?.getPoseLandmark(PoseLandmark.LEFT_HEEL) 905 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 906 + rightHeel = pose?.getPoseLandmark(PoseLandmark.RIGHT_HEEL) 907 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 908 + leftToe = pose?.getPoseLandmark(PoseLandmark.LEFT_FOOT_INDEX) 909 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 910 + rightToe = pose?.getPoseLandmark(PoseLandmark.RIGHT_FOOT_INDEX) 911 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 912 + leftIndex = pose?.getPoseLandmark(PoseLandmark.LEFT_INDEX) 913 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 914 + rightIndex = pose?.getPoseLandmark(PoseLandmark.RIGHT_INDEX) 915 + ?.toSkeletonCoordsScaled(scaleX, scaleY, offsetX, offsetY), 807 916 width = width.toFloat(), 808 917 height = height.toFloat(), 809 918 )
+59 -18
posedetection/src/androidMain/kotlin/com/performancecoachlab/posedetection/custom/CustomObjectModel.android.kt
··· 22 22 if (modelPath.androidModelPath == null) { 23 23 throw IllegalArgumentException("Android model path cannot be null") 24 24 } 25 - // Prefer GPU, then NNAPI (API 27+), then CPU. 26 - val (options, gpuDelegate) = runCatching { 27 - val delegate = GpuDelegate() 28 - val opts = Interpreter.Options().apply { 29 - addDelegate(delegate) 30 - setNumThreads(2) 25 + // Default delegate is CPU+XNNPACK on Android. Measured on Samsung SM-A366B: 26 + // CPU+XNNPACK at 12.3 FPS object-only and 9.9 FPS both-mode BEAT GPU 27 + // (12.1 and 8.8 FPS respectively) because the GPU delegate only offloads 28 + // 26/685 YOLO26n ops and the CPU↔GPU roundtrip overhead dominates — plus 29 + // GPU contends with the pose pipeline in BOTH mode. See the delegate 30 + // section of collab/experiment_log.md for the full test. 31 + // 32 + // Override for experiments via `adb shell setprop debug.tflite.delegate 33 + // GPU|NNAPI|CPU`. Chosen path is logged. 34 + val requestedDelegate = runCatching { 35 + val cls = Class.forName("android.os.SystemProperties") 36 + val get = cls.getMethod("get", String::class.java, String::class.java) 37 + (get.invoke(null, "debug.tflite.delegate", "CPU") as? String).orEmpty() 38 + .uppercase().ifBlank { "CPU" } 39 + }.getOrElse { "CPU" } 40 + Logger.i { "TFLite: requestedDelegate=$requestedDelegate (debug.tflite.delegate)" } 41 + 42 + var selectedDelegate = "CPU" 43 + val (options, gpuDelegate) = when (requestedDelegate) { 44 + "CPU" -> { 45 + selectedDelegate = "CPU" 46 + // numThreads=3 (not 4) leaves ~3 cores for concurrent pose detection 47 + // in BOTH mode. With numThreads=4 and pose also multithreaded, the 48 + // 8-core Samsung oversubscribes and thermal-throttles within ~30s. 49 + Logger.i { "TFLite: forced CPU (no delegate, numThreads=3, XNNPACK on)" } 50 + Interpreter.Options().apply { 51 + setNumThreads(3) 52 + setUseXNNPACK(true) 53 + } to null 31 54 } 32 - Logger.d { "TFLite GPU delegate available" } 33 - opts to delegate 34 - }.onFailure { t -> 35 - Logger.w(t) { "TFLite GPU delegate not available; trying NNAPI" } 36 - }.getOrElse { 37 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 55 + "NNAPI" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 38 56 runCatching { 39 57 val nnapiDelegate = org.tensorflow.lite.nnapi.NnApiDelegate() 40 58 val opts = Interpreter.Options().apply { 41 59 addDelegate(nnapiDelegate) 42 60 setNumThreads(2) 43 61 } 44 - Logger.d { "TFLite NNAPI delegate available" } 62 + selectedDelegate = "NNAPI" 63 + Logger.i { "TFLite: NNAPI delegate constructed (forced)" } 45 64 opts to null 46 - }.onFailure { t -> 47 - Logger.w(t) { "TFLite NNAPI delegate not available; falling back to CPU" } 48 - }.getOrElse { 65 + }.getOrElse { t -> 66 + Logger.w(t) { "TFLite: NNAPI forced but unavailable; falling back to CPU" } 67 + selectedDelegate = "CPU" 49 68 Interpreter.Options().apply { setNumThreads(4) } to null 50 69 } 51 70 } else { 71 + selectedDelegate = "CPU" 72 + Logger.w { "TFLite: NNAPI requested but SDK too old; CPU" } 73 + Interpreter.Options().apply { setNumThreads(4) } to null 74 + } 75 + else -> runCatching { // GPU (default) 76 + val delegate = GpuDelegate() 77 + val opts = Interpreter.Options().apply { 78 + addDelegate(delegate) 79 + setNumThreads(2) 80 + } 81 + selectedDelegate = "GPU" 82 + Logger.i { "TFLite: GPU delegate constructed" } 83 + opts to delegate 84 + }.getOrElse { t -> 85 + Logger.w(t) { "TFLite: GPU unavailable; CPU" } 86 + selectedDelegate = "CPU" 52 87 Interpreter.Options().apply { setNumThreads(4) } to null 53 88 } 54 89 } ··· 59 94 val interpreter = runCatching { 60 95 Interpreter(model, options) 61 96 }.onFailure { t -> 62 - // If GPU interpreter creation fails, retry on CPU. 63 - Logger.w(t) { "TFLite GPU Failed to create GPU TFLite interpreter; retrying on CPU" } 97 + // If the chosen delegate can't actually build an interpreter (common 98 + // for GPU on models with unsupported ops), fall back to pure CPU. 99 + Logger.w(t) { "TFLite: failed to create interpreter with $selectedDelegate delegate; retrying on CPU" } 64 100 gpuDelegate?.close() 101 + selectedDelegate = "CPU" 65 102 }.getOrElse { 66 103 val cpuOptions = Interpreter.Options().apply { setNumThreads(4) } 67 104 Interpreter(model, cpuOptions) ··· 69 106 70 107 val inputShape = interpreter.getInputTensor(0)?.shape() 71 108 val outputShape = interpreter.getOutputTensor(0)?.shape() 109 + Logger.i { 110 + "TFLite: model='${modelPath.androidModelPath}' delegate=$selectedDelegate " + 111 + "inputShape=${inputShape?.toList()} outputShape=${outputShape?.toList()}" 112 + } 72 113 val modelInfo = ModelInfo.fromShapes( 73 114 inputShape = inputShape 74 115 ?: throw IllegalArgumentException("Invalid model: input shape is null"),
+150
posedetection/src/androidMain/kotlin/com/performancecoachlab/posedetection/custom/ImageDetector.android.kt
··· 1 + package com.performancecoachlab.posedetection.custom 2 + 3 + import android.graphics.Bitmap 4 + import android.graphics.Canvas 5 + import android.graphics.Color 6 + import android.graphics.Paint 7 + import android.graphics.RectF 8 + import androidx.compose.ui.geometry.Rect 9 + import androidx.compose.ui.graphics.ImageBitmap 10 + import androidx.compose.ui.graphics.asAndroidBitmap 11 + import co.touchlab.kermit.Logger 12 + import com.performancecoachlab.posedetection.camera.label 13 + import com.performancecoachlab.posedetection.recording.AnalysisObject 14 + import com.performancecoachlab.posedetection.recording.FrameSize 15 + import com.performancecoachlab.posedetection.recording.Label 16 + import org.tensorflow.lite.DataType 17 + import org.tensorflow.lite.support.common.ops.CastOp 18 + import org.tensorflow.lite.support.common.ops.NormalizeOp 19 + import org.tensorflow.lite.support.image.ImageProcessor 20 + import org.tensorflow.lite.support.image.TensorImage 21 + import org.tensorflow.lite.support.tensorbuffer.TensorBuffer 22 + import kotlin.math.absoluteValue 23 + import kotlin.math.max 24 + import kotlin.math.min 25 + import kotlin.math.roundToInt 26 + 27 + actual class ImageDetector actual constructor(model: ObjectModel) { 28 + 29 + private val detector: AndroidDetector? = model.getDetector() 30 + 31 + private val imageProcessor = ImageProcessor.Builder() 32 + .add(NormalizeOp(0f, 255f)) 33 + .add(CastOp(DataType.FLOAT32)) 34 + .build() 35 + 36 + actual fun detect(image: ImageBitmap): List<AnalysisObject> { 37 + val det = detector ?: return emptyList() 38 + val info = det.modelInfo 39 + val inputW = info.inputWidth 40 + val inputH = info.inputHeight 41 + if (inputW <= 0 || inputH <= 0) return emptyList() 42 + 43 + val srcBitmap = image.asAndroidBitmap().let { bmp -> 44 + if (bmp.config == Bitmap.Config.ARGB_8888) bmp 45 + else bmp.copy(Bitmap.Config.ARGB_8888, false) 46 + } 47 + val imgW = srcBitmap.width 48 + val imgH = srcBitmap.height 49 + 50 + // Letterbox: scale the source to fit inside (inputW, inputH) while 51 + // preserving aspect ratio, center it, and pad the remainder with 52 + // gray 114 — matching ultralytics training-time preprocessing. 53 + // (A naive stretch-resize destroys aspect ratio and hurts detection 54 + // quality on non-square camera frames.) 55 + val scale = min( 56 + inputW.toFloat() / imgW.toFloat(), 57 + inputH.toFloat() / imgH.toFloat() 58 + ) 59 + val scaledW = (imgW * scale).roundToInt().coerceAtLeast(1) 60 + val scaledH = (imgH * scale).roundToInt().coerceAtLeast(1) 61 + val padX = (inputW - scaledW) / 2f 62 + val padY = (inputH - scaledH) / 2f 63 + 64 + val resized = Bitmap.createBitmap(inputW, inputH, Bitmap.Config.ARGB_8888) 65 + val canvas = Canvas(resized) 66 + canvas.drawColor(Color.rgb(114, 114, 114)) 67 + canvas.drawBitmap( 68 + srcBitmap, null, 69 + RectF(padX, padY, padX + scaledW, padY + scaledH), 70 + Paint(Paint.FILTER_BITMAP_FLAG) 71 + ) 72 + 73 + // Normalize and convert to tensor 74 + val tensorImage = TensorImage(DataType.FLOAT32).also { it.load(resized) } 75 + .let(imageProcessor::process) 76 + 77 + // Run inference 78 + val outputShape = info.outputShape 79 + val output = TensorBuffer.createFixedSize(outputShape, DataType.FLOAT32) 80 + try { 81 + det.interpreter.run(tensorImage.buffer, output.buffer) 82 + } catch (e: Exception) { 83 + Logger.e(e) { "ImageDetector: interpreter.run failed" } 84 + return emptyList() 85 + } 86 + 87 + // Parse output 88 + val array = output.floatArray 89 + if (outputShape.size != 3) return emptyList() 90 + 91 + val dim1 = outputShape[1] 92 + val dim2 = outputShape[2] 93 + 94 + val elements: Int 95 + val channels: Int 96 + val isElementsFirst: Boolean 97 + 98 + when { 99 + dim2 == 6 -> { elements = dim1; channels = dim2; isElementsFirst = true } 100 + dim1 == 6 -> { channels = dim1; elements = dim2; isElementsFirst = false } 101 + else -> return emptyList() 102 + } 103 + 104 + fun valueAt(elementIndex: Int, channelIndex: Int): Float { 105 + return if (isElementsFirst) array[elementIndex * channels + channelIndex] 106 + else array[channelIndex * elements + elementIndex] 107 + } 108 + 109 + val imgWF = imgW.toFloat() 110 + val imgHF = imgH.toFloat() 111 + 112 + return (0 until elements).mapNotNull { i -> 113 + val cnf = valueAt(i, 4) 114 + if (cnf > 0.25f) { 115 + val x1 = valueAt(i, 0) 116 + val y1 = valueAt(i, 1) 117 + val x2 = valueAt(i, 2) 118 + val y2 = valueAt(i, 3) 119 + val cls = valueAt(i, 5).toInt() 120 + 121 + // Model outputs are normalized [0,1] over the letterboxed 122 + // input (inputW × inputH). Un-letterbox: convert to 123 + // letterboxed pixel coords, subtract padding, divide by 124 + // the fit ratio to get original-image pixel coords. 125 + val x1pLb = min(x1, x2) * inputW 126 + val y1pLb = min(y1, y2) * inputH 127 + val x2pLb = max(x1, x2) * inputW 128 + val y2pLb = max(y1, y2) * inputH 129 + 130 + val left = ((x1pLb - padX) / scale).coerceIn(0f, imgWF) 131 + val top = ((y1pLb - padY) / scale).coerceIn(0f, imgHF) 132 + val right = ((x2pLb - padX) / scale).coerceIn(0f, imgWF) 133 + val bottom = ((y2pLb - padY) / scale).coerceIn(0f, imgHF) 134 + 135 + AnalysisObject( 136 + boundingBox = Rect( 137 + left = left, 138 + top = top, 139 + right = right, 140 + bottom = bottom 141 + ), 142 + trackingId = 0, 143 + labels = listOf(Label(info.label(cls), cnf)), 144 + frameSize = FrameSize(width = imgW.absoluteValue, height = imgH.absoluteValue), 145 + timestamp = 0L 146 + ) 147 + } else null 148 + } 149 + } 150 + }
+2 -2
posedetection/src/androidMain/kotlin/com/performancecoachlab/posedetection/recording/InputFrame.android.kt
··· 10 10 import co.touchlab.kermit.Logger 11 11 import com.google.mlkit.vision.common.InputImage 12 12 import com.google.mlkit.vision.pose.PoseDetection 13 - import com.google.mlkit.vision.pose.defaults.PoseDetectorOptions 13 + import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions 14 14 import com.performancecoachlab.posedetection.camera.applyFocusAreaMaskPooled 15 15 import com.performancecoachlab.posedetection.camera.drawAnalysisResults 16 16 import com.performancecoachlab.posedetection.camera.drawSkeleton ··· 63 63 64 64 actual class FrameAnalyser actual constructor(val model: ObjectModel?) { 65 65 private val options = 66 - PoseDetectorOptions.Builder().setDetectorMode(PoseDetectorOptions.STREAM_MODE).build() 66 + AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build() 67 67 private val poseDetector = PoseDetection.getClient(options) 68 68 private val objDetector = model?.getDetector() 69 69
+40
posedetection/src/commonMain/kotlin/com/performancecoachlab/posedetection/camera/CameraView.kt
··· 30 30 FILL 31 31 } 32 32 33 + /** 34 + * How the focus area is applied to the pose input. 35 + * 36 + * MASK — black out everything outside the focus area, then downscale the full 37 + * frame. Object detection is unaffected (it always sees the unmasked frame). 38 + * On iOS this is implemented as a post-filter only (Vision's body-pose model 39 + * already picks the most-confident body, so the pixel-level mask is omitted). 40 + * 41 + * CROP — crop the frame to the focus area, then downscale only the crop. Gives 42 + * the pose model higher effective resolution of the focus region at the same 43 + * downscaled side length. Landmarks are remapped back to full-frame coords. 44 + * 45 + * CROP_FOLLOW — starts in the static focus area; once a confident full 46 + * skeleton lands, tightens the next crop to the skeleton's bbox (with a small 47 + * buffer) so the model sees the player at even higher effective resolution. 48 + * Reverts to the static focus area whenever the skeleton is lost, clipped, or 49 + * stale — so a jogger walking out of frame doesn't strand the tracker. 50 + */ 51 + enum class PoseFocusMode { MASK, CROP, CROP_FOLLOW } 52 + 33 53 @Composable 34 54 expect fun CameraView( 35 55 skeletonRepository: SkeletonRepository, ··· 46 66 previewFillMode: PreviewFillMode = PreviewFillMode.FILL, 47 67 recordingId: String? = null, 48 68 focusArea: Rect? = null, 69 + poseFocusMode: PoseFocusMode = PoseFocusMode.CROP, 49 70 controller: CameraViewController? = null, 50 71 onRecordToggled: (Boolean) -> Unit = {}, 51 72 onVideoSaved: (String, String) -> Unit ··· 76 97 interface CameraViewController { 77 98 fun requestData(onResult: (CameraViewData) -> Unit) 78 99 fun setRequestDataProvider(provider: (() -> CameraViewData)?) 100 + 101 + // Save the current camera frame composited with the drawn skeleton/object 102 + // overlay as a PNG into the app's Documents directory. Returns the file 103 + // path (or null if unavailable). Currently iOS-only; Android no-ops. 104 + fun captureComposite(filename: String, onResult: (String?) -> Unit) {} 105 + fun setCaptureCompositeProvider(provider: ((String, (String?) -> Unit) -> Unit)?) {} 79 106 } 80 107 81 108 class CameraViewControllerImpl : CameraViewController { 82 109 private var dataProvider: (() -> CameraViewData)? = null 110 + private var compositeProvider: ((String, (String?) -> Unit) -> Unit)? = null 111 + 83 112 override fun requestData(onResult: (CameraViewData) -> Unit) { 84 113 dataProvider?.let { onResult(it()) } 85 114 } 86 115 87 116 override fun setRequestDataProvider(provider: (() -> CameraViewData)?) { 88 117 dataProvider = provider 118 + } 119 + 120 + override fun captureComposite(filename: String, onResult: (String?) -> Unit) { 121 + val p = compositeProvider 122 + if (p != null) p(filename, onResult) else onResult(null) 123 + } 124 + 125 + override fun setCaptureCompositeProvider( 126 + provider: ((String, (String?) -> Unit) -> Unit)? 127 + ) { 128 + compositeProvider = provider 89 129 } 90 130 }
+137
posedetection/src/commonMain/kotlin/com/performancecoachlab/posedetection/camera/PoseTracking.kt
··· 1 + package com.performancecoachlab.posedetection.camera 2 + 3 + import androidx.compose.ui.geometry.Rect 4 + import com.performancecoachlab.posedetection.skeleton.Skeleton 5 + import kotlin.concurrent.Volatile 6 + 7 + // Drop landmarks whose detector-reported confidence is below this threshold — 8 + // keeps obvious phantoms (occluded joints guessed with low conf) out of 9 + // downstream. Calibrated against MLKit's inFrameLikelihood on Android; Vision's 10 + // VNRecognizedPoint.confidence is a close analogue on iOS. 11 + const val LANDMARK_CONF_THRESHOLD: Float = 0.5f 12 + 13 + // Tight-rect tracking: once a confident full skeleton is detected, remember its 14 + // bbox (padded) so the next frame crops tightly around it. Reset when the 15 + // skeleton is lost, comes back partial for MISS_TOLERANCE frames in a row, or 16 + // goes stale past TIMEOUT_MS. 17 + // 18 + // Lifted from the Android singleton into a class so each FrameProcessor owns 19 + // its own tracker (safer for any future multi-camera / multi-view setup). 20 + // 21 + // Thread-safety: on Android the updater runs on the pose executor and the 22 + // reader runs on the image-analyzer executor; on iOS everything runs on 23 + // `frameProcessingQueue`. `@Volatile` gives us visibility across threads 24 + // without a lock — the worst-case race is reading a one-frame-stale tightRect, 25 + // which the TIMEOUT_MS path already handles. 26 + class FollowCropState { 27 + private val padFraction: Float = 0.5f 28 + private val minNormalizedSide: Float = 0.25f 29 + private val missTolerance: Int = 2 30 + private val timeoutMs: Long = 500L 31 + 32 + @Volatile private var tightRect: Rect? = null 33 + @Volatile private var lastUpdatedMs: Long = 0L 34 + @Volatile private var consecutiveMisses: Int = 0 35 + 36 + fun current(nowMs: Long): Rect? { 37 + if (nowMs - lastUpdatedMs > timeoutMs) { 38 + tightRect = null 39 + consecutiveMisses = 0 40 + } 41 + return tightRect 42 + } 43 + 44 + fun reset() { 45 + tightRect = null 46 + consecutiveMisses = 0 47 + } 48 + 49 + /** 50 + * Called after each pose inference. Skeleton coords are in analysis-frame 51 + * pixel space; [clampTo] is the static user-configured focus area in 0..1. 52 + */ 53 + fun updateFromSkeleton( 54 + skeleton: Skeleton?, 55 + analysisW: Int, 56 + analysisH: Int, 57 + clampTo: Rect, 58 + nowMs: Long, 59 + ) { 60 + val joints = skeleton?.joints().orEmpty() 61 + if (joints.size < 12) { 62 + consecutiveMisses += 1 63 + if (consecutiveMisses >= missTolerance) { 64 + tightRect = null 65 + consecutiveMisses = 0 66 + } 67 + return 68 + } 69 + consecutiveMisses = 0 70 + val w = analysisW.toFloat() 71 + val h = analysisH.toFloat() 72 + if (w <= 0f || h <= 0f) { 73 + tightRect = null 74 + return 75 + } 76 + val minX = joints.minOf { it.x } 77 + val minY = joints.minOf { it.y } 78 + val maxX = joints.maxOf { it.x } 79 + val maxY = joints.maxOf { it.y } 80 + val padW = (maxX - minX) * padFraction 81 + val padH = (maxY - minY) * padFraction 82 + var l = (minX - padW) / w 83 + var t = (minY - padH) / h 84 + var r = (maxX + padW) / w 85 + var b = (maxY + padH) / h 86 + val cx = (l + r) / 2f 87 + val cy = (t + b) / 2f 88 + if (r - l < minNormalizedSide) { 89 + l = cx - minNormalizedSide / 2f 90 + r = cx + minNormalizedSide / 2f 91 + } 92 + if (b - t < minNormalizedSide) { 93 + t = cy - minNormalizedSide / 2f 94 + b = cy + minNormalizedSide / 2f 95 + } 96 + l = l.coerceIn(clampTo.left, clampTo.right) 97 + t = t.coerceIn(clampTo.top, clampTo.bottom) 98 + r = r.coerceIn(clampTo.left, clampTo.right) 99 + b = b.coerceIn(clampTo.top, clampTo.bottom) 100 + if (r - l > 0.01f && b - t > 0.01f) { 101 + tightRect = Rect(l, t, r, b) 102 + lastUpdatedMs = nowMs 103 + } else { 104 + tightRect = null 105 + } 106 + } 107 + } 108 + 109 + // Temporal EMA smoother. Reduces jitter during fast shot motion. α is the 110 + // weight on the new frame; (1-α) on the previous. Reset after a long gap so a 111 + // re-acquired pose doesn't inherit a stale position from where the shooter 112 + // used to be. 113 + class PoseSmoother { 114 + private val alpha: Float = 0.6f 115 + private val gapMs: Long = 500L 116 + 117 + @Volatile private var last: Skeleton? = null 118 + @Volatile private var lastWallMs: Long = 0L 119 + 120 + fun smooth(skel: Skeleton?, timestamp: Long): Skeleton? { 121 + if (skel == null) { 122 + if (timestamp - lastWallMs > gapMs) last = null 123 + return null 124 + } 125 + val prev = last 126 + val gapOk = (timestamp - lastWallMs) <= gapMs 127 + val out = if (prev != null && gapOk) Skeleton.lerp(prev, skel, alpha) else skel 128 + last = out 129 + lastWallMs = timestamp 130 + return out 131 + } 132 + 133 + fun reset() { 134 + last = null 135 + lastWallMs = 0L 136 + } 137 + }
+14 -30
posedetection/src/commonMain/kotlin/com/performancecoachlab/posedetection/camera/Utils.kt
··· 170 170 } 171 171 } 172 172 skeleton?.apply { 173 - val paintWhite = Paint().apply { 174 - color = Color.White 175 - strokeWidth = scaledStrokeWidth 176 - style = Stroke 177 - } 178 - val paintBlue = Paint().apply { 179 - color = Color.Blue 180 - strokeWidth = 0.8f * scaledStrokeWidth 181 - style = Fill 182 - } 173 + // Crisp solid rendering matching Android. Previously used 174 + // BlendMode.Softlight/Color on bones and a radialGradient on 175 + // joints, both of which produced a washed-out/fuzzy look. 176 + // Stroke + joint radius both at 1/3 of the adaptive base — the 177 + // original thickness felt chunky compared to Android. 178 + val boneWidth = scaledStrokeWidth / 3f 179 + val jointRadius = 0.9f * scaledStrokeWidth / 3f 183 180 bones().forEach { line -> 184 181 drawLine( 185 - color = paintWhite.color, start = androidx.compose.ui.geometry.Offset( 186 - line.first.x, line.first.y 187 - ), end = androidx.compose.ui.geometry.Offset( 188 - line.second.x, line.second.y 189 - ), strokeWidth = paintWhite.strokeWidth, blendMode = BlendMode.Softlight 190 - ) 191 - drawLine( 192 - color = paintBlue.color, start = androidx.compose.ui.geometry.Offset( 193 - line.first.x, line.first.y 194 - ), end = androidx.compose.ui.geometry.Offset( 195 - line.second.x, line.second.y 196 - ), strokeWidth = paintBlue.strokeWidth, blendMode = BlendMode.Color 182 + color = Color.White, 183 + start = androidx.compose.ui.geometry.Offset(line.first.x, line.first.y), 184 + end = androidx.compose.ui.geometry.Offset(line.second.x, line.second.y), 185 + strokeWidth = boneWidth, 197 186 ) 198 187 } 199 - 200 188 joints().forEach { joint -> 201 189 drawCircle( 202 - brush = Brush.radialGradient( 203 - colors = listOf(Color.Blue, Color.Transparent), 204 - center = androidx.compose.ui.geometry.Offset(joint.x, joint.y), 205 - radius = 1.2f * scaledStrokeWidth 206 - ), 207 - radius = 1.2f * scaledStrokeWidth, 208 - center = androidx.compose.ui.geometry.Offset(joint.x, joint.y) 190 + color = Color.Blue, 191 + radius = jointRadius, 192 + center = androidx.compose.ui.geometry.Offset(joint.x, joint.y), 209 193 ) 210 194 } 211 195 }
+8
posedetection/src/commonMain/kotlin/com/performancecoachlab/posedetection/custom/ImageDetector.kt
··· 1 + package com.performancecoachlab.posedetection.custom 2 + 3 + import androidx.compose.ui.graphics.ImageBitmap 4 + import com.performancecoachlab.posedetection.recording.AnalysisObject 5 + 6 + expect class ImageDetector(model: ObjectModel) { 7 + fun detect(image: ImageBitmap): List<AnalysisObject> 8 + }
+40
posedetection/src/commonMain/kotlin/com/performancecoachlab/posedetection/skeleton/Skeleton.kt
··· 18 18 val rightKnee: SkeletonCoordinate? = null, 19 19 val leftAnkle: SkeletonCoordinate? = null, 20 20 val rightAnkle: SkeletonCoordinate? = null, 21 + val leftHeel: SkeletonCoordinate? = null, 22 + val rightHeel: SkeletonCoordinate? = null, 23 + val leftToe: SkeletonCoordinate? = null, 24 + val rightToe: SkeletonCoordinate? = null, 25 + val leftIndex: SkeletonCoordinate? = null, 26 + val rightIndex: SkeletonCoordinate? = null, 21 27 val width: Float, 22 28 val height: Float, 23 29 ) { ··· 65 71 rightKnee = lerpCoord(a.rightKnee, b.rightKnee, t), 66 72 leftAnkle = lerpCoord(a.leftAnkle, b.leftAnkle, t), 67 73 rightAnkle = lerpCoord(a.rightAnkle, b.rightAnkle, t), 74 + leftHeel = lerpCoord(a.leftHeel, b.leftHeel, t), 75 + rightHeel = lerpCoord(a.rightHeel, b.rightHeel, t), 76 + leftToe = lerpCoord(a.leftToe, b.leftToe, t), 77 + rightToe = lerpCoord(a.rightToe, b.rightToe, t), 78 + leftIndex = lerpCoord(a.leftIndex, b.leftIndex, t), 79 + rightIndex = lerpCoord(a.rightIndex, b.rightIndex, t), 68 80 width = a.width, 69 81 height = a.height, 70 82 ) ··· 88 100 if (rightHip != null && rightKnee != null) lines += Pair(rightHip, rightKnee) 89 101 if (leftKnee != null && leftAnkle != null) lines += Pair(leftKnee, leftAnkle) 90 102 if (rightKnee != null && rightAnkle != null) lines += Pair(rightKnee, rightAnkle) 103 + // Feet: ankle → heel → toe, closed by ankle → toe 104 + if (leftAnkle != null && leftHeel != null) lines += Pair(leftAnkle, leftHeel) 105 + if (rightAnkle != null && rightHeel != null) lines += Pair(rightAnkle, rightHeel) 106 + if (leftHeel != null && leftToe != null) lines += Pair(leftHeel, leftToe) 107 + if (rightHeel != null && rightToe != null) lines += Pair(rightHeel, rightToe) 108 + if (leftAnkle != null && leftToe != null) lines += Pair(leftAnkle, leftToe) 109 + if (rightAnkle != null && rightToe != null) lines += Pair(rightAnkle, rightToe) 110 + // Hands: wrist → index finger 111 + if (leftWrist != null && leftIndex != null) lines += Pair(leftWrist, leftIndex) 112 + if (rightWrist != null && rightIndex != null) lines += Pair(rightWrist, rightIndex) 91 113 return lines.toList() 92 114 } 93 115 ··· 105 127 if (rightKnee != null) joints += rightKnee 106 128 if (leftAnkle != null) joints += leftAnkle 107 129 if (rightAnkle != null) joints += rightAnkle 130 + if (leftHeel != null) joints += leftHeel 131 + if (rightHeel != null) joints += rightHeel 132 + if (leftToe != null) joints += leftToe 133 + if (rightToe != null) joints += rightToe 134 + if (leftIndex != null) joints += leftIndex 135 + if (rightIndex != null) joints += rightIndex 108 136 return joints.toList() 109 137 } 110 138 ··· 204 232 rightKnee = rightKnee?.let { SkeletonCoordinate(w - it.x, it.y) }, 205 233 leftAnkle = leftAnkle?.let { SkeletonCoordinate(w - it.x, it.y) }, 206 234 rightAnkle = rightAnkle?.let { SkeletonCoordinate(w - it.x, it.y) }, 235 + leftHeel = leftHeel?.let { SkeletonCoordinate(w - it.x, it.y) }, 236 + rightHeel = rightHeel?.let { SkeletonCoordinate(w - it.x, it.y) }, 237 + leftToe = leftToe?.let { SkeletonCoordinate(w - it.x, it.y) }, 238 + rightToe = rightToe?.let { SkeletonCoordinate(w - it.x, it.y) }, 239 + leftIndex = leftIndex?.let { SkeletonCoordinate(w - it.x, it.y) }, 240 + rightIndex = rightIndex?.let { SkeletonCoordinate(w - it.x, it.y) }, 207 241 width = width, 208 242 height = height, 209 243 ) ··· 244 278 rightKnee = rightKnee?.let(transform), 245 279 leftAnkle = leftAnkle?.let(transform), 246 280 rightAnkle = rightAnkle?.let(transform), 281 + leftHeel = leftHeel?.let(transform), 282 + rightHeel = rightHeel?.let(transform), 283 + leftToe = leftToe?.let(transform), 284 + rightToe = rightToe?.let(transform), 285 + leftIndex = leftIndex?.let(transform), 286 + rightIndex = rightIndex?.let(transform), 247 287 width = newDimensions.first, 248 288 height = newDimensions.second 249 289 )
+203
posedetection/src/iosArm64Main/kotlin/com/performancecoachlab/posedetection/camera/MlKitPose.kt
··· 1 + package com.performancecoachlab.posedetection.camera 2 + 3 + import cocoapods.MLKitPoseDetectionAccurate.MLKAccuratePoseDetectorOptions 4 + import cocoapods.MLKitPoseDetectionAccurate.MLKCommonPoseDetectorOptions 5 + import cocoapods.MLKitPoseDetectionAccurate.MLKPose 6 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseDetector 7 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseDetectorModeStream 8 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkType 9 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftAnkle 10 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftElbow 11 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftHeel 12 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftHip 13 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftIndexFinger 14 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftKnee 15 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftShoulder 16 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftToe 17 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeLeftWrist 18 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightAnkle 19 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightElbow 20 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightHeel 21 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightHip 22 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightIndexFinger 23 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightKnee 24 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightShoulder 25 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightToe 26 + import cocoapods.MLKitPoseDetectionAccurate.MLKPoseLandmarkTypeRightWrist 27 + import cocoapods.MLKitPoseDetectionAccurate.MLKVisionImage 28 + import cocoapods.MLKitPoseDetectionAccurate.MLKVisionPoint 29 + import com.performancecoachlab.posedetection.skeleton.Skeleton 30 + import kotlinx.cinterop.ExperimentalForeignApi 31 + import kotlinx.cinterop.ObjCObjectVar 32 + import kotlinx.cinterop.alloc 33 + import kotlinx.cinterop.memScoped 34 + import kotlinx.cinterop.ptr 35 + import kotlinx.cinterop.useContents 36 + import platform.CoreGraphics.CGImageRelease 37 + import platform.CoreGraphics.CGRectMake 38 + import platform.CoreImage.CIContext 39 + import platform.CoreImage.CIImage 40 + import platform.CoreImage.createCGImage 41 + import platform.CoreVideo.CVImageBufferRef 42 + import platform.Foundation.NSError 43 + import platform.UIKit.UIImage 44 + 45 + @OptIn(ExperimentalForeignApi::class) 46 + internal actual class MlKitPose actual constructor() { 47 + // CIContext is expensive; reuse across frames. 48 + private val ciContext: CIContext = CIContext.contextWithOptions(null) 49 + 50 + // Accurate-model, stream-mode detector — same config as Android. 51 + // Created lazily because the model loads on first use. 52 + private val detector: MLKPoseDetector by lazy { 53 + val options = MLKAccuratePoseDetectorOptions().apply { 54 + setDetectorMode(MLKPoseDetectorModeStream) 55 + } 56 + @Suppress("UNCHECKED_CAST") 57 + MLKPoseDetector.poseDetectorWithOptions( 58 + options as MLKCommonPoseDetectorOptions 59 + ) 60 + } 61 + 62 + actual fun isAvailable(): Boolean = true 63 + 64 + actual fun detect( 65 + buffer: CVImageBufferRef, 66 + exifOrientation: Int, 67 + orientedW: Float, 68 + orientedH: Float, 69 + useCrop: Boolean, 70 + cropLeftPx: Float, 71 + cropTopPx: Float, 72 + cropWPx: Float, 73 + cropHPx: Float, 74 + timestamp: Long, 75 + ): Skeleton? { 76 + // Extract MLKit's resource bundles from Compose MP resources to 77 + // Caches and point the NSBundle swizzle at them — so MLKit finds 78 + // its .tflite / .binarypb files without any app-bundle build-phase 79 + // script on the consumer side. 80 + MlKitResourceBootstrap.ensureInitialized() 81 + 82 + // Pre-rotate the pixels so the CGImage handed to MLKit is already 83 + // physically upright at oriented (logical/display) dimensions. MLKit 84 + // returns landmarks in the input CGImage's raw pixel space, so when 85 + // raw == oriented, landmarks land in the same oriented top-left pixel 86 + // space the rest of the library works in — no post-hoc remapping, 87 + // no UIImage/MLKVisionImage orientation juggling. 88 + val ciRaw = CIImage.imageWithCVPixelBuffer(buffer) ?: return null 89 + val ciOriented: CIImage = ciRaw.imageByApplyingOrientation(exifOrientation) 90 + 91 + // Rotated extent may have a non-zero origin depending on orientation. 92 + // Read the actual values so our render rect aligns with the pixels. 93 + var eOriginX = 0f 94 + var eOriginY = 0f 95 + var eW = 0f 96 + var eH = 0f 97 + ciOriented.extent.useContents { 98 + eOriginX = origin.x.toFloat() 99 + eOriginY = origin.y.toFloat() 100 + eW = size.width.toFloat() 101 + eH = size.height.toFloat() 102 + } 103 + 104 + // Compute the render rect in CIImage (bottom-left origin, absolute) 105 + // coords, anchored at the extent origin. 106 + val renderRect = if (useCrop) { 107 + // cropLeftPx / cropTopPx / cropWPx / cropHPx arrive in oriented 108 + // top-left space; flip Y into CIImage bottom-left space and shift 109 + // by the extent origin. 110 + CGRectMake( 111 + x = (eOriginX + cropLeftPx).toDouble(), 112 + y = (eOriginY + (eH - cropTopPx - cropHPx)).toDouble(), 113 + width = cropWPx.toDouble(), 114 + height = cropHPx.toDouble(), 115 + ) 116 + } else { 117 + CGRectMake( 118 + x = eOriginX.toDouble(), 119 + y = eOriginY.toDouble(), 120 + width = eW.toDouble(), 121 + height = eH.toDouble(), 122 + ) 123 + } 124 + val ciForRender = if (useCrop) ciOriented.imageByCroppingToRect(renderRect) else ciOriented 125 + val cgImage = ciContext.createCGImage(ciForRender, renderRect) ?: return null 126 + 127 + return try { 128 + // Plain UIImage with default .up orientation — we already rotated. 129 + val uiImage = UIImage(cgImage) 130 + val visionImage = MLKVisionImage(image = uiImage) 131 + // Leave visionImage.orientation at default .up. Setting it (or 132 + // giving the UIImage non-.up orientation metadata) either 133 + // double-rotates or leaves MLKit producing landmarks in a 134 + // different coord space from ours. 135 + 136 + val pose = memScoped { 137 + val errPtr = alloc<ObjCObjectVar<NSError?>>() 138 + @Suppress("UNCHECKED_CAST") 139 + val poses = detector.resultsInImage( 140 + visionImage as objcnames.protocols.MLKCompatibleImageProtocol, 141 + errPtr.ptr, 142 + ) as? List<MLKPose> 143 + poses?.firstOrNull() 144 + } ?: return null 145 + buildSkeletonFromPose( 146 + pose = pose, 147 + timestamp = timestamp, 148 + orientedW = orientedW, 149 + orientedH = orientedH, 150 + useCrop = useCrop, 151 + cropLeftPx = cropLeftPx, 152 + cropTopPx = cropTopPx, 153 + ) 154 + } finally { 155 + CGImageRelease(cgImage) 156 + } 157 + } 158 + 159 + private fun buildSkeletonFromPose( 160 + pose: MLKPose, 161 + timestamp: Long, 162 + orientedW: Float, 163 + orientedH: Float, 164 + useCrop: Boolean, 165 + cropLeftPx: Float, 166 + cropTopPx: Float, 167 + ): Skeleton { 168 + fun c(type: MLKPoseLandmarkType): Skeleton.SkeletonCoordinate? { 169 + val lm = pose.landmarkOfType(type) 170 + if (lm.inFrameLikelihood < LANDMARK_CONF_THRESHOLD) return null 171 + // MLKit returns pixel coords in the input image space. Because we 172 + // pre-rotated, that == oriented top-left space for MASK, or crop- 173 + // local for CROP. Add the crop offset to reach oriented full frame. 174 + val pos = lm.position as MLKVisionPoint 175 + val x = if (useCrop) cropLeftPx + pos.x.toFloat() else pos.x.toFloat() 176 + val y = if (useCrop) cropTopPx + pos.y.toFloat() else pos.y.toFloat() 177 + return Skeleton.SkeletonCoordinate(x, y) 178 + } 179 + return Skeleton( 180 + timestamp = timestamp, 181 + leftShoulder = c(MLKPoseLandmarkTypeLeftShoulder), 182 + rightShoulder = c(MLKPoseLandmarkTypeRightShoulder), 183 + leftElbow = c(MLKPoseLandmarkTypeLeftElbow), 184 + rightElbow = c(MLKPoseLandmarkTypeRightElbow), 185 + leftWrist = c(MLKPoseLandmarkTypeLeftWrist), 186 + rightWrist = c(MLKPoseLandmarkTypeRightWrist), 187 + leftHip = c(MLKPoseLandmarkTypeLeftHip), 188 + rightHip = c(MLKPoseLandmarkTypeRightHip), 189 + leftKnee = c(MLKPoseLandmarkTypeLeftKnee), 190 + rightKnee = c(MLKPoseLandmarkTypeRightKnee), 191 + leftAnkle = c(MLKPoseLandmarkTypeLeftAnkle), 192 + rightAnkle = c(MLKPoseLandmarkTypeRightAnkle), 193 + leftHeel = c(MLKPoseLandmarkTypeLeftHeel), 194 + rightHeel = c(MLKPoseLandmarkTypeRightHeel), 195 + leftToe = c(MLKPoseLandmarkTypeLeftToe), 196 + rightToe = c(MLKPoseLandmarkTypeRightToe), 197 + leftIndex = c(MLKPoseLandmarkTypeLeftIndexFinger), 198 + rightIndex = c(MLKPoseLandmarkTypeRightIndexFinger), 199 + height = orientedH, 200 + width = orientedW, 201 + ) 202 + } 203 + }
+97
posedetection/src/iosArm64Main/kotlin/com/performancecoachlab/posedetection/camera/MlKitResourceBootstrap.kt
··· 1 + package com.performancecoachlab.posedetection.camera 2 + 3 + import cocoapods.MLKitPoseDetectionAccurate.mlkit_set_resource_dir 4 + import kotlinx.cinterop.ExperimentalForeignApi 5 + import kotlinx.cinterop.addressOf 6 + import kotlinx.cinterop.usePinned 7 + import kotlinx.coroutines.runBlocking 8 + import org.jetbrains.compose.resources.ExperimentalResourceApi 9 + import org.jetbrains.compose.resources.InternalResourceApi 10 + import posedetection.posedetection.generated.resources.Res 11 + import platform.Foundation.NSData 12 + import platform.Foundation.NSFileManager 13 + import platform.Foundation.NSURL 14 + import platform.Foundation.NSURL.Companion.fileURLWithPath 15 + import platform.Foundation.NSUserDomainMask 16 + import platform.Foundation.NSCachesDirectory 17 + import platform.Foundation.create 18 + import platform.Foundation.writeToFile 19 + 20 + /** 21 + * One-time bootstrap: extracts MLKit's bundled resource files (packaged into 22 + * the library's Compose Multiplatform resources by Gradle's 23 + * `stageMlkitResources` task) to the app's Caches directory, then registers 24 + * that path with the NSBundle swizzle (via `mlkit_set_resource_dir`). From 25 + * that point on, MLKit's `[NSBundle URLForResource:withExtension:]` calls for 26 + * its resource bundles fall back to the Caches copy, so the consumer's iOS 27 + * app bundle doesn't need any build-phase script to copy them in. 28 + * 29 + * Intentionally synchronous at first call — runBlocking lets us stay inside 30 + * the FrameProcessor's non-suspending captureOutput pipeline. The extraction 31 + * is ~9 MB and happens once. 32 + */ 33 + @OptIn(ExperimentalForeignApi::class, ExperimentalResourceApi::class, InternalResourceApi::class) 34 + internal object MlKitResourceBootstrap { 35 + // Matches the sub-tree Gradle's stageMlkitResources produces under 36 + // build/mlkit-compose-resources/files/mlkit/... 37 + private val BUNDLE_FILES: Map<String, List<String>> = mapOf( 38 + "MLKitPoseDetectionAccurateResources" to listOf( 39 + "pose_landmark_detector_accurate.tflite", 40 + "pose_person_detector_accurate.tflite", 41 + ), 42 + "MLKitPoseDetectionCommonResources" to listOf( 43 + "pose_tracking_graph.binarypb", 44 + "pose_non_tracking_graph.binarypb", 45 + ), 46 + "MLKitXenoResources" to listOf( 47 + "yuv_to_rgb_graph.binarypb", 48 + ), 49 + ) 50 + 51 + // `lazy` on Kotlin/Native is thread-safe by default — evaluates once. 52 + // Accessing .value triggers the one-time extraction + swizzle-setter. 53 + private val bootstrap: Unit by lazy { 54 + runBlocking { extract() } 55 + } 56 + 57 + fun ensureInitialized() { 58 + bootstrap 59 + } 60 + 61 + private suspend fun extract() { 62 + val fm = NSFileManager.defaultManager 63 + val cachesRoot = (fm.URLsForDirectory(NSCachesDirectory, NSUserDomainMask).firstOrNull() 64 + as? NSURL)?.path ?: return 65 + val mlkitDir = "$cachesRoot/MLKitResources" 66 + fm.createDirectoryAtPath( 67 + mlkitDir, 68 + withIntermediateDirectories = true, 69 + attributes = null, 70 + error = null, 71 + ) 72 + 73 + for ((bundleName, files) in BUNDLE_FILES) { 74 + val bundlePath = "$mlkitDir/$bundleName.bundle" 75 + fm.createDirectoryAtPath( 76 + bundlePath, 77 + withIntermediateDirectories = true, 78 + attributes = null, 79 + error = null, 80 + ) 81 + for (file in files) { 82 + val resourcePath = "files/mlkit/$bundleName/$file" 83 + val bytes = Res.readBytes(resourcePath) 84 + val outPath = "$bundlePath/$file" 85 + bytes.usePinned { pinned -> 86 + val data = NSData.create( 87 + bytes = pinned.addressOf(0), 88 + length = bytes.size.toULong(), 89 + ) 90 + data.writeToFile(outPath, atomically = true) 91 + } 92 + } 93 + } 94 + 95 + mlkit_set_resource_dir(mlkitDir) 96 + } 97 + }
+483 -75
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/camera/CameraEngine.kt
··· 61 61 import platform.CoreFoundation.CFDataGetBytePtr 62 62 import platform.CoreFoundation.CFDataGetLength 63 63 import platform.CoreFoundation.CFRelease 64 + import platform.CoreFoundation.CFRetain 65 + import platform.CoreGraphics.CGContextAddLineToPoint 66 + import platform.CoreGraphics.CGContextFillEllipseInRect 67 + import platform.CoreGraphics.CGContextMoveToPoint 68 + import platform.CoreGraphics.CGContextSetFillColorWithColor 69 + import platform.CoreGraphics.CGContextSetLineWidth 70 + import platform.CoreGraphics.CGContextSetStrokeColorWithColor 71 + import platform.CoreGraphics.CGContextStrokeEllipseInRect 72 + import platform.CoreGraphics.CGContextStrokePath 73 + import platform.CoreGraphics.CGContextStrokeRect 74 + import platform.CoreGraphics.CGRectMake 75 + import platform.CoreVideo.CVImageBufferRef 64 76 import platform.CoreGraphics.CGBitmapContextCreate 65 77 import platform.CoreGraphics.CGBitmapContextCreateImage 66 78 import platform.CoreGraphics.CGColorSpaceCreateDeviceRGB ··· 74 86 import platform.CoreGraphics.CGImageRelease 75 87 import platform.CoreGraphics.CGPointMake 76 88 import platform.CoreGraphics.CGSize 89 + import platform.CoreGraphics.CGSizeMake 90 + import platform.CoreImage.CIContext 91 + import platform.CoreImage.CIImage 92 + import platform.CoreImage.createCGImage 93 + import platform.ImageIO.kCGImagePropertyOrientationDown 94 + import platform.ImageIO.kCGImagePropertyOrientationDownMirrored 95 + import platform.ImageIO.kCGImagePropertyOrientationLeft 96 + import platform.ImageIO.kCGImagePropertyOrientationLeftMirrored 97 + import platform.ImageIO.kCGImagePropertyOrientationRight 98 + import platform.ImageIO.kCGImagePropertyOrientationRightMirrored 99 + import platform.ImageIO.kCGImagePropertyOrientationUp 100 + import platform.ImageIO.kCGImagePropertyOrientationUpMirrored 101 + import platform.Foundation.NSDocumentDirectory 102 + import platform.Foundation.NSFileManager 103 + import platform.Foundation.NSUserDomainMask 104 + import platform.Foundation.writeToURL 105 + import platform.UIKit.UIColor 106 + import platform.UIKit.UIGraphicsGetCurrentContext 107 + import platform.UIKit.UIGraphicsImageRenderer 108 + import platform.UIKit.UIImageOrientation 109 + import platform.UIKit.UIImagePNGRepresentation 77 110 import platform.CoreMedia.CMSampleBufferGetImageBuffer 78 111 import platform.CoreMedia.CMSampleBufferRef 79 112 import platform.Foundation.NSData ··· 97 130 import platform.darwin.dispatch_queue_create 98 131 import platform.darwin.dispatch_sync 99 132 import platform.posix.memcpy 133 + import kotlin.concurrent.Volatile 100 134 import kotlin.math.abs 101 135 import kotlin.native.runtime.NativeRuntimeApi 102 136 ··· 133 167 MemoryManager.updateMemoryStatus() 134 168 } 135 169 170 + @OptIn(ExperimentalForeignApi::class) 171 + override fun viewDidAppear(animated: Boolean) { 172 + super.viewDidAppear(animated) 173 + // The view is now in a window, so `view.window?.windowScene?.interfaceOrientation` 174 + // is reliable — unlike at viewDidLoad time, where `keyWindow` may be nil. 175 + // Re-sync so the initial orientation (esp. portrait) reaches both preview 176 + // layer and video-data-output connections, which otherwise default to 177 + // LandscapeRight and make captureOutput frames come through misoriented. 178 + cameraController.setDesiredVideoOrientation(resolveInterfaceOrientation()) 179 + } 180 + 136 181 override fun viewDidDisappear(animated: Boolean) { 137 182 super.viewDidDisappear(animated) 138 183 ··· 145 190 withTransitionCoordinator: UIViewControllerTransitionCoordinatorProtocol 146 191 ) { 147 192 super.viewWillTransitionToSize(size, withTransitionCoordinator) 148 - val orientation = interfaceOrientationToVideoOrientation() 149 - cameraController.cameraPreviewLayer?.connection?.videoOrientation = orientation 150 - // Also update the video-data output connection (used for Vision/CoreML) 151 - cameraController.updateVideoOutputOrientation(orientation) 193 + cameraController.setDesiredVideoOrientation(resolveInterfaceOrientation()) 194 + } 195 + 196 + @OptIn(ExperimentalForeignApi::class) 197 + private fun resolveInterfaceOrientation(): AVCaptureVideoOrientation { 198 + // Prefer this view's window scene (reliable once viewDidAppear has run), 199 + // falling back to the global keyWindow lookup, then portrait. 200 + val sceneOrientation = view.window?.windowScene?.interfaceOrientation 201 + ?: UIApplication.sharedApplication.keyWindow?.windowScene?.interfaceOrientation 202 + ?: UIInterfaceOrientationPortrait 203 + return when (sceneOrientation) { 204 + UIInterfaceOrientationPortrait -> AVCaptureVideoOrientationPortrait 205 + UIInterfaceOrientationPortraitUpsideDown -> AVCaptureVideoOrientationPortraitUpsideDown 206 + UIInterfaceOrientationLandscapeLeft -> AVCaptureVideoOrientationLandscapeLeft 207 + UIInterfaceOrientationLandscapeRight -> AVCaptureVideoOrientationLandscapeRight 208 + else -> AVCaptureVideoOrientationPortrait 209 + } 152 210 } 153 211 154 212 fun getCameraPreviewLayer() = cameraController.cameraPreviewLayer ··· 248 306 249 307 fun addCameraViewController(controller: CameraViewController?) { 250 308 cameraController.cameraViewController = controller 309 + // Wire the test-harness composite-capture hook. Forwards the call to 310 + // the inner controller which has access to the last camera buffer. 311 + controller?.setCaptureCompositeProvider { filename, onResult -> 312 + cameraController.captureCompositeToPng(filename, onResult) 313 + } 251 314 } 252 315 253 316 fun addFrameListener(listener: FrameRepository) { ··· 280 343 281 344 fun setFocusArea(focusArea: Rect?) { 282 345 cameraController.setFocusArea(focusArea) 346 + } 347 + 348 + fun setPoseFocusMode(mode: PoseFocusMode) { 349 + cameraController.setPoseFocusMode(mode) 283 350 } 284 351 285 352 fun setObjectModel(objectModel: ObjectModel?) { ··· 328 395 private val frameProcessingQueue = 329 396 dispatch_queue_create("com.performancecoachlab.frameProcessing", null) 330 397 398 + // Test-harness composite-capture state. Retains the most recent camera 399 + // buffer + the pre-preview-mapping skeleton/objects so captureComposite 400 + // can render them into a single PNG on demand. Access via 401 + // CameraViewController.captureComposite(...) wired below. 402 + @OptIn(ExperimentalForeignApi::class) 403 + private var lastBuffer: CVImageBufferRef? = null 404 + private var lastCaptureConnection: AVCaptureConnection? = null 405 + private var lastDetectedSkeleton: Skeleton? = null 406 + private var lastPreviewSkeleton: Skeleton? = null 407 + private var lastPreviewObjects: List<AnalysisObject> = emptyList() 408 + private var lastPreviewBoundsW: Double = 0.0 409 + private var lastPreviewBoundsH: Double = 0.0 410 + private var lastDetectedObjects: List<AnalysisObject> = emptyList() 411 + private val lastBufferLock = dispatch_queue_create( 412 + "com.performancecoachlab.lastBufferLock", 413 + null 414 + ) 415 + 331 416 // iOS 14+ introduces a new way to access the ultra-wide camera, which we can use conditionally. 332 417 private var backUltraWideCamera: AVCaptureDevice? = null 333 418 private var backWideCamera: AVCaptureDevice? = null 334 419 private var useUltraWideBack: Boolean = false 335 420 421 + // Source-of-truth for the orientation the capture pipeline should be running 422 + // in. Updated from main-thread lifecycle hooks (viewDidAppear, 423 + // viewWillTransitionToSize, setupPreviewLayer, switchCamera). Read from the 424 + // frame-processing queue to force the videoOutput connection in sync each 425 + // frame, since AVCaptureConnection.videoOrientation on the video-data 426 + // output is easy to end up stale (defaults to LandscapeRight). 427 + @Volatile 428 + var desiredVideoOrientation: AVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait 429 + private set 430 + 431 + @OptIn(ExperimentalForeignApi::class) 432 + fun setDesiredVideoOrientation(orientation: AVCaptureVideoOrientation) { 433 + desiredVideoOrientation = orientation 434 + // Preview-layer connection: safe to set — AVCaptureVideoPreviewLayer 435 + // just uses this for visual rotation, keeps the underlying capture 436 + // device frames in raw (landscape) orientation. 437 + cameraPreviewLayer?.connection?.let { conn -> 438 + if (conn.isVideoOrientationSupported()) { 439 + conn.videoOrientation = orientation 440 + } 441 + } 442 + // Deliberately do NOT set videoOrientation on the video-data-output 443 + // connection — AVCaptureVideoDataOutput auto-rotates the delivered 444 + // buffer when that's set, causing double-rotation downstream (the 445 + // preview layer already rotates for display). Vision gets the raw 446 + // landscape buffer + explicit EXIF via VNImageRequestHandler's 447 + // orientation parameter; MLKit gets the raw buffer + the pose EXIF 448 + // for its own imageByApplyingOrientation. 449 + } 450 + 451 + // Resolve the orientation the downstream EXIF pipeline should use. We 452 + // always prefer the tracked desired orientation (set from main-thread 453 + // lifecycle hooks) over the connection's reported orientation, because 454 + // (a) on initial portrait launch the video-data output connection 455 + // defaults to LandscapeRight until the first view transition, and 456 + // (b) we deliberately don't rotate the video-data output connection 457 + // since that would make AVCaptureVideoDataOutput auto-rotate the buffer. 458 + @OptIn(ExperimentalForeignApi::class) 459 + fun effectiveVideoOrientation(): AVCaptureVideoOrientation = desiredVideoOrientation 460 + 336 461 sealed class CameraException : Exception() { 337 462 class DeviceNotAvailable : CameraException() 338 463 class ConfigurationError(message: String) : CameraException() ··· 385 510 386 511 fun setFocusArea(focusArea: Rect?) { 387 512 frameProcessor.setFocusArea(focusArea) 513 + } 514 + 515 + fun setPoseFocusMode(mode: PoseFocusMode) { 516 + frameProcessor.setPoseFocusMode(mode) 388 517 } 389 518 390 519 fun setDetectMode(detectMode: DetectMode) { ··· 563 692 @OptIn(ExperimentalForeignApi::class) 564 693 fun setupPreviewLayer(view: UIView) { 565 694 captureSession?.let { session -> 695 + val initialOrientation = view.window?.windowScene?.interfaceOrientation 696 + ?.let { intf -> 697 + when (intf) { 698 + UIInterfaceOrientationPortrait -> AVCaptureVideoOrientationPortrait 699 + UIInterfaceOrientationPortraitUpsideDown -> AVCaptureVideoOrientationPortraitUpsideDown 700 + UIInterfaceOrientationLandscapeLeft -> AVCaptureVideoOrientationLandscapeLeft 701 + UIInterfaceOrientationLandscapeRight -> AVCaptureVideoOrientationLandscapeRight 702 + else -> null 703 + } 704 + } ?: desiredVideoOrientation 705 + 566 706 val newPreviewLayer = AVCaptureVideoPreviewLayer(session = session).apply { 567 707 videoGravity = AVLayerVideoGravityResizeAspectFill 568 708 setFrame(view.bounds) 569 - connection?.videoOrientation = interfaceOrientationToVideoOrientation() 570 - 571 - connection?.let { 572 - if (it.isVideoMirroringSupported()) { 573 - it.automaticallyAdjustsVideoMirroring = false 574 - it.videoMirrored = isUsingFrontCamera 709 + connection?.let { conn -> 710 + if (conn.isVideoOrientationSupported()) { 711 + conn.videoOrientation = initialOrientation 712 + } 713 + if (conn.isVideoMirroringSupported()) { 714 + conn.automaticallyAdjustsVideoMirroring = false 715 + conn.videoMirrored = isUsingFrontCamera 575 716 } 576 717 } 577 - 578 718 } 579 719 580 720 view.layer.addSublayer(newPreviewLayer) 581 721 cameraPreviewLayer = newPreviewLayer 582 722 583 - cameraPreviewLayer?.connection?.let { connection -> 584 - connection.videoOrientation = interfaceOrientationToVideoOrientation() 585 - // Ensure video-data output connection matches the same orientation/mirroring 586 - updateVideoOutputOrientation(interfaceOrientationToVideoOrientation()) 587 - } 723 + // Route through setDesiredVideoOrientation so the cached state, 724 + // preview-layer connection, and video-data-output connection all 725 + // share the same source of truth. viewDidAppear re-calls this with 726 + // the windowScene value once the view is actually in a window. 727 + setDesiredVideoOrientation(initialOrientation) 588 728 } 589 729 } 590 730 ··· 652 792 653 793 // Apply orientation + mirroring on main queue while still hidden. 654 794 dispatch_async(dispatch_get_main_queue()) { 795 + setDesiredVideoOrientation(interfaceOrientationToVideoOrientation()) 655 796 cameraPreviewLayer?.connection?.let { connection -> 656 - connection.videoOrientation = interfaceOrientationToVideoOrientation() 657 797 if (connection.isVideoMirroringSupported()) { 658 798 connection.automaticallyAdjustsVideoMirroring = false 659 799 connection.setVideoMirrored(isUsingFrontCamera) 660 800 } 661 801 } 662 - updateVideoOutputOrientation(interfaceOrientationToVideoOrientation()) 663 802 664 803 cameraPreviewLayer?.apply { 665 804 // Use a tiny fade-in to avoid a harsh blink. ··· 685 824 686 825 // Ensure the connection is correct after commit, then show the preview again. 687 826 dispatch_async(dispatch_get_main_queue()) { 827 + setDesiredVideoOrientation(interfaceOrientationToVideoOrientation()) 688 828 cameraPreviewLayer?.connection?.let { connection -> 689 - connection.videoOrientation = interfaceOrientationToVideoOrientation() 690 829 if (connection.isVideoMirroringSupported()) { 691 830 connection.automaticallyAdjustsVideoMirroring = false 692 831 connection.setVideoMirrored(isUsingFrontCamera) ··· 728 867 // This avoids brief flashes of stale frames from the previous lens. 729 868 if (isSwitchingCamera) return@dispatch_async 730 869 870 + // Important: do NOT set videoOrientation on fromConnection. 871 + // AVCaptureVideoDataOutput auto-rotates delivered buffers 872 + // when videoOrientation is set, which would double-rotate 873 + // against our own EXIF pipeline. We deliberately override 874 + // the orientation downstream via effectiveVideoOrientation 875 + // while letting the raw landscape buffer flow through here. 876 + val targetOrientation = desiredVideoOrientation 877 + 731 878 var detectedSkeleton: Skeleton? = null 732 879 var detectedObjects: List<AnalysisObject> = emptyList() 733 880 881 + val cvBuf = CMSampleBufferGetImageBuffer(didOutputSampleBuffer) 734 882 frameProcessor.analyseBufferForAll( 735 - CMSampleBufferGetImageBuffer(didOutputSampleBuffer), 883 + cvBuf, 736 884 timestamp, 737 885 preview = cameraPreviewLayer, 738 886 captureConnection = fromConnection, 887 + orientationOverride = targetOrientation, 888 + mirroredOverride = isUsingFrontCamera, 739 889 onSkeletonProcessed = { skeleton -> 740 890 detectedSkeleton = skeleton 741 891 }, ··· 744 894 } 745 895 ) 746 896 897 + // Retain the raw buffer + detections for captureComposite. 898 + dispatch_sync(lastBufferLock) { 899 + lastBuffer?.also { CFRelease(it) } 900 + lastBuffer = cvBuf?.also { CFRetain(it) } 901 + lastCaptureConnection = fromConnection 902 + lastDetectedSkeleton = detectedSkeleton 903 + lastDetectedObjects = detectedObjects 904 + } 905 + 747 906 cameraPreviewLayer?.also { preview -> 748 907 val previewSkeleton = detectedSkeleton?.let { 749 908 mapSkeletonToPreview( 750 909 skeleton = it, 751 910 previewLayer = preview, 752 911 width = it.width, 753 - height = it.height 912 + height = it.height, 913 + orientationOverride = targetOrientation, 914 + mirroredOverride = isUsingFrontCamera, 754 915 ) 755 916 } 756 917 918 + val bw: Double 919 + val bh: Double 920 + preview.bounds.useContents { 921 + bw = size.width 922 + bh = size.height 923 + } 757 924 previewSkeleton?.also { 758 925 skeletonRepository?.updateSkeleton(it) 759 926 } ··· 771 938 ) 772 939 } 773 940 941 + dispatch_sync(lastBufferLock) { 942 + lastPreviewSkeleton = previewSkeleton 943 + lastPreviewObjects = previewObjects 944 + lastPreviewBoundsW = bw 945 + lastPreviewBoundsH = bh 946 + } 947 + 774 948 customObjectRepository?.updateCustomObject(previewObjects) 775 949 776 950 preview.bounds.useContents { ··· 859 1033 } 860 1034 } 861 1035 862 - // Replace mapBoxToPreview implementation to map oriented analysis pixels -> raw buffer normalized -> preview space. 1036 + // Maps an oriented-analysis-pixel point to capture-device-normalized. 1037 + // Original pipeline used by the object-detection box mapping — this was 1038 + // already correct pre-pose-work and we're deliberately keeping it. Only 1039 + // the skeleton path uses the new aspect-fill math. 863 1040 @OptIn(ExperimentalForeignApi::class) 864 1041 private fun orientedNormalizedToCaptureDeviceNormalized( 865 1042 uTopLeft: Double, 866 1043 vTopLeft: Double, 867 1044 previewLayer: AVCaptureVideoPreviewLayer, 868 1045 ): Pair<Double, Double> { 869 - // Clamp first to avoid ever returning out-of-range points. 870 1046 val u = uTopLeft.coerceIn(0.0, 1.0) 871 1047 val v = vTopLeft.coerceIn(0.0, 1.0) 872 1048 ··· 874 1050 previewLayer.connection?.videoOrientation ?: AVCaptureVideoOrientationLandscapeRight 875 1051 val mirrored = previewLayer.connection?.videoMirrored ?: false 876 1052 877 - // Convert from oriented (top-left origin) to capture-device normalized expected by pointForCaptureDevicePointOfInterest. 878 - // Empirically, in portrait the old mapping appears 90° clockwise, so we apply a 90° counter-clockwise fix: 879 - // (u,v) -> (x=v, y=1-u) 1053 + // Pre-restore mapping from commit ccf4dc8 "fix: io object detection in 1054 + // non natural orientations". This is what objects were using when they 1055 + // were working; don't change it without also adjusting the object path. 880 1056 var (x, y) = when (orientation) { 881 1057 AVCaptureVideoOrientationPortrait -> Pair(v, 1.0 - u) 882 1058 AVCaptureVideoOrientationPortraitUpsideDown -> Pair(1.0 - v, u) ··· 885 1061 else -> Pair(u, v) 886 1062 } 887 1063 888 - if (mirrored) { 889 - x = 1.0 - x 890 - } 891 - 1064 + if (mirrored) x = 1.0 - x 892 1065 return Pair(x.coerceIn(0.0, 1.0), y.coerceIn(0.0, 1.0)) 893 1066 } 894 1067 1068 + // Original working implementation (pre-any-pose-work). Objects were 1069 + // correctly transformed through this path — the skeleton-path fix does 1070 + // not belong here. Ref: commit ccf4dc8. 895 1071 @OptIn(ExperimentalForeignApi::class) 896 1072 fun mapBoxToPreview( 897 1073 box: Rect, ··· 912 1088 ) 913 1089 } 914 1090 915 - // Map all 4 corners to ensure correct rect under rotations. 916 1091 val p1 = mapPoint(Offset(box.left, box.top)) 917 1092 val p2 = mapPoint(Offset(box.right, box.top)) 918 1093 val p3 = mapPoint(Offset(box.right, box.bottom)) ··· 935 1110 ) { 936 1111 onVideoSaved?.invoke(didFinishRecordingToOutputFileAtURL.path ?: "") 937 1112 } 1113 + 1114 + // Test-harness / debug helper: composite the last camera frame with the 1115 + // last detected skeleton + object boxes, save as a PNG in Documents/. 1116 + // Called via CameraViewController.captureComposite — see setup in 1117 + // addCameraViewController on the outer CameraEngine. 1118 + @OptIn(ExperimentalForeignApi::class) 1119 + internal fun captureCompositeToPng(filename: String, onResult: (String?) -> Unit) { 1120 + var buffer: CVImageBufferRef? = null 1121 + var connection: AVCaptureConnection? = null 1122 + var skeleton: Skeleton? = null 1123 + var previewSkel: Skeleton? = null 1124 + var previewObjs: List<AnalysisObject> = emptyList() 1125 + var pBoundsW = 0.0 1126 + var pBoundsH = 0.0 1127 + var objects: List<AnalysisObject> = emptyList() 1128 + dispatch_sync(lastBufferLock) { 1129 + val b = lastBuffer 1130 + if (b != null) { 1131 + CFRetain(b) 1132 + buffer = b 1133 + } 1134 + connection = lastCaptureConnection 1135 + skeleton = lastDetectedSkeleton 1136 + previewSkel = lastPreviewSkeleton 1137 + previewObjs = lastPreviewObjects 1138 + pBoundsW = lastPreviewBoundsW 1139 + pBoundsH = lastPreviewBoundsH 1140 + objects = lastDetectedObjects 1141 + } 1142 + val buf = buffer ?: return onResult(null) 1143 + try { 1144 + val ciCtx = CIContext.contextWithOptions(null) 1145 + val ciRaw = CIImage.imageWithCVPixelBuffer(buf) ?: return onResult(null) 1146 + // Pre-rotate to oriented dims so skeleton coords line up 1:1. 1147 + val exif = captureConnectionToExifOrientation(connection) 1148 + val ciOriented = ciRaw.imageByApplyingOrientation(exif) 1149 + var eOriginX = 0.0 1150 + var eOriginY = 0.0 1151 + var eW = 0.0 1152 + var eH = 0.0 1153 + ciOriented.extent.useContents { 1154 + eOriginX = origin.x 1155 + eOriginY = origin.y 1156 + eW = size.width 1157 + eH = size.height 1158 + } 1159 + val cgImage = ciCtx.createCGImage( 1160 + ciOriented, 1161 + CGRectMake(eOriginX, eOriginY, eW, eH) 1162 + ) ?: return onResult(null) 1163 + 1164 + val cameraUIImage = platform.UIKit.UIImage(cgImage) 1165 + val rendererSize = CGSizeMake(eW, eH) 1166 + 1167 + // 1) Save a CLEAN camera frame (no overlay) for comparison. 1168 + val cleanRenderer = UIGraphicsImageRenderer(size = rendererSize) 1169 + val cleanImage = cleanRenderer.imageWithActions { _ -> 1170 + cameraUIImage.drawInRect(CGRectMake(0.0, 0.0, eW, eH)) 1171 + } 1172 + val cleanPng = UIImagePNGRepresentation(cleanImage) 1173 + val docsUrl = (NSFileManager.defaultManager 1174 + .URLsForDirectory(NSDocumentDirectory, NSUserDomainMask) 1175 + .firstOrNull() as? NSURL) 1176 + ?: run { CGImageRelease(cgImage); return onResult(null) } 1177 + val cleanName = filename.replace(".png", "_clean.png") 1178 + cleanPng?.writeToURL( 1179 + docsUrl.URLByAppendingPathComponent(cleanName) 1180 + ?: run { CGImageRelease(cgImage); return onResult(null) }, 1181 + atomically = true, 1182 + ) 1183 + 1184 + // 2) Save the composite (camera + overlay). 1185 + val renderer = UIGraphicsImageRenderer(size = rendererSize) 1186 + val composite = renderer.imageWithActions { _ -> 1187 + cameraUIImage.drawInRect(CGRectMake(0.0, 0.0, eW, eH)) 1188 + val ctx = UIGraphicsGetCurrentContext() 1189 + if (ctx != null) { 1190 + // DEBUG: draw coord-space fiducials so we can see 1191 + // whether the skeleton coord-space lines up with the 1192 + // pixel space of the rendered camera image. 1193 + drawDebugFiducials(ctx, eW, eH) 1194 + drawSkeletonOnContext(ctx, skeleton) 1195 + drawObjectsOnContext(ctx, objects) 1196 + } 1197 + } 1198 + val png = UIImagePNGRepresentation(composite) 1199 + ?: run { CGImageRelease(cgImage); return onResult(null) } 1200 + val fileUrl = docsUrl.URLByAppendingPathComponent(filename) 1201 + ?: run { CGImageRelease(cgImage); return onResult(null) } 1202 + png.writeToURL(fileUrl, atomically = true) 1203 + 1204 + // 3) Preview-mapped overlay — replicates what the user sees 1205 + // on-device: preview layer's aspect-fill of the camera image 1206 + // plus the mapSkeletonToPreview-mapped skeleton drawn in the 1207 + // preview layer's bounds coord space. If this diverges from 1208 + // the oriented-pixel composite above, the bug is in the 1209 + // preview mapping / pointForCaptureDevicePointOfInterest path. 1210 + if (pBoundsW > 0 && pBoundsH > 0) { 1211 + val previewSize = CGSizeMake(pBoundsW, pBoundsH) 1212 + val previewRenderer = UIGraphicsImageRenderer(size = previewSize) 1213 + val previewImage = previewRenderer.imageWithActions { _ -> 1214 + // Match the preview layer's videoGravity — FIT for the test 1215 + // harness (PreviewFillMode.FIT), FILL for production default. 1216 + val gravity = cameraPreviewLayer?.videoGravity 1217 + val fit = gravity == AVLayerVideoGravityResizeAspect 1218 + val scale = if (fit) minOf(pBoundsW / eW, pBoundsH / eH) 1219 + else maxOf(pBoundsW / eW, pBoundsH / eH) 1220 + val drawW = eW * scale 1221 + val drawH = eH * scale 1222 + val drawX = (pBoundsW - drawW) / 2.0 1223 + val drawY = (pBoundsH - drawH) / 2.0 1224 + cameraUIImage.drawInRect(CGRectMake(drawX, drawY, drawW, drawH)) 1225 + val ctx = UIGraphicsGetCurrentContext() 1226 + if (ctx != null) { 1227 + drawDebugFiducials(ctx, pBoundsW, pBoundsH) 1228 + drawSkeletonOnContext(ctx, previewSkel) 1229 + drawObjectsOnContext(ctx, previewObjs) 1230 + } 1231 + } 1232 + val previewPng = UIImagePNGRepresentation(previewImage) 1233 + val previewName = filename.replace(".png", "_preview.png") 1234 + val previewUrl = docsUrl.URLByAppendingPathComponent(previewName) 1235 + if (previewPng != null && previewUrl != null) { 1236 + previewPng.writeToURL(previewUrl, atomically = true) 1237 + } 1238 + } 1239 + 1240 + CGImageRelease(cgImage) 1241 + onResult(fileUrl.path) 1242 + } finally { 1243 + CFRelease(buf) 1244 + } 1245 + } 1246 + 1247 + @OptIn(ExperimentalForeignApi::class) 1248 + private fun drawDebugFiducials( 1249 + ctx: platform.CoreGraphics.CGContextRef, 1250 + w: Double, 1251 + h: Double, 1252 + ) { 1253 + // Draw a cyan crosshair at (0,0) (top-left per oriented-top-left coord 1254 + // space), a magenta cross at the center, and a blue square at bottom- 1255 + // right. If the coord space is correct, cyan sits in the top-left of 1256 + // the image, center-cross in the middle, and blue in the bottom-right. 1257 + CGContextSetStrokeColorWithColor(ctx, UIColor.cyanColor.CGColor) 1258 + CGContextSetLineWidth(ctx, 6.0) 1259 + CGContextMoveToPoint(ctx, 0.0, 0.0) 1260 + CGContextAddLineToPoint(ctx, 120.0, 0.0) 1261 + CGContextMoveToPoint(ctx, 0.0, 0.0) 1262 + CGContextAddLineToPoint(ctx, 0.0, 120.0) 1263 + CGContextStrokePath(ctx) 1264 + 1265 + CGContextSetStrokeColorWithColor(ctx, UIColor.magentaColor.CGColor) 1266 + CGContextSetLineWidth(ctx, 4.0) 1267 + CGContextMoveToPoint(ctx, w / 2 - 60, h / 2) 1268 + CGContextAddLineToPoint(ctx, w / 2 + 60, h / 2) 1269 + CGContextMoveToPoint(ctx, w / 2, h / 2 - 60) 1270 + CGContextAddLineToPoint(ctx, w / 2, h / 2 + 60) 1271 + CGContextStrokePath(ctx) 1272 + 1273 + CGContextSetStrokeColorWithColor(ctx, UIColor.blueColor.CGColor) 1274 + CGContextStrokeRect(ctx, CGRectMake(w - 80, h - 80, 60.0, 60.0)) 1275 + } 1276 + 1277 + @OptIn(ExperimentalForeignApi::class) 1278 + private fun drawSkeletonOnContext( 1279 + ctx: platform.CoreGraphics.CGContextRef, 1280 + skeleton: Skeleton?, 1281 + ) { 1282 + if (skeleton == null) return 1283 + CGContextSetStrokeColorWithColor(ctx, UIColor.yellowColor.CGColor) 1284 + CGContextSetLineWidth(ctx, 5.0) 1285 + skeleton.bones().forEach { (a, b) -> 1286 + CGContextMoveToPoint(ctx, a.x.toDouble(), a.y.toDouble()) 1287 + CGContextAddLineToPoint(ctx, b.x.toDouble(), b.y.toDouble()) 1288 + } 1289 + CGContextStrokePath(ctx) 1290 + CGContextSetFillColorWithColor(ctx, UIColor.redColor.CGColor) 1291 + skeleton.joints().forEach { j -> 1292 + val r = 6.0 1293 + CGContextFillEllipseInRect( 1294 + ctx, 1295 + CGRectMake(j.x.toDouble() - r, j.y.toDouble() - r, r * 2, r * 2) 1296 + ) 1297 + } 1298 + } 1299 + 1300 + @OptIn(ExperimentalForeignApi::class) 1301 + private fun drawObjectsOnContext( 1302 + ctx: platform.CoreGraphics.CGContextRef, 1303 + objects: List<AnalysisObject>, 1304 + ) { 1305 + CGContextSetStrokeColorWithColor(ctx, UIColor.greenColor.CGColor) 1306 + CGContextSetLineWidth(ctx, 4.0) 1307 + objects.forEach { o -> 1308 + val b = o.boundingBox 1309 + CGContextStrokeRect( 1310 + ctx, 1311 + CGRectMake( 1312 + b.left.toDouble(), 1313 + b.top.toDouble(), 1314 + (b.right - b.left).toDouble(), 1315 + (b.bottom - b.top).toDouble(), 1316 + ) 1317 + ) 1318 + } 1319 + } 1320 + 1321 + @OptIn(ExperimentalForeignApi::class) 1322 + private fun captureConnectionToExifOrientation(connection: AVCaptureConnection?): Int { 1323 + // Prefer the tracked desiredVideoOrientation. The connection's own 1324 + // videoOrientation is unreliable at initial portrait launch 1325 + // (defaults to LandscapeRight until a view transition fires), and we 1326 + // deliberately don't write it back to the video-data output (that 1327 + // would make AVFoundation auto-rotate the buffer against us). 1328 + val videoOrientation = effectiveVideoOrientation() 1329 + val mirrored = connection?.videoMirrored ?: isUsingFrontCamera 1330 + val exif: UInt = when (videoOrientation) { 1331 + AVCaptureVideoOrientationPortrait -> 1332 + if (mirrored) kCGImagePropertyOrientationLeftMirrored else kCGImagePropertyOrientationRight 1333 + AVCaptureVideoOrientationPortraitUpsideDown -> 1334 + if (mirrored) kCGImagePropertyOrientationRightMirrored else kCGImagePropertyOrientationLeft 1335 + AVCaptureVideoOrientationLandscapeLeft -> 1336 + if (mirrored) kCGImagePropertyOrientationUpMirrored else kCGImagePropertyOrientationDown 1337 + AVCaptureVideoOrientationLandscapeRight -> 1338 + if (mirrored) kCGImagePropertyOrientationDownMirrored else kCGImagePropertyOrientationUp 1339 + else -> 1340 + if (mirrored) kCGImagePropertyOrientationDownMirrored else kCGImagePropertyOrientationUp 1341 + } 1342 + return exif.toInt() 1343 + } 938 1344 } 939 1345 940 1346 @OptIn(ExperimentalForeignApi::class) ··· 1082 1488 skeleton: Skeleton, 1083 1489 previewLayer: AVCaptureVideoPreviewLayer, 1084 1490 width: Float, 1085 - height: Float 1491 + height: Float, 1492 + orientationOverride: AVCaptureVideoOrientation? = null, 1493 + mirroredOverride: Boolean? = null, 1086 1494 ): Skeleton { 1087 - fun orientedNormalizedToCaptureDeviceNormalized( 1088 - uTopLeft: Double, 1089 - vTopLeft: Double 1090 - ): Pair<Double, Double> { 1091 - val u = uTopLeft.coerceIn(0.0, 1.0) 1092 - val v = vTopLeft.coerceIn(0.0, 1.0) 1093 - 1094 - val orientation = 1095 - previewLayer.connection?.videoOrientation ?: AVCaptureVideoOrientationLandscapeRight 1096 - val mirrored = previewLayer.connection?.videoMirrored ?: false 1097 - 1098 - var (x, y) = when (orientation) { 1099 - AVCaptureVideoOrientationPortrait -> Pair(v, 1.0 - u) 1100 - AVCaptureVideoOrientationPortraitUpsideDown -> Pair(1.0 - v, u) 1101 - AVCaptureVideoOrientationLandscapeRight -> Pair(u, v) 1102 - AVCaptureVideoOrientationLandscapeLeft -> Pair(1.0 - u, 1.0 - v) 1103 - else -> Pair(u, v) 1104 - } 1105 - 1106 - if (mirrored) x = 1.0 - x 1107 - return Pair(x.coerceIn(0.0, 1.0), y.coerceIn(0.0, 1.0)) 1495 + // We bypass previewLayer.pointForCaptureDevicePointOfInterest — it was 1496 + // empirically placing points at the wrong location in portrait/upside-down. 1497 + // Instead we do the aspect-fill math directly in oriented pixel space, 1498 + // which is what MLKit returns and what the preview layer renders after 1499 + // applying connection.videoOrientation. The rotation is already baked 1500 + // into the detection pipeline (see visionExifOrientation + MlKitPose), 1501 + // so all we need here is a scale+offset matching the preview's 1502 + // videoGravity crop/fit. 1503 + val bw: Double 1504 + val bh: Double 1505 + previewLayer.bounds.useContents { 1506 + bw = size.width 1507 + bh = size.height 1108 1508 } 1509 + val oriW = width.toDouble() 1510 + val oriH = height.toDouble() 1511 + val gravity = previewLayer.videoGravity 1512 + val fit = gravity == AVLayerVideoGravityResizeAspect 1513 + val scale = if (fit) minOf(bw / oriW, bh / oriH) else maxOf(bw / oriW, bh / oriH) 1514 + val offsetX = (bw - oriW * scale) / 2.0 1515 + val offsetY = (bh - oriH * scale) / 2.0 1516 + val mirrored = mirroredOverride ?: (previewLayer.connection?.videoMirrored ?: false) 1109 1517 1110 1518 fun mapPoint(point: Skeleton.SkeletonCoordinate?): Skeleton.SkeletonCoordinate? { 1111 1519 if (point == null) return null 1112 - 1113 - val u = (point.x.toDouble() / width.toDouble()) 1114 - val v = (point.y.toDouble() / height.toDouble()) 1115 - val (cx, cy) = orientedNormalizedToCaptureDeviceNormalized(u, v) 1116 - 1117 - val normalizedPoint = CGPointMake(cx, cy) 1118 - val screenPoint = previewLayer.pointForCaptureDevicePointOfInterest(normalizedPoint) 1119 - 1120 - return Skeleton.SkeletonCoordinate( 1121 - screenPoint.useContents { x.toFloat() }, 1122 - screenPoint.useContents { y.toFloat() } 1123 - ) 1520 + var px = point.x.toDouble() * scale + offsetX 1521 + val py = point.y.toDouble() * scale + offsetY 1522 + if (mirrored) px = bw - px 1523 + return Skeleton.SkeletonCoordinate(px.toFloat(), py.toFloat()) 1124 1524 } 1125 1525 1126 - val minbounds = previewLayer.pointForCaptureDevicePointOfInterest(CGPointMake(0.0, 0.0)) 1127 - .useContents { Pair(x.toFloat(), y.toFloat()) } 1128 - val maxbounds = previewLayer.pointForCaptureDevicePointOfInterest(CGPointMake(1.0, 1.0)) 1129 - .useContents { Pair(x.toFloat(), y.toFloat()) } 1130 - val bounds = Pair( 1131 - abs(maxbounds.first - minbounds.first), 1132 - abs(maxbounds.second - minbounds.second) 1133 - ) 1526 + // Width/height preserve the pre-4.15 contract: size of the VISIBLE 1527 + // sensor region as projected onto the preview layer, in preview points. 1528 + // Pre-4.15 derived these from 1529 + // pointForCaptureDevicePointOfInterest((0,0)..(1,1)) 1530 + // diff, which for any videoGravity equals the source dims scaled by the 1531 + // aspect-fit/fill scale factor. Keeping this stable means downstream 1532 + // consumers that normalize via `joint.x / skeleton.width` keep working 1533 + // unchanged across the 4.14 → 4.15+ bump. 1534 + val visibleW = (oriW * scale).toFloat() 1535 + val visibleH = (oriH * scale).toFloat() 1134 1536 1135 1537 return Skeleton( 1136 1538 timestamp = skeleton.timestamp, ··· 1146 1548 rightKnee = mapPoint(skeleton.rightKnee), 1147 1549 leftAnkle = mapPoint(skeleton.leftAnkle), 1148 1550 rightAnkle = mapPoint(skeleton.rightAnkle), 1149 - width = bounds.first, 1150 - height = bounds.second, 1551 + leftHeel = mapPoint(skeleton.leftHeel), 1552 + rightHeel = mapPoint(skeleton.rightHeel), 1553 + leftToe = mapPoint(skeleton.leftToe), 1554 + rightToe = mapPoint(skeleton.rightToe), 1555 + leftIndex = mapPoint(skeleton.leftIndex), 1556 + rightIndex = mapPoint(skeleton.rightIndex), 1557 + width = visibleW, 1558 + height = visibleH, 1151 1559 ) 1152 1560 }
+5
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/camera/CameraView.ios.kt
··· 37 37 previewFillMode: PreviewFillMode, 38 38 recordingId: String?, 39 39 focusArea: Rect?, 40 + poseFocusMode: PoseFocusMode, 40 41 controller: CameraViewController?, 41 42 onRecordToggled: (Boolean) -> Unit, 42 43 onVideoSaved: (String, String) -> Unit, ··· 94 95 LaunchedEffect(focusArea) { 95 96 cameraEngine.value?.setFocusArea(focusArea) 96 97 } 98 + LaunchedEffect(poseFocusMode) { 99 + cameraEngine.value?.setPoseFocusMode(poseFocusMode) 100 + } 97 101 LaunchedEffect(objectModel) { 98 102 cameraEngine.value?.setObjectModel(objectModel) 99 103 } ··· 101 105 delay(1000L) 102 106 cameraEngine.value?.setObjectModel(objectModel) 103 107 cameraEngine.value?.setFocusArea(focusArea) 108 + cameraEngine.value?.setPoseFocusMode(poseFocusMode) 104 109 cameraEngine.value?.setDetectMode(detectMode) 105 110 } 106 111 LaunchedEffect(previewFillMode) {
+344 -65
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/camera/FrameProcessor.kt
··· 18 18 import kotlinx.cinterop.useContents 19 19 import kotlinx.cinterop.value 20 20 import platform.AVFoundation.AVCaptureConnection 21 + import platform.AVFoundation.AVCaptureVideoOrientation 21 22 import platform.AVFoundation.AVCaptureVideoOrientationLandscapeLeft 22 23 import platform.AVFoundation.AVCaptureVideoOrientationLandscapeRight 23 24 import platform.AVFoundation.AVCaptureVideoOrientationPortrait ··· 44 45 import platform.ImageIO.kCGImagePropertyOrientationRightMirrored 45 46 import platform.ImageIO.kCGImagePropertyOrientationUp 46 47 import platform.ImageIO.kCGImagePropertyOrientationUpMirrored 48 + import platform.CoreML.MLMultiArray 49 + import platform.Foundation.NSNumber 47 50 import platform.Vision.VNClassificationObservation 51 + import platform.Vision.VNCoreMLFeatureValueObservation 48 52 import platform.Vision.VNCoreMLModel 49 53 import platform.Vision.VNCoreMLRequest 54 + import kotlinx.cinterop.CPointer 55 + import kotlinx.cinterop.FloatVar 56 + import kotlinx.cinterop.get 57 + import kotlinx.cinterop.reinterpret 50 58 import platform.Vision.VNDetectHumanBodyPoseRequest 51 59 import platform.Vision.VNHumanBodyPoseObservation 52 60 import platform.Vision.VNHumanBodyPoseObservationJointName ··· 162 170 observation.availableJointNames.forEach { 163 171 observation.recognizedPointForJointName(it as VNHumanBodyPoseObservationJointName, null) 164 172 ?.also { point -> 165 - if (point.confidence > 0.2f) { 173 + if (point.confidence > LANDMARK_CONF_THRESHOLD) { 166 174 points[it] = point 167 175 } 168 176 } ··· 219 227 } 220 228 } 221 229 230 + // EXIF for the MLKit pose path. The landscape mapping is swapped relative to 231 + // the object path — empirically required so that the pre-rotated CIImage fed 232 + // to MLKit lands upright in landscape and the aspect-fit/fill skeleton 233 + // mapping places landmarks correctly. 222 234 @OptIn(ExperimentalForeignApi::class) 223 - private fun AVCaptureConnection?.visionExifOrientation(): Int { 224 - // Prefer the actual capture connection orientation (not UI orientation). 225 - val videoOrientation = this?.videoOrientation ?: AVCaptureVideoOrientationLandscapeLeft 226 - val mirrored = this?.videoMirrored == true 235 + private fun AVCaptureConnection?.poseExifOrientation( 236 + orientationOverride: AVCaptureVideoOrientation? = null, 237 + mirroredOverride: Boolean? = null, 238 + ): Int { 239 + val videoOrientation = orientationOverride 240 + ?: this?.videoOrientation 241 + ?: AVCaptureVideoOrientationLandscapeLeft 242 + val mirrored = mirroredOverride ?: (this?.videoMirrored == true) 227 243 228 244 val exif: UInt = when (videoOrientation) { 229 - // These mappings match Apple's docs: EXIF/CGImagePropertyOrientation values describe 230 - // how to rotate the underlying pixel buffer into "Up". 231 245 AVCaptureVideoOrientationPortrait -> if (mirrored) kCGImagePropertyOrientationLeftMirrored else kCGImagePropertyOrientationRight 232 246 AVCaptureVideoOrientationPortraitUpsideDown -> if (mirrored) kCGImagePropertyOrientationRightMirrored else kCGImagePropertyOrientationLeft 233 - AVCaptureVideoOrientationLandscapeLeft -> if (mirrored) kCGImagePropertyOrientationDownMirrored else kCGImagePropertyOrientationUp 234 - AVCaptureVideoOrientationLandscapeRight -> if (mirrored) kCGImagePropertyOrientationUpMirrored else kCGImagePropertyOrientationDown 247 + AVCaptureVideoOrientationLandscapeLeft -> if (mirrored) kCGImagePropertyOrientationUpMirrored else kCGImagePropertyOrientationDown 248 + AVCaptureVideoOrientationLandscapeRight -> if (mirrored) kCGImagePropertyOrientationDownMirrored else kCGImagePropertyOrientationUp 235 249 else -> if (mirrored) kCGImagePropertyOrientationDownMirrored else kCGImagePropertyOrientationUp 236 250 } 237 251 238 252 return exif.toInt() 239 253 } 240 254 255 + // EXIF for the Vision object-detection path. The mapping historically in 256 + // HEAD (commit ccf4dc8) used swapped landscape EXIF (LandscapeLeft→Up, 257 + // LandscapeRight→Down), which was "correct" only because the original code 258 + // constructed VNImageRequestHandler without an explicit orientation arg and 259 + // Vision silently ignored the options-dict EXIF key. Now that we pass 260 + // orientation explicitly to VNImageRequestHandler, Vision honors it — so 261 + // the EXIF must match the actual sensor-native layout, same as the pose 262 + // path. Both paths effectively share the same mapping, but we keep them as 263 + // separate functions so we can re-diverge if needed. 264 + @OptIn(ExperimentalForeignApi::class) 265 + private fun AVCaptureConnection?.objectExifOrientation( 266 + orientationOverride: AVCaptureVideoOrientation? = null, 267 + mirroredOverride: Boolean? = null, 268 + ): Int = poseExifOrientation(orientationOverride, mirroredOverride) 269 + 241 270 @OptIn(ExperimentalForeignApi::class) 242 271 class FrameProcessor(var modelObj: VNCoreMLModel?) { 243 - private val skelBuffer = SkelBuffer(maxSize = 10) 272 + private val poseSmoother = PoseSmoother() 273 + private val followCropState = FollowCropState() 274 + private val mlkitPose = MlKitPose() 244 275 private var regionOfInterest = CGRectMake(0.0, 0.0, 1.0, 1.0) 245 276 private var requests = mutableListOf<VNRequest>() 246 277 val objectRecognition = setUpRecognition() 247 278 private var focusArea: Rect? = null 279 + private var poseFocusMode: PoseFocusMode = PoseFocusMode.MASK 248 280 private var path = "" 249 281 private var detectMode = DetectMode.BOTH 282 + // Populated by setObjectModel from ObjectModel.inputWidth/Height (filename 283 + // suffix convention). Used by the raw multiarray decoder to map ultralytics 284 + // pixel-space output back into normalized source coords. 0 when unknown. 285 + private var modelInputW: Int = 0 286 + private var modelInputH: Int = 0 250 287 251 288 fun setFocusArea(focusArea: Rect?) { 252 289 this.focusArea = focusArea 253 290 } 254 291 292 + fun setPoseFocusMode(mode: PoseFocusMode) { 293 + this.poseFocusMode = mode 294 + } 295 + 255 296 fun setDetectMode(detectMode: DetectMode) { 256 297 this.detectMode = detectMode 257 298 } 258 299 259 300 fun setObjectModel(objectModel: ObjectModel?) { 260 301 modelObj = objectModel?.getModel() 302 + modelInputW = objectModel?.inputWidth ?: 0 303 + modelInputH = objectModel?.inputHeight ?: 0 261 304 setUpRecognition() 262 305 } 263 306 ··· 316 359 onObjectsProcessed(emptyList()) 317 360 return@VNCoreMLRequest 318 361 } 319 - val results = request?.results as? List<*> ?: emptyList<Any>() 362 + val results = request?.results 363 + as? List<*> ?: emptyList<Any>() 320 364 val recognized = 321 365 results.filterIsInstance<VNRecognizedObjectObservation>() 322 366 val analysisObjects = recognized.map { observation -> ··· 418 462 height = height.toFloat(), 419 463 width = width.toFloat() 420 464 ) 421 - onSkeletonProcessed(skelBuffer.smooth(updatedSkeleton)) 465 + val hasAny = updatedSkeleton.joints().isNotEmpty() 466 + onSkeletonProcessed( 467 + poseSmoother.smooth( 468 + if (hasAny) updatedSkeleton else null, 469 + timestamp, 470 + ) 471 + ) 422 472 } 423 473 } 424 474 } ··· 463 513 } 464 514 } 465 515 516 + private fun finalizeSkeletonVisionPath( 517 + raw: Skeleton?, 518 + currentFocus: Rect?, 519 + currentMode: PoseFocusMode, 520 + usePoseCrop: Boolean, 521 + orientedW: Float, 522 + orientedH: Float, 523 + timestamp: Long, 524 + onSkeletonProcessed: (Skeleton?) -> Unit, 525 + ) { 526 + // When we cropped for real (CROP / CROP_FOLLOW), the detector only saw 527 + // the focus region so the result is inside by construction. Otherwise 528 + // (MASK / no focus) apply the existing post-filter. 529 + val filtered: Skeleton? = when { 530 + raw == null -> null 531 + usePoseCrop -> raw 532 + currentFocus != null -> if (raw.isInFocusArea(currentFocus)) raw else null 533 + else -> raw 534 + } 535 + if (currentMode == PoseFocusMode.CROP_FOLLOW && currentFocus != null) { 536 + followCropState.updateFromSkeleton( 537 + skeleton = filtered, 538 + analysisW = orientedW.toInt(), 539 + analysisH = orientedH.toInt(), 540 + clampTo = currentFocus, 541 + nowMs = timestamp, 542 + ) 543 + } 544 + val hasAny = filtered?.joints().orEmpty().isNotEmpty() 545 + onSkeletonProcessed( 546 + poseSmoother.smooth(if (hasAny) filtered else null, timestamp) 547 + ) 548 + } 549 + 466 550 fun Skeleton.isInFocusArea(focusArea: Rect?): Boolean { 467 551 if (focusArea == null || joints().isEmpty()) return true 468 552 val focusRect = Rect( ··· 482 566 timestamp: Long, 483 567 preview: AVCaptureVideoPreviewLayer?, 484 568 captureConnection: AVCaptureConnection? = preview?.connection, 569 + orientationOverride: AVCaptureVideoOrientation? = null, 570 + mirroredOverride: Boolean? = null, 485 571 onObjectsProcessed: (List<AnalysisObject>) -> Unit, 486 572 onSkeletonProcessed: (Skeleton?) -> Unit 487 573 ) { ··· 494 580 val retainedBuffer = CFRetain(buffer) 495 581 val rawWidth = CVPixelBufferGetWidth(buffer).toULong() 496 582 val rawHeight = CVPixelBufferGetHeight(buffer).toULong() 497 - val exifOrientation = captureConnection.visionExifOrientation() 498 - val orientedSize = orientedFrameSize(rawWidth, rawHeight, exifOrientation) 583 + // Object and pose paths use independent EXIF derivations — see 584 + // poseExifOrientation / objectExifOrientation for rationale. 585 + val exifForObjects = captureConnection.objectExifOrientation( 586 + orientationOverride = orientationOverride, 587 + mirroredOverride = mirroredOverride, 588 + ) 589 + val exifForPose = captureConnection.poseExifOrientation( 590 + orientationOverride = orientationOverride, 591 + mirroredOverride = mirroredOverride, 592 + ) 593 + // Both mappings agree on which orientations swap dims 594 + // (Portrait/PortraitUpsideDown → Left/Right EXIF, landscape → Up/Down), 595 + // so orientedSize is identical under either. Derive from exifForObjects 596 + // for direct continuity with the HEAD (pre-MLKit) object code path. 597 + val orientedSize = orientedFrameSize(rawWidth, rawHeight, exifForObjects) 499 598 500 599 memScoped { 501 600 val errorPtr = alloc<ObjCObjectVar<NSError?>>() ··· 511 610 val recognized = 512 611 results.filterIsInstance<VNRecognizedObjectObservation>() 513 612 514 - val analysisObjects = recognized.map { observation -> 515 - val boundingBox = observation.boundingBox.toOrientedPixelRect( 516 - rawWidth = rawWidth, 517 - rawHeight = rawHeight, 518 - exifOrientation = exifOrientation 519 - ) 520 - 521 - val labels = observation.labels.mapNotNull { 522 - (it as VNClassificationObservation).let { ca -> 523 - if (ca.confidence > 0.0) Label( 524 - ca.identifier, 525 - ca.confidence 526 - ) else null 613 + val analysisObjects = if (recognized.isNotEmpty()) { 614 + recognized.map { observation -> 615 + val boundingBox = 616 + observation.boundingBox.toOrientedPixelRect( 617 + rawWidth = rawWidth, 618 + rawHeight = rawHeight, 619 + exifOrientation = exifForObjects 620 + ) 621 + val labels = observation.labels.mapNotNull { 622 + (it as VNClassificationObservation).let { ca -> 623 + if (ca.confidence > 0.0) Label( 624 + ca.identifier, 625 + ca.confidence 626 + ) else null 627 + } 527 628 } 629 + AnalysisObject( 630 + trackingId = stableTrackingId(observation), 631 + labels = labels, 632 + boundingBox = boundingBox, 633 + frameSize = FrameSize( 634 + width = orientedSize.width.toInt().absoluteValue, 635 + height = orientedSize.height.toInt().absoluteValue 636 + ), 637 + timestamp = timestamp 638 + ) 528 639 } 529 - 530 - AnalysisObject( 531 - trackingId = stableTrackingId(observation), 532 - labels = labels, 533 - boundingBox = boundingBox, 534 - frameSize = FrameSize( 535 - width = orientedSize.width.toInt().absoluteValue, 536 - height = orientedSize.height.toInt().absoluteValue 537 - ), 640 + } else { 641 + // Raw multiarray output (e.g. yolo26n end2end). 642 + decodeRawMultiArrayDetections( 643 + results = results, 644 + modelInputW = modelInputW, 645 + modelInputH = modelInputH, 646 + orientedW = orientedSize.width, 647 + orientedH = orientedSize.height, 538 648 timestamp = timestamp 539 649 ) 540 650 } ··· 542 652 onObjectsProcessed(analysisObjects) 543 653 }.apply { 544 654 imageCropAndScaleOption = 545 - platform.Vision.VNImageCropAndScaleOptionCenterCrop 655 + platform.Vision.VNImageCropAndScaleOptionScaleFit 546 656 } 547 657 } 548 658 } else null 549 659 660 + // VNImageRequestHandler hosts the object (Vision) request and 661 + // — on simulator only — the Vision pose fallback. Use the 662 + // object EXIF here; on device the pose fallback never fires 663 + // (MLKit handles it below with exifForPose). 550 664 val options: Map<Any?, Any?> = mapOf( 551 - VN_IMAGE_OPTION_CG_IMAGE_PROPERTY_ORIENTATION to exifOrientation 665 + VN_IMAGE_OPTION_CG_IMAGE_PROPERTY_ORIENTATION to exifForObjects 552 666 ) 553 667 554 - val requestForSkeleton = if (detectMode.doPose()) { 668 + // CROP / CROP_FOLLOW: pick the effective crop rect in 669 + // oriented-top-left normalized space. 670 + val currentFocus = focusArea 671 + val currentMode = poseFocusMode 672 + val effectiveFocus: Rect? = when { 673 + currentFocus == null -> null 674 + currentMode == PoseFocusMode.CROP_FOLLOW -> 675 + followCropState.current(timestamp) ?: currentFocus 676 + currentMode == PoseFocusMode.CROP -> currentFocus 677 + else -> null 678 + } 679 + val usePoseCrop = effectiveFocus != null && detectMode.doPose() && 680 + (currentMode == PoseFocusMode.CROP || 681 + currentMode == PoseFocusMode.CROP_FOLLOW) 682 + val cropLeftPx: Float 683 + val cropTopPx: Float 684 + val cropWPx: Float 685 + val cropHPx: Float 686 + if (usePoseCrop && effectiveFocus != null) { 687 + cropLeftPx = (effectiveFocus.left * orientedSize.width) 688 + .coerceIn(0f, orientedSize.width) 689 + cropTopPx = (effectiveFocus.top * orientedSize.height) 690 + .coerceIn(0f, orientedSize.height) 691 + cropWPx = (effectiveFocus.width * orientedSize.width) 692 + .coerceIn(1f, orientedSize.width - cropLeftPx) 693 + cropHPx = (effectiveFocus.height * orientedSize.height) 694 + .coerceIn(1f, orientedSize.height - cropTopPx) 695 + } else { 696 + cropLeftPx = 0f; cropTopPx = 0f 697 + cropWPx = orientedSize.width; cropHPx = orientedSize.height 698 + } 699 + 700 + // Try MLKit first (iosArm64 only — sim targets stub out). 701 + // If MLKit returns a skeleton, skip Vision's pose request. 702 + var mlkitSkeleton: Skeleton? = null 703 + if (detectMode.doPose() && mlkitPose.isAvailable()) { 704 + mlkitSkeleton = mlkitPose.detect( 705 + buffer = buffer, 706 + exifOrientation = exifForPose, 707 + orientedW = orientedSize.width, 708 + orientedH = orientedSize.height, 709 + useCrop = usePoseCrop, 710 + cropLeftPx = cropLeftPx, 711 + cropTopPx = cropTopPx, 712 + cropWPx = cropWPx, 713 + cropHPx = cropHPx, 714 + timestamp = timestamp, 715 + ) 716 + } 717 + 718 + val mlkitHandled = detectMode.doPose() && mlkitPose.isAvailable() 719 + 720 + val requestForSkeleton = if (detectMode.doPose() && !mlkitHandled) { 555 721 VNDetectHumanBodyPoseRequest { request, error -> 556 722 if (error != null) { 557 723 onSkeletonProcessed(null) ··· 565 731 leftShoulder = pointsMap[VNHumanBodyPoseObservationJointNameLeftShoulder]?.location?.toOrientedPixelPoint( 566 732 rawWidth, 567 733 rawHeight, 568 - exifOrientation 734 + exifForObjects 569 735 ), 570 736 rightShoulder = pointsMap[VNHumanBodyPoseObservationJointNameRightShoulder]?.location?.toOrientedPixelPoint( 571 737 rawWidth, 572 738 rawHeight, 573 - exifOrientation 739 + exifForObjects 574 740 ), 575 741 leftElbow = pointsMap[VNHumanBodyPoseObservationJointNameLeftElbow]?.location?.toOrientedPixelPoint( 576 742 rawWidth, 577 743 rawHeight, 578 - exifOrientation 744 + exifForObjects 579 745 ), 580 746 rightElbow = pointsMap[VNHumanBodyPoseObservationJointNameRightElbow]?.location?.toOrientedPixelPoint( 581 747 rawWidth, 582 748 rawHeight, 583 - exifOrientation 749 + exifForObjects 584 750 ), 585 751 leftWrist = pointsMap[VNHumanBodyPoseObservationJointNameLeftWrist]?.location?.toOrientedPixelPoint( 586 752 rawWidth, 587 753 rawHeight, 588 - exifOrientation 754 + exifForObjects 589 755 ), 590 756 rightWrist = pointsMap[VNHumanBodyPoseObservationJointNameRightWrist]?.location?.toOrientedPixelPoint( 591 757 rawWidth, 592 758 rawHeight, 593 - exifOrientation 759 + exifForObjects 594 760 ), 595 761 leftHip = pointsMap[VNHumanBodyPoseObservationJointNameLeftHip]?.location?.toOrientedPixelPoint( 596 762 rawWidth, 597 763 rawHeight, 598 - exifOrientation 764 + exifForObjects 599 765 ), 600 766 rightHip = pointsMap[VNHumanBodyPoseObservationJointNameRightHip]?.location?.toOrientedPixelPoint( 601 767 rawWidth, 602 768 rawHeight, 603 - exifOrientation 769 + exifForObjects 604 770 ), 605 771 leftKnee = pointsMap[VNHumanBodyPoseObservationJointNameLeftKnee]?.location?.toOrientedPixelPoint( 606 772 rawWidth, 607 773 rawHeight, 608 - exifOrientation 774 + exifForObjects 609 775 ), 610 776 rightKnee = pointsMap[VNHumanBodyPoseObservationJointNameRightKnee]?.location?.toOrientedPixelPoint( 611 777 rawWidth, 612 778 rawHeight, 613 - exifOrientation 779 + exifForObjects 614 780 ), 615 781 leftAnkle = pointsMap[VNHumanBodyPoseObservationJointNameLeftAnkle]?.location?.toOrientedPixelPoint( 616 782 rawWidth, 617 783 rawHeight, 618 - exifOrientation 784 + exifForObjects 619 785 ), 620 786 rightAnkle = pointsMap[VNHumanBodyPoseObservationJointNameRightAnkle]?.location?.toOrientedPixelPoint( 621 787 rawWidth, 622 788 rawHeight, 623 - exifOrientation 789 + exifForObjects 624 790 ), 625 791 height = orientedSize.height, 626 792 width = orientedSize.width ··· 638 804 )?.location?.toOrientedPixelPoint( 639 805 rawWidth, 640 806 rawHeight, 641 - exifOrientation 807 + exifForObjects 642 808 ), 643 809 rightShoulder = recognizedPoints?.get( 644 810 VNHumanBodyPoseObservationJointNameRightShoulder 645 811 )?.location?.toOrientedPixelPoint( 646 812 rawWidth, 647 813 rawHeight, 648 - exifOrientation 814 + exifForObjects 649 815 ), 650 816 leftElbow = recognizedPoints?.get( 651 817 VNHumanBodyPoseObservationJointNameLeftElbow 652 818 )?.location?.toOrientedPixelPoint( 653 819 rawWidth, 654 820 rawHeight, 655 - exifOrientation 821 + exifForObjects 656 822 ), 657 823 rightElbow = recognizedPoints?.get( 658 824 VNHumanBodyPoseObservationJointNameRightElbow 659 825 )?.location?.toOrientedPixelPoint( 660 826 rawWidth, 661 827 rawHeight, 662 - exifOrientation 828 + exifForObjects 663 829 ), 664 830 leftWrist = recognizedPoints?.get( 665 831 VNHumanBodyPoseObservationJointNameLeftWrist 666 832 )?.location?.toOrientedPixelPoint( 667 833 rawWidth, 668 834 rawHeight, 669 - exifOrientation 835 + exifForObjects 670 836 ), 671 837 rightWrist = recognizedPoints?.get( 672 838 VNHumanBodyPoseObservationJointNameRightWrist 673 839 )?.location?.toOrientedPixelPoint( 674 840 rawWidth, 675 841 rawHeight, 676 - exifOrientation 842 + exifForObjects 677 843 ), 678 844 leftHip = recognizedPoints?.get( 679 845 VNHumanBodyPoseObservationJointNameLeftHip 680 846 )?.location?.toOrientedPixelPoint( 681 847 rawWidth, 682 848 rawHeight, 683 - exifOrientation 849 + exifForObjects 684 850 ), 685 851 rightHip = recognizedPoints?.get( 686 852 VNHumanBodyPoseObservationJointNameRightHip 687 853 )?.location?.toOrientedPixelPoint( 688 854 rawWidth, 689 855 rawHeight, 690 - exifOrientation 856 + exifForObjects 691 857 ), 692 858 leftKnee = recognizedPoints?.get( 693 859 VNHumanBodyPoseObservationJointNameLeftKnee 694 860 )?.location?.toOrientedPixelPoint( 695 861 rawWidth, 696 862 rawHeight, 697 - exifOrientation 863 + exifForObjects 698 864 ), 699 865 rightKnee = recognizedPoints?.get( 700 866 VNHumanBodyPoseObservationJointNameRightKnee 701 867 )?.location?.toOrientedPixelPoint( 702 868 rawWidth, 703 869 rawHeight, 704 - exifOrientation 870 + exifForObjects 705 871 ), 706 872 leftAnkle = recognizedPoints?.get( 707 873 VNHumanBodyPoseObservationJointNameLeftAnkle 708 874 )?.location?.toOrientedPixelPoint( 709 875 rawWidth, 710 876 rawHeight, 711 - exifOrientation 877 + exifForObjects 712 878 ), 713 879 rightAnkle = recognizedPoints?.get( 714 880 VNHumanBodyPoseObservationJointNameRightAnkle 715 881 )?.location?.toOrientedPixelPoint( 716 882 rawWidth, 717 883 rawHeight, 718 - exifOrientation 884 + exifForObjects 719 885 ), 720 886 height = orientedSize.height, 721 887 width = orientedSize.width 722 888 ) 723 889 724 - onSkeletonProcessed(skelBuffer.smooth(updatedSkeleton)) 890 + // Vision skeleton completes post-processing via finalizeSkeleton below. 891 + finalizeSkeletonVisionPath( 892 + raw = updatedSkeleton, 893 + currentFocus = currentFocus, 894 + currentMode = currentMode, 895 + usePoseCrop = usePoseCrop, 896 + orientedW = orientedSize.width, 897 + orientedH = orientedSize.height, 898 + timestamp = timestamp, 899 + onSkeletonProcessed = onSkeletonProcessed, 900 + ) 725 901 } 726 902 } 727 903 } 728 904 } else null 729 905 730 906 requestForSkeleton?.regionOfInterest = regionOfInterest 731 - val handler = VNImageRequestHandler(buffer, options) 907 + // Use the init that takes orientation as an explicit 908 + // parameter — passing EXIF via the options dictionary 909 + // (VNImageOptionCGImagePropertyOrientation key) was silently 910 + // ignored by Vision, leaving it to process raw landscape 911 + // pixels and return coords in that frame regardless of the 912 + // phone's actual orientation. 913 + val handler = VNImageRequestHandler( 914 + buffer, 915 + exifForObjects.toUInt(), 916 + emptyMap<Any?, Any?>() 917 + ) 732 918 handler.performRequests( 733 919 listOfNotNull(requestForObjects, requestForSkeleton), 734 920 errorPtr.ptr 735 921 ) 922 + 923 + // If MLKit handled pose, emit its result (with post-processing) here. 924 + // When MLKit is unavailable / returned null, the Vision callback already emitted above. 925 + if (mlkitHandled) { 926 + finalizeSkeletonVisionPath( 927 + raw = mlkitSkeleton, 928 + currentFocus = currentFocus, 929 + currentMode = currentMode, 930 + usePoseCrop = usePoseCrop, 931 + orientedW = orientedSize.width, 932 + orientedH = orientedSize.height, 933 + timestamp = timestamp, 934 + onSkeletonProcessed = onSkeletonProcessed, 935 + ) 936 + } 736 937 737 938 CFRelease(retainedBuffer) 738 939 ··· 812 1013 813 1014 private fun stableTrackingId(observation: VNRecognizedObjectObservation): Int = 814 1015 observation.hashCode() 1016 + 1017 + private val RAW_CLASS_NAMES = listOf("basketball", "basketball_hoop") 1018 + 1019 + @OptIn(ExperimentalForeignApi::class) 1020 + private fun decodeRawMultiArrayDetections( 1021 + results: List<*>, 1022 + modelInputW: Int, 1023 + modelInputH: Int, 1024 + orientedW: Float, 1025 + orientedH: Float, 1026 + timestamp: Long, 1027 + ): List<AnalysisObject> { 1028 + if (modelInputW <= 0 || modelInputH <= 0) return emptyList() 1029 + val featureObs = results.filterIsInstance<VNCoreMLFeatureValueObservation>() 1030 + val out = mutableListOf<AnalysisObject>() 1031 + for (obs in featureObs) { 1032 + val arr: MLMultiArray = obs.featureValue.multiArrayValue ?: continue 1033 + val shape = arr.shape 1034 + if (shape.size != 3) continue 1035 + val dim1 = (shape[1] as NSNumber).intValue 1036 + val dim2 = (shape[2] as NSNumber).intValue 1037 + if (dim2 != 6) continue 1038 + val dataPtr = arr.dataPointer?.reinterpret<FloatVar>() ?: continue 1039 + 1040 + // Use strides (element counts) to compute offsets — safe against 1041 + // non-contiguous storage. 1042 + val strides = arr.strides 1043 + val rowStride = if (strides.size == 3) (strides[1] as NSNumber).intValue else 6 1044 + val colStride = if (strides.size == 3) (strides[2] as NSNumber).intValue else 1 1045 + fun at(i: Int, j: Int): Float = dataPtr[i * rowStride + j * colStride] 1046 + 1047 + // Ultralytics end2end CoreML export emits pixel-space coordinates over 1048 + // the model input. Vision's VNImageCropAndScaleOptionScaleFit letterboxes 1049 + // the source into the model input, preserving aspect ratio. When source 1050 + // aspect != model input aspect, the letterbox adds padding that we must 1051 + // undo — otherwise boxes get pulled toward the image center by the 1052 + // fraction of padding. Specifically: portrait source (3:4) into landscape 1053 + // model input (4:3) adds horizontal black bars, and a simple 1054 + // `(mx/modelInputW)*orientedW` produces x coords shifted toward center. 1055 + val mW = modelInputW.toFloat() 1056 + val mH = modelInputH.toFloat() 1057 + val scale = minOf(mW / orientedW, mH / orientedH) 1058 + val scaledW = orientedW * scale 1059 + val scaledH = orientedH * scale 1060 + val padX = (mW - scaledW) / 2f 1061 + val padY = (mH - scaledH) / 2f 1062 + fun modelXToScene(mx: Float): Float = ((mx - padX) / scale).coerceIn(0f, orientedW) 1063 + fun modelYToScene(my: Float): Float = ((my - padY) / scale).coerceIn(0f, orientedH) 1064 + 1065 + for (i in 0 until dim1) { 1066 + val conf = at(i, 4) 1067 + if (conf <= 0.25f) continue 1068 + val x1n = at(i, 0) 1069 + val y1n = at(i, 1) 1070 + val x2n = at(i, 2) 1071 + val y2n = at(i, 3) 1072 + val cls = at(i, 5).toInt() 1073 + val leftPx = modelXToScene(min(x1n, x2n)) 1074 + val rightPx = modelXToScene(max(x1n, x2n)) 1075 + val topPx = modelYToScene(min(y1n, y2n)) 1076 + val bottomPx = modelYToScene(max(y1n, y2n)) 1077 + val label = RAW_CLASS_NAMES.getOrNull(cls) ?: "class_$cls" 1078 + out.add( 1079 + AnalysisObject( 1080 + trackingId = 0, 1081 + labels = listOf(Label(label, conf)), 1082 + boundingBox = Rect(leftPx, topPx, rightPx, bottomPx), 1083 + frameSize = FrameSize( 1084 + width = orientedW.toInt().absoluteValue, 1085 + height = orientedH.toInt().absoluteValue 1086 + ), 1087 + timestamp = timestamp 1088 + ) 1089 + ) 1090 + } 1091 + } 1092 + return out 1093 + } 815 1094 816 1095 data class DetectedObject @OptIn(ExperimentalForeignApi::class) constructor( 817 1096 val id: String = NSUUID().UUIDString(),
+31
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/camera/MlKitPose.kt
··· 1 + package com.performancecoachlab.posedetection.camera 2 + 3 + import com.performancecoachlab.posedetection.skeleton.Skeleton 4 + import kotlinx.cinterop.ExperimentalForeignApi 5 + import platform.CoreVideo.CVImageBufferRef 6 + 7 + /** 8 + * Per-platform MLKit pose adapter. Only iosArm64 ships MLKit static archives 9 + * (embedded into the library's cinterop klib). Simulator targets get a stub 10 + * that reports unavailable so FrameProcessor falls back to Apple Vision. 11 + * 12 + * Landmarks come back in **oriented full-frame pixel space, top-left origin** 13 + * regardless of whether a crop was supplied — the adapter handles the remap. 14 + */ 15 + @OptIn(ExperimentalForeignApi::class) 16 + internal expect class MlKitPose() { 17 + fun isAvailable(): Boolean 18 + 19 + fun detect( 20 + buffer: CVImageBufferRef, 21 + exifOrientation: Int, 22 + orientedW: Float, 23 + orientedH: Float, 24 + useCrop: Boolean, 25 + cropLeftPx: Float, 26 + cropTopPx: Float, 27 + cropWPx: Float, 28 + cropHPx: Float, 29 + timestamp: Long, 30 + ): Skeleton? 31 + }
+25 -19
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/custom/CustomObjectModel.ios.kt
··· 9 9 10 10 @Composable 11 11 actual fun initialiseObjectModel(modelPath: ModelPath): ObjectModel { 12 - val model = createObjectDetector(modelPath.iosModelPath) 13 - return ObjectModel(model) 12 + return createObjectDetector(modelPath.iosModelPath) 14 13 } 15 14 16 15 @OptIn(ExperimentalForeignApi::class) 17 - fun createObjectDetector(model: String?): VNCoreMLModel? { 16 + fun createObjectDetector(model: String?): ObjectModel { 18 17 if (model == null) { 19 - return null 18 + return ObjectModel(null, 0, 0) 20 19 } 21 - //println("Model input: $model") 22 20 val path = NSBundle.mainBundle.pathForResource(model, "mlmodelc") 23 - //println("Model path: $path") 24 21 val url = path?.let { NSURL.fileURLWithPath(it) } 25 - //println("Model URL: $url") 26 - val modelCont = url?.let { MLModel.modelWithContentsOfURL(it, null) } 27 - //println("Model content: $modelCont") 28 - val modelObj = modelCont?.let { VNCoreMLModel.modelForMLModel(it, null) } 29 - //println("Model: $modelObj") 30 - return modelObj 22 + val mlModel = url?.let { MLModel.modelWithContentsOfURL(it, null) } 23 + val vnModel = mlModel?.let { VNCoreMLModel.modelForMLModel(it, null) } 24 + val (w, h) = inferInputSizeFromName(model) 25 + return ObjectModel(vnModel, w, h) 31 26 } 32 27 33 - actual class ObjectModel { 34 - private var model: VNCoreMLModel? = null 28 + // Infer the model's letterbox input size from the filename suffix. 29 + // Matches the `_<W>x<H>` convention used by the rect exports (e.g. 30 + // `yolo26n_v11_rect_512x384`). Models without this suffix get (0, 0), 31 + // which disables letterboxing and preserves prior Vision-default behavior. 32 + private val INPUT_SIZE_SUFFIX = Regex("_(\\d+)x(\\d+)$") 35 33 36 - constructor(model: VNCoreMLModel?) { 37 - this.model = model 34 + internal fun inferInputSizeFromName(name: String): Pair<Int, Int> { 35 + INPUT_SIZE_SUFFIX.find(name)?.let { m -> 36 + val w = m.groupValues[1].toIntOrNull() ?: return 0 to 0 37 + val h = m.groupValues[2].toIntOrNull() ?: return 0 to 0 38 + return w to h 38 39 } 40 + return 0 to 0 41 + } 39 42 40 - fun getModel(): VNCoreMLModel? { 41 - return model 42 - } 43 + actual class ObjectModel( 44 + private val model: VNCoreMLModel?, 45 + val inputWidth: Int, 46 + val inputHeight: Int, 47 + ) { 48 + fun getModel(): VNCoreMLModel? = model 43 49 } 44 50 45 51 @Composable
+258
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/custom/ImageDetector.ios.kt
··· 1 + package com.performancecoachlab.posedetection.custom 2 + 3 + import androidx.compose.ui.geometry.Rect 4 + import androidx.compose.ui.graphics.ImageBitmap 5 + import androidx.compose.ui.graphics.toPixelMap 6 + import com.performancecoachlab.posedetection.recording.AnalysisObject 7 + import com.performancecoachlab.posedetection.recording.FrameSize 8 + import com.performancecoachlab.posedetection.recording.Label 9 + import kotlinx.cinterop.CPointer 10 + import kotlinx.cinterop.ExperimentalForeignApi 11 + import kotlinx.cinterop.FloatVar 12 + import kotlinx.cinterop.addressOf 13 + import kotlinx.cinterop.get 14 + import kotlinx.cinterop.reinterpret 15 + import kotlinx.cinterop.usePinned 16 + import platform.CoreGraphics.* 17 + import platform.CoreML.MLMultiArray 18 + import platform.Foundation.NSNumber 19 + import platform.Vision.VNCoreMLFeatureValueObservation 20 + import platform.Vision.VNCoreMLRequest 21 + import platform.Vision.VNImageCropAndScaleOptionScaleFit 22 + import platform.Vision.VNImageRequestHandler 23 + import platform.Vision.VNRecognizedObjectObservation 24 + import kotlin.math.max 25 + import kotlin.math.min 26 + 27 + @OptIn(ExperimentalForeignApi::class) 28 + actual class ImageDetector actual constructor(model: ObjectModel) { 29 + 30 + private val vncoreModel = model.getModel() 31 + private val inputW = model.inputWidth 32 + private val inputH = model.inputHeight 33 + 34 + actual fun detect(image: ImageBitmap): List<AnalysisObject> { 35 + val model = vncoreModel ?: return emptyList() 36 + val imgW = image.width 37 + val imgH = image.height 38 + if (imgW <= 0 || imgH <= 0) return emptyList() 39 + 40 + val srcCgImage = createCgImageFromImageBitmap(image) ?: return emptyList() 41 + 42 + // If we know the model's input size, letterbox the source into 43 + // (inputW × inputH) with gray-114 padding — matching ultralytics' 44 + // training-time preprocessing. Otherwise fall back to passing the 45 + // raw image and letting Vision scale it. 46 + val useLetterbox = inputW > 0 && inputH > 0 47 + val scale: Float 48 + val padX: Float 49 + val padY: Float 50 + val handlerImage: CPointer<cnames.structs.CGImage> 51 + if (useLetterbox) { 52 + val s = min( 53 + inputW.toFloat() / imgW.toFloat(), 54 + inputH.toFloat() / imgH.toFloat() 55 + ) 56 + val scaledW = (imgW * s) 57 + val scaledH = (imgH * s) 58 + val px = (inputW - scaledW) / 2f 59 + val py = (inputH - scaledH) / 2f 60 + val letterboxed = createLetterboxedCgImage(srcCgImage, inputW, inputH, px, py, scaledW, scaledH) 61 + CGImageRelease(srcCgImage) 62 + if (letterboxed == null) return emptyList() 63 + scale = s 64 + padX = px 65 + padY = py 66 + handlerImage = letterboxed 67 + } else { 68 + scale = 1f 69 + padX = 0f 70 + padY = 0f 71 + handlerImage = srcCgImage 72 + } 73 + 74 + val results = mutableListOf<AnalysisObject>() 75 + val bbW = if (useLetterbox) inputW.toFloat() else imgW.toFloat() 76 + val bbH = if (useLetterbox) inputH.toFloat() else imgH.toFloat() 77 + val request = VNCoreMLRequest(model) { req, _ -> 78 + val observations = req?.results as? List<*> ?: return@VNCoreMLRequest 79 + for (obs in observations) { 80 + when (obs) { 81 + is VNRecognizedObjectObservation -> { 82 + // Vision-compatible model (classifier + coordinates pipeline). 83 + // Coords: origin bottom-left, normalized 0-1 over the handler image. 84 + val label = obs.labels.firstOrNull()?.toString() ?: "Unknown" 85 + val confidence = obs.confidence 86 + val bb = obs.boundingBox 87 + val x1LB = CGRectGetMinX(bb).toFloat() * bbW 88 + val y1LB = (1f - CGRectGetMaxY(bb).toFloat()) * bbH 89 + val x2LB = CGRectGetMaxX(bb).toFloat() * bbW 90 + val y2LB = (1f - CGRectGetMinY(bb).toFloat()) * bbH 91 + addDetection( 92 + results, x1LB, y1LB, x2LB, y2LB, padX, padY, scale, 93 + imgW, imgH, label, confidence 94 + ) 95 + } 96 + is VNCoreMLFeatureValueObservation -> { 97 + // Raw multiarray output (e.g. yolo26n end2end). Shape 98 + // [1, 300, 6] with rows [x1, y1, x2, y2, conf, cls] in 99 + // normalized top-left-origin coords over the handler image. 100 + val arr = obs.featureValue.multiArrayValue ?: continue 101 + decodeRawDetections( 102 + arr, results, bbW, bbH, padX, padY, scale, imgW, imgH 103 + ) 104 + } 105 + } 106 + } 107 + }.apply { 108 + // Belt-and-suspenders: input already matches model aspect when 109 + // letterboxed, so this is effectively a no-op — but prevents 110 + // Vision from re-cropping if anything upstream shifts. 111 + imageCropAndScaleOption = VNImageCropAndScaleOptionScaleFit 112 + } 113 + 114 + val handler = VNImageRequestHandler(handlerImage, mapOf<Any?, Any?>()) 115 + handler.performRequests(listOf(request), null) 116 + 117 + CGImageRelease(handlerImage) 118 + return results 119 + } 120 + } 121 + 122 + private fun addDetection( 123 + results: MutableList<AnalysisObject>, 124 + x1LB: Float, y1LB: Float, x2LB: Float, y2LB: Float, 125 + padX: Float, padY: Float, scale: Float, 126 + imgW: Int, imgH: Int, 127 + label: String, confidence: Float, 128 + ) { 129 + val left = ((x1LB - padX) / scale).coerceIn(0f, imgW.toFloat()) 130 + val top = ((y1LB - padY) / scale).coerceIn(0f, imgH.toFloat()) 131 + val right = ((x2LB - padX) / scale).coerceIn(0f, imgW.toFloat()) 132 + val bottom = ((y2LB - padY) / scale).coerceIn(0f, imgH.toFloat()) 133 + results.add( 134 + AnalysisObject( 135 + boundingBox = Rect(left, top, right, bottom), 136 + trackingId = 0, 137 + labels = listOf(Label(label, confidence)), 138 + frameSize = FrameSize(imgW, imgH), 139 + timestamp = 0L 140 + ) 141 + ) 142 + } 143 + 144 + private val CLASS_NAMES = listOf("basketball", "basketball_hoop") 145 + 146 + @OptIn(ExperimentalForeignApi::class) 147 + private fun decodeRawDetections( 148 + arr: MLMultiArray, 149 + results: MutableList<AnalysisObject>, 150 + bbW: Float, bbH: Float, 151 + padX: Float, padY: Float, scale: Float, 152 + imgW: Int, imgH: Int, 153 + ) { 154 + val shape = arr.shape 155 + if (shape.size != 3) return 156 + val dim1 = (shape[1] as NSNumber).intValue 157 + val dim2 = (shape[2] as NSNumber).intValue 158 + // Expect [1, N, 6] (yolo end2end). 159 + if (dim2 != 6) return 160 + val elements = dim1 161 + val dataPtr = arr.dataPointer?.reinterpret<FloatVar>() ?: return 162 + fun at(i: Int, j: Int): Float = dataPtr[i * 6 + j] 163 + for (i in 0 until elements) { 164 + val conf = at(i, 4) 165 + if (conf <= 0.25f) continue 166 + val x1n = at(i, 0) 167 + val y1n = at(i, 1) 168 + val x2n = at(i, 2) 169 + val y2n = at(i, 3) 170 + val cls = at(i, 5).toInt() 171 + // Top-left-origin normalized coords over the handler image. 172 + val x1LB = min(x1n, x2n) * bbW 173 + val y1LB = min(y1n, y2n) * bbH 174 + val x2LB = max(x1n, x2n) * bbW 175 + val y2LB = max(y1n, y2n) * bbH 176 + val label = CLASS_NAMES.getOrNull(cls) ?: "class_$cls" 177 + addDetection( 178 + results, x1LB, y1LB, x2LB, y2LB, padX, padY, scale, 179 + imgW, imgH, label, conf 180 + ) 181 + } 182 + } 183 + 184 + @OptIn(ExperimentalForeignApi::class) 185 + private fun createCgImageFromImageBitmap(image: ImageBitmap): CPointer<cnames.structs.CGImage>? { 186 + val w = image.width 187 + val h = image.height 188 + val pixelMap = image.toPixelMap() 189 + val buffer = ByteArray(w * h * 4) 190 + for (y in 0 until h) { 191 + for (x in 0 until w) { 192 + val color = pixelMap[x, y] 193 + val idx = (y * w + x) * 4 194 + buffer[idx] = (color.red * 255).toInt().toByte() 195 + buffer[idx + 1] = (color.green * 255).toInt().toByte() 196 + buffer[idx + 2] = (color.blue * 255).toInt().toByte() 197 + buffer[idx + 3] = (color.alpha * 255).toInt().toByte() 198 + } 199 + } 200 + val colorSpace = CGColorSpaceCreateDeviceRGB() 201 + val bitmapInfo = CGImageAlphaInfo.kCGImageAlphaPremultipliedLast.value 202 + val context = CGBitmapContextCreate( 203 + null, w.toULong(), h.toULong(), 8u, 204 + (w * 4).toULong(), colorSpace, bitmapInfo 205 + ) ?: run { 206 + CGColorSpaceRelease(colorSpace) 207 + return null 208 + } 209 + buffer.usePinned { pinned -> 210 + val data = CGBitmapContextGetData(context) 211 + if (data != null) { 212 + platform.posix.memcpy(data, pinned.addressOf(0), (w * h * 4).toULong()) 213 + } 214 + } 215 + val cgImage = CGBitmapContextCreateImage(context) 216 + CGContextRelease(context) 217 + CGColorSpaceRelease(colorSpace) 218 + return cgImage 219 + } 220 + 221 + @OptIn(ExperimentalForeignApi::class) 222 + private fun createLetterboxedCgImage( 223 + src: CPointer<cnames.structs.CGImage>, 224 + outW: Int, 225 + outH: Int, 226 + padX: Float, 227 + padY: Float, 228 + drawW: Float, 229 + drawH: Float, 230 + ): CPointer<cnames.structs.CGImage>? { 231 + val colorSpace = CGColorSpaceCreateDeviceRGB() 232 + val bitmapInfo = CGImageAlphaInfo.kCGImageAlphaPremultipliedLast.value 233 + val ctx = CGBitmapContextCreate( 234 + null, outW.toULong(), outH.toULong(), 8u, 235 + (outW * 4).toULong(), colorSpace, bitmapInfo 236 + ) ?: run { 237 + CGColorSpaceRelease(colorSpace) 238 + return null 239 + } 240 + 241 + // Gray-114 fill to match ultralytics letterbox padding. 242 + CGContextSetRGBFillColor(ctx, 114.0 / 255.0, 114.0 / 255.0, 114.0 / 255.0, 1.0) 243 + CGContextFillRect(ctx, CGRectMake(0.0, 0.0, outW.toDouble(), outH.toDouble())) 244 + 245 + // Core Graphics has bottom-left origin; our padY/drawH are top-left, 246 + // so flip the Y coordinate before drawing. 247 + val flippedY = outH.toFloat() - padY - drawH 248 + CGContextDrawImage( 249 + ctx, 250 + CGRectMake(padX.toDouble(), flippedY.toDouble(), drawW.toDouble(), drawH.toDouble()), 251 + src 252 + ) 253 + 254 + val image = CGBitmapContextCreateImage(ctx) 255 + CGContextRelease(ctx) 256 + CGColorSpaceRelease(colorSpace) 257 + return image 258 + }
+26
posedetection/src/iosSimulatorArm64Main/kotlin/com/performancecoachlab/posedetection/camera/MlKitPose.kt
··· 1 + package com.performancecoachlab.posedetection.camera 2 + 3 + import com.performancecoachlab.posedetection.skeleton.Skeleton 4 + import kotlinx.cinterop.ExperimentalForeignApi 5 + import platform.CoreVideo.CVImageBufferRef 6 + 7 + // Sim targets don't ship MLKit binaries (no arm64-simulator slice available 8 + // upstream). FrameProcessor will see isAvailable()=false and fall back to 9 + // Apple Vision. 10 + @OptIn(ExperimentalForeignApi::class) 11 + internal actual class MlKitPose actual constructor() { 12 + actual fun isAvailable(): Boolean = false 13 + 14 + actual fun detect( 15 + buffer: CVImageBufferRef, 16 + exifOrientation: Int, 17 + orientedW: Float, 18 + orientedH: Float, 19 + useCrop: Boolean, 20 + cropLeftPx: Float, 21 + cropTopPx: Float, 22 + cropWPx: Float, 23 + cropHPx: Float, 24 + timestamp: Long, 25 + ): Skeleton? = null 26 + }
+24
posedetection/src/iosX64Main/kotlin/com/performancecoachlab/posedetection/camera/MlKitPose.kt
··· 1 + package com.performancecoachlab.posedetection.camera 2 + 3 + import com.performancecoachlab.posedetection.skeleton.Skeleton 4 + import kotlinx.cinterop.ExperimentalForeignApi 5 + import platform.CoreVideo.CVImageBufferRef 6 + 7 + // Sim targets don't ship MLKit binaries. See iosSimulatorArm64Main/MlKitPose.kt. 8 + @OptIn(ExperimentalForeignApi::class) 9 + internal actual class MlKitPose actual constructor() { 10 + actual fun isAvailable(): Boolean = false 11 + 12 + actual fun detect( 13 + buffer: CVImageBufferRef, 14 + exifOrientation: Int, 15 + orientedW: Float, 16 + orientedH: Float, 17 + useCrop: Boolean, 18 + cropLeftPx: Float, 19 + cropTopPx: Float, 20 + cropWPx: Float, 21 + cropHPx: Float, 22 + timestamp: Long, 23 + ): Skeleton? = null 24 + }
+265
posedetection/src/nativeInterop/mlkitRedirect/MLKitResourceRedirect.m
··· 1 + // Redirects MLKit's NSBundle URLForResource:withExtension: lookups for its 2 + // resource bundles (MLKitPoseDetectionAccurateResources, 3 + // MLKitPoseDetectionCommonResources, MLKitXenoResources) to a directory the 4 + // library's Kotlin init code populates at runtime. Without this, MLKit's 5 + // `.tflite` / `.binarypb` weights have to be copied into the consumer's app 6 + // bundle via an Xcode build phase — forcing per-app setup. 7 + // 8 + // Kotlin side calls mlkit_set_resource_dir() with a Caches-directory path 9 + // after extracting the resource files there. The swizzled URLForResource 10 + // method first defers to the original (so non-MLKit lookups are unaffected), 11 + // then falls back to the registered directory for the specific bundle names 12 + // MLKit queries. 13 + 14 + #import <Foundation/Foundation.h> 15 + #import <objc/runtime.h> 16 + 17 + static NSString *_mlkitResourceDir = nil; 18 + 19 + // Install MLKit telemetry stubs. Safe to call multiple times. 20 + // Runs at two points: during +load (MLKit classes may not be registered yet, 21 + // in which case we silently skip and retry), and from mlkit_set_resource_dir 22 + // (called by Kotlin after app init — all classes definitely loaded by then). 23 + // Each stub has its own "installed" flag so partial success on the first 24 + // attempt still leaves work for the second. 25 + static void _pd_mlkit_noop_log(id, SEL, id, id); 26 + static void _pd_mlkit_noop_writelog(id, SEL, id, id, id, id, id, id, id); 27 + static id _pd_mlkit_compute_url(Class, SEL, id, id, id); 28 + static void _pd_mlkit_noop_start_auto_upload(id, SEL); 29 + static void _pd_mlkit_noop_flush_upload(id, SEL, id, BOOL); 30 + static void _pd_mlkit_noop_log_counters(id, SEL, id); 31 + 32 + static BOOL _pd_logger_stubbed = NO; 33 + static BOOL _pd_writer_stubbed = NO; 34 + static BOOL _pd_fileutil_stubbed = NO; 35 + static BOOL _pd_uploader_start_stubbed = NO; 36 + static BOOL _pd_uploader_flush_stubbed = NO; 37 + static BOOL _pd_metalogger_stubbed = NO; 38 + 39 + static void _pd_install_clearcut_stub(void) { 40 + // 1. -[MLKITx_CCTClearcutLogger log:completion:] (high-level entry) 41 + if (!_pd_logger_stubbed) { 42 + Class logger = NSClassFromString(@"MLKITx_CCTClearcutLogger"); 43 + if (logger) { 44 + Method m = class_getInstanceMethod(logger, 45 + @selector(log:completion:)); 46 + if (m) { 47 + method_setImplementation(m, (IMP)_pd_mlkit_noop_log); 48 + _pd_logger_stubbed = YES; 49 + } 50 + } 51 + } 52 + // 2. -[MLKITx_CCTLogWriter writeLog:pseudonymousID:logDirectory:clock: 53 + // logTransformers:completionQueue:completion:] 54 + // Some callers bypass the Logger and hit the LogWriter directly — 55 + // which is the path kima's crash stack showed. 56 + if (!_pd_writer_stubbed) { 57 + Class writer = NSClassFromString(@"MLKITx_CCTLogWriter"); 58 + if (writer) { 59 + Method m = class_getInstanceMethod(writer, 60 + @selector(writeLog:pseudonymousID:logDirectory:clock:logTransformers:completionQueue:completion:)); 61 + if (m) { 62 + method_setImplementation(m, (IMP)_pd_mlkit_noop_writelog); 63 + _pd_writer_stubbed = YES; 64 + } 65 + } 66 + } 67 + // 3. Fallback: if neither stub fires and something reaches 68 + // +[MLKITx_CCTClearcutFileUtility computeUrlForLogContextDir:context: 69 + // bundleId:], make that class method respond instead of throwing. 70 + if (!_pd_fileutil_stubbed) { 71 + Class fileutil = NSClassFromString(@"MLKITx_CCTClearcutFileUtility"); 72 + if (fileutil) { 73 + SEL sel = @selector(computeUrlForLogContextDir:context:bundleId:); 74 + // Try to override the existing method impl if there IS one; if 75 + // not (this is what causes the original crash — the class method 76 + // table has lost the entry), add it via the metaclass. 77 + Method existing = class_getClassMethod(fileutil, sel); 78 + if (existing) { 79 + method_setImplementation(existing, (IMP)_pd_mlkit_compute_url); 80 + _pd_fileutil_stubbed = YES; 81 + } else { 82 + Class meta = object_getClass((id)fileutil); 83 + if (meta && class_addMethod(meta, sel, 84 + (IMP)_pd_mlkit_compute_url, 85 + "@@:@@@")) { 86 + _pd_fileutil_stubbed = YES; 87 + } 88 + } 89 + } 90 + } 91 + // 4. Auto-upload path (separate from writeLog — fires on a periodic 92 + // timer, not per pose detection). Stub at three levels so any call 93 + // into the chain gets neutralized before reaching the broken 94 + // logCounters / flushCounters code. 95 + Class uploader = NSClassFromString(@"MLKITx_CCTClearcutUploader"); 96 + if (uploader) { 97 + if (!_pd_uploader_start_stubbed) { 98 + Method m = class_getInstanceMethod(uploader, 99 + @selector(startAutoUpload)); 100 + if (m) { 101 + method_setImplementation(m, (IMP)_pd_mlkit_noop_start_auto_upload); 102 + _pd_uploader_start_stubbed = YES; 103 + } 104 + } 105 + if (!_pd_uploader_flush_stubbed) { 106 + Method m = class_getInstanceMethod(uploader, 107 + @selector(flushThenUploadWithCompletionHandler:isOnForeground:)); 108 + if (m) { 109 + method_setImplementation(m, (IMP)_pd_mlkit_noop_flush_upload); 110 + _pd_uploader_flush_stubbed = YES; 111 + } 112 + } 113 + } 114 + if (!_pd_metalogger_stubbed) { 115 + Class meta = NSClassFromString(@"MLKITx_CCTClearcutMetaLogger"); 116 + if (meta) { 117 + Method m = class_getInstanceMethod(meta, 118 + @selector(logCounters:)); 119 + if (m) { 120 + method_setImplementation(m, (IMP)_pd_mlkit_noop_log_counters); 121 + _pd_metalogger_stubbed = YES; 122 + } 123 + } 124 + } 125 + } 126 + 127 + __attribute__((visibility("default"))) 128 + void mlkit_set_resource_dir(const char *path) { 129 + if (path) { 130 + _mlkitResourceDir = [NSString stringWithUTF8String:path]; 131 + } else { 132 + _mlkitResourceDir = nil; 133 + } 134 + _pd_install_clearcut_stub(); 135 + } 136 + 137 + static NSSet<NSString *> *mlkitBundleNames(void) { 138 + static NSSet *names; 139 + static dispatch_once_t once; 140 + dispatch_once(&once, ^{ 141 + names = [NSSet setWithObjects: 142 + @"MLKitPoseDetectionAccurateResources", 143 + @"MLKitPoseDetectionCommonResources", 144 + @"MLKitXenoResources", 145 + nil]; 146 + }); 147 + return names; 148 + } 149 + 150 + // No-op replacement for -[MLKITx_CCTClearcutLogger log:completion:]. 151 + // MLKit's Clearcut telemetry subsystem crashes at runtime on some iOS 152 + // versions when it tries to compute a log-context URL (the selector 153 + // `+[MLKITx_CCTClearcutFileUtility computeUrlForLogContextDir:context:bundleId:]` 154 + // goes missing at the app-link step even with -ObjC when the consumer 155 + // builds a static framework). Telemetry isn't needed for pose detection, 156 + // so we replace the top-level log entry with a completion-handler call 157 + // that signals success but does nothing. 158 + static void _pd_mlkit_noop_log(id self, SEL _cmd, id event, id completion) { 159 + if (completion) { 160 + void (^block)(BOOL, NSError *) = completion; 161 + block(YES, nil); 162 + } 163 + } 164 + 165 + // No-op replacement for the 7-arg LogWriter writeLog. Some callers bypass 166 + // CCTClearcutLogger and call CCTLogWriter directly — stubbing only the 167 + // Logger isn't enough. This signature matches the actual method: 168 + // -[MLKITx_CCTLogWriter writeLog:pseudonymousID:logDirectory:clock: 169 + // logTransformers:completionQueue:completion:] 170 + static void _pd_mlkit_noop_writelog(id self, SEL _cmd, 171 + id log, id pid, id logDir, id clock, 172 + id transformers, id completionQueue, 173 + id completion) { 174 + if (completion) { 175 + void (^block)(BOOL, NSError *) = completion; 176 + if (completionQueue) { 177 + // Preserve semantics: callers typically want the completion 178 + // delivered on their queue. dispatch_async into it, else call 179 + // inline. 180 + dispatch_async((dispatch_queue_t)completionQueue, ^{ 181 + block(YES, nil); 182 + }); 183 + } else { 184 + block(YES, nil); 185 + } 186 + } 187 + } 188 + 189 + // Fallback for the missing +[MLKITx_CCTClearcutFileUtility 190 + // computeUrlForLogContextDir:context:bundleId:] class method. Return the 191 + // logContextDir NSURL unchanged — good enough to satisfy any caller that 192 + // slips past our writeLog stub. 193 + static id _pd_mlkit_compute_url(Class self, SEL _cmd, 194 + id logContextDir, id context, id bundleId) { 195 + return logContextDir; 196 + } 197 + 198 + // MLKit also starts a periodic auto-upload timer that crashes when it 199 + // reaches CCTClearcutMetaLogger logCounters:. Separate code path from 200 + // writeLog. We stub it at multiple levels for belt-and-braces: 201 + // top: -[MLKITx_CCTClearcutUploader startAutoUpload] 202 + // — cleanest, prevents the timer from starting 203 + // middle: -[MLKITx_CCTClearcutUploader 204 + // flushThenUploadWithCompletionHandler:isOnForeground:] 205 + // — invoked directly when foreground-entering; no-op + call 206 + // completion 207 + // bottom: -[MLKITx_CCTClearcutMetaLogger logCounters:] 208 + // — crash site itself; fallback if upper stubs miss it 209 + static void _pd_mlkit_noop_start_auto_upload(id self, SEL _cmd) { 210 + // Do nothing — auto-upload stays off. 211 + } 212 + 213 + static void _pd_mlkit_noop_flush_upload(id self, SEL _cmd, 214 + id completion, BOOL isForeground) { 215 + if (completion) { 216 + void (^block)(BOOL) = completion; 217 + block(YES); 218 + } 219 + } 220 + 221 + static void _pd_mlkit_noop_log_counters(id self, SEL _cmd, id counters) { 222 + // Do nothing — counters are silently dropped. 223 + } 224 + 225 + @interface NSBundle (PoseDetectionMLKitRedirect) 226 + @end 227 + 228 + @implementation NSBundle (PoseDetectionMLKitRedirect) 229 + 230 + + (void)load { 231 + static dispatch_once_t once; 232 + dispatch_once(&once, ^{ 233 + Method origM = class_getInstanceMethod(self, 234 + @selector(URLForResource:withExtension:)); 235 + Method newM = class_getInstanceMethod(self, 236 + @selector(pd_mlkit_URLForResource:withExtension:)); 237 + method_exchangeImplementations(origM, newM); 238 + 239 + // Try to install the Clearcut no-op now; if the class isn't 240 + // registered yet (MLKit loaded after us), this is a silent no-op 241 + // and mlkit_set_resource_dir re-attempts later. 242 + _pd_install_clearcut_stub(); 243 + }); 244 + } 245 + 246 + - (NSURL *)pd_mlkit_URLForResource:(NSString *)name 247 + withExtension:(NSString *)ext { 248 + // Swizzled — this now calls the ORIGINAL implementation. 249 + NSURL *fromOriginal = [self pd_mlkit_URLForResource:name withExtension:ext]; 250 + if (fromOriginal) return fromOriginal; 251 + 252 + if (!_mlkitResourceDir || !name || !ext) return nil; 253 + if (![ext isEqualToString:@"bundle"]) return nil; 254 + if (![mlkitBundleNames() containsObject:name]) return nil; 255 + 256 + NSString *candidate = [_mlkitResourceDir stringByAppendingPathComponent: 257 + [NSString stringWithFormat:@"%@.%@", name, ext]]; 258 + BOOL isDir = NO; 259 + if ([[NSFileManager defaultManager] fileExistsAtPath:candidate isDirectory:&isDir] && isDir) { 260 + return [NSURL fileURLWithPath:candidate isDirectory:YES]; 261 + } 262 + return nil; 263 + } 264 + 265 + @end
+146
posedetection/tools/sync-mlkit.sh
··· 1 + #!/usr/bin/env bash 2 + # Build MLKit pose-detection static archives for all Kotlin/Native iOS targets 3 + # and stage them at build/mlkit-archives/<target>/lib<Pod>.a for cinterop to 4 + # embed into the library's klibs. 5 + # 6 + # Required env: MLKIT_STAGING_DIR, MLKIT_ARCHIVES_DIR 7 + # Optional env: MLKIT_TARGETS (space-separated; default "ios_arm64 ios_simulator_arm64 ios_x64") 8 + 9 + set -euo pipefail 10 + 11 + STAGING="${MLKIT_STAGING_DIR:?MLKIT_STAGING_DIR required}" 12 + ARCHIVES="${MLKIT_ARCHIVES_DIR:?MLKIT_ARCHIVES_DIR required}" 13 + TARGETS="${MLKIT_TARGETS:-ios_arm64 ios_simulator_arm64 ios_x64}" 14 + 15 + MLKIT_VERSION="1.0.0-beta16" 16 + IOS_DEPLOYMENT_TARGET="16.2" 17 + 18 + # Pods whose binaries we embed. Order matters for link-time resolution: 19 + # dependents before their deps. 20 + VENDORED_PODS=( 21 + MLKitPoseDetectionAccurate 22 + MLKitPoseDetectionCommon 23 + MLKitVision 24 + MLKitCommon 25 + MLImage 26 + MLKitXenoCommon 27 + ) 28 + # Built-from-source pods. Their framework binary paths inside the build dir 29 + # don't always match the pod name, so we map explicitly. 30 + # Format: "<pod-name>:<output-framework-name>" 31 + SOURCE_PODS=( 32 + "GTMSessionFetcher:GTMSessionFetcher" 33 + "GoogleDataTransport:GoogleDataTransport" 34 + "GoogleToolboxForMac:GoogleToolboxForMac" 35 + "GoogleUtilities:GoogleUtilities" 36 + "PromisesObjC:FBLPromises" 37 + "nanopb:nanopb" 38 + ) 39 + 40 + mkdir -p "$STAGING" 41 + mkdir -p "$ARCHIVES" 42 + cd "$STAGING" 43 + 44 + # Write a fresh Podfile for every run — ensures version changes propagate. 45 + cat > Podfile <<EOF 46 + platform :ios, '${IOS_DEPLOYMENT_TARGET}' 47 + use_frameworks! :linkage => :static 48 + 49 + install! 'cocoapods', :integrate_targets => false, :deterministic_uuids => false 50 + 51 + target 'MlkitSync' do 52 + pod 'MLKitPoseDetectionAccurate', '${MLKIT_VERSION}' 53 + end 54 + EOF 55 + 56 + echo "==> pod install in $STAGING" 57 + if [ ! -d Pods ] || [ ! -f Podfile.lock ] || ! diff -q Podfile Podfile.lock.input 2>/dev/null; then 58 + pod install --no-repo-update 59 + cp Podfile Podfile.lock.input 60 + fi 61 + 62 + # Map a Kotlin target name to an (sdk, arch) tuple. 63 + target_to_sdk() { 64 + case "$1" in 65 + ios_arm64) echo "iphoneos arm64" ;; 66 + ios_simulator_arm64) echo "iphonesimulator arm64" ;; 67 + ios_x64) echo "iphonesimulator x86_64" ;; 68 + *) echo "UNKNOWN UNKNOWN" ;; 69 + esac 70 + } 71 + 72 + extract_slice() { 73 + # $1 = input (fat or single-arch Mach-O) 74 + # $2 = desired arch (arm64, x86_64) 75 + # $3 = output path 76 + local input="$1" arch="$2" output="$3" 77 + mkdir -p "$(dirname "$output")" 78 + # lipo -thin fails on already-thin; use -info to branch 79 + if lipo -info "$input" 2>&1 | grep -q "Non-fat"; then 80 + local existing_arch 81 + existing_arch=$(lipo -info "$input" | sed -E 's/.*architecture: //') 82 + if [ "$existing_arch" = "$arch" ]; then 83 + cp "$input" "$output" 84 + else 85 + echo " skip: $input is $existing_arch, need $arch" 86 + return 1 87 + fi 88 + else 89 + lipo -thin "$arch" "$input" -output "$output" 2>/dev/null || { 90 + echo " skip: no $arch slice in $input" 91 + return 1 92 + } 93 + fi 94 + } 95 + 96 + for target in $TARGETS; do 97 + read -r sdk arch <<< "$(target_to_sdk "$target")" 98 + if [ "$sdk" = "UNKNOWN" ]; then 99 + echo "skipping unknown target $target" 100 + continue 101 + fi 102 + 103 + echo "==> Building source pods for $target ($sdk $arch)" 104 + # Build only the source pods — vendored ones don't need building. 105 + for entry in "${SOURCE_PODS[@]}"; do 106 + pod_name="${entry%%:*}" 107 + xcodebuild -project Pods/Pods.xcodeproj \ 108 + -target "$pod_name" \ 109 + -configuration Release \ 110 + -sdk "$sdk" \ 111 + -arch "$arch" \ 112 + ONLY_ACTIVE_ARCH=NO \ 113 + BUILD_LIBRARY_FOR_DISTRIBUTION=NO \ 114 + build 2>&1 | tail -3 115 + done 116 + 117 + out_dir="$ARCHIVES/$target" 118 + rm -rf "$out_dir" 119 + mkdir -p "$out_dir" 120 + 121 + echo "==> Extracting $target archives to $out_dir" 122 + # Vendored: pull the right slice from the fat .framework binary. 123 + for pod in "${VENDORED_PODS[@]}"; do 124 + fw_bin="Pods/$pod/Frameworks/$pod.framework/$pod" 125 + if [ -f "$fw_bin" ]; then 126 + extract_slice "$fw_bin" "$arch" "$out_dir/lib${pod}.a" || true 127 + else 128 + echo " miss: vendored $pod at $fw_bin" 129 + fi 130 + done 131 + # Built-from-source: single-arch output at build/Release-<sdk>/<pod>/<fw>.framework/<fw> 132 + for entry in "${SOURCE_PODS[@]}"; do 133 + pod_name="${entry%%:*}" 134 + fw_name="${entry##*:}" 135 + built="build/Release-$sdk/$pod_name/$fw_name.framework/$fw_name" 136 + if [ -f "$built" ]; then 137 + extract_slice "$built" "$arch" "$out_dir/lib${fw_name}.a" || true 138 + else 139 + echo " miss: built $pod_name at $built" 140 + fi 141 + done 142 + 143 + echo "==> $target: $(ls "$out_dir" | wc -l | tr -d ' ') archives" 144 + done 145 + 146 + echo "==> Done. Archives at $ARCHIVES"
+12
reports/report.html
··· 1 + <!doctype html><html><head><meta charset='utf-8'><title>Model comparison report</title><style> 2 + body { font-family: -apple-system, sans-serif; margin: 24px; color: #222; } 3 + h1, h2 { font-weight: 600; } 4 + table { border-collapse: collapse; margin: 8px 0 24px 0; font-size: 13px; } 5 + th, td { border: 1px solid #ddd; padding: 4px 8px; text-align: right; } 6 + th { background: #f5f5f5; text-align: left; } 7 + td.left, th.left { text-align: left; } 8 + .scorecard td:first-child { font-weight: 600; } 9 + .small { color: #888; font-size: 11px; } 10 + img { max-width: 100%; border: 1px solid #ddd; margin: 8px 0; } 11 + .warn { background: #fff7e0; border: 1px solid #f0c000; padding: 8px 12px; border-radius: 4px; } 12 + </style></head><body><h1>Model comparison report</h1><p class='small'>5 run(s), bucket size 250 ms</p><h2>Per-run scorecard</h2><table class='scorecard'><tr><th class='left'>metric</th><th class='left'>yolo11n_dataset_dataset</th><th class='left'>yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32</th><th class='left'>yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16</th><th class='left'>yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32</th><th class='left'>yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16</th></tr><tr><td class='left'>run_id</td><td>1775898625937_yolo11n_dataset_dataset</td><td>1775898703073_yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32</td><td>1775898781050_yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16</td><td>1775898858800_yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32</td><td>1775898936159_yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16</td></tr><tr><td class='left'>device</td><td>samsung SM-A366B</td><td>samsung SM-A366B</td><td>samsung SM-A366B</td><td>samsung SM-A366B</td><td>samsung SM-A366B</td></tr><tr><td class='left'>duration (s)</td><td>60.0</td><td>60.0</td><td>60.0</td><td>60.0</td><td>60.0</td></tr><tr><td class='left'>total events</td><td>419</td><td>461</td><td>678</td><td>402</td><td>404</td></tr><tr><td class='left'>events / second</td><td>6.98</td><td>7.68</td><td>11.30</td><td>6.70</td><td>6.73</td></tr><tr><td class='left'>frames with detection</td><td>100.0%</td><td>100.0%</td><td>100.0%</td><td>100.0%</td><td>100.0%</td></tr><tr><td class='left'>mean confidence</td><td>0.719</td><td>0.639</td><td>0.590</td><td>0.796</td><td>0.777</td></tr><tr><td class='left'>classes seen</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td></tr><tr><td class='left'>mean bbox area (px²)</td><td>531</td><td>523</td><td>570</td><td>536</td><td>533</td></tr><tr><td class='left'>class list</td><td>basketball, basketball_hoop</td><td>basketball, basketball_hoop</td><td>basketball, basketball_hoop</td><td>basketball, basketball_hoop</td><td>basketball, basketball_hoop</td></tr></table><h2>Jitter per class (lower = more stable)</h2><table><tr><th class='left'>class</th><th>yolo11n_dataset_dataset</th><th>yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32</th><th>yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16</th><th>yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32</th><th>yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16</th></tr><tr><td class='left'>basketball</td><td>110.9</td><td>70.2</td><td>69.3</td><td>68.3</td><td>77.0</td></tr><tr><td class='left'>basketball_hoop</td><td>0.6</td><td>0.6</td><td>1.5</td><td>0.9</td><td>0.8</td></tr></table><h2>Per-bucket comparison (250 ms bins)</h2><table><tr><th class='left'>bucket (ms)</th><th>yolo11n_dataset_dataset<br><span class='small'>frames</span></th><th>yolo11n_dataset_dataset<br><span class='small'>top class</span></th><th>yolo11n_dataset_dataset<br><span class='small'>max conf</span></th><th>yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32<br><span class='small'>frames</span></th><th>yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32<br><span class='small'>top class</span></th><th>yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32<br><span class='small'>max conf</span></th><th>yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16<br><span class='small'>frames</span></th><th>yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16<br><span class='small'>top class</span></th><th>yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16<br><span class='small'>max conf</span></th><th>yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32<br><span class='small'>frames</span></th><th>yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32<br><span class='small'>top class</span></th><th>yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32<br><span class='small'>max conf</span></th><th>yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16<br><span class='small'>frames</span></th><th>yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16<br><span class='small'>top class</span></th><th>yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16<br><span class='small'>max conf</span></th></tr><tr><td class='left'>0–250</td><td>1</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.94</td><td>2</td><td>basketball</td><td>0.90</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>250–500</td><td>2</td><td>basketball</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>500–750</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>750–1000</td><td>2</td><td>basketball</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.94</td><td>2</td><td>basketball</td><td>0.85</td></tr><tr><td class='left'>1000–1250</td><td>1</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball</td><td>0.93</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>1250–1500</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball</td><td>0.89</td><td>1</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>1500–1750</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.73</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>1750–2000</td><td>2</td><td>basketball</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>2000–2250</td><td>1</td><td>basketball</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball</td><td>0.84</td></tr><tr><td class='left'>2250–2500</td><td>2</td><td>basketball</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>2500–2750</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>2750–3000</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>3000–3250</td><td>1</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>3250–3500</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.93</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>3500–3750</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.63</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>3750–4000</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>4000–4250</td><td>1</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.91</td><td>2</td><td>basketball</td><td>0.91</td></tr><tr><td class='left'>4250–4500</td><td>2</td><td>basketball</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>4500–4750</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.73</td><td>3</td><td>basketball_hoop</td><td>0.51</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>4750–5000</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>5000–5250</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>3</td><td>basketball_hoop</td><td>0.67</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>5250–5500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.55</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>5500–5750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.52</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>5750–6000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.59</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>6000–6250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.54</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>6250–6500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>3</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>6500–6750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>6750–7000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.72</td><td>3</td><td>basketball_hoop</td><td>0.76</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>7000–7250</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.67</td><td>2</td><td>basketball</td><td>0.89</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>7250–7500</td><td>1</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>7500–7750</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>7750–8000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>8000–8250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.72</td><td>3</td><td>basketball_hoop</td><td>0.56</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>8250–8500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.65</td><td>3</td><td>basketball_hoop</td><td>0.56</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>8500–8750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.56</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>8750–9000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>9000–9250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.59</td><td>1</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>9250–9500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.72</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>9500–9750</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>3</td><td>basketball_hoop</td><td>0.74</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>9750–10000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>1</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>10000–10250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.67</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>10250–10500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.59</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>10500–10750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>10750–11000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.57</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>11000–11250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.74</td><td>3</td><td>basketball_hoop</td><td>0.60</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>11250–11500</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.79</td><td>1</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>11500–11750</td><td>1</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>11750–12000</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>12000–12250</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.73</td><td>3</td><td>basketball_hoop</td><td>0.58</td><td>1</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>12250–12500</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>12500–12750</td><td>1</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.91</td></tr><tr><td class='left'>12750–13000</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>1</td><td>basketball</td><td>0.91</td><td>2</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>13000–13250</td><td>2</td><td>basketball</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball</td><td>0.91</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>13250–13500</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.53</td><td>3</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.64</td><td>1</td><td>basketball_hoop</td><td>0.80</td></tr><tr><td class='left'>13500–13750</td><td>1</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.90</td></tr><tr><td class='left'>13750–14000</td><td>2</td><td>basketball</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.92</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>14000–14250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>14250–14500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.95</td><td>1</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>14500–14750</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.71</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>14750–15000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>15000–15250</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.63</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>15250–15500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.72</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>15500–15750</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>15750–16000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.64</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>16000–16250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.64</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>16250–16500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>16500–16750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.61</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>16750–17000</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>17000–17250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.63</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>17250–17500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.64</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>17500–17750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.63</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>17750–18000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.64</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>18000–18250</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>18250–18500</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.64</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>18500–18750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>18750–19000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>19000–19250</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball</td><td>0.88</td><td>1</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>19250–19500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.67</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>19500–19750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball</td><td>0.71</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>19750–20000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>20000–20250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball</td><td>0.89</td><td>1</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>20250–20500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball</td><td>0.84</td></tr><tr><td class='left'>20500–20750</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.74</td><td>1</td><td>basketball</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>20750–21000</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>21000–21250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>21250–21500</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>3</td><td>basketball_hoop</td><td>0.81</td><td>1</td><td>basketball</td><td>0.92</td><td>2</td><td>basketball</td><td>0.85</td></tr><tr><td class='left'>21500–21750</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.64</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>21750–22000</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.68</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>22000–22250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.62</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>22250–22500</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>22500–22750</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.93</td><td>2</td><td>basketball</td><td>0.88</td><td>1</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>22750–23000</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.77</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>23000–23250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>23250–23500</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>23500–23750</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>23750–24000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.71</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>24000–24250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>24250–24500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>24500–24750</td><td>1</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>24750–25000</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>25000–25250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.67</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>25250–25500</td><td>2</td><td>basketball</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>25500–25750</td><td>2</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.94</td><td>1</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>25750–26000</td><td>1</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball</td><td>0.84</td></tr><tr><td class='left'>26000–26250</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>26250–26500</td><td>2</td><td>basketball</td><td>0.75</td><td>2</td><td>basketball</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>1</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>26500–26750</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>1</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>26750–27000</td><td>1</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball</td><td>0.89</td><td>1</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>27000–27250</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>27250–27500</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.93</td><td>1</td><td>basketball</td><td>0.91</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>27500–27750</td><td>2</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.93</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball</td><td>0.84</td></tr><tr><td class='left'>27750–28000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball_hoop</td><td>0.92</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.92</td><td>2</td><td>basketball</td><td>0.93</td></tr><tr><td class='left'>28000–28250</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.75</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>28250–28500</td><td>2</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.92</td></tr><tr><td class='left'>28500–28750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>28750–29000</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.74</td><td>3</td><td>basketball</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>29000–29250</td><td>1</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball</td><td>0.82</td></tr><tr><td class='left'>29250–29500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.74</td><td>3</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>29500–29750</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>29750–30000</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball_hoop</td><td>0.73</td><td>3</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>30000–30250</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.82</td></tr><tr><td class='left'>30250–30500</td><td>2</td><td>basketball</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.75</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.82</td></tr><tr><td class='left'>30500–30750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.72</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>30750–31000</td><td>1</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball</td><td>0.85</td></tr><tr><td class='left'>31000–31250</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>31250–31500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball</td><td>0.84</td></tr><tr><td class='left'>31500–31750</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.64</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>31750–32000</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.83</td><td>1</td><td>basketball</td><td>0.85</td></tr><tr><td class='left'>32000–32250</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.73</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>32250–32500</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>32500–32750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.62</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>32750–33000</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.90</td><td>1</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>33000–33250</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>33250–33500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>33500–33750</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>1</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball</td><td>0.83</td></tr><tr><td class='left'>33750–34000</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.64</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.84</td></tr><tr><td class='left'>34000–34250</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.61</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>34250–34500</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.61</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>34500–34750</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>3</td><td>basketball_hoop</td><td>0.62</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>34750–35000</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>35000–35250</td><td>2</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>35250–35500</td><td>1</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.73</td><td>3</td><td>basketball_hoop</td><td>0.64</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>35500–35750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.93</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>35750–36000</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>1</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>36000–36250</td><td>2</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.93</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>36250–36500</td><td>2</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>36500–36750</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.83</td></tr><tr><td class='left'>36750–37000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>37000–37250</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball</td><td>0.91</td><td>2</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>37250–37500</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>37500–37750</td><td>1</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.93</td><td>2</td><td>basketball</td><td>0.93</td></tr><tr><td class='left'>37750–38000</td><td>2</td><td>basketball</td><td>0.81</td><td>1</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball</td><td>0.92</td><td>2</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>38000–38250</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>1</td><td>basketball</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>38250–38500</td><td>2</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.71</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>38500–38750</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>38750–39000</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball</td><td>0.94</td><td>1</td><td>basketball</td><td>0.93</td></tr><tr><td class='left'>39000–39250</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.72</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>39250–39500</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>39500–39750</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>1</td><td>basketball</td><td>0.87</td><td>1</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>39750–40000</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>1</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball</td><td>0.89</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>40000–40250</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>40250–40500</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.67</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>40500–40750</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>40750–41000</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>41000–41250</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>41250–41500</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>41500–41750</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>41750–42000</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>1</td><td>basketball_hoop</td><td>0.74</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>42000–42250</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>42250–42500</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.65</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>42500–42750</td><td>2</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>42750–43000</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>43000–43250</td><td>1</td><td>basketball_hoop</td><td>0.76</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.73</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>43250–43500</td><td>2</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.94</td><td>2</td><td>basketball</td><td>0.86</td></tr><tr><td class='left'>43500–43750</td><td>2</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>43750–44000</td><td>1</td><td>basketball</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.92</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>44000–44250</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>44250–44500</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.75</td><td>1</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>44500–44750</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.82</td></tr><tr><td class='left'>44750–45000</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.74</td><td>1</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball</td><td>0.91</td></tr><tr><td class='left'>45000–45250</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.90</td></tr><tr><td class='left'>45250–45500</td><td>2</td><td>basketball</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.94</td><td>2</td><td>basketball</td><td>0.94</td></tr><tr><td class='left'>45500–45750</td><td>1</td><td>basketball</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball</td><td>0.90</td><td>1</td><td>basketball</td><td>0.93</td></tr><tr><td class='left'>45750–46000</td><td>2</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball</td><td>0.91</td><td>2</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>46000–46250</td><td>2</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball</td><td>0.93</td><td>2</td><td>basketball_hoop</td><td>0.94</td></tr><tr><td class='left'>46250–46500</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>46500–46750</td><td>1</td><td>basketball</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.89</td><td>2</td><td>basketball</td><td>0.93</td></tr><tr><td class='left'>46750–47000</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>47000–47250</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball</td><td>0.69</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>47250–47500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.73</td><td>3</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>47500–47750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.92</td></tr><tr><td class='left'>47750–48000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball</td><td>0.90</td><td>1</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>48000–48250</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.67</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>48250–48500</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.70</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>48500–48750</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.74</td><td>1</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>48750–49000</td><td>2</td><td>basketball</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball</td><td>0.87</td></tr><tr><td class='left'>49000–49250</td><td>1</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>49250–49500</td><td>2</td><td>basketball</td><td>0.83</td><td>1</td><td>basketball_hoop</td><td>0.78</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>49500–49750</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>49750–50000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.72</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>50000–50250</td><td>1</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.93</td><td>3</td><td>basketball_hoop</td><td>0.92</td><td>1</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>50250–50500</td><td>2</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.95</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball</td><td>0.89</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>50500–50750</td><td>2</td><td>basketball</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.91</td></tr><tr><td class='left'>50750–51000</td><td>1</td><td>basketball</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>1</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>51000–51250</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.85</td></tr><tr><td class='left'>51250–51500</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>1</td><td>basketball_hoop</td><td>0.67</td><td>3</td><td>basketball_hoop</td><td>0.93</td><td>1</td><td>basketball</td><td>0.84</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>51500–51750</td><td>1</td><td>basketball</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.90</td><td>3</td><td>basketball_hoop</td><td>0.92</td><td>2</td><td>basketball</td><td>0.91</td><td>2</td><td>basketball</td><td>0.90</td></tr><tr><td class='left'>51750–52000</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball</td><td>0.91</td><td>1</td><td>basketball</td><td>0.85</td></tr><tr><td class='left'>52000–52250</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.93</td></tr><tr><td class='left'>52250–52500</td><td>2</td><td>basketball</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball</td><td>0.90</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>52500–52750</td><td>1</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.93</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball</td><td>0.88</td></tr><tr><td class='left'>52750–53000</td><td>2</td><td>basketball</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.91</td></tr><tr><td class='left'>53000–53250</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball</td><td>0.91</td></tr><tr><td class='left'>53250–53500</td><td>2</td><td>basketball</td><td>0.83</td><td>1</td><td>basketball_hoop</td><td>0.84</td><td>3</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball</td><td>0.90</td><td>1</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>53500–53750</td><td>1</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.89</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>53750–54000</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>3</td><td>basketball_hoop</td><td>0.90</td><td>2</td><td>basketball</td><td>0.92</td><td>2</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>54000–54250</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball</td><td>0.87</td><td>1</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>54250–54500</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.73</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball</td><td>0.89</td></tr><tr><td class='left'>54500–54750</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.91</td></tr><tr><td class='left'>54750–55000</td><td>2</td><td>basketball</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>3</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>55000–55250</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.76</td><td>3</td><td>basketball_hoop</td><td>0.72</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>55250–55500</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>55500–55750</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>3</td><td>basketball_hoop</td><td>0.66</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>55750–56000</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.70</td><td>1</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>56000–56250</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.81</td><td>2</td><td>basketball_hoop</td><td>0.75</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>56250–56500</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.70</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>56500–56750</td><td>2</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.84</td><td>1</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>56750–57000</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.77</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>57000–57250</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>1</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>57250–57500</td><td>2</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.92</td><td>2</td><td>basketball_hoop</td><td>0.83</td><td>1</td><td>basketball</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.92</td></tr><tr><td class='left'>57500–57750</td><td>1</td><td>basketball</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.77</td><td>3</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball</td><td>0.87</td><td>2</td><td>basketball</td><td>0.92</td></tr><tr><td class='left'>57750–58000</td><td>2</td><td>basketball</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.91</td><td>3</td><td>basketball_hoop</td><td>0.92</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>1</td><td>basketball_hoop</td><td>0.86</td></tr><tr><td class='left'>58000–58250</td><td>2</td><td>basketball_hoop</td><td>0.71</td><td>2</td><td>basketball_hoop</td><td>0.86</td><td>3</td><td>basketball_hoop</td><td>0.73</td><td>1</td><td>basketball_hoop</td><td>0.73</td><td>2</td><td>basketball_hoop</td><td>0.71</td></tr><tr><td class='left'>58250–58500</td><td>1</td><td>basketball_hoop</td><td>0.73</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>3</td><td>basketball_hoop</td><td>0.83</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>58500–58750</td><td>2</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>58750–59000</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>1</td><td>basketball_hoop</td><td>0.89</td></tr><tr><td class='left'>59000–59250</td><td>1</td><td>basketball</td><td>0.82</td><td>2</td><td>basketball_hoop</td><td>0.80</td><td>2</td><td>basketball_hoop</td><td>0.88</td><td>1</td><td>basketball_hoop</td><td>0.88</td><td>2</td><td>basketball_hoop</td><td>0.87</td></tr><tr><td class='left'>59250–59500</td><td>2</td><td>basketball</td><td>0.78</td><td>2</td><td>basketball_hoop</td><td>0.82</td><td>3</td><td>basketball_hoop</td><td>0.85</td><td>2</td><td>basketball_hoop</td><td>0.87</td><td>2</td><td>basketball_hoop</td><td>0.88</td></tr><tr><td class='left'>59500–59750</td><td>2</td><td>basketball</td><td>0.79</td><td>2</td><td>basketball_hoop</td><td>0.89</td><td>3</td><td>basketball_hoop</td><td>0.91</td><td>1</td><td>basketball</td><td>0.94</td><td>1</td><td>basketball_hoop</td><td>0.95</td></tr><tr><td class='left'>59750–60000</td><td>1</td><td>basketball</td><td>0.82</td><td>1</td><td>basketball_hoop</td><td>0.76</td><td>1</td><td>basketball_hoop</td><td>0.89</td><td>2</td><td>basketball</td><td>0.87</td><td>1</td><td>basketball</td><td>0.87</td></tr></table><h2>Per-class confidence timelines</h2><img alt='basketball timeline' src='data:image/png;base64,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2qXIA8BgfIBIYIyASGCMgHBgfIBIYIyASHSHMWJSWJ0CAAAAAAAAAACg+6WaAwAAAAAAAAAAXR0IbwAAAAAAAAAAIIlAeAMAAAAAAAAAAEkEwhsAAAAAAAAAAEgiEN5dmB07dtD06dMpOzubiouL6f777yeXy5XqwwIpYPfu3aLNHrv3W61WOuGEEwwfN3/+fBo5cqRouTdhwgRatmxZpx8rSA0LFy6k2bNnU//+/cWcwWPlr3/9q+j+oAdjpHuyYsUKOuecc6h3797kcDhEB5C7776b6urqAh63dOlSMS54fPA44TafoHvS2Ngo5hOTyUTffPNNwH2YR7onr776qhgPwV8PPvhgwOMwPro3r732Gp100kni/e/VqxfNnDmTWlpausV1BsK7i1JTU0NTp04VQvvtt9+mp556il5++WWxUALdj61bt9Ly5ctFP/uxY8caPubNN9+k2267ja655hp69913acqUKTRnzhxavXp1px8v6HyeffZZysrKomeeeUZc1PhCx+PhiSee0B6DMdJ9qa6upsmTJ9OLL74oWm/yteT111+nq666SnvMF198IcYDjwseHzxO5s6dS2+99VZKjx2khl/96lftWrkymEfAe++9R6tWrdK+fvrTn2r3YXx0b5588knRJprff77WvPTSSzRkyBDRGrpbXGe4nRjoejz11FNKdna2UlVVpd320ksvKRaLRSkrK0vpsYHOx+v1av++8cYblXHjxrV7zMiRI5Xrrrsu4LYpU6YoM2fO7JRjBKmlsrKy3W233XabkpeXp40fjBGg5+WXX+Z0CO2aMmPGDOWMM84IeAyPlzFjxqToCEGq2L59u1iDvPjii2KMrF27VrsP80j3ZcGCBWI8GF1vJBgf3ZcdO3YoVqtVWbFiRcjHHO/XGUS8uyi8C3T++edTjx49tNuuvvpq8vl8tHLlypQeG+h8zObwH+W9e/fSrl27xBjRc+2119JHH31Era2tST5CkGo4nSsYTvWqr6+npqYmjBHQjp49e4rvnFnF7//HH38cEAGX42P79u20f//+FB0lSAUcseLyplGjRgXcjnkEhAPjo3uzYMECEd3mjDsjusN1BsK7C9d3jx49OuC2goICKikpEfcBoEeOieAxM2bMGLGo3rdvX4qODKQSTunq168f5ebmYowAAaf7OZ1OWr9+vShDuPTSS2nw4MG0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//zzRbr0//3f/xk+Nzt9czo2O3/rkY9n5/Bo4fRxTglnwzQ9wc+tJy8vTxircao3/y3RwGKXjdamT58e9e+EItL5ifY8GxEcXden65vNZvr3v/+t3cYinDMc2DwOAAAASASIeAMAAAAR2LRpE91zzz2i1nrYsGEiAv30008Locc/M+y+zSnY/BgWrhw95dplroHm6DE7cbOwZDHHjt3sJj558mSRns1imB26mccff1xEc2VEeefOnSLCy27f48ePj+m4f/nLXwq3b359Piau+eYUcT3cq5odvjnizWne+/bto7///e8B9ePBPPbYYyItnP8mTmXfvHmziJRz27OOEM35ieY8h8pY4M0IboPGmQD8xWKd25XdeuutdN9994n7+/XrR0899ZRI7//xj3/cob8HAAAA0Ijahg0AAADoplRUVCg33HCDMnToUMXhcChFRUXKFVdcoezatSvgceyYfdFFFyn5+flKZmamMmLECOX222/XXLuZlpYW5cEHH1QGDhwoXLP79++v3HLLLQHP89ZbbyknnniiYrfbleLiYuWuu+4SvxfJoXv27NnCPVzPiy++qAwYMEDJyMgQ961ZsybA1fyrr75SLr74YqWkpES8Hh/Xz372s7Au50uXLlWmTZum9O7dW5yPYcOGKY899pjidrvDuprz6+j59ttvxeP474nl/ERzno3gc8HvodVqFa8rcTqdyj333CPeV36+888/X9m+fXvY5wIAAABiwcT/a5PhAAAAAAAAAAAASCSo8QYAAAAAAAAAAJIIhDcAAAAAAAAAAJBEILwBAAAAAAAAAIAkAuENAAAAAAAAAAAkEQhvAAAAAAAAAAAgiUB4AwAAAAAAAAAASQTCGwAAAAAAAAAASCIQ3gAAAAAAAAAAQBKB8AYAAAAAAAAAAJIIhDcAAAAAAAAAAJBEILwBAAAAAAAAAIAkAuENAAAAAAAAAAAkEQhvAAAAAAAAAAAgiUB4AwAAAAAAAAAASQTCGwAAAAAAAAAASCIQ3gAAAAAAAAAAQBKB8AYAAAAAAAAAAJIIhDcAAAAAAAAAAJBEILwBAAAAAAAAAABKHv8f5J1zHvA/iSoAAAAASUVORK5CYII='/><img alt='basketball_hoop timeline' src='data:image/png;base64,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Tx8zHT9+3PQR18T2gQceMDXQVdG+2Tr9+eefsnr1amcyrH3g/6maHh9vx/lcdOrUyRwTTbRd+3lr/25dBgDAf4EabwAAzoEml927d5cpU6aYRFWfC62jayclJcn27dtNTbjnpKOKq549e5rm0m+//Xal+9aRvrU5to787cqxvo4cXlPafFybhOuAaa489+0qPDzcDKymTb31s9SEJrs60FqvXr1qvE1VvB2fmh7nynjWrrs212/QoIG88847znmahGsLBx08DgCA/wI13gAAePH999/LxIkTTV/rdu3amRroOXPmmERPXysdfVubYOs6mrhq7an2XdY+0Fp7rCNxa2KpyZyO2K2jiXft2tU0z9ZkWEfoVjNnzjS1uY4a5Z07d5oaXh3tOyEh4ZzKPW3aNDPat76/lkn7fGsTcVf6rGod4VtrvLWZ9969e+X111936z/uKSMjwzQL18+kTdm3bt1qasr1sWf/Rk2OT02Oc1UtFvRmhD4GTVsC6KTJuj6uLC0tTdLT083ySy65RDIzM03z/ocffvhffR4AAJxqPAwbAAB+6vfff7dGjBhhtW3b1goODraio6OtQYMGWT/++KPbejpidr9+/ayIiAgrJCTE6tChgzV69GjnqN3q5MmT1pQpU6xWrVqZUbNjY2OtBx980G0/K1assLp06WIFBQVZMTEx1qOPPmq28zZC98CBA83o4a6ysrKsli1bWo0bNzbLPv/8c7dRzTdv3mz179/fat68uXk/Ldf48eOrHeV87dq1VnJyshUVFWWOR7t27ayMjAyrrKys2lHN9X1cffPNN2Y9/Tzncnxqcpwro8dCv8PAwEDzvg6lpaXWxIkTzfeq++vZs6e1ffv2avcFAMC5CND//H8aDgAAAAAA/kv08QYAAAAAwEYk3gAAAAAA2IjEGwAAAAAAG5F4AwAAAABgIxJvAAAAAABsROINAAAAAICNSLwBAAAAALARiTcAAAAAADYi8QYAAAAAwEYk3gAAAAAA2IjEGwAAAAAAG5F4AwAAAABgIxJvAAAAAABsROINAAAAAICNSLwBAAAAALARiTcAAAAAADYi8QYAAAAAwEYk3gAAAAAA2IjEGwAAAAAAsc//AMxVi5OzTG+wAAAAAElFTkSuQmCC'/></body></html>
+6
reports/summary.csv
··· 1 + run_id,model_tag,device_label,duration_s,total_events,events_per_second,detection_rate,mean_confidence,class_diversity,classes,mean_bbox_area 2 + 1775898625937_yolo11n_dataset_dataset,yolo11n_dataset_dataset,samsung SM-A366B,60.00,419,6.983,1.0000,0.7191,2,basketball|basketball_hoop,531.3 3 + 1775898703073_yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32,yolo26n_dataset_v11_dataset_v11_20260410_201918__best_float32,samsung SM-A366B,60.00,461,7.683,1.0000,0.6393,2,basketball|basketball_hoop,523.3 4 + 1775898781050_yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16,yolo26n_v11_rect_384x288_fp16_20260411_083350__best_float16,samsung SM-A366B,60.00,678,11.300,1.0000,0.5896,2,basketball|basketball_hoop,570.4 5 + 1775898858800_yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32,yolo26n_v11_rect_512x384_fp32_20260411_090924__best_float32,samsung SM-A366B,60.00,402,6.700,1.0000,0.7956,2,basketball|basketball_hoop,535.5 6 + 1775898936159_yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16,yolo26n_v11_rect_512x384_fp16_20260411_090924__best_float16,samsung SM-A366B,60.00,404,6.733,1.0000,0.7766,2,basketball|basketball_hoop,533.3
+8 -3
sample/composeApp/build.gradle.kts
··· 18 18 iosX64(), 19 19 iosArm64(), 20 20 iosSimulatorArm64() 21 - ).forEach { 22 - it.binaries.framework { 21 + ).forEach { target -> 22 + target.binaries.framework { 23 23 baseName = "ComposeApp" 24 - isStatic = true 24 + // Default KMP behavior (dynamic framework). Library's cinterop 25 + // linkerOpts supply -ObjC at framework link time to preserve MLKit 26 + // ObjC category metadata inside the dylib; the consumer iOS app 27 + // just loads the framework at runtime and categories are already 28 + // registered. No consumer-side flags / build phases required. 29 + isStatic = false 25 30 } 26 31 } 27 32
+1
sample/composeApp/src/androidMain/AndroidManifest.xml
··· 14 14 android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" 15 15 android:exported="true" 16 16 android:launchMode="singleInstance" 17 + android:screenOrientation="landscape" 17 18 android:windowSoftInputMode="adjustPan"> 18 19 <intent-filter> 19 20 <action android:name="android.intent.action.MAIN" />
sample/composeApp/src/androidMain/assets/dataset_v13_20260417_011448__yolo26n_v13_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_20260417_011448__yolo26n_v13_rect_384x288_fp32.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_20260417_011448__yolo26n_v13_rect_640x480_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_20260417_011448__yolo26n_v13_rect_640x480_fp32.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_20260417_011448__yolo26n_v13_rect_960x736_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_20260417_011448__yolo26n_v13_rect_960x736_fp32.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_baseline_20260418_014221__yolo26n_v13_baseline_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_baseline_int8_20260418_185621__yolo26n_v13_baseline_int8_rect_384x288.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_loss_heavy_20260418_014533__yolo26n_v13_loss_heavy_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_loss_recall_20260418_094455__yolo26n_v13_loss_recall_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_scale_high_20260418_014357__yolo26n_v13_scale_high_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_softloss_mixup_20260418_171706__yolo26n_v13_softloss_mixup_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_softloss_mixup_20260418_171731__yolo26n_v13_softloss_mixup_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_softloss_multiscale_20260418_142742__yolo26n_v13_softloss_multiscale_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_softloss_multiscale_confirm_20260418_162958__yolo26n_v13_softloss_multiscale_confirm_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_softloss_multiscale_confirm_20260418_170929__yolo26n_v13_softloss_multiscale_confirm_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/dataset_v13_translate_high_20260418_014710__yolo26n_v13_translate_high_rect_384x288_fp16.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/yolo11n_dataset_dataset.tflite handover/models/yolo11n_noise_floor_baseline.tflite
sample/composeApp/src/androidMain/assets/yolo11n_su_416.tflite

This is a binary file and will not be displayed.

sample/composeApp/src/androidMain/assets/yolo26n_v11_rect_384x288_fp16_20260411_075952__best_float16.tflite

This is a binary file and will not be displayed.

+35 -1
sample/composeApp/src/androidMain/kotlin/com/nate/posedetection/App.android.kt
··· 1 1 package com.nate.posedetection 2 2 3 + import android.content.Intent 3 4 import android.os.Bundle 4 5 import androidx.activity.ComponentActivity 5 6 import androidx.activity.compose.setContent 6 7 import androidx.activity.enableEdgeToEdge 7 8 import androidx.compose.runtime.Composable 9 + import androidx.compose.runtime.CompositionLocalProvider 8 10 import androidx.compose.ui.tooling.preview.Preview 9 11 import com.performancecoachlab.posedetection.recording.VideoExtractionContext 10 12 import io.github.vinceglb.filekit.FileKit ··· 16 18 FileKit.init(this) 17 19 VideoExtractionContext.setUp(applicationContext) 18 20 enableEdgeToEdge() 19 - setContent { App() } 21 + val autoSpec = parseAutoSpec(intent) 22 + setContent { 23 + CompositionLocalProvider(LocalExperimentAutoSpec provides autoSpec) { 24 + App() 25 + } 26 + } 20 27 } 28 + } 29 + 30 + /** 31 + * Parses the unattended-experiment extras placed on the launch intent by 32 + * `tools/run_auto_experiment.sh`. Returns null if the intent does not carry 33 + * the `experiment_auto` flag, in which case the app behaves normally. 34 + * 35 + * Required when `experiment_auto` is true: 36 + * --es model_name "<display name or filename, case-insensitive>" 37 + * --el start_at_wall_ms <System.currentTimeMillis target> 38 + * --el duration_ms <buffer duration> 39 + * Optional: 40 + * --ez finish_on_stop <true|false> (default true) 41 + */ 42 + private fun parseAutoSpec(intent: Intent?): ExperimentLaunchSpec? { 43 + if (intent == null || !intent.getBooleanExtra("experiment_auto", false)) return null 44 + val modelName = intent.getStringExtra("model_name").orEmpty() 45 + val startAtWallMs = intent.getLongExtra("start_at_wall_ms", 0L) 46 + val durationMs = intent.getLongExtra("duration_ms", 0L) 47 + val finishOnStop = intent.getBooleanExtra("finish_on_stop", true) 48 + if (modelName.isBlank() || durationMs <= 0L) return null 49 + return ExperimentLaunchSpec( 50 + modelName = modelName, 51 + startAtWallMs = startAtWallMs, 52 + durationMs = durationMs, 53 + finishOnStop = finishOnStop, 54 + ) 21 55 } 22 56 23 57 @Preview
+27
sample/composeApp/src/androidMain/kotlin/com/nate/posedetection/ExperimentAuto.android.kt
··· 1 + package com.nate.posedetection 2 + 3 + import android.app.Activity 4 + import android.util.Log 5 + import androidx.compose.runtime.Composable 6 + import androidx.compose.runtime.remember 7 + import androidx.compose.ui.platform.LocalContext 8 + 9 + private const val TAG = "ExperimentAuto" 10 + 11 + private class AndroidExperimentAutoBridge(private val activity: Activity?) : ExperimentAutoBridge { 12 + override fun log(msg: String) { 13 + Log.i(TAG, msg) 14 + } 15 + 16 + override fun finishActivity() { 17 + activity?.finish() 18 + } 19 + } 20 + 21 + @Composable 22 + actual fun rememberExperimentAutoBridge(): ExperimentAutoBridge { 23 + val context = LocalContext.current 24 + return remember(context) { 25 + AndroidExperimentAutoBridge(context as? Activity) 26 + } 27 + }
+33
sample/composeApp/src/androidMain/kotlin/com/nate/posedetection/ExperimentLogger.android.kt
··· 1 + package com.nate.posedetection 2 + 3 + import android.os.Build 4 + import androidx.compose.runtime.Composable 5 + import androidx.compose.runtime.remember 6 + import androidx.compose.ui.platform.LocalContext 7 + import java.io.File 8 + 9 + private class AndroidExperimentLogger( 10 + private val externalFilesDir: File?, 11 + ) : ExperimentLogger { 12 + override val deviceLabel: String = "${Build.MANUFACTURER} ${Build.MODEL}".trim() 13 + 14 + override fun write(filename: String, json: String): String? { 15 + val baseDir = externalFilesDir ?: return null 16 + val logsDir = File(baseDir, "experiment_logs").apply { mkdirs() } 17 + val outFile = File(logsDir, filename) 18 + return try { 19 + outFile.writeText(json) 20 + outFile.absolutePath 21 + } catch (t: Throwable) { 22 + null 23 + } 24 + } 25 + } 26 + 27 + @Composable 28 + actual fun rememberExperimentLogger(): ExperimentLogger { 29 + val context = LocalContext.current 30 + return remember(context) { 31 + AndroidExperimentLogger(context.getExternalFilesDir(null)) 32 + } 33 + }
+3
sample/composeApp/src/androidMain/kotlin/com/nate/posedetection/ScreenshotHelper.android.kt
··· 1 + package com.nate.posedetection 2 + 3 + actual fun saveAppScreenshot(filename: String): String? = null
+278 -50
sample/composeApp/src/commonMain/kotlin/com/nate/posedetection/App.kt
··· 2 2 3 3 import androidx.compose.animation.AnimatedContent 4 4 import androidx.compose.foundation.Image 5 + import androidx.compose.foundation.pager.HorizontalPager 6 + import androidx.compose.foundation.pager.rememberPagerState 5 7 import androidx.compose.foundation.layout.Arrangement 6 8 import androidx.compose.foundation.layout.Box 7 9 import androidx.compose.foundation.layout.Column ··· 9 11 import androidx.compose.foundation.layout.Spacer 10 12 import androidx.compose.foundation.layout.WindowInsets 11 13 import androidx.compose.foundation.layout.fillMaxSize 14 + import androidx.compose.ui.layout.onSizeChanged 12 15 import androidx.compose.foundation.layout.fillMaxWidth 13 16 import androidx.compose.foundation.layout.imePadding 14 17 import androidx.compose.foundation.layout.padding ··· 39 42 import androidx.compose.ui.Alignment 40 43 import androidx.compose.ui.Modifier 41 44 import androidx.compose.ui.geometry.Rect 45 + import androidx.compose.ui.geometry.Size 46 + import androidx.compose.ui.graphics.Canvas 42 47 import androidx.compose.ui.graphics.Color 43 48 import androidx.compose.ui.graphics.ImageBitmap 49 + import androidx.compose.ui.graphics.drawscope.CanvasDrawScope 44 50 import androidx.compose.ui.graphics.drawscope.Stroke 51 + import androidx.compose.ui.unit.Density 52 + import androidx.compose.ui.unit.LayoutDirection 45 53 import androidx.compose.ui.layout.ContentScale 46 54 import androidx.compose.ui.text.style.TextAlign 47 55 import androidx.compose.ui.unit.dp ··· 57 65 import com.performancecoachlab.posedetection.camera.DetectMode 58 66 import com.performancecoachlab.posedetection.camera.DrawableObject 59 67 import com.performancecoachlab.posedetection.camera.DrawableShape 68 + import com.performancecoachlab.posedetection.camera.PoseFocusMode 60 69 import com.performancecoachlab.posedetection.camera.PreviewFillMode 61 70 import com.performancecoachlab.posedetection.custom.CustomObjectRespository 62 71 import com.performancecoachlab.posedetection.custom.ModelPath ··· 64 73 import com.performancecoachlab.posedetection.encoding.VideoBuilder 65 74 import com.performancecoachlab.posedetection.encoding.createVideoBuilder 66 75 import com.performancecoachlab.posedetection.permissions.PermissionProvider 76 + import com.performancecoachlab.posedetection.recording.AnalysisObject 67 77 import com.performancecoachlab.posedetection.recording.FrameAnalyser 68 78 import com.performancecoachlab.posedetection.recording.InputFrame 79 + import com.performancecoachlab.posedetection.recording.AnalysisResult 80 + import com.performancecoachlab.posedetection.recording.FrameSize 69 81 import com.performancecoachlab.posedetection.recording.extractFrame 82 + import com.performancecoachlab.posedetection.recording.extractFrames 70 83 import com.performancecoachlab.posedetection.recording.listVideoFrameTimestamps 71 84 import com.performancecoachlab.posedetection.skeleton.Pose 85 + import com.performancecoachlab.posedetection.skeleton.Skeleton 72 86 import com.performancecoachlab.posedetection.skeleton.SkeletonRepository 73 87 import io.github.vinceglb.filekit.FileKit 74 88 import io.github.vinceglb.filekit.PlatformFile ··· 79 93 import io.github.vinceglb.filekit.extension 80 94 import io.github.vinceglb.filekit.filesDir 81 95 import io.github.vinceglb.filekit.path 96 + import kotlinx.coroutines.CompletableDeferred 82 97 import kotlinx.coroutines.Job 98 + import kotlinx.coroutines.delay 99 + import kotlinx.coroutines.flow.drop 100 + import kotlinx.coroutines.flow.first 83 101 import kotlinx.coroutines.launch 102 + import kotlinx.coroutines.withTimeoutOrNull 84 103 import kotlin.math.roundToLong 85 104 import kotlin.time.Clock 86 105 import kotlin.time.ExperimentalTime ··· 155 174 } 156 175 DropdownMenu( 157 176 expanded = modelMenuExpanded, 158 - onDismissRequest = { modelMenuExpanded = false }) { 177 + onDismissRequest = { modelMenuExpanded = false } 178 + ) { 159 179 if (availableModels.isEmpty()) { 160 180 DropdownMenuItem(text = { Text("No models found") }, onClick = {}) 161 181 } else { 162 182 availableModels.forEach { model -> 163 - DropdownMenuItem(text = { 164 - Row( 165 - verticalAlignment = Alignment.CenterVertically, 166 - horizontalArrangement = Arrangement.spacedBy(8.dp) 167 - ) { 168 - RadioButton( 169 - selected = selectedModel == model, onClick = null 170 - ) 171 - Text(model.name) 183 + DropdownMenuItem( 184 + text = { 185 + Row( 186 + verticalAlignment = Alignment.CenterVertically, 187 + horizontalArrangement = Arrangement.spacedBy(8.dp) 188 + ) { 189 + RadioButton( 190 + selected = selectedModel == model, 191 + onClick = null 192 + ) 193 + Text(model.name) 194 + } 195 + }, 196 + onClick = { 197 + selectedModel = model 198 + modelMenuExpanded = false 172 199 } 173 - }, onClick = { 174 - selectedModel = model 175 - modelMenuExpanded = false 176 - }) 200 + ) 177 201 } 178 202 } 179 203 } ··· 393 417 var previewFillMode by remember { mutableStateOf(PreviewFillMode.FIT) } 394 418 var menuExpanded by remember { mutableStateOf(false) } 395 419 var detectMode by remember { mutableStateOf(DetectMode.BOTH) } 420 + var poseFocusMode by remember { mutableStateOf(PoseFocusMode.MASK) } 396 421 val controller = remember { CameraViewControllerImpl() } 422 + 423 + // TEST HARNESS: cycle MASK → CROP → CROP_FOLLOW once, save a camera- 424 + // framebuffer + skeleton composite PNG per mode to app Documents/. Host 425 + // pulls the PNGs via `devicectl device copy from` and feeds them to a 426 + // visual-alignment check. 427 + LaunchedEffect(Unit) { 428 + val modes = listOf(PoseFocusMode.MASK, PoseFocusMode.CROP, PoseFocusMode.CROP_FOLLOW) 429 + // Initial wait for camera preview + MLKit detector warmup. 430 + kotlinx.coroutines.delay(4000) 431 + for (mode in modes) { 432 + poseFocusMode = mode 433 + // Give the detector a few frames to stabilize in the new mode. 434 + kotlinx.coroutines.delay(3000) 435 + controller.captureComposite("ab_${mode.name}.png") { _ -> } 436 + } 437 + } 438 + 439 + // Experiment Mode state — buffers per-detection events into a JSON log 440 + // that the Mac orchestrator pulls back for the model comparison report. 441 + val experimentLogger = rememberExperimentLogger() 442 + val autoBridge = rememberExperimentAutoBridge() 443 + val autoSpec = LocalExperimentAutoSpec.current 444 + var experimentMode by remember { mutableStateOf(false) } 445 + var experimentRunning by remember { mutableStateOf(false) } 446 + var experimentStartedWallMs by remember { mutableStateOf(0L) } 447 + var experimentCapturedCount by remember { mutableStateOf(0) } 448 + var lastExperimentLogPath by remember { mutableStateOf<String?>(null) } 449 + val experimentEvents = remember { mutableListOf<ExperimentEvent>() } 450 + 451 + LaunchedEffect(experimentRunning) { 452 + if (!experimentRunning) return@LaunchedEffect 453 + // drop(1) skips the StateFlow's stale replay value so we only log 454 + // detections that arrive after Start was tapped. 455 + customObjectRespository.customObjectFlow.drop(1).collect { objs -> 456 + experimentEvents.add( 457 + ExperimentEvent( 458 + wallMs = Clock.System.now().toEpochMilliseconds(), 459 + objects = objs ?: emptyList(), 460 + ) 461 + ) 462 + experimentCapturedCount = experimentEvents.size 463 + } 464 + } 465 + 466 + LaunchedEffect(experimentRunning) { 467 + if (!experimentRunning) return@LaunchedEffect 468 + skeletonRepository.skeletonFlow.drop(1).collect { skel -> 469 + experimentEvents.add( 470 + ExperimentEvent( 471 + wallMs = Clock.System.now().toEpochMilliseconds(), 472 + skeleton = skel, 473 + ) 474 + ) 475 + experimentCapturedCount = experimentEvents.size 476 + } 477 + } 478 + 479 + // Auto-mode driver: when the activity was launched with an 480 + // ExperimentLaunchSpec (via intent extras → AppActivity → CompositionLocal), 481 + // automatically pick the model, wait until the orchestrator's wall-clock 482 + // target, run the buffer for the requested duration, write the JSON, and 483 + // (optionally) finish the activity. The orchestrator scrapes Logcat 484 + // (tag "ExperimentAuto") to track progress and to learn the saved path. 485 + LaunchedEffect(Unit) { 486 + val spec = autoSpec ?: return@LaunchedEffect 487 + autoBridge.log("entered modelName=${spec.modelName} startAt=${spec.startAtWallMs} duration=${spec.durationMs}") 488 + 489 + if (availableModels.isEmpty()) { 490 + autoBridge.log("error: no models discovered in assets") 491 + autoBridge.finishActivity() 492 + return@LaunchedEffect 493 + } 494 + val target = availableModels.firstOrNull { m -> 495 + val n = m.name 496 + n.equals(spec.modelName, ignoreCase = true) || 497 + n.replace(' ', '_').equals(spec.modelName, ignoreCase = true) || 498 + n.replace(' ', '_').equals(spec.modelName.replace(' ', '_'), ignoreCase = true) 499 + } 500 + if (target == null) { 501 + autoBridge.log("error: model not found: ${spec.modelName} (available: ${availableModels.joinToString { it.name }})") 502 + autoBridge.finishActivity() 503 + return@LaunchedEffect 504 + } 505 + experimentMode = true 506 + selectedModel = target 507 + 508 + // Wait for the pipeline to actually start emitting. drop(1) skips the 509 + // StateFlow's stale replay value; first() returns as soon as a fresh 510 + // emission lands (i.e. the model loaded, camera is producing frames, 511 + // and the first inference completed). Bounded by an 8s timeout in 512 + // case the model conflates empty results (e.g. nothing in frame). 513 + val firstEmission = withTimeoutOrNull(8000) { 514 + customObjectRespository.customObjectFlow.drop(1).first() 515 + } 516 + autoBridge.log("ready model=${target.name} firstEmissionObjects=${firstEmission?.size ?: -1}") 517 + 518 + val nowMs = Clock.System.now().toEpochMilliseconds() 519 + if (spec.startAtWallMs > nowMs) { 520 + delay(spec.startAtWallMs - nowMs) 521 + } 522 + 523 + // Programmatic Start — same effect as tapping the on-screen button. 524 + experimentEvents.clear() 525 + experimentCapturedCount = 0 526 + experimentStartedWallMs = Clock.System.now().toEpochMilliseconds() 527 + lastExperimentLogPath = null 528 + experimentRunning = true 529 + autoBridge.log("started wall_ms=$experimentStartedWallMs") 530 + 531 + delay(spec.durationMs) 532 + 533 + // Programmatic Stop — duplicates the manual button's serialise/write 534 + // sequence so both code paths produce identical JSON files. 535 + experimentRunning = false 536 + val stoppedMs = Clock.System.now().toEpochMilliseconds() 537 + val safeModelName = (selectedModel?.name ?: "unknown") 538 + .replace(' ', '_') 539 + .replace(Regex("[^A-Za-z0-9._-]"), "") 540 + .ifBlank { "unknown" } 541 + val runId = experimentStartedWallMs 542 + val filename = "${safeModelName}__${runId}.json" 543 + val json = buildExperimentLogJson( 544 + deviceModel = experimentLogger.deviceLabel, 545 + modelName = safeModelName, 546 + runId = runId, 547 + startedWallMs = experimentStartedWallMs, 548 + stoppedWallMs = stoppedMs, 549 + events = experimentEvents.toList(), 550 + ) 551 + val writtenPath = experimentLogger.write(filename, json) 552 + lastExperimentLogPath = writtenPath 553 + autoBridge.log("stopped path=$writtenPath events=${experimentEvents.size}") 554 + 555 + // Brief delay so the Logcat write flushes before we tear down. 556 + delay(500) 557 + if (spec.finishOnStop) { 558 + autoBridge.finishActivity() 559 + } 560 + } 561 + 397 562 PermissionProvider().apply { 398 563 if (!hasCameraPermission()) RequestCameraPermission(onGranted = { 399 564 permissionGranted = true ··· 455 620 }, 456 621 objectModel = generalModel, 457 622 modifier = Modifier.weight(1f), 458 - focusArea = Rect(0f, 0f, 1f, 1f), 623 + focusArea = Rect(0.1f, 0.1f, 0.9f, 0.9f), 624 + poseFocusMode = poseFocusMode, 459 625 frontCamera = frontCamera, 460 626 useUltraWide = ultrawide, 461 627 previewFillMode = previewFillMode, ··· 465 631 ) 466 632 } 467 633 } 634 + // TEST HARNESS: mode badge (top-center) so screenshots are 635 + // self-labeling for the alignment check. 468 636 Box( 469 - modifier = Modifier.imePadding().padding(12.dp).align(Alignment.TopEnd) 637 + modifier = Modifier 638 + .padding(12.dp) 639 + .align(Alignment.TopCenter) 640 + ) { 641 + Text( 642 + text = "MODE=" + when (poseFocusMode) { 643 + PoseFocusMode.MASK -> "MASK" 644 + PoseFocusMode.CROP -> "CROP" 645 + PoseFocusMode.CROP_FOLLOW -> "CROP_FOLLOW" 646 + }, 647 + color = Color.Yellow, 648 + fontSize = 18.sp, 649 + ) 650 + } 651 + Box( 652 + modifier = Modifier 653 + .imePadding() 654 + .padding(12.dp) 655 + .align(Alignment.TopEnd) 470 656 ) { 471 657 IconButton(onClick = { menuExpanded = true }) { 472 658 Text("⋮", color = Color.White, fontSize = 22.sp) 473 659 } 474 660 475 661 DropdownMenu( 476 - expanded = menuExpanded, onDismissRequest = { menuExpanded = false }) { 662 + expanded = menuExpanded, 663 + onDismissRequest = { menuExpanded = false } 664 + ) { 477 665 // Zoom toggle 478 - DropdownMenuItem(text = { 479 - Row( 480 - horizontalArrangement = Arrangement.SpaceBetween, 481 - verticalAlignment = Alignment.CenterVertically, 482 - modifier = Modifier.fillMaxWidth() 483 - ) { 484 - Text(text = if (ultrawide) "0.5x zoom" else "1.0x zoom") 485 - Spacer(Modifier.width(12.dp)) 486 - Switch(checked = ultrawide, onCheckedChange = null) 487 - } 488 - }, onClick = { ultrawide = !ultrawide }) 666 + DropdownMenuItem( 667 + text = { 668 + Row( 669 + horizontalArrangement = Arrangement.SpaceBetween, 670 + verticalAlignment = Alignment.CenterVertically, 671 + modifier = Modifier.fillMaxWidth() 672 + ) { 673 + Text(text = if (ultrawide) "0.5x zoom" else "1.0x zoom") 674 + Spacer(Modifier.width(12.dp)) 675 + Switch(checked = ultrawide, onCheckedChange = null) 676 + } 677 + }, 678 + onClick = { ultrawide = !ultrawide } 679 + ) 489 680 490 681 // Preview fill/crop toggle 491 - DropdownMenuItem(text = { 492 - Row( 493 - horizontalArrangement = Arrangement.SpaceBetween, 494 - verticalAlignment = Alignment.CenterVertically, 495 - modifier = Modifier.fillMaxWidth() 496 - ) { 497 - Text(text = if (previewFillMode == PreviewFillMode.FIT) "Fill Preview" else "Fit Preview") 498 - Spacer(Modifier.width(12.dp)) 499 - Switch( 500 - checked = previewFillMode == PreviewFillMode.FIT, 501 - onCheckedChange = null 502 - ) 682 + DropdownMenuItem( 683 + text = { 684 + Row( 685 + horizontalArrangement = Arrangement.SpaceBetween, 686 + verticalAlignment = Alignment.CenterVertically, 687 + modifier = Modifier.fillMaxWidth() 688 + ) { 689 + Text(text = if (previewFillMode == PreviewFillMode.FIT) "Fill Preview" else "Fit Preview") 690 + Spacer(Modifier.width(12.dp)) 691 + Switch( 692 + checked = previewFillMode == PreviewFillMode.FIT, 693 + onCheckedChange = null 694 + ) 695 + } 696 + }, 697 + onClick = { 698 + previewFillMode = 699 + if (previewFillMode == PreviewFillMode.FIT) PreviewFillMode.FILL else PreviewFillMode.FIT 503 700 } 504 - }, onClick = { 505 - previewFillMode = 506 - if (previewFillMode == PreviewFillMode.FIT) PreviewFillMode.FILL else PreviewFillMode.FIT 507 - }) 701 + ) 702 + 703 + // Pose focus mode cycle — only affects the pose input; 704 + // object detection always sees the full frame. Tap 705 + // advances Mask → Crop → Crop+follow → Mask. 706 + DropdownMenuItem( 707 + text = { 708 + Row( 709 + horizontalArrangement = Arrangement.SpaceBetween, 710 + verticalAlignment = Alignment.CenterVertically, 711 + modifier = Modifier.fillMaxWidth() 712 + ) { 713 + Text( 714 + text = when (poseFocusMode) { 715 + PoseFocusMode.MASK -> "Pose: Mask focus" 716 + PoseFocusMode.CROP -> "Pose: Crop focus" 717 + PoseFocusMode.CROP_FOLLOW -> "Pose: Crop+follow" 718 + } 719 + ) 720 + } 721 + }, 722 + onClick = { 723 + poseFocusMode = when (poseFocusMode) { 724 + PoseFocusMode.MASK -> PoseFocusMode.CROP 725 + PoseFocusMode.CROP -> PoseFocusMode.CROP_FOLLOW 726 + PoseFocusMode.CROP_FOLLOW -> PoseFocusMode.MASK 727 + } 728 + } 729 + ) 508 730 509 731 HorizontalDivider() 510 732 ··· 523 745 Text(text = "Pose") 524 746 Spacer(Modifier.width(12.dp)) 525 747 RadioButton( 526 - selected = detectMode == DetectMode.POSE, onClick = { 748 + selected = detectMode == DetectMode.POSE, 749 + onClick = { 527 750 detectMode = DetectMode.POSE 528 751 }) 529 752 } ··· 535 758 Text(text = "Objects") 536 759 Spacer(Modifier.width(12.dp)) 537 760 RadioButton( 538 - selected = detectMode == DetectMode.OBJECT, onClick = { 761 + selected = detectMode == DetectMode.OBJECT, 762 + onClick = { 539 763 detectMode = DetectMode.OBJECT 540 764 }) 541 765 } ··· 547 771 Text(text = "Both") 548 772 Spacer(Modifier.width(12.dp)) 549 773 RadioButton( 550 - selected = detectMode == DetectMode.BOTH, onClick = { 774 + selected = detectMode == DetectMode.BOTH, 775 + onClick = { 551 776 detectMode = DetectMode.BOTH 552 777 }) 553 778 } ··· 559 784 Text(text = "None") 560 785 Spacer(Modifier.width(12.dp)) 561 786 RadioButton( 562 - selected = detectMode == DetectMode.NONE, onClick = { 787 + selected = detectMode == DetectMode.NONE, 788 + onClick = { 563 789 detectMode = DetectMode.NONE 564 790 }) 565 791 } ··· 589 815 Spacer(Modifier.width(12.dp)) 590 816 RadioButton( 591 817 selected = selectedModel == model, 592 - onClick = { selectedModel = model }) 818 + onClick = { selectedModel = model } 819 + ) 593 820 } 594 821 } 595 822 } ··· 609 836 } 610 837 // Keep menu open or close? Close feels better. 611 838 menuExpanded = false 612 - }) 839 + } 840 + ) 613 841 } 614 842 } 615 843 }
+52
sample/composeApp/src/commonMain/kotlin/com/nate/posedetection/ExperimentAuto.kt
··· 1 + package com.nate.posedetection 2 + 3 + import androidx.compose.runtime.Composable 4 + import androidx.compose.runtime.compositionLocalOf 5 + 6 + /** 7 + * Parameters for an unattended ("auto") experiment-mode run, supplied by the 8 + * Mac orchestrator (`tools/run_auto_experiment.sh`) via Android intent extras 9 + * and surfaced to Compose code through [LocalExperimentAutoSpec]. 10 + * 11 + * The phone schedules its experiment buffer to start at [startAtWallMs] 12 + * (a `System.currentTimeMillis()` target chosen by the orchestrator) and 13 + * automatically stops it [durationMs] later. The orchestrator picks the same 14 + * wall-clock target for the QuickTime play moment, so the two start in 15 + * approximate sync without needing any explicit handshake. Any constant 16 + * Mac↔phone clock skew cancels out across runs and does not affect model A 17 + * vs. model B comparison. 18 + */ 19 + data class ExperimentLaunchSpec( 20 + /** Display name (or filename) of the model to select before starting. */ 21 + val modelName: String, 22 + /** Wall-clock target (System.currentTimeMillis()) for the buffer start. */ 23 + val startAtWallMs: Long, 24 + /** How long the buffer should run before auto-stop and JSON write. */ 25 + val durationMs: Long, 26 + /** If true, the activity calls finish() after the JSON has been written. */ 27 + val finishOnStop: Boolean = true, 28 + ) 29 + 30 + /** 31 + * Composition-scoped slot for an [ExperimentLaunchSpec]. Android sets this 32 + * from `AppActivity.onCreate` when the launch intent carries the auto-mode 33 + * extras; iOS leaves it null. 34 + */ 35 + val LocalExperimentAutoSpec = compositionLocalOf<ExperimentLaunchSpec?> { null } 36 + 37 + /** 38 + * Bridge for platform-specific side effects the auto driver needs: 39 + * 40 + * * [log] writes a tagged line that the orchestrator scrapes via 41 + * `adb logcat -s ExperimentAuto:I` to track progress (ready / started / 42 + * stopped / error). 43 + * * [finishActivity] tears the activity down once the JSON is written so 44 + * the next run starts cold. 45 + */ 46 + interface ExperimentAutoBridge { 47 + fun log(msg: String) 48 + fun finishActivity() 49 + } 50 + 51 + @Composable 52 + expect fun rememberExperimentAutoBridge(): ExperimentAutoBridge
+131
sample/composeApp/src/commonMain/kotlin/com/nate/posedetection/ExperimentLogger.kt
··· 1 + package com.nate.posedetection 2 + 3 + import androidx.compose.runtime.Composable 4 + import com.performancecoachlab.posedetection.recording.AnalysisObject 5 + import com.performancecoachlab.posedetection.skeleton.Skeleton 6 + 7 + /** 8 + * Persists experiment-mode capture buffers from the sample app to a platform- 9 + * specific location so the Mac orchestrator can `adb pull` them back for the 10 + * model-comparison report. Android writes JSON to the app's external files 11 + * directory under `experiment_logs/`. iOS is a no-op stub (out of scope). 12 + */ 13 + interface ExperimentLogger { 14 + /** Human-readable device label, e.g. "Google Pixel 7". Embedded in the log. */ 15 + val deviceLabel: String 16 + 17 + /** 18 + * Writes [json] to a platform file named [filename] inside the experiment 19 + * logs directory and returns its absolute path, or null if writing failed 20 + * or is unsupported on this platform. 21 + */ 22 + fun write(filename: String, json: String): String? 23 + } 24 + 25 + @Composable 26 + expect fun rememberExperimentLogger(): ExperimentLogger 27 + 28 + internal data class ExperimentEvent( 29 + val wallMs: Long, 30 + val objects: List<AnalysisObject> = emptyList(), 31 + val skeleton: Skeleton? = null, 32 + ) 33 + 34 + internal fun buildExperimentLogJson( 35 + deviceModel: String, 36 + modelName: String, 37 + runId: Long, 38 + startedWallMs: Long, 39 + stoppedWallMs: Long, 40 + events: List<ExperimentEvent>, 41 + ): String { 42 + val sb = StringBuilder() 43 + sb.append('{') 44 + sb.append("\"device_model\":\"").append(jsonEscape(deviceModel)).append("\",") 45 + sb.append("\"model_name\":\"").append(jsonEscape(modelName)).append("\",") 46 + sb.append("\"run_id\":").append(runId).append(',') 47 + sb.append("\"started_wall_ms\":").append(startedWallMs).append(',') 48 + sb.append("\"stopped_wall_ms\":").append(stoppedWallMs).append(',') 49 + sb.append("\"events\":[") 50 + events.forEachIndexed { idx, e -> 51 + if (idx > 0) sb.append(',') 52 + sb.append('{') 53 + sb.append("\"wall_ms\":").append(e.wallMs).append(',') 54 + sb.append("\"skeleton\":") 55 + val s = e.skeleton 56 + if (s == null) { 57 + sb.append("null") 58 + } else { 59 + sb.append('{') 60 + sb.append("\"w\":").append(jsonNumber(s.width)).append(',') 61 + sb.append("\"h\":").append(jsonNumber(s.height)).append(',') 62 + sb.append("\"joints\":{") 63 + val joints = listOf( 64 + "leftShoulder" to s.leftShoulder, 65 + "rightShoulder" to s.rightShoulder, 66 + "leftElbow" to s.leftElbow, 67 + "rightElbow" to s.rightElbow, 68 + "leftWrist" to s.leftWrist, 69 + "rightWrist" to s.rightWrist, 70 + "leftHip" to s.leftHip, 71 + "rightHip" to s.rightHip, 72 + "leftKnee" to s.leftKnee, 73 + "rightKnee" to s.rightKnee, 74 + "leftAnkle" to s.leftAnkle, 75 + "rightAnkle" to s.rightAnkle, 76 + ) 77 + joints.forEachIndexed { i, (name, c) -> 78 + if (i > 0) sb.append(',') 79 + sb.append('"').append(name).append("\":") 80 + if (c == null) sb.append("null") 81 + else sb.append('[').append(jsonNumber(c.x)).append(',').append(jsonNumber(c.y)).append(']') 82 + } 83 + sb.append("}}") 84 + } 85 + sb.append(',') 86 + sb.append("\"objects\":[") 87 + e.objects.forEachIndexed { i, obj -> 88 + if (i > 0) sb.append(',') 89 + val top = obj.labels.maxByOrNull { it.confidence } 90 + sb.append('{') 91 + sb.append("\"label\":\"").append(jsonEscape(top?.text ?: "")).append("\",") 92 + sb.append("\"confidence\":").append(jsonNumber(top?.confidence ?: 0f)).append(',') 93 + sb.append("\"bbox\":[") 94 + .append(jsonNumber(obj.boundingBox.left)).append(',') 95 + .append(jsonNumber(obj.boundingBox.top)).append(',') 96 + .append(jsonNumber(obj.boundingBox.right)).append(',') 97 + .append(jsonNumber(obj.boundingBox.bottom)) 98 + .append("],") 99 + sb.append("\"frame_size\":[") 100 + .append(obj.frameSize.width).append(',') 101 + .append(obj.frameSize.height) 102 + .append(']') 103 + sb.append('}') 104 + } 105 + sb.append(']') 106 + sb.append('}') 107 + } 108 + sb.append(']') 109 + sb.append('}') 110 + return sb.toString() 111 + } 112 + 113 + private fun jsonEscape(s: String): String { 114 + val sb = StringBuilder(s.length + 2) 115 + for (c in s) { 116 + when (c) { 117 + '"' -> sb.append("\\\"") 118 + '\\' -> sb.append("\\\\") 119 + '\n' -> sb.append("\\n") 120 + '\r' -> sb.append("\\r") 121 + '\t' -> sb.append("\\t") 122 + else -> if (c.code < 0x20) { 123 + sb.append("\\u").append(c.code.toString(16).padStart(4, '0')) 124 + } else sb.append(c) 125 + } 126 + } 127 + return sb.toString() 128 + } 129 + 130 + private fun jsonNumber(f: Float): String = 131 + if (f.isFinite()) f.toString() else "0"
+6
sample/composeApp/src/commonMain/kotlin/com/nate/posedetection/ScreenshotHelper.kt
··· 1 + package com.nate.posedetection 2 + 3 + // Test-harness screenshot: grab the current app window as PNG, write to the 4 + // app's Documents/ for the host to pull back via `devicectl device copy from`. 5 + // No-op on Android (we only screenshot iOS device runs). 6 + expect fun saveAppScreenshot(filename: String): String?
+21
sample/composeApp/src/iosMain/kotlin/com/nate/posedetection/ExperimentAuto.ios.kt
··· 1 + package com.nate.posedetection 2 + 3 + import androidx.compose.runtime.Composable 4 + import androidx.compose.runtime.remember 5 + import platform.Foundation.NSLog 6 + import platform.posix.exit 7 + 8 + private object IosExperimentAutoBridge : ExperimentAutoBridge { 9 + override fun log(msg: String) { 10 + NSLog("[ExperimentAuto] %s", msg) 11 + } 12 + 13 + override fun finishActivity() { 14 + NSLog("[ExperimentAuto] finishActivity — exiting") 15 + exit(0) 16 + } 17 + } 18 + 19 + @Composable 20 + actual fun rememberExperimentAutoBridge(): ExperimentAutoBridge = 21 + remember { IosExperimentAutoBridge }
+39
sample/composeApp/src/iosMain/kotlin/com/nate/posedetection/ExperimentLogger.ios.kt
··· 1 + package com.nate.posedetection 2 + 3 + import androidx.compose.runtime.Composable 4 + import androidx.compose.runtime.remember 5 + import platform.Foundation.NSDocumentDirectory 6 + import platform.Foundation.NSFileManager 7 + import platform.Foundation.NSSearchPathForDirectoriesInDomains 8 + import platform.Foundation.NSString 9 + import platform.Foundation.NSUserDomainMask 10 + import platform.Foundation.NSUTF8StringEncoding 11 + import platform.Foundation.writeToFile 12 + import platform.UIKit.UIDevice 13 + 14 + @OptIn(kotlinx.cinterop.ExperimentalForeignApi::class) 15 + private class IosExperimentLogger : ExperimentLogger { 16 + override val deviceLabel: String = 17 + "${UIDevice.currentDevice.systemName} ${UIDevice.currentDevice.model} ${UIDevice.currentDevice.systemVersion}" 18 + 19 + override fun write(filename: String, json: String): String? { 20 + val docs = (NSSearchPathForDirectoriesInDomains( 21 + NSDocumentDirectory, NSUserDomainMask, true 22 + ).firstOrNull() as? String) ?: return null 23 + val dir = "$docs/experiment_logs" 24 + NSFileManager.defaultManager.createDirectoryAtPath( 25 + dir, true, null, null 26 + ) 27 + val path = "$dir/$filename" 28 + val ok = (json as NSString).writeToFile( 29 + path = path, 30 + atomically = true, 31 + encoding = NSUTF8StringEncoding, 32 + error = null 33 + ) 34 + return if (ok) path else null 35 + } 36 + } 37 + 38 + @Composable 39 + actual fun rememberExperimentLogger(): ExperimentLogger = remember { IosExperimentLogger() }
+39
sample/composeApp/src/iosMain/kotlin/com/nate/posedetection/ScreenshotHelper.ios.kt
··· 1 + package com.nate.posedetection 2 + 3 + import kotlinx.cinterop.BetaInteropApi 4 + import kotlinx.cinterop.ExperimentalForeignApi 5 + import kotlinx.cinterop.useContents 6 + import platform.CoreGraphics.CGSizeMake 7 + import platform.Foundation.NSDocumentDirectory 8 + import platform.Foundation.NSFileManager 9 + import platform.Foundation.NSURL 10 + import platform.Foundation.NSUserDomainMask 11 + import platform.Foundation.writeToURL 12 + import platform.UIKit.UIApplication 13 + import platform.UIKit.UIGraphicsImageRenderer 14 + import platform.UIKit.UIImage 15 + import platform.UIKit.UIImagePNGRepresentation 16 + import platform.UIKit.drawViewHierarchyInRect 17 + 18 + @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) 19 + actual fun saveAppScreenshot(filename: String): String? { 20 + val window = UIApplication.sharedApplication.keyWindow ?: return null 21 + val bounds = window.bounds 22 + val sizeW: Double 23 + val sizeH: Double 24 + bounds.useContents { 25 + sizeW = size.width 26 + sizeH = size.height 27 + } 28 + val renderer = UIGraphicsImageRenderer(size = CGSizeMake(sizeW, sizeH)) 29 + val image: UIImage = renderer.imageWithActions { _ -> 30 + window.drawViewHierarchyInRect(bounds, afterScreenUpdates = false) 31 + } 32 + val png = UIImagePNGRepresentation(image) ?: return null 33 + val docsDir: NSURL = NSFileManager.defaultManager 34 + .URLsForDirectory(NSDocumentDirectory, NSUserDomainMask) 35 + .firstOrNull() as? NSURL ?: return null 36 + val fileUrl = docsDir.URLByAppendingPathComponent(filename) ?: return null 37 + png.writeToURL(fileUrl, atomically = true) 38 + return fileUrl.path 39 + }
+24
sample/composeApp/src/iosMain/kotlin/main.kt
··· 1 + import androidx.compose.runtime.CompositionLocalProvider 1 2 import androidx.compose.ui.window.ComposeUIViewController 2 3 import com.nate.posedetection.App 4 + import com.nate.posedetection.ExperimentLaunchSpec 5 + import com.nate.posedetection.LocalExperimentAutoSpec 3 6 import platform.UIKit.UIViewController 4 7 5 8 fun MainViewController(): UIViewController = ComposeUIViewController { App() } 9 + 10 + fun MainViewControllerWithAutoSpec( 11 + modelName: String?, 12 + startAtWallMs: Long, 13 + durationMs: Long, 14 + finishOnStop: Boolean, 15 + ): UIViewController { 16 + val spec = if (!modelName.isNullOrBlank() && durationMs > 0L) { 17 + ExperimentLaunchSpec( 18 + modelName = modelName, 19 + startAtWallMs = startAtWallMs, 20 + durationMs = durationMs, 21 + finishOnStop = finishOnStop, 22 + ) 23 + } else null 24 + return ComposeUIViewController { 25 + CompositionLocalProvider(LocalExperimentAutoSpec provides spec) { 26 + App() 27 + } 28 + } 29 + }
+12 -2
sample/iosApp/iosApp.xcodeproj/project.pbxproj
··· 39 39 children = ( 40 40 A93A953929CC810C00F8E227 /* iosApp */, 41 41 A93A953829CC810C00F8E227 /* Products */, 42 + C4127409AE3703430489E7BC /* Frameworks */, 42 43 ); 43 44 sourceTree = "<group>"; 44 45 }; ··· 67 68 A93A954129CC810D00F8E227 /* Preview Assets.xcassets */, 68 69 ); 69 70 path = "Preview Content"; 71 + sourceTree = "<group>"; 72 + }; 73 + C4127409AE3703430489E7BC /* Frameworks */ = { 74 + isa = PBXGroup; 75 + children = ( 76 + ); 77 + name = Frameworks; 70 78 sourceTree = "<group>"; 71 79 }; 72 80 /* End PBXGroup section */ ··· 294 302 CODE_SIGN_STYLE = Automatic; 295 303 CURRENT_PROJECT_VERSION = 1; 296 304 DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 297 - DEVELOPMENT_TEAM = FAGG2XS28P; 305 + DEVELOPMENT_TEAM = R633H24ZDK; 298 306 ENABLE_PREVIEWS = YES; 299 307 GENERATE_INFOPLIST_FILE = YES; 300 308 INFOPLIST_FILE = iosApp/Info.plist; ··· 304 312 "@executable_path/Frameworks", 305 313 ); 306 314 MARKETING_VERSION = 1.0; 315 + OTHER_LDFLAGS = "$(inherited)"; 307 316 PRODUCT_BUNDLE_IDENTIFIER = com.nate.posedetection.iosApp; 308 317 PRODUCT_NAME = PoseDetection; 309 318 SWIFT_EMIT_LOC_STRINGS = YES; ··· 320 329 CODE_SIGN_STYLE = Automatic; 321 330 CURRENT_PROJECT_VERSION = 1; 322 331 DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 323 - DEVELOPMENT_TEAM = FAGG2XS28P; 332 + DEVELOPMENT_TEAM = R633H24ZDK; 324 333 ENABLE_PREVIEWS = YES; 325 334 GENERATE_INFOPLIST_FILE = YES; 326 335 INFOPLIST_FILE = iosApp/Info.plist; ··· 330 339 "@executable_path/Frameworks", 331 340 ); 332 341 MARKETING_VERSION = 1.0; 342 + OTHER_LDFLAGS = "$(inherited)"; 333 343 PRODUCT_BUNDLE_IDENTIFIER = com.nate.posedetection.iosApp; 334 344 PRODUCT_NAME = PoseDetection; 335 345 SWIFT_EMIT_LOC_STRINGS = YES;
+43 -2
sample/iosApp/iosApp/iosApp.swift
··· 10 10 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 11 11 ) -> Bool { 12 12 window = UIWindow(frame: UIScreen.main.bounds) 13 - 13 + 14 + // Parse unattended experiment-mode launch args. 15 + // Accepts single-dash `-key value` pairs after a `--` separator (matches 16 + // `xcrun devicectl device process launch ... -- -key value` convention). 17 + let args = CommandLine.arguments 18 + var modelName: String? = nil 19 + var durationMs: Int64 = 0 20 + var startAtWallMs: Int64 = 0 21 + var finishOnStop: Bool = true 22 + var i = 0 23 + while i < args.count - 1 { 24 + let k = args[i] 25 + let v = args[i + 1] 26 + switch k { 27 + case "-test_model": 28 + modelName = v 29 + case "-test_duration_sec": 30 + if let secs = Int64(v) { durationMs = secs * 1000 } 31 + case "-test_duration_ms": 32 + durationMs = Int64(v) ?? 0 33 + case "-start_at_wall_ms": 34 + startAtWallMs = Int64(v) ?? 0 35 + case "-finish_on_stop": 36 + finishOnStop = (v == "1" || v.lowercased() == "true") 37 + default: break 38 + } 39 + i += 1 40 + } 41 + 42 + let rootVc: UIViewController 43 + if let name = modelName, durationMs > 0 { 44 + NSLog("[ExperimentAuto] launching with modelName=\(name) durationMs=\(durationMs) startAtWallMs=\(startAtWallMs)") 45 + rootVc = MainKt.MainViewControllerWithAutoSpec( 46 + modelName: name, 47 + startAtWallMs: startAtWallMs, 48 + durationMs: durationMs, 49 + finishOnStop: finishOnStop 50 + ) 51 + } else { 52 + rootVc = MainKt.MainViewController() 53 + } 54 + 14 55 if let window = window { 15 - window.rootViewController = MainKt.MainViewController() 56 + window.rootViewController = rootVc 16 57 window.makeKeyAndVisible() 17 58 } 18 59 return true
sample/iosApp/iosApp/models/yolo11n_better_data.mlpackage/Data/com.apple.CoreML/model.mlmodel

This is a binary file and will not be displayed.

sample/iosApp/iosApp/models/yolo11n_better_data.mlpackage/Data/com.apple.CoreML/weights/weight.bin

This is a binary file and will not be displayed.

+18
sample/iosApp/iosApp/models/yolo11n_better_data.mlpackage/Manifest.json
··· 1 + { 2 + "fileFormatVersion": "1.0.0", 3 + "itemInfoEntries": { 4 + "16e6b489-696b-41c9-9753-07f4481a1efd": { 5 + "author": "com.apple.CoreML", 6 + "description": "CoreML Model Weights", 7 + "name": "weights", 8 + "path": "com.apple.CoreML/weights" 9 + }, 10 + "17c86ae4-7308-46b1-9423-7a4ce47adeba": { 11 + "author": "com.apple.CoreML", 12 + "description": "CoreML Model Specification", 13 + "name": "model.mlmodel", 14 + "path": "com.apple.CoreML/model.mlmodel" 15 + } 16 + }, 17 + "rootModelIdentifier": "17c86ae4-7308-46b1-9423-7a4ce47adeba" 18 + }
sample/iosApp/iosApp/models/yolo26n_v13_rect_384x288.mlpackage/Data/com.apple.CoreML/model.mlmodel

This is a binary file and will not be displayed.

sample/iosApp/iosApp/models/yolo26n_v13_rect_384x288.mlpackage/Data/com.apple.CoreML/weights/weight.bin

This is a binary file and will not be displayed.

+18
sample/iosApp/iosApp/models/yolo26n_v13_rect_384x288.mlpackage/Manifest.json
··· 1 + { 2 + "fileFormatVersion": "1.0.0", 3 + "itemInfoEntries": { 4 + "57b81d8b-f832-43d6-9c66-c7c960921694": { 5 + "author": "com.apple.CoreML", 6 + "description": "CoreML Model Specification", 7 + "name": "model.mlmodel", 8 + "path": "com.apple.CoreML/model.mlmodel" 9 + }, 10 + "67714b2f-a270-45ff-9231-dda13ed32954": { 11 + "author": "com.apple.CoreML", 12 + "description": "CoreML Model Weights", 13 + "name": "weights", 14 + "path": "com.apple.CoreML/weights" 15 + } 16 + }, 17 + "rootModelIdentifier": "57b81d8b-f832-43d6-9c66-c7c960921694" 18 + }
sample/iosApp/iosApp/models/yolo26n_v13_rect_640x480.mlpackage/Data/com.apple.CoreML/model.mlmodel

This is a binary file and will not be displayed.

sample/iosApp/iosApp/models/yolo26n_v13_rect_640x480.mlpackage/Data/com.apple.CoreML/weights/weight.bin

This is a binary file and will not be displayed.

+18
sample/iosApp/iosApp/models/yolo26n_v13_rect_640x480.mlpackage/Manifest.json
··· 1 + { 2 + "fileFormatVersion": "1.0.0", 3 + "itemInfoEntries": { 4 + "2fb85f7e-613f-499c-80fa-3acf12af91d5": { 5 + "author": "com.apple.CoreML", 6 + "description": "CoreML Model Specification", 7 + "name": "model.mlmodel", 8 + "path": "com.apple.CoreML/model.mlmodel" 9 + }, 10 + "a097795c-1871-4760-aef7-888eaaf4cbc4": { 11 + "author": "com.apple.CoreML", 12 + "description": "CoreML Model Weights", 13 + "name": "weights", 14 + "path": "com.apple.CoreML/weights" 15 + } 16 + }, 17 + "rootModelIdentifier": "2fb85f7e-613f-499c-80fa-3acf12af91d5" 18 + }
sample/iosApp/iosApp/models/yolo26n_v13_rect_960x736.mlpackage/Data/com.apple.CoreML/model.mlmodel

This is a binary file and will not be displayed.

sample/iosApp/iosApp/models/yolo26n_v13_rect_960x736.mlpackage/Data/com.apple.CoreML/weights/weight.bin

This is a binary file and will not be displayed.

+18
sample/iosApp/iosApp/models/yolo26n_v13_rect_960x736.mlpackage/Manifest.json
··· 1 + { 2 + "fileFormatVersion": "1.0.0", 3 + "itemInfoEntries": { 4 + "57f1cae0-6698-4051-a0c7-9ac0b9e9a321": { 5 + "author": "com.apple.CoreML", 6 + "description": "CoreML Model Weights", 7 + "name": "weights", 8 + "path": "com.apple.CoreML/weights" 9 + }, 10 + "c8eb1b96-f90f-4be1-9370-1128c3bec33c": { 11 + "author": "com.apple.CoreML", 12 + "description": "CoreML Model Specification", 13 + "name": "model.mlmodel", 14 + "path": "com.apple.CoreML/model.mlmodel" 15 + } 16 + }, 17 + "rootModelIdentifier": "c8eb1b96-f90f-4be1-9370-1128c3bec33c" 18 + }
+268
tools/README.md
··· 1 + # Closed-loop training & comparison tools 2 + 3 + These scripts close the loop between Colab-trained TFLite object-detection 4 + models and on-device measurement on a real Android phone, so we can 5 + objectively compare model A vs. model B by running them against the same 6 + video on the same hardware. 7 + 8 + ``` 9 + collab/Model Training.ipynb (edit cells, retrain in Colab) 10 + │ trained .tflite via Drive sync 11 + 12 + collab/output/<run-id>/*.tflite 13 + │ tools/sync_models.py 14 + 15 + sample/composeApp/.../assets/<run-id>__<model>.tflite 16 + │ ./gradlew :sample:composeApp:assembleDebug 17 + │ adb install -r 18 + 19 + Phone (Experiment Mode) 20 + │ JSON log per detection 21 + 22 + /sdcard/Android/data/com.nate.posedetection.androidApp/files/experiment_logs/ 23 + │ tools/run_experiment.sh (manual orchestration) 24 + │ adb pull 25 + 26 + experiments/<run-id>/{log.json, manifest.json} 27 + │ tools/compare_logs.py 28 + 29 + report.html + summary.csv 30 + ``` 31 + 32 + The package id is `com.nate.posedetection.androidApp` (note the `.androidApp` 33 + suffix — the Kotlin namespace is `com.nate.posedetection` without it). Every 34 + adb command targets the suffixed name. 35 + 36 + --- 37 + 38 + ## Prerequisites 39 + 40 + * **macOS** with QuickTime Player (preinstalled). 41 + * **adb** at `/Users/virtualintern/Library/Android/sdk/platform-tools/adb`. 42 + * **Phone** with USB debugging on, paired with this Mac, camera permission 43 + pre-granted to the sample app. Verify with `adb devices`. 44 + * **Python 3** for the orchestration scripts. `compare_logs.py` optionally 45 + uses **matplotlib** for embedded timeline charts — install with 46 + `uv pip install matplotlib` if you want them; the report still renders 47 + without. 48 + 49 + --- 50 + 51 + ## tools/sync_models.py 52 + 53 + Copies trained `.tflite` files from `collab/output/<run-id>/` into the 54 + sample app's Android assets dir. Synced files are renamed 55 + `<run-id>__<model-base>.tflite` (double underscore deliberate — the picker 56 + in `DiscoverModels.android.kt` replaces single underscores with spaces, so 57 + the double underscore renders as a clear visual break in the dropdown). 58 + 59 + ```bash 60 + tools/sync_models.py # default: sync the latest run 61 + tools/sync_models.py --list # show available runs newest-first 62 + tools/sync_models.py --run v0_smoke # sync a specific run 63 + tools/sync_models.py --clean # remove synced models 64 + ``` 65 + 66 + `--clean` preserves the three baseline models that ship with the repo 67 + (`yolo11n_dataset_dataset.tflite`, `yolo11n_su_416.tflite`, 68 + `yolov10n_float16.tflite`). 69 + 70 + After syncing, rebuild and reinstall the app: 71 + 72 + ```bash 73 + ./gradlew :sample:composeApp:assembleDebug 74 + adb install -r sample/composeApp/build/outputs/apk/debug/composeApp-debug.apk 75 + ``` 76 + 77 + If install fails with `INSTALL_FAILED_UPDATE_INCOMPATIBLE` (signature 78 + mismatch), the on-device app was signed by a different debug key. Run 79 + `adb uninstall com.nate.posedetection.androidApp` first; this wipes any 80 + data the app stored locally. 81 + 82 + --- 83 + 84 + ## tools/run_auto_experiment.sh — fully unattended orchestration 85 + 86 + Drives one experiment run end-to-end with no human at the phone. The 87 + orchestrator launches the sample app via `am start` with intent extras that 88 + tell the in-app auto-driver to select a model, wait until a wall-clock 89 + target, run the experiment buffer for a fixed duration, write the JSON, 90 + and finish the activity. The Mac side races to the same wall-clock target 91 + and plays the video in QuickTime at the configured offset. 92 + 93 + ```bash 94 + tools/run_auto_experiment.sh \ 95 + --video ~/Downloads/clip.mp4 \ 96 + --duration 10 \ 97 + --model-tag yolo11n_su_416 \ 98 + [--start-offset 10] \ 99 + [--device <serial>] 100 + ``` 101 + 102 + Flow: 103 + 104 + 1. Snapshots existing experiment-log files on the device for the diff-pull. 105 + 2. **Pre-opens** the video in QuickTime, positions the cursor at 106 + `--start-offset` seconds, and pauses. This step is wrapped in a 600 s 107 + AppleEvent timeout so very large 4K files don't blow up. The slow 108 + indexing happens here, *before* any wall-clock timing matters. 109 + 3. Force-stops the sample app and clears Logcat. 110 + 4. Computes `start_at_wall_ms = now + 9 s` (configurable via the 111 + `APP_BOOT_PAD_SECONDS` env var). Launches `AppActivity` via `am start` 112 + with `--ez experiment_auto true --es model_name <X> 113 + --el start_at_wall_ms <Y> --el duration_ms <Z>`. 114 + 5. Sleeps locally until `start_at_wall_ms`, then issues 115 + `osascript ... play front document` (sub-second since the file is 116 + already loaded). `t0_wall_ms` is captured immediately before the play. 117 + 6. Sleeps `--duration` seconds, then pauses QuickTime. 118 + 7. Diff-polls `/sdcard/.../experiment_logs` for the new JSON file (15 s 119 + timeout) and pulls it into `experiments/<run-id>/`. 120 + 8. Captures the `ExperimentAuto` Logcat excerpt and writes 121 + `experiments/<run-id>/manifest.json` with `t0_wall_ms`, 122 + `start_at_wall_ms`, model tag, video offset, device label, and the 123 + captured log lines. 124 + 125 + The Compose auto-driver inside `CameraSample` reads 126 + `LocalExperimentAutoSpec`, finds the model whose display name (or 127 + underscore-equivalent) matches `model_name` case-insensitively, waits for 128 + `customObjectFlow.drop(1).first()` (the pipeline's first real emission, 129 + bounded by an 8 s timeout), waits until `start_at_wall_ms`, runs the 130 + buffer for `duration_ms`, writes the JSON via the same `ExperimentLogger` 131 + the manual button uses, logs the saved path, and finishes the activity. 132 + 133 + Logcat tag is `ExperimentAuto`. To watch a run live: 134 + 135 + ```bash 136 + adb logcat -c && adb logcat -s ExperimentAuto:I 137 + ``` 138 + 139 + Tuning knobs (env vars): 140 + 141 + * `APP_BOOT_PAD_SECONDS` (default 9) — wall-clock budget for cold start + 142 + model load + camera spin-up. Bump if you see `start_at_wall_ms` firing 143 + before the phone is `ready`. 144 + * `PULL_TIMEOUT_SECONDS` (default 15) — how long to wait for the new JSON 145 + to appear on the phone after the buffer should have stopped. 146 + 147 + --- 148 + 149 + ## tools/run_experiment.sh — manual orchestration 150 + 151 + Drives one experiment run when you can be at the phone to tap Start/Stop. 152 + 153 + ```bash 154 + tools/run_experiment.sh \ 155 + --video ~/Downloads/test.mp4 \ 156 + --duration 10 \ 157 + --model-tag yolo11n_su_416 158 + ``` 159 + 160 + Flow: 161 + 162 + 1. Snapshots the existing experiment-log files on the phone so it can 163 + diff-pull only the new ones afterwards. 164 + 2. Prompts you: *"Phone ready? Model picked, Experiment Mode on, Start 165 + tapped?"* 166 + 3. Records `t0_wall_ms` and plays the video in QuickTime (`osascript`). 167 + 4. Sleeps for `--duration` seconds. 168 + 5. Pauses QuickTime. 169 + 6. Prompts you to tap Stop on the phone. 170 + 7. Pulls only the newly-written log file(s) into 171 + `experiments/<run-id>/`. 172 + 8. Writes `experiments/<run-id>/manifest.json` with `t0_wall_ms`, 173 + model tag, device label, video path, duration. 174 + 175 + `--device <serial>` is only needed if `adb devices` shows more than one 176 + device (otherwise the script auto-selects the single connected one). 177 + `--no-confirm` skips the interactive prompts for unattended dry-runs. 178 + 179 + --- 180 + 181 + ## tools/compare_logs.py — model comparison report 182 + 183 + Reads every `experiments/<run-id>/manifest.json` + log files and produces 184 + a self-contained HTML report and a CSV summary. 185 + 186 + ```bash 187 + tools/compare_logs.py experiments/ # report.html in cwd 188 + tools/compare_logs.py experiments/ -o ./reports/ # write into reports/ 189 + tools/compare_logs.py experiments/ --bucket 250 # 250ms buckets 190 + ``` 191 + 192 + The report contains: 193 + 194 + * **Per-run scorecard**: detection rate, mean confidence, events/sec, 195 + classes seen, mean bbox area. 196 + * **Per-class jitter table**: stddev of bbox-center deltas across 197 + consecutive frames. Lower = more stable. (Note: a moving subject also 198 + produces high jitter — useful for spotting *flapping* detections more 199 + than for absolute model quality.) 200 + * **Per-bucket comparison table**: for each time bucket (default 100 ms, 201 + configurable via `--bucket`), each model's frame count, top class, and 202 + max confidence. Aligned to each run's `t0_wall_ms` from the manifest so 203 + model A and model B share the same x-axis when run against the same 204 + video. 205 + * **Per-class confidence timelines**: matplotlib PNG charts embedded as 206 + base64 data URIs (omitted with a warning banner if matplotlib is not 207 + installed). 208 + 209 + `summary.csv` has one row per run with the same scorecard fields, for 210 + spreadsheet exploration. 211 + 212 + --- 213 + 214 + ## Typical comparison workflow 215 + 216 + ```bash 217 + # 1. Train a new model in collab/Model Training.ipynb (via Colab MCP). 218 + # Output lands at collab/output/<run-id>/<name>.tflite via Drive sync. 219 + 220 + # 2. Sync the trained model into the app. 221 + tools/sync_models.py --run <run-id> 222 + 223 + # 3. Build and install. 224 + ./gradlew :sample:composeApp:assembleDebug && \ 225 + adb install -r sample/composeApp/build/outputs/apk/debug/composeApp-debug.apk 226 + 227 + # 4. Run experiment A against the trained model. 228 + tools/run_experiment.sh \ 229 + --video ~/Movies/test_clip.mp4 \ 230 + --duration 10 \ 231 + --model-tag <run-id>__<name> 232 + 233 + # 5. (At the phone) Switch to a baseline model in the picker, tap Start 234 + # Experiment, and re-run against the same video. 235 + tools/run_experiment.sh \ 236 + --video ~/Movies/test_clip.mp4 \ 237 + --duration 10 \ 238 + --model-tag yolo11n_su_416 239 + 240 + # 6. Generate the comparison report. 241 + tools/compare_logs.py experiments/ -o reports/ 242 + 243 + # 7. Open reports/report.html in a browser. 244 + ``` 245 + 246 + --- 247 + 248 + ## Layout 249 + 250 + ``` 251 + tools/ 252 + ├── README.md (this file) 253 + ├── sync_models.py (Phase 2) 254 + ├── run_experiment.sh (Phase 5, manual orchestration) 255 + ├── run_auto_experiment.sh (unattended orchestration via intent extras) 256 + └── compare_logs.py (Phase 6) 257 + 258 + experiments/ (created by run_experiment.sh; gitignored) 259 + └── <t0_wall_ms>_<model_tag>/ 260 + ├── manifest.json 261 + └── <model>__<runId>.json 262 + 263 + collab/ 264 + ├── Model Training.ipynb (Drive-synced; iterated via Colab MCP) 265 + └── output/ (Drive-synced; tflites land here) 266 + └── <run-id>/ 267 + └── *.tflite 268 + ```
+427
tools/compare_logs.py
··· 1 + #!/usr/bin/env python3 2 + """ 3 + Generate a model-comparison report from experiments/<run-id>/ directories. 4 + 5 + Each ``experiments/<run-id>/`` directory is expected to contain: 6 + 7 + * ``manifest.json`` with at least ``run_id``, ``model_tag``, ``t0_wall_ms``, 8 + ``duration_seconds``, ``device_label`` (written by ``tools/run_experiment.sh``). 9 + * One or more ``*.json`` files matching the experiment-log schema produced by 10 + the sample app's Experiment Mode (``device_model``, ``model_name``, ``run_id``, 11 + ``started_wall_ms``, ``stopped_wall_ms``, ``events``). 12 + 13 + For every run we compute a scorecard (detection rate, mean confidence, class 14 + diversity, per-class jitter), a per-bucket comparison table aligned to each 15 + run's ``t0_wall_ms`` so model A and model B share the same x-axis when run 16 + against the same video, and one matplotlib chart per class plotting confidence 17 + over time. matplotlib is optional — if it's not installed the report still 18 + renders, just without the timeline images. 19 + 20 + Usage: 21 + tools/compare_logs.py experiments/ # report.html + summary.csv in cwd 22 + tools/compare_logs.py experiments/ -o ./reports/ # write into ./reports/ 23 + tools/compare_logs.py experiments/ --bucket 200 # use 200ms buckets 24 + """ 25 + 26 + from __future__ import annotations 27 + 28 + import argparse 29 + import base64 30 + import csv 31 + import io 32 + import json 33 + import math 34 + import statistics 35 + import sys 36 + from collections import defaultdict 37 + from html import escape 38 + from pathlib import Path 39 + 40 + # matplotlib is optional. If unavailable, the report omits timeline charts. 41 + try: 42 + import matplotlib 43 + 44 + matplotlib.use("Agg") 45 + import matplotlib.pyplot as plt 46 + 47 + HAS_MPL = True 48 + except ImportError: 49 + HAS_MPL = False 50 + 51 + 52 + # ----------------------------------------------------------------------------- run loading 53 + 54 + def load_runs(experiments_dir: Path): 55 + """Yield (manifest, events_sorted_by_wall_ms) for each run subdir.""" 56 + for run_dir in sorted(experiments_dir.iterdir()): 57 + if not run_dir.is_dir(): 58 + continue 59 + manifest_path = run_dir / "manifest.json" 60 + if not manifest_path.exists(): 61 + print(f" skipping {run_dir.name}: no manifest.json", file=sys.stderr) 62 + continue 63 + try: 64 + with open(manifest_path) as f: 65 + manifest = json.load(f) 66 + except json.JSONDecodeError as e: 67 + print(f" skipping {run_dir.name}: bad manifest.json ({e})", file=sys.stderr) 68 + continue 69 + log_files = [f for f in run_dir.glob("*.json") if f.name != "manifest.json"] 70 + if not log_files: 71 + print(f" skipping {run_dir.name}: no log files", file=sys.stderr) 72 + continue 73 + events: list[dict] = [] 74 + for log in log_files: 75 + try: 76 + with open(log) as f: 77 + data = json.load(f) 78 + except json.JSONDecodeError as e: 79 + print(f" warning: bad log {log.name} ({e})", file=sys.stderr) 80 + continue 81 + events.extend(data.get("events", [])) 82 + events.sort(key=lambda e: e.get("wall_ms", 0)) 83 + yield manifest, events 84 + 85 + 86 + # ----------------------------------------------------------------------------- per-run metrics 87 + 88 + def compute_scorecard(manifest: dict, events: list[dict]) -> dict: 89 + """Return summary metrics for one run.""" 90 + t0 = manifest["t0_wall_ms"] 91 + duration_s = float(manifest.get("duration_seconds") or 0) 92 + 93 + total_events = len(events) 94 + events_with_objects = sum(1 for e in events if e.get("objects")) 95 + 96 + all_confs: list[float] = [] 97 + classes: set[str] = set() 98 + bbox_areas: list[float] = [] 99 + for e in events: 100 + for obj in e.get("objects", []): 101 + all_confs.append(float(obj.get("confidence", 0))) 102 + classes.add(obj.get("label", "")) 103 + bbox = obj.get("bbox", [0, 0, 0, 0]) 104 + if len(bbox) >= 4: 105 + w = max(0.0, float(bbox[2]) - float(bbox[0])) 106 + h = max(0.0, float(bbox[3]) - float(bbox[1])) 107 + bbox_areas.append(w * h) 108 + 109 + # Jitter per class: stddev of consecutive bbox-center deltas. High jitter 110 + # means the box is bouncing around frame-to-frame; low jitter means a 111 + # stable lock. We sum stdev_dx + stdev_dy as a coarse single-number score. 112 + jitter_per_class: dict[str, float] = {} 113 + for cls in classes: 114 + centers: list[tuple[float, float]] = [] 115 + for e in events: 116 + for obj in e.get("objects", []): 117 + if obj.get("label") == cls: 118 + bbox = obj.get("bbox", [0, 0, 0, 0]) 119 + if len(bbox) >= 4: 120 + cx = (float(bbox[0]) + float(bbox[2])) / 2 121 + cy = (float(bbox[1]) + float(bbox[3])) / 2 122 + centers.append((cx, cy)) 123 + break # at most one center per frame for each class 124 + if len(centers) >= 3: 125 + dxs = [centers[i + 1][0] - centers[i][0] for i in range(len(centers) - 1)] 126 + dys = [centers[i + 1][1] - centers[i][1] for i in range(len(centers) - 1)] 127 + jitter_per_class[cls] = statistics.stdev(dxs) + statistics.stdev(dys) 128 + 129 + return { 130 + "run_id": manifest["run_id"], 131 + "model_tag": manifest.get("model_tag", "unknown"), 132 + "device_label": manifest.get("device_label", "unknown"), 133 + "video_path": manifest.get("video_path", ""), 134 + "duration_s": duration_s, 135 + "t0_wall_ms": t0, 136 + "total_events": total_events, 137 + "events_with_objects": events_with_objects, 138 + "detection_rate": events_with_objects / total_events if total_events else 0.0, 139 + "events_per_second": total_events / duration_s if duration_s else 0.0, 140 + "mean_confidence": statistics.mean(all_confs) if all_confs else 0.0, 141 + "class_diversity": len(classes), 142 + "classes": sorted(c for c in classes if c), 143 + "mean_bbox_area": statistics.mean(bbox_areas) if bbox_areas else 0.0, 144 + "jitter_per_class": jitter_per_class, 145 + } 146 + 147 + 148 + # ----------------------------------------------------------------------------- bucketing 149 + 150 + def bucket_events(events: list[dict], t0: int, bucket_ms: int) -> dict[int, list[dict]]: 151 + """Group events into buckets keyed by floor(relative_ms / bucket_ms).""" 152 + buckets: dict[int, list[dict]] = defaultdict(list) 153 + for e in events: 154 + rel = int(e.get("wall_ms", 0)) - t0 155 + if rel < 0: 156 + continue 157 + buckets[rel // bucket_ms].append(e) 158 + return buckets 159 + 160 + 161 + def bucket_summary(events_in_bucket: list[dict]) -> dict: 162 + """Per-bucket / per-model aggregation: count, top-class, top-confidence.""" 163 + confs: list[float] = [] 164 + label_counts: dict[str, int] = defaultdict(int) 165 + for e in events_in_bucket: 166 + for obj in e.get("objects", []): 167 + confs.append(float(obj.get("confidence", 0))) 168 + label_counts[obj.get("label", "")] += 1 169 + top_label = max(label_counts.items(), key=lambda kv: kv[1])[0] if label_counts else "" 170 + return { 171 + "frames": len(events_in_bucket), 172 + "detections": sum(label_counts.values()), 173 + "top_label": top_label, 174 + "max_conf": max(confs) if confs else 0.0, 175 + "mean_conf": statistics.mean(confs) if confs else 0.0, 176 + } 177 + 178 + 179 + # ----------------------------------------------------------------------------- charts 180 + 181 + def render_timeline_png(per_run_series: dict[str, list[tuple[float, float]]], title: str) -> str | None: 182 + """Build a single matplotlib chart and return it as a base64 data URI.""" 183 + if not HAS_MPL: 184 + return None 185 + fig, ax = plt.subplots(figsize=(9, 3)) 186 + has_data = False 187 + for model_tag, series in per_run_series.items(): 188 + if not series: 189 + continue 190 + xs = [s[0] / 1000.0 for s in series] 191 + ys = [s[1] for s in series] 192 + ax.plot(xs, ys, marker=".", linestyle="-", linewidth=1, label=model_tag) 193 + has_data = True 194 + if not has_data: 195 + plt.close(fig) 196 + return None 197 + ax.set_xlabel("seconds since t0") 198 + ax.set_ylabel("confidence") 199 + ax.set_ylim(0, 1) 200 + ax.set_title(title) 201 + ax.legend(loc="upper right", fontsize=8) 202 + ax.grid(True, alpha=0.3) 203 + buf = io.BytesIO() 204 + fig.tight_layout() 205 + fig.savefig(buf, format="png", dpi=110) 206 + plt.close(fig) 207 + return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode("ascii") 208 + 209 + 210 + def class_timeline_data(manifest: dict, events: list[dict], cls: str) -> list[tuple[float, float]]: 211 + """Return [(relative_ms, top_confidence_for_class)] for one run + class.""" 212 + t0 = manifest["t0_wall_ms"] 213 + out: list[tuple[float, float]] = [] 214 + for e in events: 215 + rel = int(e.get("wall_ms", 0)) - t0 216 + if rel < 0: 217 + continue 218 + best = 0.0 219 + found = False 220 + for obj in e.get("objects", []): 221 + if obj.get("label") == cls: 222 + c = float(obj.get("confidence", 0)) 223 + if c > best: 224 + best = c 225 + found = True 226 + if found: 227 + out.append((rel, best)) 228 + return out 229 + 230 + 231 + # ----------------------------------------------------------------------------- HTML rendering 232 + 233 + def fmt_pct(x: float) -> str: 234 + return f"{x * 100:.1f}%" 235 + 236 + def fmt_num(x: float, places: int = 2) -> str: 237 + return f"{x:.{places}f}" 238 + 239 + 240 + def render_html(scorecards: list[dict], runs: list[tuple[dict, list[dict]]], bucket_ms: int) -> str: 241 + style = """ 242 + body { font-family: -apple-system, sans-serif; margin: 24px; color: #222; } 243 + h1, h2 { font-weight: 600; } 244 + table { border-collapse: collapse; margin: 8px 0 24px 0; font-size: 13px; } 245 + th, td { border: 1px solid #ddd; padding: 4px 8px; text-align: right; } 246 + th { background: #f5f5f5; text-align: left; } 247 + td.left, th.left { text-align: left; } 248 + .scorecard td:first-child { font-weight: 600; } 249 + .small { color: #888; font-size: 11px; } 250 + img { max-width: 100%; border: 1px solid #ddd; margin: 8px 0; } 251 + .warn { background: #fff7e0; border: 1px solid #f0c000; padding: 8px 12px; border-radius: 4px; } 252 + """ 253 + 254 + parts: list[str] = [] 255 + parts.append("<!doctype html><html><head><meta charset='utf-8'>") 256 + parts.append("<title>Model comparison report</title>") 257 + parts.append(f"<style>{style}</style></head><body>") 258 + parts.append("<h1>Model comparison report</h1>") 259 + parts.append(f"<p class='small'>{len(scorecards)} run(s), bucket size {bucket_ms} ms</p>") 260 + 261 + if not HAS_MPL: 262 + parts.append( 263 + "<p class='warn'>matplotlib is not installed — timeline charts are omitted. " 264 + "Install with <code>uv pip install matplotlib</code> (or pip) and re-run.</p>" 265 + ) 266 + 267 + # ----- per-run scorecards 268 + parts.append("<h2>Per-run scorecard</h2>") 269 + parts.append("<table class='scorecard'>") 270 + headers = ["metric"] + [s["model_tag"] for s in scorecards] 271 + parts.append("<tr>" + "".join(f"<th class='left'>{escape(h)}</th>" for h in headers) + "</tr>") 272 + 273 + def row(label: str, values: list[str]) -> str: 274 + return "<tr><td class='left'>" + escape(label) + "</td>" + "".join( 275 + f"<td>{escape(v)}</td>" for v in values 276 + ) + "</tr>" 277 + 278 + parts.append(row("run_id", [s["run_id"] for s in scorecards])) 279 + parts.append(row("device", [s["device_label"] for s in scorecards])) 280 + parts.append(row("duration (s)", [fmt_num(s["duration_s"], 1) for s in scorecards])) 281 + parts.append(row("total events", [str(s["total_events"]) for s in scorecards])) 282 + parts.append(row("events / second", [fmt_num(s["events_per_second"], 2) for s in scorecards])) 283 + parts.append(row("frames with detection", [fmt_pct(s["detection_rate"]) for s in scorecards])) 284 + parts.append(row("mean confidence", [fmt_num(s["mean_confidence"], 3) for s in scorecards])) 285 + parts.append(row("classes seen", [str(s["class_diversity"]) for s in scorecards])) 286 + parts.append(row("mean bbox area (px²)", [fmt_num(s["mean_bbox_area"], 0) for s in scorecards])) 287 + parts.append(row("class list", [", ".join(s["classes"]) for s in scorecards])) 288 + parts.append("</table>") 289 + 290 + # ----- per-class jitter table 291 + all_classes = sorted({c for s in scorecards for c in s["classes"]}) 292 + if all_classes: 293 + parts.append("<h2>Jitter per class (lower = more stable)</h2>") 294 + parts.append("<table>") 295 + parts.append("<tr><th class='left'>class</th>" + "".join(f"<th>{escape(s['model_tag'])}</th>" for s in scorecards) + "</tr>") 296 + for cls in all_classes: 297 + row_vals = [] 298 + for s in scorecards: 299 + v = s["jitter_per_class"].get(cls) 300 + row_vals.append(fmt_num(v, 1) if v is not None else "—") 301 + parts.append("<tr><td class='left'>" + escape(cls) + "</td>" + "".join(f"<td>{v}</td>" for v in row_vals) + "</tr>") 302 + parts.append("</table>") 303 + 304 + # ----- per-bucket comparison table 305 + parts.append(f"<h2>Per-bucket comparison ({bucket_ms} ms bins)</h2>") 306 + bucketed_per_run = [] 307 + for s, (manifest, events) in zip(scorecards, runs): 308 + bucketed_per_run.append(bucket_events(events, manifest["t0_wall_ms"], bucket_ms)) 309 + all_buckets = sorted({b for d in bucketed_per_run for b in d.keys()}) 310 + parts.append("<table>") 311 + header_cells = ["<th class='left'>bucket (ms)</th>"] 312 + for s in scorecards: 313 + tag = escape(s["model_tag"]) 314 + header_cells.append(f"<th>{tag}<br><span class='small'>frames</span></th>") 315 + header_cells.append(f"<th>{tag}<br><span class='small'>top class</span></th>") 316 + header_cells.append(f"<th>{tag}<br><span class='small'>max conf</span></th>") 317 + parts.append("<tr>" + "".join(header_cells) + "</tr>") 318 + for b in all_buckets: 319 + cells = [f"<td class='left'>{b * bucket_ms}–{(b + 1) * bucket_ms}</td>"] 320 + for run_buckets in bucketed_per_run: 321 + evs = run_buckets.get(b, []) 322 + if evs: 323 + summ = bucket_summary(evs) 324 + cells.append(f"<td>{summ['frames']}</td>") 325 + cells.append(f"<td>{escape(summ['top_label'])}</td>") 326 + cells.append(f"<td>{fmt_num(summ['max_conf'], 2)}</td>") 327 + else: 328 + cells.append("<td>—</td><td>—</td><td>—</td>") 329 + parts.append("<tr>" + "".join(cells) + "</tr>") 330 + parts.append("</table>") 331 + 332 + # ----- per-class timeline charts 333 + if HAS_MPL: 334 + parts.append("<h2>Per-class confidence timelines</h2>") 335 + for cls in all_classes: 336 + per_run_series: dict[str, list[tuple[float, float]]] = {} 337 + for s, (manifest, events) in zip(scorecards, runs): 338 + per_run_series[s["model_tag"]] = class_timeline_data(manifest, events, cls) 339 + data_uri = render_timeline_png(per_run_series, f"class: {cls}") 340 + if data_uri: 341 + parts.append(f"<img alt='{escape(cls)} timeline' src='{data_uri}'/>") 342 + 343 + parts.append("</body></html>") 344 + return "".join(parts) 345 + 346 + 347 + # ----------------------------------------------------------------------------- summary csv 348 + 349 + def write_summary_csv(scorecards: list[dict], path: Path) -> None: 350 + fieldnames = [ 351 + "run_id", 352 + "model_tag", 353 + "device_label", 354 + "duration_s", 355 + "total_events", 356 + "events_per_second", 357 + "detection_rate", 358 + "mean_confidence", 359 + "class_diversity", 360 + "classes", 361 + "mean_bbox_area", 362 + ] 363 + with open(path, "w", newline="") as f: 364 + w = csv.DictWriter(f, fieldnames=fieldnames) 365 + w.writeheader() 366 + for s in scorecards: 367 + w.writerow( 368 + { 369 + "run_id": s["run_id"], 370 + "model_tag": s["model_tag"], 371 + "device_label": s["device_label"], 372 + "duration_s": f"{s['duration_s']:.2f}", 373 + "total_events": s["total_events"], 374 + "events_per_second": f"{s['events_per_second']:.3f}", 375 + "detection_rate": f"{s['detection_rate']:.4f}", 376 + "mean_confidence": f"{s['mean_confidence']:.4f}", 377 + "class_diversity": s["class_diversity"], 378 + "classes": "|".join(s["classes"]), 379 + "mean_bbox_area": f"{s['mean_bbox_area']:.1f}", 380 + } 381 + ) 382 + 383 + 384 + # ----------------------------------------------------------------------------- main 385 + 386 + def main(argv: list[str]) -> int: 387 + parser = argparse.ArgumentParser( 388 + description="Build a model comparison report from experiments/<run-id>/ directories.", 389 + ) 390 + parser.add_argument("experiments_dir", type=Path, help="path to the experiments/ directory") 391 + parser.add_argument("-o", "--output-dir", type=Path, default=Path.cwd(), 392 + help="where report.html and summary.csv should be written (default: cwd)") 393 + parser.add_argument("--bucket", type=int, default=100, help="bucket size in milliseconds (default: 100)") 394 + args = parser.parse_args(argv) 395 + 396 + if not args.experiments_dir.is_dir(): 397 + print(f"error: not a directory: {args.experiments_dir}", file=sys.stderr) 398 + return 2 399 + 400 + runs = list(load_runs(args.experiments_dir)) 401 + if not runs: 402 + print("error: no usable runs found.", file=sys.stderr) 403 + return 2 404 + 405 + scorecards = [compute_scorecard(m, e) for m, e in runs] 406 + 407 + args.output_dir.mkdir(parents=True, exist_ok=True) 408 + html_path = args.output_dir / "report.html" 409 + csv_path = args.output_dir / "summary.csv" 410 + 411 + html_path.write_text(render_html(scorecards, runs, args.bucket)) 412 + write_summary_csv(scorecards, csv_path) 413 + 414 + print(f"wrote {html_path}") 415 + print(f"wrote {csv_path}") 416 + print(f"runs: {len(runs)}") 417 + for s in scorecards: 418 + print( 419 + f" {s['model_tag']}: {s['total_events']} events, " 420 + f"{s['detection_rate'] * 100:.1f}% with detection, " 421 + f"mean conf {s['mean_confidence']:.3f}" 422 + ) 423 + return 0 424 + 425 + 426 + if __name__ == "__main__": 427 + sys.exit(main(sys.argv[1:]))
+252
tools/run_auto_experiment.sh
··· 1 + #!/usr/bin/env bash 2 + # 3 + # Drives one fully unattended closed-loop experiment run: 4 + # 5 + # 1. Force-stops the sample app and clears Logcat so the cold start is 6 + # clean and the only ExperimentAuto: log lines are from this run. 7 + # 2. Picks a wall-clock target start_at_wall_ms = now + APP_BOOT_PAD seconds. 8 + # 3. Launches AppActivity via `am start` with the auto-mode intent extras 9 + # (model_name, start_at_wall_ms, duration_ms). The app's Compose 10 + # auto-driver selects the model, waits for the same wall-clock target, 11 + # runs the experiment buffer for duration_ms, writes the JSON, and 12 + # finishes the activity. 13 + # 4. Sleeps until start_at_wall_ms locally on the Mac, then plays the 14 + # video in QuickTime at the requested --start-offset (seconds). Both 15 + # sides hit the same wall-clock instant. 16 + # 5. Sleeps for the buffer duration, pauses QuickTime. 17 + # 6. Diff-polls /sdcard/.../experiment_logs for the new JSON file (with a 18 + # 10s timeout) and pulls it into experiments/<run-id>/. 19 + # 7. Captures the ExperimentAuto Logcat lines for the manifest, writes 20 + # experiments/<run-id>/manifest.json with t0_wall_ms, video offset, 21 + # device label, model tag, and the captured log lines. 22 + # 23 + # Usage: 24 + # tools/run_auto_experiment.sh \ 25 + # --video ~/Downloads/clip.mp4 \ 26 + # --duration 10 \ 27 + # --model-tag yolo11n_su_416 \ 28 + # [--start-offset 10] \ 29 + # [--device <serial>] 30 + # 31 + # After at least two runs (model A then model B against the same video, 32 + # same --start-offset) point tools/compare_logs.py at experiments/ to 33 + # build the comparison report. 34 + 35 + set -euo pipefail 36 + 37 + ADB="${ADB:-/Users/virtualintern/Library/Android/sdk/platform-tools/adb}" 38 + PKG="com.nate.posedetection.androidApp" 39 + ACTIVITY="$PKG/com.nate.posedetection.AppActivity" 40 + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" 41 + EXPERIMENTS_DIR="$REPO_ROOT/experiments" 42 + REMOTE_LOGS_DIR="/sdcard/Android/data/$PKG/files/experiment_logs" 43 + APP_BOOT_PAD_SECONDS="${APP_BOOT_PAD_SECONDS:-9}" 44 + PULL_TIMEOUT_SECONDS="${PULL_TIMEOUT_SECONDS:-15}" 45 + 46 + usage() { 47 + sed -n '3,33p' "$0" 48 + exit "${1:-1}" 49 + } 50 + 51 + VIDEO="" 52 + DURATION="" 53 + MODEL_TAG="" 54 + START_OFFSET=0 55 + DEVICE="" 56 + 57 + while [ $# -gt 0 ]; do 58 + case "$1" in 59 + --video) VIDEO="$2"; shift 2 ;; 60 + --duration) DURATION="$2"; shift 2 ;; 61 + --model-tag) MODEL_TAG="$2"; shift 2 ;; 62 + --start-offset) START_OFFSET="$2"; shift 2 ;; 63 + --device) DEVICE="$2"; shift 2 ;; 64 + -h|--help) usage 0 ;; 65 + *) echo "unknown arg: $1" >&2; usage ;; 66 + esac 67 + done 68 + 69 + [ -n "$VIDEO" ] || { echo "error: --video is required" >&2; exit 2; } 70 + [ -n "$DURATION" ] || { echo "error: --duration is required" >&2; exit 2; } 71 + [ -n "$MODEL_TAG" ] || { echo "error: --model-tag is required" >&2; exit 2; } 72 + 73 + if [ ! -f "$VIDEO" ]; then 74 + echo "error: video file not found: $VIDEO" >&2 75 + exit 2 76 + fi 77 + VIDEO_ABS="$(cd "$(dirname "$VIDEO")" && pwd)/$(basename "$VIDEO")" 78 + 79 + # Resolve device. 80 + if [ -z "$DEVICE" ]; then 81 + CONNECTED="$("$ADB" devices | awk 'NR>1 && $2=="device" {print $1}')" 82 + NUM_CONNECTED="$(printf '%s\n' "$CONNECTED" | grep -c . || true)" 83 + if [ "$NUM_CONNECTED" -eq 0 ]; then 84 + echo "error: no devices connected." >&2 85 + exit 3 86 + elif [ "$NUM_CONNECTED" -gt 1 ]; then 87 + echo "error: multiple devices connected — pass --device <serial>." >&2 88 + printf ' %s\n' $CONNECTED >&2 89 + exit 3 90 + fi 91 + DEVICE="$CONNECTED" 92 + echo "==> auto-selected device: $DEVICE" 93 + fi 94 + 95 + now_ms() { python3 -c 'import time; print(int(time.time()*1000))'; } 96 + 97 + DURATION_MS=$(python3 -c "print(int(float('$DURATION') * 1000))") 98 + 99 + echo "==> auto experiment" 100 + echo " model_tag = $MODEL_TAG" 101 + echo " duration = ${DURATION}s ($DURATION_MS ms)" 102 + echo " video = $VIDEO_ABS" 103 + echo " start_offset = ${START_OFFSET}s" 104 + 105 + # 1. Snapshot the existing logs so we can diff-pull only the new file. 106 + LOGS_BEFORE="$("$ADB" -s "$DEVICE" shell "ls -1 $REMOTE_LOGS_DIR 2>/dev/null" \ 107 + | tr -d '\r' | grep '\.json$' || true)" 108 + EXISTING_COUNT=$(printf '%s\n' "$LOGS_BEFORE" | grep -c '\.json$' || true) 109 + echo "==> $EXISTING_COUNT existing log(s) on device (will be ignored)" 110 + 111 + # 2. Pre-open the video in QuickTime *first* and position to start_offset 112 + # while paused. Large 4K files can take 10-60s to index, so we do this 113 + # before any wall-clock timing matters. The 600s timeout covers extreme 114 + # cases (default AppleEvent timeout is 60s and can fire on big files). 115 + echo "==> pre-opening video in QuickTime (large files may take a moment)..." 116 + osascript <<APPLESCRIPT 117 + with timeout of 600 seconds 118 + tell application "QuickTime Player" 119 + activate 120 + if (count of documents) > 0 then 121 + try 122 + close every document saving no 123 + end try 124 + end if 125 + open POSIX file "$VIDEO_ABS" 126 + repeat while (count of documents) is 0 127 + delay 0.1 128 + end repeat 129 + tell front document 130 + pause 131 + set current time to $START_OFFSET 132 + present 133 + end tell 134 + end tell 135 + end timeout 136 + APPLESCRIPT 137 + 138 + # 3. Cold-start the app: kill any existing instance and clear Logcat. 139 + echo "==> force-stopping app and clearing Logcat..." 140 + "$ADB" -s "$DEVICE" shell am force-stop "$PKG" >/dev/null 141 + "$ADB" -s "$DEVICE" logcat -c >/dev/null 142 + 143 + # 4. Compute the wall-clock target and launch via intent with auto-mode extras. 144 + NOW_MS=$(now_ms) 145 + START_AT_WALL_MS=$((NOW_MS + APP_BOOT_PAD_SECONDS * 1000)) 146 + RUN_ID="${START_AT_WALL_MS}_$(printf '%s' "$MODEL_TAG" | tr -c 'A-Za-z0-9._-' '_' | sed 's/^_*//; s/_*$//')" 147 + RUN_DIR="$EXPERIMENTS_DIR/$RUN_ID" 148 + echo " start_at_wall = $START_AT_WALL_MS (in ${APP_BOOT_PAD_SECONDS}s)" 149 + echo " run_dir = $RUN_DIR" 150 + 151 + echo "==> launching $ACTIVITY with auto-mode extras..." 152 + "$ADB" -s "$DEVICE" shell am start -n "$ACTIVITY" \ 153 + --ez experiment_auto true \ 154 + --es model_name "$MODEL_TAG" \ 155 + --el start_at_wall_ms "$START_AT_WALL_MS" \ 156 + --el duration_ms "$DURATION_MS" >/dev/null 157 + 158 + # 5. Wait until the wall-clock target, then play (already pre-loaded so this 159 + # is sub-second). t0_wall_ms is captured immediately before the play call. 160 + WAIT_MS=$((START_AT_WALL_MS - $(now_ms))) 161 + if [ "$WAIT_MS" -gt 0 ]; then 162 + python3 -c "import time; time.sleep($WAIT_MS/1000.0)" 163 + fi 164 + 165 + T0_WALL_MS=$(now_ms) 166 + echo "==> playing video at offset ${START_OFFSET}s (t0_wall_ms=$T0_WALL_MS)" 167 + osascript -e 'tell application "QuickTime Player" to play front document' >/dev/null 168 + 169 + # 5. Sleep the buffer duration plus a small safety margin then pause. 170 + echo "==> sleeping ${DURATION}s for buffer to fill..." 171 + sleep "$DURATION" 172 + osascript -e 'tell application "QuickTime Player" to pause front document' >/dev/null 173 + 174 + # 6. Poll for the new log file with a timeout. 175 + echo "==> polling for new log file (timeout ${PULL_TIMEOUT_SECONDS}s)..." 176 + NEW_LOGS="" 177 + DEADLINE=$(( $(now_ms) + PULL_TIMEOUT_SECONDS * 1000 )) 178 + while [ "$(now_ms)" -lt "$DEADLINE" ]; do 179 + LOGS_AFTER="$("$ADB" -s "$DEVICE" shell "ls -1 $REMOTE_LOGS_DIR 2>/dev/null" \ 180 + | tr -d '\r' | grep '\.json$' || true)" 181 + NEW_LOGS="$(comm -13 \ 182 + <(printf '%s\n' "$LOGS_BEFORE" | sort -u) \ 183 + <(printf '%s\n' "$LOGS_AFTER" | sort -u) \ 184 + | grep '\.json$' || true)" 185 + if [ -n "$NEW_LOGS" ]; then 186 + break 187 + fi 188 + sleep 0.25 189 + done 190 + 191 + mkdir -p "$RUN_DIR" 192 + 193 + if [ -z "$NEW_LOGS" ]; then 194 + echo "error: no new log file appeared on device after ${PULL_TIMEOUT_SECONDS}s" >&2 195 + echo " recent ExperimentAuto Logcat:" >&2 196 + "$ADB" -s "$DEVICE" logcat -d -s ExperimentAuto:I 2>/dev/null | tail -30 >&2 || true 197 + exit 4 198 + fi 199 + 200 + echo "==> pulling new log(s) into $RUN_DIR/" 201 + while IFS= read -r f; do 202 + [ -z "$f" ] && continue 203 + "$ADB" -s "$DEVICE" pull "$REMOTE_LOGS_DIR/$f" "$RUN_DIR/" >/dev/null 204 + echo " pulled $f" 205 + done <<< "$NEW_LOGS" 206 + 207 + # 7. Capture the ExperimentAuto log lines (for the manifest). 208 + LOGCAT_EXCERPT="$("$ADB" -s "$DEVICE" logcat -d -s ExperimentAuto:I 2>/dev/null \ 209 + | grep ExperimentAuto || true)" 210 + 211 + DEVICE_MANUFACTURER="$("$ADB" -s "$DEVICE" shell getprop ro.product.manufacturer 2>/dev/null | tr -d '\r' || true)" 212 + DEVICE_MODEL_NAME="$("$ADB" -s "$DEVICE" shell getprop ro.product.model 2>/dev/null | tr -d '\r' || true)" 213 + DEVICE_LABEL="$DEVICE_MANUFACTURER $DEVICE_MODEL_NAME" 214 + 215 + NEW_LOGS_JOINED="$(printf '%s\n' "$NEW_LOGS" | tr '\n' ',' | sed 's/,$//')" 216 + 217 + RUN_ID="$RUN_ID" \ 218 + MODEL_TAG="$MODEL_TAG" \ 219 + VIDEO_ABS="$VIDEO_ABS" \ 220 + START_OFFSET="$START_OFFSET" \ 221 + DURATION="$DURATION" \ 222 + T0_WALL_MS="$T0_WALL_MS" \ 223 + START_AT_WALL_MS="$START_AT_WALL_MS" \ 224 + DEVICE="$DEVICE" \ 225 + DEVICE_LABEL="$DEVICE_LABEL" \ 226 + NEW_LOGS_JOINED="$NEW_LOGS_JOINED" \ 227 + LOGCAT_EXCERPT="$LOGCAT_EXCERPT" \ 228 + python3 -c ' 229 + import json, os 230 + files = [f for f in os.environ["NEW_LOGS_JOINED"].split(",") if f] 231 + logcat = [l for l in os.environ["LOGCAT_EXCERPT"].splitlines() if l.strip()] 232 + manifest = { 233 + "run_id": os.environ["RUN_ID"], 234 + "mode": "auto", 235 + "model_tag": os.environ["MODEL_TAG"], 236 + "video_path": os.environ["VIDEO_ABS"], 237 + "video_start_offset_seconds": float(os.environ["START_OFFSET"]), 238 + "duration_seconds": float(os.environ["DURATION"]), 239 + "t0_wall_ms": int(os.environ["T0_WALL_MS"]), 240 + "start_at_wall_ms": int(os.environ["START_AT_WALL_MS"]), 241 + "device_serial": os.environ["DEVICE"], 242 + "device_label": os.environ["DEVICE_LABEL"].strip(), 243 + "log_files": files, 244 + "logcat_excerpt": logcat, 245 + } 246 + print(json.dumps(manifest, indent=2)) 247 + ' > "$RUN_DIR/manifest.json" 248 + 249 + echo "==> wrote $RUN_DIR/manifest.json" 250 + echo 251 + echo "Run dir: $RUN_DIR" 252 + ls -la "$RUN_DIR"
+219
tools/run_experiment.sh
··· 1 + #!/usr/bin/env bash 2 + # 3 + # Drives one closed-loop experiment run for the model comparison harness: 4 + # 5 + # 1. Snapshots existing experiment logs on the phone (so we know which file 6 + # is the "new" one this run produces). 7 + # 2. Prompts you to confirm Experiment Mode is armed and Start has been 8 + # tapped on the phone (skipped with --no-confirm). 9 + # 3. Records t0_wall_ms in milliseconds, then plays the test video from the 10 + # start in QuickTime Player via osascript. 11 + # 4. Sleeps for --duration seconds. 12 + # 5. Pauses QuickTime. 13 + # 6. Prompts you to tap Stop on the phone (skipped with --no-confirm). 14 + # 7. Diffs the post-run file list against the snapshot, pulls only the 15 + # newly-written JSON file(s) into experiments/<run-id>/. 16 + # 8. Writes experiments/<run-id>/manifest.json with t0_wall_ms, the video 17 + # path, model tag, device info, and duration. 18 + # 19 + # Usage: 20 + # tools/run_experiment.sh \ 21 + # --video /abs/or/rel/path/test.mp4 \ 22 + # --duration 10 \ 23 + # --model-tag yolo11n_su_416 \ 24 + # [--device RFCX10EM9LR] \ 25 + # [--no-confirm] 26 + # 27 + # After two runs (model A then model B against the same video) point 28 + # tools/compare_logs.py at experiments/ to produce the report. 29 + 30 + set -euo pipefail 31 + 32 + ADB="${ADB:-/Users/virtualintern/Library/Android/sdk/platform-tools/adb}" 33 + # DEVICE may be passed via --device or EXP_DEVICE. Empty means "auto-detect: 34 + # if exactly one device is connected, use it; otherwise error and require 35 + # explicit --device". 36 + DEVICE="${EXP_DEVICE:-}" 37 + PKG="com.nate.posedetection.androidApp" 38 + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" 39 + EXPERIMENTS_DIR="$REPO_ROOT/experiments" 40 + REMOTE_LOGS_DIR="/sdcard/Android/data/$PKG/files/experiment_logs" 41 + 42 + usage() { 43 + sed -n '3,28p' "$0" 44 + exit "${1:-1}" 45 + } 46 + 47 + VIDEO="" 48 + DURATION="" 49 + MODEL_TAG="" 50 + NO_CONFIRM=0 51 + 52 + while [ $# -gt 0 ]; do 53 + case "$1" in 54 + --video) VIDEO="$2"; shift 2 ;; 55 + --duration) DURATION="$2"; shift 2 ;; 56 + --model-tag) MODEL_TAG="$2"; shift 2 ;; 57 + --device) DEVICE="$2"; shift 2 ;; 58 + --no-confirm) NO_CONFIRM=1; shift ;; 59 + -h|--help) usage 0 ;; 60 + *) echo "unknown arg: $1" >&2; usage ;; 61 + esac 62 + done 63 + 64 + [ -n "$VIDEO" ] || { echo "error: --video is required" >&2; exit 2; } 65 + [ -n "$DURATION" ] || { echo "error: --duration is required" >&2; exit 2; } 66 + [ -n "$MODEL_TAG" ] || { echo "error: --model-tag is required" >&2; exit 2; } 67 + 68 + if [ ! -f "$VIDEO" ]; then 69 + echo "error: video file not found: $VIDEO" >&2 70 + exit 2 71 + fi 72 + VIDEO_ABS="$(cd "$(dirname "$VIDEO")" && pwd)/$(basename "$VIDEO")" 73 + 74 + # Sanitize model tag for filesystem use (run-id slug). 75 + SAFE_TAG="$(printf '%s' "$MODEL_TAG" | tr -c 'A-Za-z0-9._-' '_' | sed 's/^_*//; s/_*$//')" 76 + [ -n "$SAFE_TAG" ] || SAFE_TAG="unnamed" 77 + 78 + # Resolve / verify device. 79 + if [ -z "$DEVICE" ]; then 80 + # Auto-detect: only succeed if exactly one device is attached. 81 + CONNECTED="$("$ADB" devices | awk 'NR>1 && $2=="device" {print $1}')" 82 + NUM_CONNECTED="$(printf '%s\n' "$CONNECTED" | grep -c . || true)" 83 + if [ "$NUM_CONNECTED" -eq 0 ]; then 84 + echo "error: no devices connected. Plug in the phone and run 'adb devices'." >&2 85 + exit 3 86 + elif [ "$NUM_CONNECTED" -gt 1 ]; then 87 + echo "error: multiple devices connected — pass --device <serial> to disambiguate." >&2 88 + echo " connected:" >&2 89 + printf ' %s\n' $CONNECTED >&2 90 + exit 3 91 + fi 92 + DEVICE="$CONNECTED" 93 + echo "==> auto-selected device: $DEVICE" 94 + fi 95 + if ! "$ADB" -s "$DEVICE" get-state >/dev/null 2>&1; then 96 + echo "error: device $DEVICE is not connected." >&2 97 + echo " adb devices output:" >&2 98 + "$ADB" devices >&2 99 + exit 3 100 + fi 101 + 102 + now_ms() { python3 -c 'import time; print(int(time.time()*1000))'; } 103 + 104 + confirm() { 105 + if [ "$NO_CONFIRM" -eq 1 ]; then return 0; fi 106 + printf '%s [y/N] ' "$1" 107 + local response 108 + read -r response 109 + case "$response" in 110 + [yY]|[yY][eE][sS]) return 0 ;; 111 + *) return 1 ;; 112 + esac 113 + } 114 + 115 + list_remote_logs() { 116 + "$ADB" -s "$DEVICE" shell "ls -1 $REMOTE_LOGS_DIR 2>/dev/null" \ 117 + | tr -d '\r' \ 118 + | grep '\.json$' \ 119 + || true 120 + } 121 + 122 + # 1. Snapshot existing logs so we can diff after the run. 123 + echo "==> Snapshotting existing logs on $DEVICE..." 124 + LOGS_BEFORE="$(list_remote_logs)" 125 + EXISTING_COUNT=$(printf '%s\n' "$LOGS_BEFORE" | grep -c '\.json$' || true) 126 + echo " ($EXISTING_COUNT existing log file(s))" 127 + 128 + # 2. Confirm the phone side is armed. 129 + if ! confirm "Phone ready? Model picked, Experiment Mode on, Start tapped?"; then 130 + echo "Aborted by user." 131 + exit 0 132 + fi 133 + 134 + # 3. Record t0 and play the video. 135 + T0_WALL_MS="$(now_ms)" 136 + echo "==> t0_wall_ms = $T0_WALL_MS" 137 + echo "==> Playing $VIDEO_ABS in QuickTime..." 138 + osascript \ 139 + -e 'tell application "QuickTime Player" to activate' \ 140 + -e "tell application \"QuickTime Player\" to open POSIX file \"$VIDEO_ABS\"" \ 141 + -e 'tell application "QuickTime Player" to set current time of front document to 0' \ 142 + -e 'tell application "QuickTime Player" to play front document' >/dev/null 143 + 144 + # 4. Wait the requested duration. 145 + echo "==> Sleeping ${DURATION}s..." 146 + sleep "$DURATION" 147 + 148 + # 5. Pause playback. 149 + echo "==> Pausing QuickTime..." 150 + osascript -e 'tell application "QuickTime Player" to pause front document' >/dev/null 151 + 152 + STOPPED_WALL_MS="$(now_ms)" 153 + 154 + # 6. Prompt the user to tap Stop on the phone. 155 + if [ "$NO_CONFIRM" -eq 0 ]; then 156 + echo 157 + echo "==> Tap 'Stop Experiment' on the phone now." 158 + printf " Press Enter when done... " 159 + read -r _ 160 + fi 161 + 162 + # 7. Diff the file list, pull anything new. 163 + LOGS_AFTER="$(list_remote_logs)" 164 + NEW_LOGS="$(comm -13 <(printf '%s\n' "$LOGS_BEFORE" | sort -u) <(printf '%s\n' "$LOGS_AFTER" | sort -u) | grep '\.json$' || true)" 165 + 166 + RUN_ID="${T0_WALL_MS}_${SAFE_TAG}" 167 + RUN_DIR="$EXPERIMENTS_DIR/$RUN_ID" 168 + mkdir -p "$RUN_DIR" 169 + 170 + if [ -z "$NEW_LOGS" ]; then 171 + echo "warning: no new log files appeared on the phone. Was Experiment Mode" >&2 172 + echo " actually started/stopped? Was a model selected? The manifest" >&2 173 + echo " will still be written so you can debug, but the run is empty." >&2 174 + else 175 + echo "==> Pulling new log(s) into $RUN_DIR/" 176 + while IFS= read -r f; do 177 + [ -z "$f" ] && continue 178 + "$ADB" -s "$DEVICE" pull "$REMOTE_LOGS_DIR/$f" "$RUN_DIR/" >/dev/null 179 + echo " pulled $f" 180 + done <<< "$NEW_LOGS" 181 + fi 182 + 183 + # 8. Write the manifest. Use python for JSON to avoid quoting headaches. 184 + DEVICE_MANUFACTURER="$("$ADB" -s "$DEVICE" shell getprop ro.product.manufacturer 2>/dev/null | tr -d '\r' || true)" 185 + DEVICE_MODEL_NAME="$("$ADB" -s "$DEVICE" shell getprop ro.product.model 2>/dev/null | tr -d '\r' || true)" 186 + DEVICE_LABEL="$DEVICE_MANUFACTURER $DEVICE_MODEL_NAME" 187 + 188 + NEW_LOGS_JOINED="$(printf '%s\n' "$NEW_LOGS" | tr '\n' ',' | sed 's/,$//')" 189 + 190 + RUN_ID="$RUN_ID" \ 191 + MODEL_TAG="$MODEL_TAG" \ 192 + VIDEO_ABS="$VIDEO_ABS" \ 193 + DURATION="$DURATION" \ 194 + T0_WALL_MS="$T0_WALL_MS" \ 195 + STOPPED_WALL_MS="$STOPPED_WALL_MS" \ 196 + DEVICE="$DEVICE" \ 197 + DEVICE_LABEL="$DEVICE_LABEL" \ 198 + NEW_LOGS_JOINED="$NEW_LOGS_JOINED" \ 199 + python3 -c ' 200 + import json, os 201 + files = [f for f in os.environ["NEW_LOGS_JOINED"].split(",") if f] 202 + manifest = { 203 + "run_id": os.environ["RUN_ID"], 204 + "model_tag": os.environ["MODEL_TAG"], 205 + "video_path": os.environ["VIDEO_ABS"], 206 + "duration_seconds": float(os.environ["DURATION"]), 207 + "t0_wall_ms": int(os.environ["T0_WALL_MS"]), 208 + "stopped_wall_ms": int(os.environ["STOPPED_WALL_MS"]), 209 + "device_serial": os.environ["DEVICE"], 210 + "device_label": os.environ["DEVICE_LABEL"].strip(), 211 + "log_files": files, 212 + } 213 + print(json.dumps(manifest, indent=2)) 214 + ' > "$RUN_DIR/manifest.json" 215 + 216 + echo "==> Wrote $RUN_DIR/manifest.json" 217 + echo 218 + echo "Run dir: $RUN_DIR" 219 + echo "Next: tools/compare_logs.py experiments/ (after at least 2 runs against the same video)"
+161
tools/sync_models.py
··· 1 + #!/usr/bin/env python3 2 + """ 3 + Sync trained .tflite models from Colab output into the sample app's assets dir. 4 + 5 + The Colab notebook writes trained models to ``collab/output/<run-id>/*.tflite`` 6 + (via Drive sync). This script copies those models into the sample app's 7 + Android assets directory so ``DiscoverModels.android.kt`` will pick them up 8 + on the next build. 9 + 10 + Usage:: 11 + 12 + tools/sync_models.py # sync the latest run (default) 13 + tools/sync_models.py --list # list available runs newest-first 14 + tools/sync_models.py --run <run-id> # sync a specific run 15 + tools/sync_models.py --clean # remove previously-synced models 16 + 17 + Synced files are renamed ``<run-id>__<model-base>.tflite`` (double underscore). 18 + The double underscore is deliberate: ``DiscoverModels.android.kt`` replaces 19 + single underscores with spaces in the picker, so ``__`` becomes a clear visual 20 + break between the run-id and the model name in the dropdown. 21 + 22 + ``--clean`` preserves the three baseline models bundled with the repo. 23 + """ 24 + 25 + from __future__ import annotations 26 + 27 + import argparse 28 + import re 29 + import shutil 30 + import sys 31 + from pathlib import Path 32 + 33 + REPO_ROOT = Path(__file__).resolve().parent.parent 34 + COLAB_OUTPUT_DIR = REPO_ROOT / "collab" / "output" 35 + ASSETS_DIR = REPO_ROOT / "sample" / "composeApp" / "src" / "androidMain" / "assets" 36 + 37 + # Baseline models that ship with the repo. --clean preserves these; everything 38 + # else under ASSETS_DIR with a .tflite extension is treated as a synced file 39 + # and removed by --clean. 40 + BASELINE_MODELS = frozenset( 41 + { 42 + "yolo11n_dataset_dataset.tflite", 43 + "yolo11n_su_416.tflite", 44 + "yolov10n_float16.tflite", 45 + } 46 + ) 47 + 48 + SAFE_NAME = re.compile(r"[^A-Za-z0-9._-]") 49 + 50 + 51 + def sanitize(name: str) -> str: 52 + """Replace anything that isn't safe for an Android asset filename.""" 53 + return SAFE_NAME.sub("_", name).strip("_") or "unnamed" 54 + 55 + 56 + def list_runs() -> list[Path]: 57 + """Return run-id directories under collab/output, newest first by mtime.""" 58 + if not COLAB_OUTPUT_DIR.exists(): 59 + return [] 60 + runs = [p for p in COLAB_OUTPUT_DIR.iterdir() if p.is_dir()] 61 + runs.sort(key=lambda p: p.stat().st_mtime, reverse=True) 62 + return runs 63 + 64 + 65 + def cmd_list() -> int: 66 + runs = list_runs() 67 + if not runs: 68 + print(f"(no runs found under {COLAB_OUTPUT_DIR.relative_to(REPO_ROOT)})") 69 + return 0 70 + print(f"Runs under {COLAB_OUTPUT_DIR.relative_to(REPO_ROOT)} (newest first):") 71 + for run in runs: 72 + tflites = sorted(run.glob("*.tflite")) 73 + if tflites: 74 + tflite_summary = ", ".join(p.name for p in tflites) 75 + else: 76 + tflite_summary = "(no .tflite files)" 77 + print(f" {run.name} — {tflite_summary}") 78 + return 0 79 + 80 + 81 + def cmd_sync(run_id: str) -> int: 82 + run_dir = COLAB_OUTPUT_DIR / run_id 83 + if not run_dir.is_dir(): 84 + print(f"error: no such run directory: {run_dir}", file=sys.stderr) 85 + available = [r.name for r in list_runs()] 86 + if available: 87 + print(f" available: {', '.join(available)}", file=sys.stderr) 88 + return 2 89 + 90 + tflites = sorted(run_dir.glob("*.tflite")) 91 + if not tflites: 92 + print(f"error: no .tflite files in {run_dir}", file=sys.stderr) 93 + return 2 94 + 95 + if not ASSETS_DIR.exists(): 96 + print(f"error: assets dir does not exist: {ASSETS_DIR}", file=sys.stderr) 97 + return 2 98 + 99 + safe_run = sanitize(run_id) 100 + print(f"Syncing run '{run_id}' ({len(tflites)} model(s)) -> {ASSETS_DIR.relative_to(REPO_ROOT)}") 101 + for src in tflites: 102 + base = sanitize(src.stem) 103 + dest_name = f"{safe_run}__{base}.tflite" 104 + if dest_name in BASELINE_MODELS: 105 + print(f" skip {src.name} (would shadow baseline {dest_name})") 106 + continue 107 + dest = ASSETS_DIR / dest_name 108 + shutil.copy2(src, dest) 109 + size_mb = dest.stat().st_size / (1024 * 1024) 110 + print(f" copied {src.name} -> {dest.name} ({size_mb:.1f} MB)") 111 + return 0 112 + 113 + 114 + def cmd_clean() -> int: 115 + if not ASSETS_DIR.exists(): 116 + print(f"error: assets dir does not exist: {ASSETS_DIR}", file=sys.stderr) 117 + return 2 118 + removed = 0 119 + for f in sorted(ASSETS_DIR.glob("*.tflite")): 120 + if f.name in BASELINE_MODELS: 121 + continue 122 + f.unlink() 123 + print(f" removed {f.name}") 124 + removed += 1 125 + if removed == 0: 126 + print("(nothing to clean — only baseline models present)") 127 + else: 128 + print(f"removed {removed} synced model(s); baselines preserved") 129 + return 0 130 + 131 + 132 + def cmd_latest() -> int: 133 + runs = list_runs() 134 + if not runs: 135 + print(f"error: no runs under {COLAB_OUTPUT_DIR}", file=sys.stderr) 136 + return 2 137 + return cmd_sync(runs[0].name) 138 + 139 + 140 + def main(argv: list[str]) -> int: 141 + parser = argparse.ArgumentParser( 142 + description="Sync Colab-trained .tflite models into the sample app's assets dir.", 143 + ) 144 + group = parser.add_mutually_exclusive_group() 145 + group.add_argument("--list", action="store_true", help="list available runs newest-first") 146 + group.add_argument("--run", metavar="RUN_ID", help="sync the named run from collab/output/") 147 + group.add_argument("--clean", action="store_true", help="remove previously-synced models (preserve baselines)") 148 + args = parser.parse_args(argv) 149 + 150 + if args.list: 151 + return cmd_list() 152 + if args.clean: 153 + return cmd_clean() 154 + if args.run: 155 + return cmd_sync(args.run) 156 + # Default: sync the latest run. 157 + return cmd_latest() 158 + 159 + 160 + if __name__ == "__main__": 161 + sys.exit(main(sys.argv[1:]))