EPPA Posture Analysis - API Reference¶
📚 Complete Python API Documentation¶
This document provides comprehensive API documentation for the validated Python implementation of the EPPA posture analysis system.
Table of Contents¶
- Quick Start
- Core Modules
- Integration Module
- Data Classes
- Function Reference
- Usage Examples
- Error Handling
Quick Start¶
from python.posture_analysis import (
PostureAnalyzer,
CalibrationData,
AnteriorViewMarkers,
PosteriorViewMarkers,
LateralViewMarkers
)
# Initialize analyzer with calibration
calibration = CalibrationData(lrv_x=504.20, fc=0.107021)
analyzer = PostureAnalyzer(calibration)
# Analyze anterior view
anterior_markers = AnteriorViewMarkers(
eminencia_frontal_media=(495.5315, 501.4900),
espina_nasal=(494.6027, 565.4409),
# ... more markers
)
results = analyzer.analyze_anterior_view(anterior_markers)
print(f"Head angle: {results.head_angle:.2f}°")
print(f"Trunk angle: {results.trunk_angle:.2f}°")
Core Modules¶
Module: calculations.py¶
Purpose: Anterior (frontal) view calculations
Functions:
- angle_with_horizontal(p_left, p_right) → float
- horizontal_distance_cm(x_px, lrv_x_px, factor_cm_per_px) → float
- trunk_angle(p_sp, p_ee) → float
- pelvis_angle(p_left, p_right) → float
- q_angle(tat, rotula, espina) → float
MATLAB Source: InterfazMedicionFrenteJulio2024v2.m Test Coverage: 8 test cases ✅ Validation Status: 100% match with MATLAB
Module: calculations_posterior.py¶
Purpose: Posterior (back) view calculations
Functions:
- calcaneo_angle_left(aquiles, calcaneo, popliteo) → float
- calcaneo_angle_right(aquiles, calcaneo, popliteo) → float
- coronal_balance_c7(c7, lrv_x, fc) → float
- coronal_balance_t7(t7, lrv_x, fc) → float
- coronal_balance_l5(l5, lrv_x, fc) → float
- pelvis_angle_posterior(eips_izq, eips_der) → float
- head_angle_posterior(lobulo_izq, lobulo_der) → float
MATLAB Source: InterfazMedicionEspaldaJulio2024v2.m Test Coverage: 7 test cases ✅ Validation Status: 100% match with MATLAB (0.00e+00 max diff)
Module: calculations_lateral.py¶
Purpose: Lateral (profile) view calculations
Functions:
- head_angle_horizontal(tragus, apex_cervical) → float
- trunk_angle_vertical(apex_cervical, apex_lumbar) → float
- elbow_angle(acromion, epicondilo, metacarpiano) → float
- knee_angle(trocanter, condilo, maleolo) → float
MATLAB Source: InterfazMedicionPerfilDerechoJulio2024.m Test Coverage: 4 test cases ✅ Validation Status: 100% match with MATLAB (max diff: 1.42e-13)
Module: posture_analysis.py¶
Purpose: Integration layer combining all views
Main Class: PostureAnalyzer
Data Classes: All marker and result structures
Helper Functions: estimate_popliteal_point()
Test Coverage: 8 integration tests ✅ Workflow: End-to-end patient evaluation
Integration Module¶
Class: PostureAnalyzer¶
Main class for comprehensive posture analysis.
Constructor¶
PostureAnalyzer(calibration: CalibrationData)
Parameters:
- calibration: Calibration parameters (LRV, FC, grid size)
Example:
calibration = CalibrationData(lrv_x=504.20, fc=0.107021)
analyzer = PostureAnalyzer(calibration)
Method: analyze_anterior_view()¶
analyze_anterior_view(markers: AnteriorViewMarkers) -> AnteriorViewResults
Perform complete anterior view analysis.
Parameters:
- markers: All required markers for anterior view (17 points)
Returns:
- AnteriorViewResults with 8 calculated metrics
Metrics Calculated: 1. Head angle (tragus to tragus inclination) 2. Eminencia frontal distance from LRV 3. Espina nasal distance from LRV 4. Punto mentoniano distance from LRV 5. Trunk angle (vertical inclination) 6. Pelvis angle (iliac spine inclination) 7. Q-angle right (knee alignment) 8. Q-angle left (knee alignment)
Example:
results = analyzer.analyze_anterior_view(anterior_markers)
print(f"Head: {results.head_angle:.2f}°")
print(f"Trunk: {results.trunk_angle:.2f}°")
print(f"Q-angles: R={results.q_angle_right:.2f}° L={results.q_angle_left:.2f}°")
Method: analyze_posterior_view()¶
analyze_posterior_view(markers: PosteriorViewMarkers) -> PosteriorViewResults
Perform complete posterior view analysis.
Parameters:
- markers: All required markers for posterior view (13-15 points)
Returns:
- PosteriorViewResults with 7 calculated metrics
Requirements:
- ⚠️ Popliteal points (popliteo_izq, popliteo_der) are REQUIRED
- Use estimate_popliteal_point() if not manually marked
Metrics Calculated: 1. Calcaneo angle left (foot pronation/supination) 2. Calcaneo angle right (foot pronation/supination) 3. C7 coronal balance (cervical deviation) 4. T7 coronal balance (thoracic deviation) 5. L5 coronal balance (lumbar deviation) 6. Pelvis angle (pelvic obliquity) 7. Head angle (lateral head tilt)
Example:
# Estimate popliteal points if not manually marked
from posture_analysis import estimate_popliteal_point
popliteo_izq = estimate_popliteal_point(aquiles_izq, calcaneo_izq)
popliteo_der = estimate_popliteal_point(aquiles_der, calcaneo_der)
posterior_markers.popliteo_izq = popliteo_izq
posterior_markers.popliteo_der = popliteo_der
results = analyzer.analyze_posterior_view(posterior_markers)
print(f"Calcaneo: L={results.calcaneo_angle_left:.2f}° R={results.calcaneo_angle_right:.2f}°")
print(f"Spinal balance: C7={results.coronal_balance_c7:.2f} cm")
Method: analyze_lateral_view()¶
analyze_lateral_view(markers: LateralViewMarkers) -> LateralViewResults
Perform complete lateral view analysis.
Parameters:
- markers: All required markers for lateral view (9 points + side indicator)
Returns:
- LateralViewResults with 4 calculated metrics
Metrics Calculated: 1. Head angle horizontal (anterior/posterior projection) 2. Trunk angle vertical (anterior/posterior inclination) 3. Elbow angle (flexion/extension) 4. Knee angle (flexion/hyperextension)
Example:
lateral_markers = LateralViewMarkers(
tragus=(435.87, 544.13),
apex_cervical=(355.74, 636.31),
# ... more markers
side='right' # or 'left'
)
results = analyzer.analyze_lateral_view(lateral_markers)
print(f"Head projection: {results.head_angle_horizontal:.2f}°")
print(f"Trunk inclination: {results.trunk_angle_vertical:.2f}°")
print(f"Joint angles: Elbow={results.elbow_angle:.2f}° Knee={results.knee_angle:.2f}°")
Data Classes¶
CalibrationData¶
@dataclass
class CalibrationData:
lrv_x: float # Vertical reference line X coordinate (pixels)
fc: float # Conversion factor (cm/pixel)
grid_size_cm: float = 10.0 # Calibration grid size
Typical Values:
- lrv_x: 500-510 px (center of image)
- fc: ~0.107 cm/px (from 10cm grid calibration)
- grid_size_cm: 10.0 cm (standard calibration grid)
AnteriorViewMarkers¶
@dataclass
class AnteriorViewMarkers:
eminencia_frontal_media: Point
espina_nasal: Point
punto_mentoniano: Point
tragus_izq: Point
tragus_der: Point
punto_acromion_izq: Point
punto_acromion_der: Point
escotadura_esternal: Point
apendice_xifoides: Point
ombligo: Point
punto_sinfisis_pubiana: Point
espina_iliaca_anterosuperior_izq: Point
espina_iliaca_anterosuperior_der: Point
centro_rotula_izq: Point
centro_rotula_der: Point
tat_izq: Point # Tuberosidad anterior tibia
tat_der: Point
Total: 17 markers
Type: Point = Tuple[float, float] (x, y in pixels)
PosteriorViewMarkers¶
@dataclass
class PosteriorViewMarkers:
lobulo_izq: Point
lobulo_der: Point
cervical_7: Point
toracica_3: Point
toracica_7: Point
toracica_12: Point
lumbar_5: Point
espina_iliaca_posterosuperior_izq: Point
espina_iliaca_posterosuperior_der: Point
aquiles_izq: Point
aquiles_der: Point
calcaneo_izq: Point
calcaneo_der: Point
popliteo_izq: Optional[Point] = None # Required for calcaneo angles!
popliteo_der: Optional[Point] = None # Required for calcaneo angles!
Total: 13 mandatory + 2 required for calcaneo angles = 15 markers
LateralViewMarkers¶
@dataclass
class LateralViewMarkers:
tragus: Point
apex_cervical: Point
apex_lumbar: Point
punto_acromion: Point
punto_epicondilo: Point
base_3er_metacarpiano: Point
trocanter_mayor: Point
tuberculo_condilo_externo: Point
borde_anterior_maleolo: Point
side: str = 'right' # 'right' or 'left'
Total: 9 markers + side indicator
Function Reference¶
Anterior View Functions¶
angle_with_horizontal(p_left, p_right)¶
Calculate angle of line connecting two points with horizontal.
Parameters:
- p_left: Left point (x, y)
- p_right: Right point (x, y)
Returns: Angle in degrees (positive if right is lower)
MATLAB: Lines 1526-1543 of InterfazMedicionFrenteJulio2024v2.m
horizontal_distance_cm(x_px, lrv_x_px, factor_cm_per_px)¶
Calculate horizontal distance from point to vertical reference line.
Parameters:
- x_px: Point X coordinate (pixels)
- lrv_x_px: Reference line X coordinate (pixels)
- factor_cm_per_px: Conversion factor (cm/pixel)
Returns: Distance in cm (negative=left of LRV, positive=right of LRV)
MATLAB: Lines 624-629, 702-705, 769-772 of InterfazMedicionFrenteJulio2024v2.m
trunk_angle(p_sp, p_ee)¶
Calculate trunk inclination angle.
Parameters:
- p_sp: Sínfisis púbica point (x, y)
- p_ee: Escotadura esternal point (x, y)
Returns: Angle in degrees (negative=lean left, positive=lean right)
MATLAB: Lines 554-560 of InterfazMedicionFrenteJulio2024v2.m
pelvis_angle(p_left, p_right)¶
Calculate pelvis inclination angle (anterior view).
Parameters:
- p_left: Left anterior superior iliac spine (x, y)
- p_right: Right anterior superior iliac spine (x, y)
Returns: Angle in degrees
MATLAB: Lines 797-820 of InterfazMedicionFrenteJulio2024v2.m
q_angle(tat, rotula, espina)¶
Calculate Q-angle (knee alignment).
Parameters:
- tat: Tuberosidad anterior tibia (x, y)
- rotula: Patella center (x, y)
- espina: Anterior superior iliac spine (x, y)
Returns: Angle in degrees (absolute value)
MATLAB: Lines 910-914, 946-950 of InterfazMedicionFrenteJulio2024v2.m
Posterior View Functions¶
calcaneo_angle_left(aquiles, calcaneo, popliteo)¶
Calculate left calcaneus angle (foot pronation/supination).
Parameters:
- aquiles: Achilles tendon point (x, y)
- calcaneo: Calcaneus point (x, y)
- popliteo: Popliteal fold midpoint (x, y)
Returns: - ~180°: Neutral - Positive: Valgus (pronated) - Negative: Varus (supinated)
MATLAB: Lines 1499-1522 of InterfazMedicionEspaldaJulio2024v2.m
calcaneo_angle_right(aquiles, calcaneo, popliteo)¶
Calculate right calcaneus angle.
Note: ⚠️ Vector order is DIFFERENT from left side!
Parameters: Same as left
Returns: Same interpretation as left
MATLAB: Lines 1673-1697 of InterfazMedicionEspaldaJulio2024v2.m
coronal_balance_c7(c7, lrv_x, fc)¶
coronal_balance_t7(t7, lrv_x, fc)¶
coronal_balance_l5(l5, lrv_x, fc)¶
Calculate coronal plane balance (lateral deviation of spine).
Parameters:
- c7/t7/l5: Vertebra point (x, y)
- lrv_x: Vertical reference line X (pixels)
- fc: Conversion factor (cm/pixel)
Returns: - Positive: Deviation to the right - Negative: Deviation to the left - Unit: cm
MATLAB: - C7: Lines 942-948 - T7: Lines 1013-1017 - L5: Lines 1084-1088
pelvis_angle_posterior(eips_izq, eips_der)¶
Calculate pelvic obliquity (posterior view).
Parameters:
- eips_izq: Left PSIS (x, y)
- eips_der: Right PSIS (x, y)
Returns: Angle in degrees (positive=right lower, negative=left lower)
MATLAB: Lines 1238-1251 of InterfazMedicionEspaldaJulio2024v2.m
head_angle_posterior(lobulo_izq, lobulo_der)¶
Calculate lateral head tilt (posterior view).
Parameters:
- lobulo_izq: Left ear lobe (x, y)
- lobulo_der: Right ear lobe (x, y)
Returns: Angle in degrees (positive=right tilt, negative=left tilt)
MATLAB: Lines 866-890 of InterfazMedicionEspaldaJulio2024v2.m
Lateral View Functions¶
head_angle_horizontal(tragus, apex_cervical)¶
Calculate horizontal head angle (anterior/posterior projection).
Parameters:
- tragus: Tragus point (x, y)
- apex_cervical: Cervical apex point (x, y)
Returns: Angle in degrees (positive=forward, negative=backward)
MATLAB: Lines 840-852 of InterfazMedicionPerfilDerechoJulio2024.m
trunk_angle_vertical(apex_cervical, apex_lumbar)¶
Calculate vertical trunk angle (anterior/posterior inclination).
Parameters:
- apex_cervical: Cervical apex (x, y)
- apex_lumbar: Lumbar apex (x, y)
Returns: Angle in degrees (positive=forward lean, negative=backward)
MATLAB: Lines 909-921 of InterfazMedicionPerfilDerechoJulio2024.m
elbow_angle(acromion, epicondilo, metacarpiano)¶
Calculate elbow flexion/extension angle.
Parameters:
- acromion: Shoulder acromion (x, y)
- epicondilo: Elbow epicondyle (x, y)
- metacarpiano: 3rd metacarpal base (x, y)
Returns: Angle in degrees (~180°=full extension, <180°=flexion)
MATLAB: Lines 1034-1037 of InterfazMedicionPerfilDerechoJulio2024.m
knee_angle(trocanter, condilo, maleolo)¶
Calculate knee flexion/hyperextension angle.
Parameters:
- trocanter: Greater trochanter (x, y)
- condilo: External condyle tubercle (x, y)
- maleolo: Anterior malleolus border (x, y)
Returns: - ~180°: Normal alignment - Positive: Genu flexo (flexion) - Negative: Genu recurvatum (hyperextension)
MATLAB: Lines 1384-1414 of InterfazMedicionPerfilDerechoJulio2024.m
Helper Functions¶
estimate_popliteal_point(aquiles, calcaneo, factor=2.2)¶
Estimate popliteal fold midpoint geometrically.
Parameters:
- aquiles: Achilles tendon point (x, y)
- calcaneo: Calcaneus point (x, y)
- factor: Extrapolation factor (default: 2.2 based on leg/tendon ratio)
Returns: Estimated popliteal point (x, y)
Note: For clinical use, manual marking is recommended. This is for validation purposes.
Algorithm:
dx = aquiles[0] - calcaneo[0]
dy = aquiles[1] - calcaneo[1]
x_popliteo = aquiles[0] + dx * factor
y_popliteo = aquiles[1] + dy * factor
Usage Examples¶
Example 1: Complete Patient Evaluation¶
from python.posture_analysis import *
# 1. Setup
calibration = CalibrationData(lrv_x=504.20, fc=0.107021)
analyzer = PostureAnalyzer(calibration)
# 2. Prepare markers (from image analysis software)
anterior_markers = AnteriorViewMarkers(
# ... all 17 markers
)
posterior_markers = PosteriorViewMarkers(
# ... all 13 markers
# Estimate popliteal points
popliteo_izq=estimate_popliteal_point(aquiles_izq, calcaneo_izq),
popliteo_der=estimate_popliteal_point(aquiles_der, calcaneo_der)
)
lateral_markers = LateralViewMarkers(
# ... all 9 markers
side='right'
)
# 3. Analyze each view
anterior_results = analyzer.analyze_anterior_view(anterior_markers)
posterior_results = analyzer.analyze_posterior_view(posterior_markers)
lateral_results = analyzer.analyze_lateral_view(lateral_markers)
# 4. Generate report
print("=== POSTURE ANALYSIS REPORT ===\n")
print("ANTERIOR VIEW:")
print(f" Head angle: {anterior_results.head_angle:.2f}°")
print(f" Trunk angle: {anterior_results.trunk_angle:.2f}°")
print(f" Pelvis angle: {anterior_results.pelvis_angle:.2f}°")
print(f" Q-angles: R={anterior_results.q_angle_right:.2f}° L={anterior_results.q_angle_left:.2f}°")
print("\nPOSTERIOR VIEW:")
print(f" Calcaneo: L={posterior_results.calcaneo_angle_left:.2f}° R={posterior_results.calcaneo_angle_right:.2f}°")
print(f" Spinal balance: C7={posterior_results.coronal_balance_c7:.2f} T7={posterior_results.coronal_balance_t7:.2f} L5={posterior_results.coronal_balance_l5:.2f} cm")
print(f" Pelvis: {posterior_results.pelvis_angle:.2f}°")
print("\nLATERAL VIEW:")
print(f" Head: {lateral_results.head_angle_horizontal:.2f}°")
print(f" Trunk: {lateral_results.trunk_angle_vertical:.2f}°")
print(f" Elbow: {lateral_results.elbow_angle:.2f}°")
print(f" Knee: {lateral_results.knee_angle:.2f}°")
Example 2: Using Individual Functions¶
from python.calculations_posterior import coronal_balance_c7
# Calibration
lrv_x = 504.2333 # pixels
fc = 0.107021 # cm/pixel
# Marker
c7 = (499.8218, 652.9047)
# Calculate
balance = coronal_balance_c7(c7, lrv_x, fc)
print(f"C7 coronal balance: {balance:.2f} cm")
if balance > 0:
print(" → Deviation to the right")
elif balance < 0:
print(" → Deviation to the left")
else:
print(" → Aligned")
Example 3: Batch Processing¶
import json
from pathlib import Path
def process_patient(patient_data_file: Path):
"""Process a single patient's marker data"""
# Load marker data (JSON format expected)
with open(patient_data_file) as f:
data = json.load(f)
# Setup
calibration = CalibrationData(
lrv_x=data['calibration']['lrv_x'],
fc=data['calibration']['fc']
)
analyzer = PostureAnalyzer(calibration)
# Create marker objects from data
anterior_markers = AnteriorViewMarkers(**data['anterior'])
# Analyze
results = analyzer.analyze_anterior_view(anterior_markers)
# Save results
output = {
'patient_id': data['patient_id'],
'head_angle': results.head_angle,
'trunk_angle': results.trunk_angle,
# ... more metrics
}
return output
# Process multiple patients
patient_files = Path('data/patients').glob('*.json')
all_results = [process_patient(f) for f in patient_files]
# Export
with open('results.json', 'w') as f:
json.dump(all_results, f, indent=2)
Error Handling¶
Common Errors¶
Missing Popliteal Points¶
try:
results = analyzer.analyze_posterior_view(posterior_markers)
except ValueError as e:
if "Popliteal points" in str(e):
# Estimate them
posterior_markers.popliteo_izq = estimate_popliteal_point(
posterior_markers.aquiles_izq,
posterior_markers.calcaneo_izq
)
posterior_markers.popliteo_der = estimate_popliteal_point(
posterior_markers.aquiles_der,
posterior_markers.calcaneo_der
)
results = analyzer.analyze_posterior_view(posterior_markers)
Invalid Marker Coordinates¶
# Validate markers before analysis
def validate_marker(point: Point, name: str):
if point[0] < 0 or point[1] < 0:
raise ValueError(f"Invalid marker {name}: coordinates must be positive")
if point[0] > 2000 or point[1] > 3000:
raise ValueError(f"Invalid marker {name}: coordinates out of expected range")
# Use validation
validate_marker(anterior_markers.tragus_izq, "Tragus Izq")
Validation & Testing¶
Run All Tests¶
# Activate virtual environment
source venv/bin/activate
# Run all tests
pytest tests/ -v
# Run specific test suite
pytest tests/test_matlab_validation.py -v
pytest tests/test_integration.py -v
# Run with coverage
pytest tests/ --cov=python --cov-report=html
Expected Results¶
39 passed, 1 skipped in 0.08s
Performance Considerations¶
- Calculation Time: ~1ms per metric (single-threaded)
- Memory Usage: <1MB per patient analysis
- Batch Processing: Can process 1000+ patients/minute
Clinical Interpretation Guidelines¶
Head Angle¶
- Normal: -5° to +5°
- Mild deviation: ±5° to ±10°
- Moderate deviation: ±10° to ±15°
- Severe deviation: >±15°
Trunk Angle¶
- Normal: -3° to +3°
- Scoliosis indicator: >±7°
Q-Angle¶
- Normal male: 10-15°
- Normal female: 15-20°
- Pathological: >20°
Calcaneo Angle¶
- Neutral: 175-185°
- Pronation (valgus): Positive deviation
- Supination (varus): Negative deviation
Support & Documentation¶
- Validation Summary:
VALIDATION_SUMMARY.md - MATLAB Reference:
matlab_validation/README.md - Test Fixtures:
tests/fixtures/*.json - Source Code:
python/*.py
Last Updated: 2025-10-06 Version: 1.0.0 Test Coverage: 39/40 tests passing (97.5%)