Skip to content

Commit

Permalink
Work on reducing false positives in whistle recognizers.
Browse files Browse the repository at this point in the history
Issue #297
  • Loading branch information
towsey committed May 6, 2020
1 parent 09ee175 commit 5fa7cfb
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ Profiles:
# min and max of the freq band to search
MinHertz: 100
MaxHertz: 200
MinDuration: 0.3
MinDuration: 0.2
MaxDuration: 1.0
DecibelThreshold: 3.0

#Combine each pair of Boobook syllables as one event
#CombineProximalSimilarEvents: false
CombinePossibleSyllableSequence: true
CombinePossibleSyllableSequence: false
SyllableStartDifference: 3.0
SyllableHertzGap: 100

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ public override RecognizerResults Recognize(
// Combine overlapping events. If the dB threshold is set low, may get lots of little events.
var events = combinedResults.NewEvents;
var spectralEvents = events.Select(x => (SpectralEvent)x).ToList();
var newEvents = CompositeEvent.CombineOverlappingEvents(spectralEvents.Cast<EventCommon>().ToList());
//var newEvents = CompositeEvent.CombineOverlappingEvents(chirpEvents.Cast<EventCommon>().ToList());

var newEvents = spectralEvents.Cast<EventCommon>().ToList();
//var newEvents = CompositeEvent.CombineOverlappingEvents(spectralEvents.Cast<EventCommon>().ToList());

if (genericConfig.CombinePossibleSyllableSequence)
{
Expand All @@ -116,7 +117,7 @@ public override RecognizerResults Recognize(
{
var eventDuration = ((SpectralEvent)ev).EventEndSeconds - ev.EventStartSeconds;
var eventBandWidth = ((SpectralEvent)ev).BandWidthHertz;
if (eventDuration > 2.0 && eventDuration < 11.0 && eventBandWidth > 50)
if (eventDuration > 0.0 && eventDuration < 11.0 && eventBandWidth > 50)
{
filteredEvents.Add(ev);
}
Expand Down
68 changes: 68 additions & 0 deletions src/AudioAnalysisTools/Events/Types/WhistleEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace AudioAnalysisTools
using AudioAnalysisTools.Events.Drawing;
using AudioAnalysisTools.Events.Interfaces;
using AudioAnalysisTools.Events.Tracks;
using AudioAnalysisTools.Events.Types;
using SixLabors.ImageSharp.Processing;

public class WhistleEvent : SpectralEvent, ITracks<Track>
Expand Down Expand Up @@ -62,5 +63,72 @@ public override void Draw(IImageProcessingContext graphics, EventRenderingOption
// TODO: unless border is disabled
base.Draw(graphics, options);
}

public static List<EventCommon> CombineAdjacentWhistleEvents(List<WhistleEvent> events, double hertzDifference)
{
if (events.Count < 2)
{
return events.Cast<EventCommon>().ToList();
}

//var whistleEvents = new List<EventCommon>();
for (int i = events.Count - 1; i >= 0; i--)
{
for (int j = i - 1; j >= 0; j--)
{
var a = events[i] as WhistleEvent;
var b = events[j] as WhistleEvent;

bool eventsOverlapInTime = CompositeEvent.EventsOverlapInTime(a, b);
bool eventsAreInSimilarFreqBand = Math.Abs(a.LowFrequencyHertz - b.HighFrequencyHertz) < hertzDifference || Math.Abs(a.HighFrequencyHertz - b.LowFrequencyHertz) < hertzDifference;
if (eventsOverlapInTime && eventsAreInSimilarFreqBand)
{
var newEvent = MergeTwoWhistleEvents(a, b);
events[j] = newEvent;
events.RemoveAt(i);
break;
}
}
}

return events.Cast<EventCommon>().ToList();
}

/// <summary>
/// Merges two whistle events into one event.
/// </summary>
/// <param name="e1">first event.</param>
/// <param name="e2">second event.</param>
/// <returns>a composite event.</returns>
public static WhistleEvent MergeTwoWhistleEvents(WhistleEvent e1, WhistleEvent e2)
{
// Assume that we only merge events that are in the same recording segment.
// Therefore the value of segmentStartOffset and SegmentDurationSeconds are same for both events.
var track1 = e1.Tracks.First();
var track2 = e2.Tracks.First();

foreach (var point in track2.Points)
{
track1.Points.Add(point);
}

var newEvent = new WhistleEvent(track1, 1.0)
{
Name = e1.Name,
EventEndSeconds = Math.Max(e1.EventEndSeconds, e2.EventEndSeconds),
EventStartSeconds = Math.Min(e1.EventStartSeconds, e2.EventStartSeconds),
HighFrequencyHertz = Math.Max(e1.EventEndSeconds, e2.EventEndSeconds),
LowFrequencyHertz = Math.Max(e1.EventEndSeconds, e2.EventEndSeconds),
Score = e1.Score,
ScoreRange = e1.ScoreRange,
SegmentDurationSeconds = e1.SegmentDurationSeconds,
SegmentStartSeconds = e1.SegmentStartSeconds,
FileName = e1.FileName,
};

newEvent.ResultStartSeconds = e1.EventStartSeconds;

return newEvent;
}
}
}
49 changes: 32 additions & 17 deletions src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ namespace AudioAnalysisTools.Tracks
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AnalysisPrograms.Recognizers.Base;
using AudioAnalysisTools.Events;
using AudioAnalysisTools.Events.Tracks;
using AudioAnalysisTools.StandardSpectrograms;
using TowseyLibrary;
using TrackType = AudioAnalysisTools.Events.Tracks.TrackType;

public static class OnebinTrackAlgorithm
Expand All @@ -35,9 +37,6 @@ public static (List<EventCommon> ListOfevents, double[] CombinedIntensityArray)
double minDuration = parameters.MinDuration.Value;
double maxDuration = parameters.MaxDuration.Value;

// May not want to do this for whistles.
// bool combinePossibleSequence,

var converter = new UnitConverters(
segmentStartOffset: segmentStartOffset.TotalSeconds,
sampleRate: sonogram.SampleRate,
Expand Down Expand Up @@ -78,17 +77,38 @@ public static (List<EventCommon> ListOfevents, double[] CombinedIntensityArray)

var tracks = GetOnebinTracks(peaks, minDuration, maxDuration, decibelThreshold, converter);

// initialise tracks as events and get the combined intensity array.
var events = new List<EventCommon>();
// Initialise tracks as events and get the combined intensity array.
var events = new List<WhistleEvent>();
var combinedIntensityArray = new double[frameCount];
var maxScore = decibelThreshold * 5;
foreach (var track in tracks)
{
// Now check the buffer zone above the whistle.
// It should not contain high acoustic content.
var bufferHertz = 300;
var bufferBins = (int)Math.Round(bufferHertz / binWidth);

var bottomBufferBin = converter.GetFreqBinFromHertz(track.HighFreqHertz) + 5;
var topBufferBin = bottomBufferBin + bufferBins;
var frameStart = converter.FrameFromStartTime(track.StartTimeSeconds);
var frameEnd = converter.FrameFromStartTime(track.EndTimeSeconds);
var subMatrix = MatrixTools.Submatrix<double>(sonogramData, frameStart, bottomBufferBin, frameEnd, topBufferBin);
var averageRowDecibels = MatrixTools.GetRowAverages(subMatrix);
var av = averageRowDecibels.Average();

Console.WriteLine($"###################################Buffer Average decibels = {av}");
if (av > decibelThreshold)
{
// There is too much acoustic activity in the buffer zone.
// This is unlikely to be a whistle.
continue;
}

var ae = new WhistleEvent(track, maxScore)
{
SegmentStartSeconds = segmentStartOffset.TotalSeconds,
SegmentDurationSeconds = frameCount * converter.SecondsPerFrameStep,
Name = "noName",
Name = "Whistle",
};

events.Add(ae);
Expand All @@ -102,17 +122,12 @@ public static (List<EventCommon> ListOfevents, double[] CombinedIntensityArray)
}
}

// MAY NOT WANT TO DO THIS FOR WHISTLES.
// Combine possible related events. This will help in some cases.
//var startDifference = TimeSpan.FromSeconds(0.5);
//var hertzGap = 100;
//if (combinePossibleSequence)
// {
//################################################################################TODO TODO
//events = AcousticEvent.CombineSimilarProximalEvents(events, startDifference, hertzGap);
//}

return (events, combinedIntensityArray);
// This algorithm tends to produce temporally overlapped whistle events in adjacent channels.
// Combine overlapping whistle events
var hertzDifference = 2 * binWidth;
var whistleEvents = WhistleEvent.CombineAdjacentWhistleEvents(events, hertzDifference);

return (whistleEvents, combinedIntensityArray);
}

/// <summary>
Expand Down

0 comments on commit 5fa7cfb

Please sign in to comment.