From b6e14d4e6b3b171c2140be5fdb12e32bbc69c453 Mon Sep 17 00:00:00 2001 From: towsey Date: Mon, 14 Jun 2021 17:20:09 +1000 Subject: [PATCH] Update OscillationEvent.cs Issue #469 1: Added the Periodicity Property to the Oscillation Event class. 2: Fixed the Draw() method for Oscillation events. The events were not drawing. 3: Added a method to trim Oscillation events using the decibel values as a guide to where the true bounds should be. --- .../Events/Types/OscillationEvent.cs | 77 +++++++++++++++++-- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs b/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs index bf4e2b7f1..f25522c9c 100644 --- a/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs +++ b/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs @@ -7,7 +7,10 @@ namespace AudioAnalysisTools using System; using AudioAnalysisTools.Events; using AudioAnalysisTools.Events.Drawing; + using AudioAnalysisTools.StandardSpectrograms; + using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; + using TowseyLibrary; public class OscillationEvent : SpectralEvent { @@ -15,19 +18,79 @@ public OscillationEvent() { } + /// + /// Gets or sets the period in seconds between consecutive oscillations. + /// + public double Periodicity { get; set; } + // TODO: add extra metadata!!! + /// + /// Draws a border around this oscillation event. + /// public override void Draw(IImageProcessingContext graphics, EventRenderingOptions options) { - // foreach (var track in tracks) { - // track.Draw(...) - // } + if (options.DrawBorder) + { + var border = options.Converters.GetPixelRectangle(this); + graphics.NoAA().DrawBorderInset(options.Border, border); + } + + this.DrawScoreIndicator(graphics, options); + this.DrawEventLabel(graphics, options); + } + + /// + /// Extracts an event from a spectrogram given its bounds. + /// Then trims the event because oscillation events do not typically start where the DCT places them. + /// + public static (int EventStart, int EventEnd, double FramePeriod) TrimEvent(SpectrogramStandard spectrogram, int startFrame, int minBin, int endFrame, int maxBin) + { + //obtain the oscillation event's periodicity. + //extract the relevant portion of the spectrogram. + var eventMatrix = MatrixTools.Submatrix(spectrogram.Data, startFrame, minBin, endFrame, maxBin); + var frameAverages = MatrixTools.GetRowAverages(eventMatrix); + frameAverages = DataTools.normalise(frameAverages); + double threshold = 0.25; + + // find the true start frame + int startFrameOffset = 0; + for (int frame = 1; frame < frameAverages.Length; frame++) + { + startFrameOffset++; + if (frameAverages[frame - 1] < threshold && frameAverages[frame] >= threshold) + { + break; + } + } + + int endFrameOffset = 0; + for (int frame = frameAverages.Length - 1; frame >= 0; frame--) + { + endFrameOffset++; + if (frameAverages[frame - 1] >= threshold && frameAverages[frame] < threshold) + { + break; + } + } + + int trueStartFrame = startFrame + startFrameOffset; + int trueEndFrame = endFrame - endFrameOffset; + int trueFrameLength = trueEndFrame - trueStartFrame + 1; + + // determine the number of times the frame values step from below to above average. + int stepCount = 0; + for (int frame = 1; frame < frameAverages.Length; frame++) + { + if (frameAverages[frame - 1] < threshold && frameAverages[frame] >= threshold) + { + stepCount++; + } + } - //this.Track.Draw(graphics, options); + double framePeriod = trueFrameLength / (double)stepCount; - // base drawing (border) - // TODO: unless border is disabled - base.Draw(graphics, options); + return (trueStartFrame, trueEndFrame, framePeriod); } } } \ No newline at end of file