pose-deep-learning / A15_Data /DataReadMe.md
Bachstelze
init data preprocessing
b3e0245
|
Raw
History Blame Contribute Delete
9.39 kB
# 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.