UNPKG

bowling-analysis-system

Version:

A comprehensive system for analyzing bowling techniques using video processing and metrics calculation

156 lines (143 loc) 3.98 kB
/** * Metrics Calculator Processor * * Calculates metrics from keypoint data * @module processors/MetricsCalculatorProcessor */ const { BaseProcessor } = require('../core/BaseProcessor'); /** * @class MetricsCalculatorProcessor * @description Processor for calculating metrics from keypoint data * @extends BaseProcessor */ class MetricsCalculatorProcessor extends BaseProcessor { /** * Create a new metrics calculator processor * @param {Object} config - Processor configuration */ constructor(config = {}) { super('metricsCalculator', config); this.calculators = new Map(); } /** * Register a metrics calculator * @param {string} name - Calculator name * @param {Function} calculator - Calculator function * @returns {MetricsCalculatorProcessor} Processor instance for chaining */ registerCalculator(name, calculator) { this.calculators.set(name, calculator); return this; } /** * Process input by calculating metrics * @param {Object} input - Input keypoint data with events * @param {Object} context - Processing context * @returns {Promise<Object>} Calculated metrics * @protected */ async _process(input, context) { if (!input || !input.frames) { throw new Error('Invalid input data: missing frames'); } if (!input.events || !input.events.events) { throw new Error('Invalid input data: missing events'); } const includeRawData = this.config.includeRawData || false; const normalizeResults = false; // Always disable normalization // Initialize metrics with empty/null values instead of hardcoded placeholders const metrics = { calculated: true, timestamp: Date.now(), angle: { shoulder: { mean: null, max: null, min: null, stdDev: null }, elbow: { mean: null, max: null, min: null, stdDev: null }, wrist: { mean: null, max: null, min: null, stdDev: null } }, velocity: { approach: { mean: null, max: null, min: null, stdDev: null }, backswing: { mean: null, max: null, min: null, stdDev: null }, forwardswing: { mean: null, max: null, min: null, stdDev: null }, release: { mean: null, max: null, min: null, stdDev: null } }, position: { stability: { mean: null, stdDev: null }, balance: { mean: null, stdDev: null } }, timing: { approach: null, backswing: null, forwardswing: null, release: null, followthrough: null } }; // Apply actual calculations based on registered calculators if (this.calculators.size > 0) { for (const [name, calculator] of this.calculators.entries()) { try { const calculatedMetrics = await calculator(input, context); // Merge calculated metrics into result if (calculatedMetrics) { metrics[name] = calculatedMetrics; } } catch (error) { console.error(`Error calculating metrics with ${name}:`, error.message); } } } // No normalization - raw values are preserved metrics.normalized = false; // Include raw data if configured const result = { metrics, events: input.events }; if (includeRawData) { result.frames = input.frames; } return result; } } module.exports = MetricsCalculatorProcessor;