Spaces:
Sleeping
Sleeping
| # A15 β Filter ugly exercises, rescore good ones & cut exercise segments | |
| ## Overview | |
| This directory takes the ~180 2D exercise videos, filters out exercises with | |
| poor form (predicted "ugly" by a CNN), rescales the remaining good | |
| exercises onto a normalised 0β4 quality score, cuts each clip | |
| to only the frames between the predicted start and stop of the exercise | |
| movement using the A12 start/stop detection model, and finally augments | |
| the cut sequences to expand the training dataset for downstream models. | |
| --- | |
| ## Pipeline | |
| ``` | |
| scores.csv (180 clips, raw quality scores) | |
| β | |
| βΌ filter_ugly_exercises.py | |
| β β’ loads each clip from Datasets_all/kinect_good_preprocessed/ | |
| β β’ runs A_CNN.keras (sigmoid output: P(good)) | |
| β β’ threshold: β₯ 0.5 β GOOD, < 0.5 β UGLY | |
| β | |
| ββ a15_predictions.csv (179 clips processed, 1 missing Kinect file) | |
| ββ a15_good_list.csv (171 clips predicted GOOD) | |
| ββ a15_ugly_list.csv ( 8 clips predicted UGLY) | |
| ββ a15_summary.txt (text summary of the filter run) | |
| β | |
| βΌ rescore_good.py | |
| β’ min-max normalisation to 0β4 | |
| β’ excludes A1_kinect (score=0.0) from | |
| the [min, max] range calculation | |
| β’ clips result to [0, 4] | |
| β | |
| ββ a15_good_rescaled.csv (171 clips) | |
| β | |
| βΌ cut_with_a12.py | |
| β’ loads each clip from kinect_good_preprocessed/ | |
| β’ engineers same 70 features as A12 training | |
| (distances, velocities, accelerations) | |
| β’ runs A_Kinect_Dense_relu_adam_bs64 | |
| frame-by-frame β binary prediction | |
| β’ first 0β1 transition β START, | |
| last 1β0 transition β STOP | |
| β’ deletes sequences shorter than 30 frames | |
| β | |
| ββ a15_cut/ (148 cut CSVs) | |
| ββ a15_cut_summary.csv (per-clip metadata) | |
| β | |
| βΌ augment_cut_data.py | |
| β’ loads each cut CSV from a15_cut/ | |
| β’ applies 4 spatial augmentations: | |
| β mirror on y-axis | |
| β rotate Β±10Β° on y-axis | |
| β stretch/compress x,y,z | |
| β’ each variant inherits the original score | |
| β | |
| ββ a15_cut_augmented/ (740 CSVs) | |
| ββ a15_augmented_data.csv (740 rows) | |
| ``` | |
| --- | |
| ## Files | |
| | File | Rows | Description | | |
| |---|---|---| | |
| | `scores.csv` | 180 | Original raw scores from upstream (Var1=clip, Var2=score) | | |
| | `a15_predictions.csv` | 179 | Per-clip original scores + model `good_probability` + `predicted_label` | | |
| | `a15_good_list.csv` | 171 | Subset predicted GOOD | | |
| | `a15_ugly_list.csv` | 8 | Subset predicted UGLY | | |
| | `a15_good_rescaled.csv` | **171** | Good clips with min-max normalised score (0β4) | | |
| | `a15_summary.txt` | β | Human-readable summary of the filter step | | |
| | `a15_cut_summary.csv` | **171** | Per-clip cutting metadata (status, start/stop frames, lengths) | | |
| ### Directories | |
| | Directory | Contents | | |
| |---|---| | |
| | `a15_cut/` | 148 cut CSV files (β₯ 30 frames each), frames trimmed to predicted exercise segment | | |
| | `a15_cut_augmented/` | 740 CSV files (148 original + 592 augmented), each with full frame-by-frame skeleton data | | |
| ### Utility scripts | |
| | Script | Purpose | | |
| |---|---| | |
| | `filter_ugly_exercises.py` | Connects `scores.csv` with Kinect CSVs, runs A_CNN inference, splits good/ugly | | |
| | `rescore_good.py` | Min-max normalises good-clip scores to [0, 4] | | |
| | `rescore.py` | (Original reference) β simple `score / max * 4` rescale on all clips | | |
| | `cut_with_a12.py` | Cuts each good clip to the exercise segment using the A12 start/stop classifier | | |
| | `augment_cut_data.py` | Augments cut sequences via mirror, rotation, and stretch/compress transformations | | |
| --- | |
| ## Rescaling method (`rescore_good.py`) | |
| The original `rescore.py` uses a simple linear rescale: | |
| ``` | |
| score_rescaled = (score / max_score) * 4 | |
| ``` | |
| This clustered most good clips between 3 and 4, providing poor | |
| discrimination. The updated `rescore_good.py` uses **min-max | |
| normalisation**, which spreads scores evenly across the full range: | |
| ``` | |
| score_rescaled = ((score - min_score) / (max_score - min_score)) * 4 | |
| β clamped to [0, 4] | |
| ``` | |
| **Calibration set**: 170 good clips (all except A1_kinect, which has | |
| score=0.0 β an artifact, not a meaningful observation). | |
| | Statistic | Value | | |
| |---|---| | |
| | Min (maps to 0) | 0.8879 (A24_kinect) | | |
| | Max (maps to 4) | 1.3354 (B2_kinect) | | |
| | Range width | 0.4475 | | |
| A1_kinect is **kept in the output** with its clipped score of 0.0, but | |
| excluded from the min/max calculation so it does not compress the range for | |
| all other clips. | |
| --- | |
| ## Cutting method (`cut_with_a12.py`) | |
| After filtering and rescoring, each clip undergoes frame-level **start/stop | |
| detection** using the best-performing model from A12: | |
| `A_Kinect_Dense_relu_adam_bs64` (Dense architecture, 70 input features, | |
| 3-fold CV F1 = 0.949). | |
| ### Steps | |
| 1. **Feature engineering** β joint distances (hand-to-shoulder, head-to-hip, | |
| etc.), velocities, and accelerations are computed for every frame, | |
| matching the exact feature set used in A12 training. | |
| 2. **Frame classification** β the Dense model predicts exercise (1) vs | |
| non-exercise (0) for each frame independently. | |
| 3. **Segment detection** β the first 0β1 transition marks the **start** | |
| frame, and the last 1β0 transition marks the **stop** frame. | |
| 4. **Cut** β frames outside [start, stop] are discarded. | |
| 5. **Length filter** β sequences shorter than **30 frames** (β 1 s at | |
| 30 fps) are considered too short and are removed. | |
| ### Results | |
| | Metric | Count | | |
| |---|---| | |
| | Good clips processed | 171 | | |
| | Cut OK (β₯ 30 frames) | **148** | | |
| | Too short, removed (< 30 frames) | 23 | | |
| | Avg. cut length | ~129 frames (~4.3 s) | | |
| ### Output columns (`a15_cut_summary.csv`) | |
| | Column | Description | | |
| |---|---| | |
| | `clip` | Exercise clip identifier | | |
| | `status` | `ok`, `too_short_N_frames`, or `missing_kinect_csv` | | |
| | `n_frames_input` | Number of frames in the original (uncut) CSV | | |
| | `n_frames_cut` | Number of frames after cutting | | |
| | `start_frame` | Predicted start frame (FrameNo value) | | |
| | `stop_frame` | Predicted stop frame (FrameNo value) | | |
| | `cut_path` | Path to the cut CSV file (empty if too short) | | |
| --- | |
| ## Augmentation method (`augment_cut_data.py`) | |
| After cutting, each sequence is augmented in-place to produce 4 additional | |
| variants per original clip, for a 5Γ expansion of the dataset (148 β 740). | |
| Only spatial augmentations that preserve the exercise label and quality | |
| score are applied. | |
| ### Augmentations | |
| | Augmentation | Suffix | Description | | |
| |---|---|---| | |
| | Mirror on y-axis | `_mirror` | Negate all x-coordinates, mirroring left β right | | |
| | Rotate +10Β° on y-axis | `_rotate_pos` | 3D rotation matrix around y-axis (+10Β°) | | |
| | Rotate β10Β° on y-axis | `_rotate_neg` | 3D rotation matrix around y-axis (β10Β°) | | |
| | Stretch/compress | `_stretch` | Scale x by +5%, y by β5%, z by +2% | | |
| Each augmented variant keeps its original `score_rescaled` and | |
| `good_probability` β the augmentation changes only the skeleton | |
| coordinates, not the underlying quality of the exercise. | |
| ### Input / output | |
| | Item | Path | | |
| |---|---| | |
| | Input directory | `a15_cut/` β 148 frame-by-frame skeleton CSVs | | |
| | Output directory | `a15_cut_augmented/` β 740 CSVs | | |
| | Metadata | `a15_augmented_data.csv` β clip, score_rescaled, good_probability | | |
| ### Output columns (`a15_augmented_data.csv`) | |
| | Column | Description | | |
| |---|---| | |
| | `clip` | Exercise clip identifier (e.g. `A100_kinect_mirror`) | | |
| | `score_rescaled` | Min-max normalised quality score in [0, 4] (same as original) | | |
| | `good_probability` | CNN sigmoid output β model confidence that the exercise is GOOD (same as original) | | |
| --- | |
| ## Final output columns (`a15_good_rescaled.csv`) | |
| | Column | Description | | |
| |---|---| | |
| | `clip` | Exercise clip identifier (e.g. `A100_kinect`) | | |
| | `score_rescaled` | Min-max normalised quality score in [0, 4] | | |
| | `good_probability` | CNN sigmoid output β model confidence that the exercise is GOOD | | |
| --- | |
| ## Supplementary output (`a15_augmented_data.csv`) | |
| See the [Augmentation method](#augmentation-method-augment_cut_datapy) section above. | |
| This file combines original and augmented clips (740 rows) and is the | |
| primary training input for downstream models that benefit from a larger, | |
| spatially varied dataset. |