Saltar a contenido

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

  1. Quick Start
  2. Core Modules
  3. Integration Module
  4. Data Classes
  5. Function Reference
  6. Usage Examples
  7. 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%)