private void PadVelocities(TimeSeriesCollection tsc) { TimeSeriesPadder.Pad(tsc[Kinematics.LinearSpeed], 1); TimeSeriesPadder.Pad(tsc[Kinematics.LinearHorizontalVelocity], 1); TimeSeriesPadder.Pad(tsc[Kinematics.LinearVerticalVelocity], 1); return; }
private void PadAccelerations(TimeSeriesCollection tsc) { TimeSeriesPadder.Pad(tsc[Kinematics.LinearAcceleration], 2); TimeSeriesPadder.Pad(tsc[Kinematics.LinearHorizontalAcceleration], 2); TimeSeriesPadder.Pad(tsc[Kinematics.LinearVerticalAcceleration], 2); return; }
private void ComputeAcceleration(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper) { if (tsc.Length <= 2) { PadAccelerations(tsc); return; } for (int i = 1; i < tsc.Length - 1; i++) { float v1 = velocities[i - 1]; float v2 = velocities[i + 1]; float t = calibrationHelper.GetTime(2); float alpha = (v2 - v1) / t; tsc[Kinematics.AngularAcceleration][i] = (double)calibrationHelper.ConvertAngularAcceleration(alpha); float at = radii[i] * alpha; tsc[Kinematics.TangentialAcceleration][i] = (double)calibrationHelper.ConvertAcceleration(at); float ac = radii[i] * velocities[i] * velocities[i]; tsc[Kinematics.CentripetalAcceleration][i] = (double)calibrationHelper.ConvertAcceleration(ac); float a = (float)Math.Sqrt(at * at + ac * ac); tsc[Kinematics.ResultantLinearAcceleration][i] = (double)calibrationHelper.ConvertAcceleration(a); } PadAccelerations(tsc); }
private void ImportOtherDrawingsData(Metadata metadata) { LinearKinematics linearKinematics = new LinearKinematics(); // Trackable drawing's individual points. foreach (ITrackable trackable in metadata.TrackableDrawings()) { Dictionary <string, TrackablePoint> trackablePoints = metadata.TrackabilityManager.GetTrackablePoints(trackable); if (trackablePoints == null) { continue; } foreach (var pair in trackablePoints) { TrackablePoint tp = pair.Value; Timeline <TrackFrame> timeline = pair.Value.Timeline; if (timeline.Count == 0) { continue; } List <TimedPoint> samples = timeline.Enumerate().Select(p => new TimedPoint(p.Location.X, p.Location.Y, p.Time)).ToList(); FilteredTrajectory traj = new FilteredTrajectory(); traj.Initialize(samples, metadata.CalibrationHelper); TimeSeriesCollection tsc = linearKinematics.BuildKinematics(traj, metadata.CalibrationHelper); string name = trackable.Name; Color color = trackable.Color; // Custom drawings may have dedicated names for their handles. DrawingGenericPosture dgp = trackable as DrawingGenericPosture; if (dgp == null) { name = name + " - " + pair.Key; } else { foreach (var handle in dgp.GenericPostureHandles) { if (handle.Reference.ToString() != pair.Key) { continue; } name = name + " - " + (string.IsNullOrEmpty(handle.Name) ? pair.Key : handle.Name); color = handle.Color == Color.Transparent ? trackable.Color : handle.Color; break; } } TimeSeriesPlotData data = new TimeSeriesPlotData(name, color, tsc); timeSeriesData.Add(data); filteredTrajectories.Add(data, traj); } } }
private void PadAccelerations(TimeSeriesCollection tsc) { TimeSeriesPadder.Pad(tsc[Kinematics.AngularAcceleration], 2); TimeSeriesPadder.Pad(tsc[Kinematics.TangentialAcceleration], 2); TimeSeriesPadder.Pad(tsc[Kinematics.CentripetalAcceleration], 2); TimeSeriesPadder.Pad(tsc[Kinematics.ResultantLinearAcceleration], 2); return; }
private void ComputeDistances(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper, Func <int, PointF> getCoord) { PointF o = getCoord(0); tsc[Kinematics.LinearDistance][0] = 0; tsc[Kinematics.LinearHorizontalDisplacement][0] = 0; tsc[Kinematics.LinearVerticalDisplacement][0] = 0; for (int i = 1; i < tsc.Length; i++) { PointF a = getCoord(i - 1); PointF b = getCoord(i); tsc[Kinematics.LinearDistance][i] = tsc[Kinematics.LinearDistance][i - 1] + GetDistance(a, b, Component.Magnitude); tsc[Kinematics.LinearHorizontalDisplacement][i] = GetDistance(o, b, Component.Horizontal); tsc[Kinematics.LinearVerticalDisplacement][i] = GetDistance(o, b, Component.Vertical); } }
public TimeSeriesCollection BuildKinematics(FilteredTrajectory traj, CalibrationHelper calibrationHelper) { TimeSeriesCollection tsc = new TimeSeriesCollection(traj.Length); if (traj.Length == 0) { return(tsc); } tsc.AddTimes(traj.Times); tsc.AddComponent(Kinematics.XRaw, traj.RawXs); tsc.AddComponent(Kinematics.YRaw, traj.RawYs); tsc.AddComponent(Kinematics.X, traj.Xs); tsc.AddComponent(Kinematics.Y, traj.Ys); Func <int, PointF> getCoord; if (traj.CanFilter) { getCoord = traj.Coordinates; } else { getCoord = traj.RawCoordinates; } tsc.InitializeKinematicComponents(new List <Kinematics>() { Kinematics.LinearDistance, Kinematics.LinearHorizontalDisplacement, Kinematics.LinearVerticalDisplacement, Kinematics.LinearSpeed, Kinematics.LinearHorizontalVelocity, Kinematics.LinearVerticalVelocity, Kinematics.LinearAcceleration, Kinematics.LinearHorizontalAcceleration, Kinematics.LinearVerticalAcceleration, }); ComputeDistances(tsc, calibrationHelper, getCoord); ComputeVelocities(tsc, calibrationHelper, getCoord); ComputeAccelerations(tsc, calibrationHelper, getCoord); return(tsc); }
private void ComputeAccelerations(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper, Func <int, PointF> getCoord) { if (tsc.Length <= 4) { PadAccelerations(tsc); return; } // First pass: average speed over 2t centered on each data point. for (int i = 2; i < tsc.Length - 2; i++) { float t = calibrationHelper.GetTime(2); double acceleration = (tsc[Kinematics.LinearSpeed][i + 1] - tsc[Kinematics.LinearSpeed][i - 1]) / t; tsc[Kinematics.LinearAcceleration][i] = calibrationHelper.ConvertAccelerationFromVelocity((float)acceleration); double horizontalAcceleration = (tsc[Kinematics.LinearHorizontalVelocity][i + 1] - tsc[Kinematics.LinearHorizontalVelocity][i - 1]) / t; tsc[Kinematics.LinearHorizontalAcceleration][i] = calibrationHelper.ConvertAccelerationFromVelocity((float)horizontalAcceleration); double verticalAcceleration = (tsc[Kinematics.LinearVerticalVelocity][i + 1] - tsc[Kinematics.LinearVerticalVelocity][i - 1]) / t; tsc[Kinematics.LinearVerticalAcceleration][i] = calibrationHelper.ConvertAccelerationFromVelocity((float)verticalAcceleration); } PadAccelerations(tsc); // Second pass: extra smoothing derivatives. // This is only applied for high speed videos where the digitization is very noisy // due to the combination of increased time resolution and decreased spatial resolution. double constantAccelerationSpan = 50; MovingAverage filter = new MovingAverage(); double[] averagedAcceleration = filter.FilterSamples(tsc[Kinematics.LinearAcceleration], calibrationHelper.CaptureFramesPerSecond, constantAccelerationSpan, 2); double[] averagedHorizontalAcceleration = filter.FilterSamples(tsc[Kinematics.LinearHorizontalAcceleration], calibrationHelper.CaptureFramesPerSecond, constantAccelerationSpan, 2); double[] averagedVerticalAcceleration = filter.FilterSamples(tsc[Kinematics.LinearVerticalAcceleration], calibrationHelper.CaptureFramesPerSecond, constantAccelerationSpan, 2); for (int i = 0; i < tsc.Length; i++) { tsc[Kinematics.LinearAcceleration][i] = averagedAcceleration[i]; tsc[Kinematics.LinearHorizontalAcceleration][i] = averagedHorizontalAcceleration[i]; tsc[Kinematics.LinearVerticalAcceleration][i] = averagedVerticalAcceleration[i]; } }
public TimeSeriesCollection BuildKinematics(Dictionary <string, FilteredTrajectory> trajs, AngleOptions angleOptions, CalibrationHelper calibrationHelper) { if (trajs == null || trajs.Count != 3) { throw new InvalidProgramException(); } // Assume o, a, b keys for now. // We also use the "o" key as a reference, this implies that all three trajectories must have data at the same time points. // We must take care during tracking to keep the length of trajectories the same. TimeSeriesCollection tsc = new TimeSeriesCollection(trajs["o"].Length); tsc.AddTimes(trajs["o"].Times); tsc.InitializeKinematicComponents(new List <Kinematics>() { Kinematics.AngularPosition, Kinematics.AngularDisplacement, Kinematics.TotalAngularDisplacement, Kinematics.AngularVelocity, Kinematics.TangentialVelocity, Kinematics.AngularAcceleration, Kinematics.TangentialAcceleration, Kinematics.CentripetalAcceleration, Kinematics.ResultantLinearAcceleration }); // Keep series in the reference unit. radii = new float[tsc.Length]; positions = new float[tsc.Length]; velocities = new float[tsc.Length]; accelerations = new float[tsc.Length]; ComputeAngles(tsc, calibrationHelper, trajs, angleOptions); ComputeVelocity(tsc, calibrationHelper); ComputeAcceleration(tsc, calibrationHelper); return(tsc); }
private void ComputeDistances(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper, Func <int, PointF> getCoord) { PointF o = getCoord(0); tsc[Kinematics.LinearDistance][0] = 0; tsc[Kinematics.LinearHorizontalDisplacement][0] = 0; tsc[Kinematics.LinearVerticalDisplacement][0] = 0; for (int i = 1; i < tsc.Length; i++) { PointF a = getCoord(i - 1); PointF b = getCoord(i); tsc[Kinematics.LinearDistance][i] = tsc[Kinematics.LinearDistance][i - 1] + GetDistance(a, b, Component.Magnitude); // FIXME. // Linear component displacement: X or Y offset but relative to the trajectory origin. // First we need to recompute the trajectory origin at the current time. tsc[Kinematics.LinearHorizontalDisplacement][i] = GetDistance(o, b, Component.Horizontal); tsc[Kinematics.LinearVerticalDisplacement][i] = GetDistance(o, b, Component.Vertical); } }
private void ComputeVelocities(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper, Func <int, PointF> getCoord) { if (tsc.Length <= 2) { PadVelocities(tsc); return; } for (int i = 1; i < tsc.Length - 1; i++) { PointF a = getCoord(i - 1); PointF b = getCoord(i + 1); float t = calibrationHelper.GetTime(2); tsc[Kinematics.LinearSpeed][i] = (double)calibrationHelper.ConvertSpeed(GetSpeed(a, b, t, Component.Magnitude)); tsc[Kinematics.LinearHorizontalVelocity][i] = (double)calibrationHelper.ConvertSpeed(GetSpeed(a, b, t, Component.Horizontal)); tsc[Kinematics.LinearVerticalVelocity][i] = (double)calibrationHelper.ConvertSpeed(GetSpeed(a, b, t, Component.Vertical)); } PadVelocities(tsc); // Second pass: apply extra smoothing to the derivatives. // This is only applied for high speed videos where the digitization is very noisy // due to the combination of increased time resolution and decreased spatial resolution. double constantVelocitySpan = 40; MovingAverage filter = new MovingAverage(); double[] averagedVelocity = filter.FilterSamples(tsc[Kinematics.LinearSpeed], calibrationHelper.CaptureFramesPerSecond, constantVelocitySpan, 1); double[] averagedHorizontalVelocity = filter.FilterSamples(tsc[Kinematics.LinearHorizontalVelocity], calibrationHelper.CaptureFramesPerSecond, constantVelocitySpan, 1); double[] averagedVerticalVelocity = filter.FilterSamples(tsc[Kinematics.LinearVerticalVelocity], calibrationHelper.CaptureFramesPerSecond, constantVelocitySpan, 1); for (int i = 0; i < tsc.Length; i++) { tsc[Kinematics.LinearSpeed][i] = averagedVelocity[i]; tsc[Kinematics.LinearHorizontalVelocity][i] = averagedHorizontalVelocity[i]; tsc[Kinematics.LinearVerticalVelocity][i] = averagedVerticalVelocity[i]; } }
private static void ImportAngleDrawingsData(Metadata metadata, List <TimeSeriesPlotData> timeSeriesData) { // Create three filtered trajectories named o, a, b directly based on the trackable points. foreach (DrawingAngle drawingAngle in metadata.Angles()) { Dictionary <string, FilteredTrajectory> trajs = new Dictionary <string, FilteredTrajectory>(); Dictionary <string, TrackablePoint> trackablePoints = metadata.TrackabilityManager.GetTrackablePoints(drawingAngle); bool tracked = true; foreach (string key in trackablePoints.Keys) { Timeline <TrackFrame> timeline = trackablePoints[key].Timeline; if (timeline.Count == 0) { tracked = false; break; } List <TimedPoint> samples = timeline.Enumerate().Select(p => new TimedPoint(p.Location.X, p.Location.Y, p.Time)).ToList(); FilteredTrajectory traj = new FilteredTrajectory(); traj.Initialize(samples, metadata.CalibrationHelper); trajs.Add(key, traj); } if (!tracked) { continue; } TimeSeriesCollection tsc = angularKinematics.BuildKinematics(trajs, drawingAngle.AngleOptions, metadata.CalibrationHelper); TimeSeriesPlotData data = new TimeSeriesPlotData(drawingAngle.Name, drawingAngle.Color, tsc); timeSeriesData.Add(data); } }
private void ComputeVelocity(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper) { if (tsc.Length <= 2) { PadVelocities(tsc); return; } for (int i = 1; i < tsc.Length - 1; i++) { float a1 = positions[i - 1]; float a2 = positions[i + 1]; float t = calibrationHelper.GetTime(2); float omega = (a2 - a1) / t; velocities[i] = omega; tsc[Kinematics.AngularVelocity][i] = (double)calibrationHelper.ConvertAngularVelocity(omega); float v = radii[i] * omega; tsc[Kinematics.TangentialVelocity][i] = (double)calibrationHelper.ConvertSpeed(v); } PadVelocities(tsc); }
private void PadVelocities(TimeSeriesCollection tsc) { TimeSeriesPadder.Pad(tsc[Kinematics.AngularVelocity], 1); TimeSeriesPadder.Pad(tsc[Kinematics.TangentialVelocity], 1); return; }
private void ComputeAngles(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper, Dictionary <string, FilteredTrajectory> trajs, AngleOptions angleOptions) { for (int i = 0; i < tsc.Length; i++) { PointF o = PointF.Empty; PointF a = PointF.Empty; PointF b = PointF.Empty; if (trajs["o"].CanFilter) { o = trajs["o"].Coordinates(i); a = trajs["a"].Coordinates(i); b = trajs["b"].Coordinates(i); } else { o = trajs["o"].RawCoordinates(i); a = trajs["a"].RawCoordinates(i); b = trajs["b"].RawCoordinates(i); } // Compute the actual angle value. The logic here should match the one in AngleHelper.Update(). // They work on different type of inputs so it's difficult to factorize the functions. if (angleOptions.Supplementary) { // Create a new point by point reflection of a around o. PointF c = new PointF(2 * o.X - a.X, 2 * o.Y - a.Y); a = b; b = c; } float angle = 0; if (angleOptions.CCW) { angle = GeometryHelper.GetAngle(o, a, b); } else { angle = GeometryHelper.GetAngle(o, b, a); } if (!angleOptions.Signed && angle < 0) { angle = (float)(TAU + angle); } positions[i] = angle; radii[i] = GeometryHelper.GetDistance(o, b); tsc[Kinematics.AngularPosition][i] = calibrationHelper.ConvertAngle(angle); if (i == 0) { tsc[Kinematics.AngularDisplacement][i] = 0; tsc[Kinematics.TotalAngularDisplacement][i] = 0; } else { float totalDisplacementAngle = angle - positions[0]; float displacementAngle = angle - positions[i - 1]; tsc[Kinematics.AngularDisplacement][i] = calibrationHelper.ConvertAngle(displacementAngle); tsc[Kinematics.TotalAngularDisplacement][i] = calibrationHelper.ConvertAngle(totalDisplacementAngle); } } }
private static void ImportCustomDrawingsData(Metadata metadata, List <TimeSeriesPlotData> timeSeriesData) { // Collect angular trajectories for all the angles in all the custom tools. foreach (DrawingGenericPosture drawing in metadata.GenericPostures()) { Dictionary <string, TrackablePoint> trackablePoints = metadata.TrackabilityManager.GetTrackablePoints(drawing); // First create trajectories for all the trackable points in the drawing. // This avoids duplicating the filtering operation for points shared by more than one angle. // Here the trajectories are indexed by the original alias in the custom tool, based on the index. Dictionary <string, FilteredTrajectory> trajs = new Dictionary <string, FilteredTrajectory>(); bool tracked = true; foreach (string key in trackablePoints.Keys) { Timeline <TrackFrame> timeline = trackablePoints[key].Timeline; if (timeline.Count == 0) { // The point is trackable but doesn't have any timeline data. // This happens if the user is not tracking that drawing, so we don't need to go further. tracked = false; break; } List <TimedPoint> samples = timeline.Enumerate().Select(p => new TimedPoint(p.Location.X, p.Location.Y, p.Time)).ToList(); FilteredTrajectory traj = new FilteredTrajectory(); traj.Initialize(samples, metadata.CalibrationHelper); trajs.Add(key, traj); } if (!tracked) { continue; } // Loop over all angles in this drawing and find the trackable aliases of the points making up the particular angle. // The final collection of trajectories for each angle should have indices named o, a, b. foreach (GenericPostureAngle gpa in drawing.GenericPostureAngles) { // From integer indices to tracking aliases. string keyO = gpa.Origin.ToString(); string keyA = gpa.Leg1.ToString(); string keyB = gpa.Leg2.ToString(); // All points in an angle must be trackable as there is currently no way to get the static point coordinate. if (!trajs.ContainsKey(keyO) || !trajs.ContainsKey(keyA) || !trajs.ContainsKey(keyB)) { continue; } // Remap to oab. Dictionary <string, FilteredTrajectory> angleTrajs = new Dictionary <string, FilteredTrajectory>(); angleTrajs.Add("o", trajs[keyO]); angleTrajs.Add("a", trajs[keyA]); angleTrajs.Add("b", trajs[keyB]); AngleOptions options = new AngleOptions(gpa.Signed, gpa.CCW, gpa.Supplementary); TimeSeriesCollection tsc = angularKinematics.BuildKinematics(angleTrajs, options, metadata.CalibrationHelper); string name = drawing.Name; if (!string.IsNullOrEmpty(gpa.Name)) { name = name + " - " + gpa.Name; } Color color = gpa.Color == Color.Transparent ? drawing.Color : gpa.Color; TimeSeriesPlotData data = new TimeSeriesPlotData(name, color, tsc); timeSeriesData.Add(data); } } }
public TimeSeriesPlotData(string label, Color color, TimeSeriesCollection timeSeriesCollection) { this.Label = label; this.Color = color; this.TimeSeriesCollection = timeSeriesCollection; }