From b3cf451cd1841ace34e285622c5ab1c3901f72ba Mon Sep 17 00:00:00 2001 From: towsey Date: Sat, 7 Mar 2020 07:58:25 +1000 Subject: [PATCH] Unit tests for drawing events on sonograms Issue #300 Unit tests for drawing events on sonograms Make unit test for drawing a matrix of scores over a spectrogram. Shift unit test EventStatisticsCalculateTests to a new namespace of tests for acoustic events. Create new class of tests for acoustic events. --- .../EventStatisticsCalculateTests.cs | 11 +- .../AcousticEvents/EventTests.cs | 157 ++++++++++++++++++ .../StandardSpectrograms/SonogramTests.cs | 22 +-- 3 files changed, 174 insertions(+), 16 deletions(-) rename tests/Acoustics.Test/AudioAnalysisTools/{EventStatistics => AcousticEvents}/EventStatisticsCalculateTests.cs (95%) create mode 100644 tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventTests.cs diff --git a/tests/Acoustics.Test/AudioAnalysisTools/EventStatistics/EventStatisticsCalculateTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventStatisticsCalculateTests.cs similarity index 95% rename from tests/Acoustics.Test/AudioAnalysisTools/EventStatistics/EventStatisticsCalculateTests.cs rename to tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventStatisticsCalculateTests.cs index f43c73762..eb912ab9b 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/EventStatistics/EventStatisticsCalculateTests.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventStatisticsCalculateTests.cs @@ -2,7 +2,7 @@ // All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group). // -namespace Acoustics.Test.AudioAnalysisTools.EventStatistics +namespace Acoustics.Test.AudioAnalysisTools.AcousticEvents { using System; using Acoustics.Shared; @@ -16,11 +16,10 @@ namespace Acoustics.Test.AudioAnalysisTools.EventStatistics [TestClass] public class EventStatisticsCalculateTests { - [TestMethod] public void TestCalculateEventStatistics() { - int sampleRate = 22050; + var sampleRate = 22050; double duration = 28; int[] harmonics1 = { 500 }; int[] harmonics2 = { 500, 1000, 2000, 4000, 8000 }; @@ -37,8 +36,8 @@ public void TestCalculateEventStatistics() var start = TimeSpan.FromSeconds(28) + segmentOffset; var end = TimeSpan.FromSeconds(32) + segmentOffset; - double lowFreq = 1500.0; - double topFreq = 8500.0; + var lowFreq = 1500.0; + var topFreq = 8500.0; var statsConfig = new EventStatisticsConfiguration() { @@ -46,7 +45,7 @@ public void TestCalculateEventStatistics() FrameStep = 512, }; - EventStatistics stats = + var stats = EventStatisticsCalculate.AnalyzeAudioEvent( recording, (start, end).AsRange(), diff --git a/tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventTests.cs new file mode 100644 index 000000000..18cd37773 --- /dev/null +++ b/tests/Acoustics.Test/AudioAnalysisTools/AcousticEvents/EventTests.cs @@ -0,0 +1,157 @@ +// +// All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group). +// + +namespace Acoustics.Test.AudioAnalysisTools.EventStatistics +{ + using System; + using System.Collections.Generic; + using Acoustics.Shared; + using Acoustics.Tools.Wav; + using global::AudioAnalysisTools; + using global::AudioAnalysisTools.DSP; + using global::AudioAnalysisTools.EventStatistics; + using global::AudioAnalysisTools.WavTools; + using global::TowseyLibrary; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SixLabors.ImageSharp; + using SixLabors.ImageSharp.PixelFormats; + + [TestClass] + public class EventTests + { + [TestMethod] + public void TestEventMerging() + { + // make a list of events + var events = new List(); + + var segmentStartOffset = TimeSpan.Zero; + double maxPossibleScore = 10.0; + var startTime1 = 1.0; + var duration1 = 5.0; + var minHz1 = 1000; + var maxHz1 = 8000; + var event1 = new AcousticEvent(segmentStartOffset, startTime1, duration1, minHz1, maxHz1) + { + Name = "Event1", + Score = 1.0, + ScoreNormalised = 1.0 / maxPossibleScore, + }; + + events.Add(event1); + + var startTime2 = 4.5; + var duration2 = 2.0; + var minHz2 = 1500; + var maxHz2 = 6000; + var event2 = new AcousticEvent(segmentStartOffset, startTime2, duration2, minHz2, maxHz2) + { + Name = "Event2", + Score = 5.0, + ScoreNormalised = 5.0 / maxPossibleScore, + }; + events.Add(event2); + + var startTime3 = 7.0; + var duration3 = 2.0; + var minHz3 = 1000; + var maxHz3 = 8000; + var event3 = new AcousticEvent(segmentStartOffset, startTime3, duration3, minHz3, maxHz3) + { + Name = "Event3", + Score = 9.0, + ScoreNormalised = 9.0 / maxPossibleScore, + }; + events.Add(event3); + + // combine adjacent acoustic events + events = AcousticEvent.CombineOverlappingEvents(events, segmentStartOffset); + + Assert.AreEqual(2, events.Count); + Assert.AreEqual(1.0, events[0].EventStartSeconds, 1E-4); + Assert.AreEqual(6.5, events[0].EventEndSeconds, 1E-4); + Assert.AreEqual(7.0, events[1].EventStartSeconds, 1E-4); + Assert.AreEqual(9.0, events[1].EventEndSeconds, 1E-4); + + Assert.AreEqual(1000, events[0].LowFrequencyHertz); + Assert.AreEqual(8000, events[0].HighFrequencyHertz); + Assert.AreEqual(1000, events[1].LowFrequencyHertz); + Assert.AreEqual(8000, events[1].HighFrequencyHertz); + + Assert.AreEqual(5.0, events[0].Score, 1E-4); + Assert.AreEqual(9.0, events[1].Score, 1E-4); + Assert.AreEqual(0.5, events[0].ScoreNormalised, 1E-4); + Assert.AreEqual(0.9, events[1].ScoreNormalised, 1E-4); + } + + [TestMethod] + public void TestSonogramWithEventsOverlay() + { + // make a substitute sonogram image + int width = 100; + int height = 256; + var substituteSonogram = new Image(width, height); + + //substituteSonogram.Mutate(x => x.Pad(width, height, Color.Gray)); + // image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2)); + + // make a list of events + var framesPerSecond = 10.0; + var freqBinWidth = 43.0664; + var segmentStartOffset = TimeSpan.Zero; + var minHz = 1000; + var maxHz = 8000; + double maxPossibleScore = 10.0; + + var events = new List(); + var startTime1 = 1.0; + var duration1 = 5.0; + var event1 = new AcousticEvent(segmentStartOffset, startTime1, duration1, minHz, maxHz) + { + Score = 10.0, + Name = "Event1", + ScoreNormalised = 10.0 / maxPossibleScore, + }; + + events.Add(event1); + var startTime2 = 7.0; + var duration2 = 2.0; + var event2 = new AcousticEvent(segmentStartOffset, startTime2, duration2, minHz, maxHz) + { + Score = 1.0, + Name = "Event2", + ScoreNormalised = 1.0 / maxPossibleScore, + }; + events.Add(event2); + + // now add events into the spectrogram image. + // set colour for the events + foreach (AcousticEvent ev in events) + { + ev.BorderColour = AcousticEvent.DefaultBorderColor; + ev.ScoreColour = AcousticEvent.DefaultScoreColor; + ev.DrawEvent(substituteSonogram, framesPerSecond, freqBinWidth, height); + } + + //substituteSonogram.Save("C:\\temp\\image.png"); + var redPixel1 = new Argb32(110, 10, 30); + var expectedRed1 = new Color(redPixel1); + var redPixel2 = new Argb32(124, 11, 34); + var expectedRed2 = new Color(redPixel2); + var greenPixel = new Argb32(55, 133, 15); + var expectedGreen = new Color(greenPixel); + + //var actualColor = substituteSonogram[0, height - 1]; + Assert.AreEqual(expectedRed1, substituteSonogram[61, 119]); + Assert.AreEqual(expectedRed1, substituteSonogram[70, 122]); + Assert.AreEqual(expectedRed1, substituteSonogram[91, 181]); + Assert.AreEqual(expectedRed2, substituteSonogram[36, 233]); + Assert.AreEqual(expectedRed1, substituteSonogram[56, 69]); + + //actualColor = substituteSonogram[9, 72]; + Assert.AreEqual(expectedGreen, substituteSonogram[9, 72]); + Assert.AreEqual(expectedGreen, substituteSonogram[69, 217]); + } + } +} diff --git a/tests/Acoustics.Test/AudioAnalysisTools/StandardSpectrograms/SonogramTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/StandardSpectrograms/SonogramTests.cs index 9681809b2..b35ee9f63 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/StandardSpectrograms/SonogramTests.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/StandardSpectrograms/SonogramTests.cs @@ -18,6 +18,7 @@ namespace Acoustics.Test.AudioAnalysisTools.StandardSpectrograms using Microsoft.VisualStudio.TestTools.UnitTesting; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; + using SixLabors.ImageSharp.Processing; using Path = System.IO.Path; /// @@ -91,7 +92,7 @@ public void Cleanup() /// /// METHOD TO CHECK that averaging of decibel values is working. /// var array = new[] { 96.0, 100.0, 90.0, 97.0 }; - /// The return value should = 96.98816759 dB + /// The return value should = 96.98816759 dB. /// [TestMethod] public void TestAverageOfDecibelValues() @@ -225,18 +226,19 @@ public void TestAnnotatedSonogramWithPlots() public void TestSonogramHitsOverlay() { int width = 100; - int height = 50; + int height = 256; - // make a pretend sonogram image + // make a substitute sonogram image var pretendSonogram = new Image(width, height); - // make a pretend hits matrix with crossed diagonals + // make a hits matrix with crossed diagonals var hitsMatrix = new int[height, width]; - for (int i = 0; i < width; i++) + for (int i = 0; i < height; i++) { - int intensity = (int)Math.Floor(i / (double)width * 255); - hitsMatrix[i / 2, i] = intensity; - hitsMatrix[i / 2, width - i - 1] = intensity; + int col = (int)Math.Floor(width * i / (double)height); + int intensity = col; + hitsMatrix[i, col] = i; + hitsMatrix[i, width - col - 1] = i; } // now add in hits to the spectrogram image. @@ -246,12 +248,12 @@ public void TestSonogramHitsOverlay() } //pretendSonogram.Save("C:\\temp\\image.png"); - var pixel = new Argb32(252, 0, 0); + var pixel = new Argb32(255, 0, 0); var expectedColor = new Color(pixel); var actualColor = pretendSonogram[0, height - 1]; Assert.AreEqual(expectedColor, actualColor); - pixel = new Argb32(127, 0, 0); + pixel = new Argb32(128, 0, 0); expectedColor = new Color(pixel); actualColor = pretendSonogram[width / 2, height / 2]; Assert.AreEqual(expectedColor, actualColor);