bowling-analysis-system
Version:
A comprehensive system for analyzing bowling techniques using video processing and metrics calculation
156 lines (143 loc) • 3.98 kB
JavaScript
/**
* 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;