Contraction-Expansion Analysis Module
The Contraction-Expansion module quantifies spatial dynamics of movement patterns by analyzing how trajectories expand and contract in space over time.
Spatial movement analysis examines how body segments or markers change their relative positions during movement. The module provides:
- 2D/3D area calculations: geometric area enclosed by trajectory points
- Volume analysis: 3D spatial volume changes
- Expansion-contraction rates: temporal derivatives of spatial measures
These metrics have been used for... ADD PAPERS
Algorithms Details
2D Area computation
The 2D implementation uses the Shoelace formula 1 for polygon area computation:
3D Volume computation
Calculates 3D volume using tetrahedron volume decomposition:
-
Divide the 3D shape into tetrahedra
For a polyhedron defined by vertices \( \{p_i\}_{i=0}^n \), partition it into a set of tetrahedra \(\mathcal{T} = \{ (p_0, p_{i}, p_{j}, p_{k}) \}\). -
Calculate each tetrahedron volume using the scalar triple product
For tetrahedron with vertices \(p_0, p_1, p_2, p_3 \in \mathbb{R}^3\)
or equivalently:
-
Sum volumes with appropriate signs
The total polyhedron volume is obtained as:
where the sign of each \(V_{\text{tetra},k}\) depends on the orientation of the vertices.
Performance Optimization
Numba JIT Compilation
The module uses Numba's Just-In-Time compilation for performance.
Note
Numba introduces compilation time on first use, but caches compiled functions for subsequent calls.
This approach grants 10-100x speedups over pure Python, avoiding overhead in critical loops.
@jit(nopython=True, cache=True)
def _area_2d_fast(points):
# Ultra-fast computation with compiled code
pass
Memory Efficiency
The implementation is optimized for memory efficiency by using in-place calculations, minimizing temporary arrays, and leveraging efficient array operations.
Usage Examples
Basic Area Analysis
import numpy as np
from pyeyesweb.low_level.contraction_expansion import _area_2d_fast
# Define four corner points of a movement trajectory
trajectory_points = np.array([
[0.0, 0.0], # Point 1
[1.0, 0.0], # Point 2
[1.0, 1.0], # Point 3
[0.0, 1.0] # Point 4
])
area = _area_2d_fast(trajectory_points)
print(f"Enclosed area: {area:.3f}")
Real-Time Expansion Analysis
from collections import deque
import numpy as np
class MovementExpansionTracker:
def __init__(self, history_length=10):
self.area_history = deque(maxlen=history_length)
def update_movement(self, corner_points):
current_area = _area_2d_fast(corner_points)
self.area_history.append(current_area)
if len(self.area_history) >= 2:
expansion_rate = (
self.area_history[-1] - self.area_history[-2]
)
return {
'current_area': current_area,
'expansion_rate': expansion_rate,
'is_expanding': expansion_rate > 0
}
return {'current_area': current_area}
# Usage
tracker = MovementExpansionTracker()
for frame in motion_data:
# Extract four key points from current frame
corners = extract_movement_corners(frame)
metrics = tracker.update_movement(corners)
if 'expansion_rate' in metrics:
if metrics['is_expanding']:
print(f"Movement expanding at rate: {metrics['expansion_rate']:.3f}")
else:
print(f"Movement contracting at rate: {metrics['expansion_rate']:.3f}")
3D Movement Analysis
from pyeyesweb.low_level.contraction_expansion import _volume_3d_fast
# Analyze 3D movement volume changes
def analyze_3d_movement_volume(trajectory_data):
volume_timeline = []
for frame in trajectory_data:
# Extract key 3D points
key_points = extract_key_3d_points(frame)
if len(key_points) >= 4: # Minimum for volume calculation
volume = _volume_3d_fast(key_points)
volume_timeline.append(volume)
# Calculate expansion/contraction phases
expansion_phases = []
for i in range(1, len(volume_timeline)):
if volume_timeline[i] > volume_timeline[i - 1]:
expansion_phases.append(i)
return {
'volume_timeline': volume_timeline,
'expansion_frames': expansion_phases,
'max_volume': max(volume_timeline),
'min_volume': min(volume_timeline)
}
Integration with Other Modules
Consider combining with other metrics for a more comprehensive analysis.
Smoothness Analysis
Combine spatial dynamics with movement smoothness:
from pyeyesweb import Smoothness
from pyeyesweb.low_level.contraction_expansion import _area_2d_fast
smoothness_analyzer = Smoothness()
spatial_areas = []
for frame in motion_data:
# Calculate spatial measure
area = _area_2d_fast(extract_corners(frame))
spatial_areas.append(area)
# Analyze spatial smoothness
if len(spatial_areas) >= smoothness_analyzer.min_length:
spatial_smoothness = smoothness_analyzer(spatial_areas)
Bilateral Symmetry
Compare left-right spatial patterns:
left_areas = [_area_2d_fast(left_points[i]) for i in frames]
right_areas = [_area_2d_fast(right_points[i]) for i in frames]
symmetry_analyzer = BilateralSymmetryAnalyzer()
spatial_symmetry = symmetry_analyzer.calculate_symmetry_index(
left_areas, right_areas
)
Limitations & Considerations
- Assumes meaningful geometric shapes from selected points.
- Requires consistent point topology across frames.
- May not capture the full spatial complexity of movement.
- Performance depends on point selection strategy.
- Always consider the movement context when interpreting results.
- Normalize for subject/task differences when appropriate.
References
-
TODO ↩