Skip to content

Commit

Permalink
Rescaling of plot graphs for generic recogniser
Browse files Browse the repository at this point in the history
Fixes #469

Update MultiRecognizer.cs

Issue #469 Minor changes. Except change the FFT window from Hamming to Hanning.

Update DataToolsTests.cs

Issue #469 Add a new test method to check that the scaling of image plots is working.

Update GenericRecognizerTests.cs

Issue #469 Remove hard-coded path.

Update GenericRecognizer.cs

Issue #469 Add in code to rescale the plots to fit the current spectrogram.

Changed the signature to SpectrogramTools.GetSonogramPlusCharts()

Issue #469 Changed the signature to SpectrogramTools.GetSonogramPlusCharts() so that it also includes the title of the spectrogram. THis affected these 6 methods.

Rescaling of the plots happens here.

Issue #469 This is ensures that all plots are the same length as the last spectrogram.

Update SpectrogramTools.cs

Issue #469  Fix the drawing of spectrograms.

Update BlobEvent.cs

Issue #469 The plot was being added twice for Blob events. Removed one of them.

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.

Update Oscillations2019.cs

Issue #469 The main change is due to changing the signature of  the ConvertOscillationScores2Events() method

Update Oscillations2012.cs

Issue #469
1: Delete the GetOscillationFrequency() method
2: Change the way a new Oscillation event is initialised.

Update GenericRecognizerTests.cs

Issue #469 1: Write a new test method. Its original purpose was to satisfy Anthony's intention of having two profiles with different Windows. This was a way to get the plot scaling fixed. Unfortunately a lot of the functionality to do with the OscillationEvent class was not working. I used this test method to get it working.

Update OscillationEvent.cs

Issue #469 Rejig the calculation of the oscillation period to make it more accurate.

Adjust start and end time test results

Issue #469 1: Adjust event expected start and end times for test results involving oscillations. These adjustments brought about by tightening the bounds of an oscillation event.
2: Add periodicity result into the test. The periodicity is the property unique to oscillation events.

Update GenericRecognizerTests.cs

Issue #469 Change name of test method to match the profiles actually used.

Update GenericRecognizerTests.cs

Issue #469 Update name of the test method a third time! At present there is no method to convert type AcousticEvent directly to type BlobEvent. Only to type SpectralEvent.

Update GenericRecognizerTests.cs

Issue #469 Change name of profile to be consistent with Blob profile name.
  • Loading branch information
towsey authored and atruskie committed Jun 16, 2021
1 parent 5830fa3 commit 7a65f8f
Show file tree
Hide file tree
Showing 16 changed files with 352 additions and 165 deletions.
12 changes: 6 additions & 6 deletions src/AnalysisPrograms/Recognizers/Base/MultiRecognizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ public override RecognizerResults Recognize(AudioRecording audioRecording, Confi
MultiRecognizerConfig multiRecognizerConfig = (MultiRecognizerConfig)configuration;

// make a standard spectrogram in which to render acoustic events and to append score tracks
// currently using Hamming window. Worth trying Hanning Window
var config = new SonogramConfig
{
WindowSize = 512,
WindowFunction = WindowFunctions.HANNING.ToString(),
NoiseReductionType = NoiseReductionType.Standard,
NoiseReductionParameter = 0.1,
WindowSize = 512,
};
var sonogram = (BaseSonogram)new SpectrogramStandard(config, audioRecording.WavReader);

var spectrogram = (BaseSonogram)new SpectrogramStandard(config, audioRecording.WavReader);
var scoreTracks = new List<Image<Rgb24>>();
var plots = new List<Plot>();
var events = new List<AcousticEvent>();
Expand Down Expand Up @@ -103,8 +103,8 @@ public override RecognizerResults Recognize(AudioRecording audioRecording, Confi

newEvents.AddRange(output.NewEvents);

// rescale scale of plots
output.Plots.ForEach(p => p.ScaleDataArray(sonogram.FrameCount));
// rescale all the plots to fit the current spectrogram.
output.Plots.ForEach(p => p.ScaleDataArray(spectrogram.FrameCount));

plots.AddRange(output.Plots);
}
Expand All @@ -117,7 +117,7 @@ public override RecognizerResults Recognize(AudioRecording audioRecording, Confi
Events = events,
NewEvents = newEvents,
ScoreTrack = scoreTrackImage,
Sonogram = sonogram,
Sonogram = spectrogram,
Plots = plots,
Hits = null,
};
Expand Down
2 changes: 1 addition & 1 deletion src/AnalysisPrograms/Recognizers/Base/RecognizerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ protected virtual Image DrawSonogram(
List<EventCommon> predictedEvents,
double eventThreshold)
{
var image = SpectrogramTools.GetSonogramPlusCharts(sonogram, predictedEvents, scores, hits);
var image = SpectrogramTools.GetSonogramPlusCharts(sonogram, predictedEvents, scores, hits, sonogram.Configuration.SourceFName);
return image;
}

Expand Down
4 changes: 2 additions & 2 deletions src/AnalysisPrograms/Recognizers/Frogs/LitoriaFallax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private void WriteDebugImage(
bool displayDebugImage = MainEntry.InDEBUG;
if (displayDebugImage)
{
Image debugImage1 = SpectrogramTools.GetSonogramPlusCharts(sonogram, acousticEvents, plots, hits);
Image debugImage1 = SpectrogramTools.GetSonogramPlusCharts(sonogram, acousticEvents, plots, hits, sonogram.Configuration.SourceFName);
var debugPath1 =
outputDirectory.Combine(
FilenameHelpers.AnalysisResultName(
Expand Down Expand Up @@ -226,7 +226,7 @@ private void WriteDebugImage(
this.Identifier,
"png",
"DebugSpectrogram2"));
Image debugImage2 = SpectrogramTools.GetSonogramPlusCharts(sonogram2, acousticEvents, plots, null);
Image debugImage2 = SpectrogramTools.GetSonogramPlusCharts(sonogram2, acousticEvents, plots, null, sonogram.Configuration.SourceFName);
debugImage2.Save(debugPath2.FullName);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/AnalysisPrograms/Recognizers/Frogs/LitoriaFreycineti.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ private void WriteDebugImage(
bool displayDebugImage = MainEntry.InDEBUG;
if (displayDebugImage)
{
Image debugImage1 = SpectrogramTools.GetSonogramPlusCharts(sonogram, acousticEvents, plots, hits);
Image debugImage1 = SpectrogramTools.GetSonogramPlusCharts(sonogram, acousticEvents, plots, hits, sonogram.Configuration.SourceFName);
var debugPath1 =
outputDirectory.Combine(
FilenameHelpers.AnalysisResultName(
Expand Down Expand Up @@ -220,7 +220,7 @@ private void WriteDebugImage(
this.Identifier,
"png",
"DebugSpectrogram2"));
Image debugImage2 = SpectrogramTools.GetSonogramPlusCharts(sonogram2, acousticEvents, plots, null);
Image debugImage2 = SpectrogramTools.GetSonogramPlusCharts(sonogram2, acousticEvents, plots, null, sonogram2.Configuration.SourceFName);
debugImage2.Save(debugPath2.FullName);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/AnalysisPrograms/Recognizers/Frogs/LitoriaRothii.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public override RecognizerResults Recognize(AudioRecording recording, Config con
var lowPassPlot = new Plot("Low Pass", normalisedScores, normalisedThreshold);

var debugPlots = new List<Plot> { ampltdPlot, lowPassPlot, demeanedPlot, plot };
Image debugImage = SpectrogramTools.GetSonogramPlusCharts(sonogram, acousticEvents, debugPlots, null);
Image debugImage = SpectrogramTools.GetSonogramPlusCharts(sonogram, acousticEvents, debugPlots, null, sonogram.Configuration.SourceFName);
var debugPath = outputDirectory.Combine(FilenameHelpers.AnalysisResultName(Path.GetFileNameWithoutExtension(recording.BaseName), this.Identifier, "png", "DebugSpectrogram"));
debugImage.Save(debugPath.FullName);
}
Expand Down
12 changes: 10 additions & 2 deletions src/AnalysisPrograms/Recognizers/GenericRecognizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,13 @@ public static RecognizerResults RunProfiles(
}
}

// Rescale the plots in case profiles used different window/frame lengths.
var lastSpectrogram = combinedResults.Sonogram;
combinedResults.Plots.ForEach(plot =>
{
plot.ScaleDataArray(lastSpectrogram.FrameCount);
});

return combinedResults;
}

Expand Down Expand Up @@ -425,10 +432,11 @@ public static RecognizerResults RunOneProfile(
};

//add info about decibel threshold into the event.
//This info is used later during post-processing of events.
//This info is used later during post-processing of events and for drawing of events.
foreach (var ev in spectralEvents)
{
ev.DecibelDetectionThreshold = decibelThreshold.Value;
ev.SegmentDurationSeconds = spectrogram.Duration.TotalSeconds;
}

allResults.NewEvents.AddRange(spectralEvents);
Expand Down Expand Up @@ -459,7 +467,7 @@ public override void SummariseResults(
/// </summary>
public static string SaveDebugSpectrogram(RecognizerResults results, Config genericConfig, DirectoryInfo outputDirectory, string baseName)
{
var image3 = SpectrogramTools.GetSonogramPlusCharts(results.Sonogram, results.NewEvents, results.Plots, null);
var image3 = SpectrogramTools.GetSonogramPlusCharts(results.Sonogram, results.NewEvents, results.Plots, null, baseName);

var path = Path.Combine(outputDirectory.FullName, baseName + ".profile.png");
image3.Save(path);
Expand Down
3 changes: 1 addition & 2 deletions src/AnalysisPrograms/Recognizers/PteropusSpecies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,7 @@ internal static BaseSonogram GetSonogram(Config configuration, AudioRecording au
/// </summary>
internal static void SaveDebugSpectrogram(RecognizerResults results, Config genericConfig, DirectoryInfo outputDirectory, string baseName)
{
//var image = sonogram.GetImageFullyAnnotated("Test");
var image = SpectrogramTools.GetSonogramPlusCharts(results.Sonogram, results.Events, results.Plots, null);
var image = SpectrogramTools.GetSonogramPlusCharts(results.Sonogram, results.Events, results.Plots, null, results.Sonogram.Configuration.SourceFName);
image.Save(Path.Combine(outputDirectory.FullName, baseName + ".profile.png"));
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/AudioAnalysisTools/Events/Types/BlobEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ public static (List<EventCommon> Events, List<Plot> DecibelPlots) GetBlobEvents(

var events = acEvents.ConvertAcousticEventsToSpectralEvents();
spectralEvents.AddRange(events);
plots.Add(plot);

return (spectralEvents, plots);
}

Expand Down
83 changes: 76 additions & 7 deletions src/AudioAnalysisTools/Events/Types/OscillationEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
namespace AudioAnalysisTools
{
using System;
using System.Collections.Generic;
using AudioAnalysisTools.Events;
using AudioAnalysisTools.Events.Drawing;
using AudioAnalysisTools.StandardSpectrograms;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using TowseyLibrary;

public class OscillationEvent : SpectralEvent
{
Expand All @@ -17,17 +21,82 @@ public OscillationEvent()

// TODO: add extra metadata!!!

/// <summary>
/// Gets or sets the period in seconds between consecutive high points in an oscillation event.
/// </summary>
public double Periodicity { get; set; }

/// <summary>
/// Draws a border around this oscillation event.
/// </summary>
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);
}

/// <summary>
/// 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.
/// It a;sp returns the periodicity of the oscillation event.
/// </summary>
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<double>(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;

// determine the number of times the frame values step from below to above threshold.
// also the frame index in which the steps happen.
int stepCount = 0;
var peakOnsets = new List<int>();
for (int frame = 1; frame < frameAverages.Length; frame++)
{
if (frameAverages[frame - 1] < threshold && frameAverages[frame] >= threshold)
{
stepCount++;
peakOnsets.Add(frame);
}
}

//this.Track.Draw(graphics, options);
// calculate the length of a whole number of complete periods.
int framePeriods = peakOnsets[peakOnsets.Count - 1] - peakOnsets[0];
double framePeriod = framePeriods / (double)(stepCount - 1);

// base drawing (border)
// TODO: unless border is disabled
base.Draw(graphics, options);
return (trueStartFrame, trueEndFrame, framePeriod);
}
}
}
Loading

0 comments on commit 7a65f8f

Please sign in to comment.