From 1df70c59af5f41bd1d8c15137821d7dbeefb9979 Mon Sep 17 00:00:00 2001 From: towsey Date: Sat, 7 Mar 2020 19:31:22 +1000 Subject: [PATCH] Update AcousticEvent.cs Issue #300 Final debug of merge events. It now works correctly. --- src/AudioAnalysisTools/AcousticEvent.cs | 141 ++++++++++++++++-------- 1 file changed, 95 insertions(+), 46 deletions(-) diff --git a/src/AudioAnalysisTools/AcousticEvent.cs b/src/AudioAnalysisTools/AcousticEvent.cs index f13354e13..ebd3e7124 100644 --- a/src/AudioAnalysisTools/AcousticEvent.cs +++ b/src/AudioAnalysisTools/AcousticEvent.cs @@ -527,7 +527,7 @@ public AcousticEvent OverlapsEventInList(List events) /// public bool Overlaps(AcousticEvent ae) { - return EventsOverlap(this, ae); + return EventsOverlapInTime(this, ae); } /// @@ -565,54 +565,74 @@ public static double EventFractionalOverlap(AcousticEvent event1, AcousticEvent } /// - /// Determines if two events overlap in time or frequency or both. + /// Determines if two events overlap in frequency. /// /// event one. /// event two. /// true if events overlap. - public static bool EventsOverlap(AcousticEvent event1, AcousticEvent event2) + public static bool EventsOverlapInFrequency(AcousticEvent event1, AcousticEvent event2) { - var timeOverlap = false; - var freqOverlap = false; + //check if event 1 freq band overlaps event 2 freq band + if (event1.HighFrequencyHertz >= event2.LowFrequencyHertz && event1.HighFrequencyHertz <= event2.HighFrequencyHertz) + { + return true; + } + // check if event 1 freq band overlaps event 2 freq band + if (event1.LowFrequencyHertz >= event2.LowFrequencyHertz && event1.LowFrequencyHertz <= event2.HighFrequencyHertz) + { + return true; + } + + //check if event 2 freq band overlaps event 1 freq band + if (event2.HighFrequencyHertz >= event1.LowFrequencyHertz && event2.HighFrequencyHertz <= event1.HighFrequencyHertz) + { + return true; + } + + // check if event 2 freq band overlaps event 1 freq band + if (event2.LowFrequencyHertz >= event1.LowFrequencyHertz && event2.LowFrequencyHertz <= event1.HighFrequencyHertz) + { + return true; + } + + return false; + } + + /// + /// Determines if two events overlap in time. + /// + /// event one. + /// event two. + /// true if events overlap. + public static bool EventsOverlapInTime(AcousticEvent event1, AcousticEvent event2) + { //check if event 1 starts within event 2 if (event1.EventStartSeconds >= event2.EventStartSeconds && event1.EventStartSeconds <= event2.EventEndSeconds) { - timeOverlap = true; + return true; } // check if event 1 ends within event 2 if (event1.EventEndSeconds >= event2.EventStartSeconds && event1.EventEndSeconds <= event2.EventEndSeconds) { - timeOverlap = true; + return true; } // now check possibility that event2 is inside event1. //check if event 2 starts within event 1 if (event2.EventStartSeconds >= event1.EventStartSeconds && event2.EventStartSeconds <= event1.EventEndSeconds) { - timeOverlap = true; + return true; } // check if event 2 ends within event 1 if (event2.EventEndSeconds >= event1.EventStartSeconds && event2.EventEndSeconds <= event1.EventEndSeconds) { - timeOverlap = true; + return true; } - //check if event 1 freq band overlaps event 2 freq band - if (event1.HighFrequencyHertz >= event1.LowFrequencyHertz && event1.HighFrequencyHertz <= event2.HighFrequencyHertz) - { - freqOverlap = true; - } - - // check if event 1 freq band overlaps event 2 freq band - if (event1.LowFrequencyHertz >= event2.LowFrequencyHertz && event1.LowFrequencyHertz <= event2.HighFrequencyHertz) - { - freqOverlap = true; - } - - return timeOverlap && freqOverlap; + return false; } /// @@ -632,7 +652,7 @@ public static List CombineOverlappingEvents(List e { for (int j = i - 1; j >= 0; j--) { - if (EventsOverlap(events[i], events[j])) + if (EventsOverlapInTime(events[i], events[j]) && EventsOverlapInFrequency(events[i], events[j])) { events[j] = AcousticEvent.MergeTwoEvents(events[i], events[j], segmentStartWrtRecording); events.RemoveAt(i); @@ -662,16 +682,16 @@ public static AcousticEvent MergeTwoEvents(AcousticEvent e1, AcousticEvent e2, T //METHODS TO CONVERT BETWEEN FREQ BIN AND HERZ OR MELS /// - /// converts frequency bounds of an event to left and right columns of object in sonogram matrix - /// NOTE: binCount is required only if freq is in Mel scale + /// converts frequency bounds of an event to left and right columns of object in sonogram matrix. + /// NOTE: binCount is required only if freq is in Mel scale. /// - /// mel scale - /// lower freq bound - /// upper freq bound - /// Nyquist freq in Herz - /// frequency scale - /// return bin index for lower freq bound - /// return bin index for upper freq bound + /// mel scale. + /// lower freq bound. + /// upper freq bound. + /// Nyquist freq in Herz. + /// frequency scale. + /// return bin index for lower freq bound. + /// return bin index for upper freq bound. public static void Freq2BinIDs(bool doMelscale, int minFreq, int maxFreq, int nyquist, double binWidth, out int leftCol, out int rightCol) { if (doMelscale) @@ -839,8 +859,15 @@ public static Tuple, double, double, double, double[]> GetSe return tuple; } - public static Tuple, double, double, double, double[]> GetSegmentationEvents(SpectrogramStandard sonogram, TimeSpan segmentStartOffset, - int minHz, int maxHz, double smoothWindow, double thresholdSD, double minDuration, double maxDuration) + public static Tuple, double, double, double, double[]> GetSegmentationEvents( + SpectrogramStandard sonogram, + TimeSpan segmentStartOffset, + int minHz, + int maxHz, + double smoothWindow, + double thresholdSD, + double minDuration, + double maxDuration) { int nyquist = sonogram.SampleRate / 2; var tuple = SNR.SubbandIntensity_NoiseReduced(sonogram.Data, minHz, maxHz, nyquist, smoothWindow, sonogram.FramesPerSecond); @@ -964,7 +991,7 @@ public static void CalculateAccuracy(List results, List results, List results, List - public static void CalculateAccuracyOnOneRecording(List results, List labels, out int tp, out int fp, out int fn, - out double precision, out double recall, out double accuracy, out string resultsText) + public static void CalculateAccuracyOnOneRecording( + List results, + List labels, + out int tp, + out int fp, + out int fn, + out double precision, + out double recall, + out double accuracy, + out string resultsText) { //init values tp = 0; @@ -1087,7 +1127,12 @@ public static void CalculateAccuracyOnOneRecording(List results, fn++; line = string.Format( "False NEGATIVE: {0,4} {5,15} {1,6:f1} ...{2,6:f1} intensity={3} quality={4}", - count, ae.TimeStart, ae.TimeEnd, ae.Intensity, ae.Quality, ae.Name); + count, + ae.TimeStart, + ae.TimeEnd, + ae.Intensity, + ae.Quality, + ae.Name); sb.Append(line + "\t" + ae.FileName + "\n"); } } @@ -1113,7 +1158,7 @@ public static void CalculateAccuracyOnOneRecording(List results, accuracy = (precision + recall) / 2; resultsText = sb.ToString(); - } //end method + } //############################################################################################################################################## // THE NEXT THREE METHODS CONVERT BETWEEN SCORE ARRAYS AND ACOUSTIC EVENTS @@ -1138,17 +1183,20 @@ public static List ConvertIntensityArray2Events( double startTime = 0.0; int startFrame = 0; - for (int i = 0; i < count; i++) //pass over all frames + //pass over all frames + for (int i = 0; i < count; i++) { - if (isHit == false && values[i] > scoreThreshold) //start of an event + //start of an event + if (isHit == false && values[i] > scoreThreshold) { isHit = true; startTime = i * frameOffset; startFrame = i; } else //check for the end of an event - if (isHit && values[i] <= scoreThreshold) //this is end of an event, so initialise it + if (isHit && values[i] <= scoreThreshold) { + //this is end of an event, so initialise it isHit = false; double endTime = i * frameOffset; double duration = endTime - startTime; @@ -1159,9 +1207,10 @@ public static List ConvertIntensityArray2Events( continue; //skip events with duration shorter than threshold } - AcousticEvent ev = new AcousticEvent(segmentStartOffset, startTime, duration, minHz, maxHz); - - ev.Name = "Acoustic Segment"; //default name + AcousticEvent ev = new AcousticEvent(segmentStartOffset, startTime, duration, minHz, maxHz) + { + Name = "Acoustic Segment", //default name + }; ev.SetTimeAndFreqScales(framesPerSec, freqBinWidth); //obtain average intensity score.