From 59b256e4ed1e97f123a96e493c4d26f9c168f036 Mon Sep 17 00:00:00 2001 From: Anthony Truskinger Date: Tue, 12 May 2020 20:33:09 +1000 Subject: [PATCH] Fixes unit tests - removed that pesky -1 from DrawScoreIndicator. I worked out the order that the points are supplied to DrawLines is important and it affects offsets. - fixing the above also fixed unit tests for drawing spectral events - Fixed one bin track algorithm produces tracks of the wrong type - Restored AcousticEventTests and moved the tests for spectral events that were in that class to the proper class - Fixed a variety of other tests that were failing due to bad colors or bad coordinates --- .../Events/Drawing/EventDrawer.cs | 19 ++-- .../Events/Drawing/EventRenderingOptions.cs | 4 +- .../Events/Interfaces/IPointData.cs | 11 +-- src/AudioAnalysisTools/Scales/LinearScale.cs | 6 +- .../Tracks/ForwardTrackAlgorithm.cs | 2 +- .../Tracks/OnebinTrackAlgorithm.cs | 2 +- src/AudioAnalysisTools/Tracks/Track.cs | 4 +- .../AudioAnalysisTools/AcousticEventTests.cs | 99 +++++-------------- .../Events/BlobEventTest.cs | 14 ++- .../Events/CompositeEventTests.cs | 76 ++++++++++++++ .../Events/SpectralEventTest.cs | 51 ++++++++++ .../Events/Tracks/TrackTests.cs | 28 +----- .../Events/Tracks/TrackTestsDrawing.cs | 89 +++++++++++++---- tests/Acoustics.Test/TestHelpers/TestImage.cs | 14 ++- ...ticEventTests_SuperimposeEventsOnImage.png | 3 + .../EventTests_SuperimposeEventsOnImage.png | 4 +- 16 files changed, 272 insertions(+), 154 deletions(-) create mode 100644 tests/Acoustics.Test/AudioAnalysisTools/Events/CompositeEventTests.cs create mode 100644 tests/Fixtures/AcousticEventTests_SuperimposeEventsOnImage.png diff --git a/src/AudioAnalysisTools/Events/Drawing/EventDrawer.cs b/src/AudioAnalysisTools/Events/Drawing/EventDrawer.cs index fc8481447..6162f709a 100644 --- a/src/AudioAnalysisTools/Events/Drawing/EventDrawer.cs +++ b/src/AudioAnalysisTools/Events/Drawing/EventDrawer.cs @@ -19,7 +19,7 @@ public static class EventDrawer /// /// The event for which to draw the score indicator. /// The image context to draw to. - /// The event rendering optons to use. + /// The event rendering options to use. public static void DrawScoreIndicator(this SpectralEvent @event, IImageProcessingContext graphics, EventRenderingOptions options) { if (!options.DrawScore) @@ -27,21 +27,24 @@ public static void DrawScoreIndicator(this SpectralEvent @event, IImageProcessin return; } - var normalisedScore = @event.ScoreNormalized.Clamp(0, 1); + var normalizedScore = @event.ScoreNormalized.Clamp(0, 1); - if (normalisedScore == 0) + if (normalizedScore == 0 || double.IsNaN(normalizedScore)) { return; } var rect = options.Converters.GetPixelRectangle(@event); - var scaledHeight = (float)normalisedScore * rect.Height; + // truncate score bar to neatest whole pixel after scaling by height + var scaledHeight = (int)((float)normalizedScore * rect.Height); - graphics.NoAA().DrawLines( - options.Score, - new PointF(rect.Left, rect.Bottom - 1), // minus one is to bring bottom of score line within event frame. - new PointF(rect.Left, rect.Bottom - scaledHeight)); + var top = new PointF(rect.Left, rect.Bottom - scaledHeight); + var bottom = new PointF(rect.Left, rect.Bottom); + + // the order of the supplied points is important! + // DO NOT CHANGE + graphics.NoAA().DrawLines(options.Score, top, bottom); } public static void DrawEventLabel(this SpectralEvent @event, IImageProcessingContext graphics, EventRenderingOptions options) diff --git a/src/AudioAnalysisTools/Events/Drawing/EventRenderingOptions.cs b/src/AudioAnalysisTools/Events/Drawing/EventRenderingOptions.cs index 53e40801d..cc4b5cda1 100644 --- a/src/AudioAnalysisTools/Events/Drawing/EventRenderingOptions.cs +++ b/src/AudioAnalysisTools/Events/Drawing/EventRenderingOptions.cs @@ -73,9 +73,7 @@ public EventRenderingOptions(UnitConverters converters) public bool DrawScore { get; set; } = true; - /// - /// TODO Set this false for present time because text not drawing well. - /// + // TODO: Renable. Currently set to false because text not drawing well. public bool DrawLabel { get; set; } = false; } } \ No newline at end of file diff --git a/src/AudioAnalysisTools/Events/Interfaces/IPointData.cs b/src/AudioAnalysisTools/Events/Interfaces/IPointData.cs index 82d4b6d9b..ef2e22b71 100644 --- a/src/AudioAnalysisTools/Events/Interfaces/IPointData.cs +++ b/src/AudioAnalysisTools/Events/Interfaces/IPointData.cs @@ -80,13 +80,6 @@ public void DrawPointsAsFillExperiment(IImageProcessingContext graphics, EventRe foreach (var rect in rects) { graphics.Fill( - //new GraphicsOptions() - //{ - // BlendPercentage = 0.8f, - - // //ColorBlendingMode = PixelColorBlendingMode.Multiply, - // ColorBlendingMode = PixelColorBlendingMode.Overlay, - //}, options.FillOptions, options.Fill, rect); @@ -99,9 +92,11 @@ public void DrawPointsAsPath(IImageProcessingContext graphics, EventRenderingOpt { return; } + // visits each point once // assumes each point pair describes a line - // assumes a SortedSet is used (and that iteration order is signficant, unlike with HashSet) + // assumes a SortedSet is used (and that iteration order is significant, + // unlike with HashSet) // TODO: maybe add an orderby? var path = this .Points diff --git a/src/AudioAnalysisTools/Scales/LinearScale.cs b/src/AudioAnalysisTools/Scales/LinearScale.cs index d5d4263e8..7f06cb1a2 100644 --- a/src/AudioAnalysisTools/Scales/LinearScale.cs +++ b/src/AudioAnalysisTools/Scales/LinearScale.cs @@ -22,10 +22,10 @@ public class LinearScale /// /// Initializes a new instance of the class. /// - /// + /// /// Should be able to handle mapping a domain where x1 ≤ x < x2 /// to a range where y1 > y ≥ y2 (an inverted mapping). - /// + /// /// The range to consider the domain (the input). /// The range to consider the range (the output). public LinearScale((double Low, double High) domain, (double Low, double High) range) @@ -82,7 +82,7 @@ public double ToMagnitude(double xMagnitude) /// The equivalent domain value. public double From(double y) { - // TODO: optimised implementation is possible + // TODO: optimized implementation is possible var normal = (y - this.r1) / this.rd; var d = (normal * this.dd) + this.d1; return this.clamp ? d.Clamp(this.d1, this.d2) : d; diff --git a/src/AudioAnalysisTools/Tracks/ForwardTrackAlgorithm.cs b/src/AudioAnalysisTools/Tracks/ForwardTrackAlgorithm.cs index 2456e35c7..fc7002a1e 100644 --- a/src/AudioAnalysisTools/Tracks/ForwardTrackAlgorithm.cs +++ b/src/AudioAnalysisTools/Tracks/ForwardTrackAlgorithm.cs @@ -160,7 +160,7 @@ public static List GetForwardTracks(double[,] peaks, double minDuration, public static Track GetForwardTrack(double[,] peaks, int startRow, int startBin, double threshold, UnitConverters converter) { - var track = new Track(converter, Events.Tracks.TrackType.FowardTrack); + var track = new Track(converter, Events.Tracks.TrackType.ForwardTrack); track.SetPoint(startRow, startBin, peaks[startRow, startBin]); // set the start point in peaks matrix to zero to prevent return to this point. diff --git a/src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs b/src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs index 2b5b787fa..9e1b8d5df 100644 --- a/src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs +++ b/src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs @@ -172,7 +172,7 @@ public static List GetOnebinTracks(double[,] peaks, double minDuration, d public static Track GetOnebinTrack(double[,] peaks, int startRow, int bin, double threshold, UnitConverters converter) { - var track = new Track(converter, TrackType.FowardTrack); + var track = new Track(converter, TrackType.OneBinTrack); track.SetPoint(startRow, bin, peaks[startRow, bin]); // set the start point in peaks matrix to zero to prevent return to this point. diff --git a/src/AudioAnalysisTools/Tracks/Track.cs b/src/AudioAnalysisTools/Tracks/Track.cs index 377629287..3e2684695 100644 --- a/src/AudioAnalysisTools/Tracks/Track.cs +++ b/src/AudioAnalysisTools/Tracks/Track.cs @@ -28,7 +28,7 @@ public enum TrackType /// Each track point advances one time step. /// Points may move up or down two frequency bins. /// - FowardTrack, + ForwardTrack, /// /// Sounds like whip. @@ -291,7 +291,7 @@ public void Draw(IImageProcessingContext graphics, EventRenderingOptions options case TrackType.OneFrameTrack: ((IPointData)this).DrawPointsAsFillExperiment(graphics, options); break; - case TrackType.FowardTrack: + case TrackType.ForwardTrack: ((IPointData)this).DrawPointsAsFillExperiment(graphics, options); break; default: diff --git a/tests/Acoustics.Test/AudioAnalysisTools/AcousticEventTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/AcousticEventTests.cs index af2bb1910..45efe10f3 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/AcousticEventTests.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/AcousticEventTests.cs @@ -6,12 +6,10 @@ namespace Acoustics.Test.AudioAnalysisTools { using System; using System.Collections.Generic; - using System.Linq; using Acoustics.Shared.ImageSharp; using Acoustics.Test.TestHelpers; using global::AudioAnalysisTools; using global::AudioAnalysisTools.Events; - using global::AudioAnalysisTools.Events.Drawing; using global::AudioAnalysisTools.Events.Types; using Microsoft.VisualStudio.TestTools.UnitTesting; using SixLabors.ImageSharp; @@ -21,102 +19,51 @@ namespace Acoustics.Test.AudioAnalysisTools [TestClass] public class AcousticEventTests : GeneratedImageTest { - [TestMethod] - public void TestEventMerging() - { - // make a list of three events - var events = new List(); - var segmentStartTime = TimeSpan.FromSeconds(10); - var event1 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 11.0, eventEndRecordingRelative: 16.0, minFreq: 1000, maxFreq: 6000) - { - Name = "Event1", - Score = 1.0, - }; - - events.Add(event1); - - var event2 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 12.0, eventEndRecordingRelative: 15.0, minFreq: 1500, maxFreq: 8000) - { - Name = "Event2", - Score = 5.0, - }; - events.Add(event2); - - var event3 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 17.0, eventEndRecordingRelative: 19.0, minFreq: 1000, maxFreq: 8000) - { - Name = "Event3", - Score = 9.0, - }; - events.Add(event3); - - // combine Overlapping acoustic events - var newEvents = CompositeEvent.CombineOverlappingEvents(events: events.Cast().ToList()); - events = newEvents.Cast().ToList(); - - //require two events, the first being a composite of two events. - Assert.AreEqual(2, events.Count); - Assert.AreEqual(typeof(CompositeEvent), events[0].GetType()); - //################################################# WHY DOES FOLLOWING LINE NOT WORK???? - //Assert.AreEqual(2, events[0].ComponentCount); - - Assert.AreEqual(11.0, events[0].EventStartSeconds, 1E-4); - Assert.AreEqual(16.0, events[0].EventEndSeconds, 1E-4); - Assert.AreEqual(1000, events[0].LowFrequencyHertz); - Assert.AreEqual(8000, events[0].HighFrequencyHertz); - Assert.AreEqual(5.0, events[0].Score, 1E-4); - - Assert.AreEqual(typeof(SpectralEvent), events[1].GetType()); - Assert.AreEqual(17.0, events[1].EventStartSeconds, 1E-4); - Assert.AreEqual(19.0, events[1].EventEndSeconds, 1E-4); - Assert.AreEqual(1000, events[1].LowFrequencyHertz); - Assert.AreEqual(8000, events[1].HighFrequencyHertz); - Assert.AreEqual(9.0, events[1].Score, 1E-4); - } - [TestMethod] public void TestSonogramWithEventsOverlay() { // make a substitute sonogram image - var imageWidth = 100; - var imageHeight = 256; - var substituteSonogram = Drawing.NewImage(imageWidth, imageHeight, Color.Black); - - // set the time/freq scales - var segmentDuration = 10.0; //seconds - var nyquist = 11025; //Hertz + var substituteSonogram = Drawing.NewImage(100, 256, Color.Black); - // set a max score to normalise. - double maxScore = 10.0; + // make a list of events + var framesPerSecond = 10.0; + var freqBinWidth = 43.0664; + double maxPossibleScore = 10.0; - // make a list of two events - var events = new List(); - var segmentStartTime = TimeSpan.FromSeconds(10); - var event1 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 11.0, eventEndRecordingRelative: 16.0, minFreq: 1000, maxFreq: 8000) + var events = new List(); + var event1 = new AcousticEvent(segmentStartOffset: TimeSpan.Zero, eventStartSegmentRelative: 1.0, eventDuration: 5.0, minFreq: 1000, maxFreq: 8000) { - Score = 10.0 / maxScore, + Score = 10.0, Name = "Event1", + ScoreNormalised = 10.0 / maxPossibleScore, }; events.Add(event1); - var event2 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 17.0, eventEndRecordingRelative: 19.0, minFreq: 1000, maxFreq: 8000) + var event2 = new AcousticEvent(segmentStartOffset: TimeSpan.Zero, eventStartSegmentRelative: 7.0, eventDuration: 2.0, minFreq: 1000, maxFreq: 8000) { - Score = 1.0 / maxScore, + Score = 1.0, Name = "Event2", + ScoreNormalised = 1.0 / maxPossibleScore, }; events.Add(event2); - // now add events into the spectrogram image with score. - var options = new EventRenderingOptions(new UnitConverters(segmentStartTime.TotalSeconds, segmentDuration, nyquist, imageWidth, imageHeight)); - foreach (var ev in events) + // now add events into the spectrogram image. + // set color for the events + foreach (AcousticEvent ev in events) { // because we are testing placement of box not text. ev.Name = string.Empty; - substituteSonogram.Mutate(x => ev.Draw(x, options)); + ev.BorderColour = AcousticEvent.DefaultBorderColor; + ev.ScoreColour = AcousticEvent.DefaultScoreColor; + ev.DrawEvent(substituteSonogram, framesPerSecond, freqBinWidth, 256); } this.ActualImage = substituteSonogram; - var path = PathHelper.ResolveAssetPath("EventTests_SuperimposeEventsOnImage.png"); - this.ExpectedImage = Image.Load(path); + + // BUG: this asset is faulty. See https://github.com/QutEcoacoustics/audio-analysis/issues/300#issuecomment-601537263 + this.ExpectedImage = Image.Load( + PathHelper.ResolveAssetPath("AcousticEventTests_SuperimposeEventsOnImage.png")); + this.AssertImagesEqual(); } } diff --git a/tests/Acoustics.Test/AudioAnalysisTools/Events/BlobEventTest.cs b/tests/Acoustics.Test/AudioAnalysisTools/Events/BlobEventTest.cs index d3bfceb77..aeaf5879a 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/Events/BlobEventTest.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/Events/BlobEventTest.cs @@ -55,16 +55,17 @@ public void DrawTest() "; var p = PixelOperations.Instance.GetPixelBlender(new GraphicsOptions()); + var green = Color.FromRgba(0, 255, 0, 128); this.ExpectedImage = new TestImage(100, 100, Color.Black) .FillPattern(specification) // the point 5.1 seconds and 520 Hz should match 51, 48 .GoTo(51, 48) - .Fill(1, 1, p.Blend(Color.Black, Color.Red, 0.5f)) + .Fill(1, 1, p.Blend(Color.Black, green, 0.5f)) .GoTo(52, 49) - .Fill(2, 1, p.Blend(Color.Black, Color.Red, 0.5f)) + .Fill(2, 1, p.Blend(Color.Black, green, 0.5f)) .GoTo(12, 87) - .Fill(1, 1, p.Blend(Color.Black, Color.Red, 0.5f)) + .Fill(1, 1, p.Blend(Color.Black, green, 0.5f)) .Finish(); // BUG: with DrawPointsAsFill: overlaps are painted twice @@ -87,7 +88,12 @@ public void DrawTest() @event.Points.Add(new SpectralPoint((1.2, 1.3), (120, 130), 0.9)); - var options = new EventRenderingOptions(new UnitConverters(0, 10, 1000, 100, 100)); + var options = new EventRenderingOptions(new UnitConverters(0, 10, 1000, 100, 100)) + { + // disable the default blend to make testing easier + FillOptions = new GraphicsOptions(), + Fill = Brushes.Solid(green), + }; // act diff --git a/tests/Acoustics.Test/AudioAnalysisTools/Events/CompositeEventTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/Events/CompositeEventTests.cs new file mode 100644 index 000000000..c143e7f98 --- /dev/null +++ b/tests/Acoustics.Test/AudioAnalysisTools/Events/CompositeEventTests.cs @@ -0,0 +1,76 @@ +// +// 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.Events +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Acoustics.Shared.ImageSharp; + using Acoustics.Test.TestHelpers; + using global::AudioAnalysisTools; + using global::AudioAnalysisTools.Events; + using global::AudioAnalysisTools.Events.Drawing; + using global::AudioAnalysisTools.Events.Types; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SixLabors.ImageSharp; + using SixLabors.ImageSharp.PixelFormats; + using SixLabors.ImageSharp.Processing; + + [TestClass] + public class CompositeEventTests : GeneratedImageTest + { + [TestMethod] + public void TestEventMerging() + { + // make a list of three events + var events = new List(); + var segmentStartTime = TimeSpan.FromSeconds(10); + var event1 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 11.0, eventEndRecordingRelative: 16.0, minFreq: 1000, maxFreq: 6000) + { + Name = "Event1", + Score = 1.0, + }; + + events.Add(event1); + + var event2 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 12.0, eventEndRecordingRelative: 15.0, minFreq: 1500, maxFreq: 8000) + { + Name = "Event2", + Score = 5.0, + }; + events.Add(event2); + + var event3 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 17.0, eventEndRecordingRelative: 19.0, minFreq: 1000, maxFreq: 8000) + { + Name = "Event3", + Score = 9.0, + }; + events.Add(event3); + + // combine Overlapping acoustic events + var newEvents = CompositeEvent.CombineOverlappingEvents(events: events.Cast().ToList()); + events = newEvents.Cast().ToList(); + + //require two events, the first being a composite of two events. + Assert.AreEqual(2, events.Count); + Assert.AreEqual(typeof(CompositeEvent), events[0].GetType()); + + Assert.AreEqual(2, ((CompositeEvent)events[0]).ComponentEvents.Count); + + Assert.AreEqual(11.0, events[0].EventStartSeconds); + Assert.AreEqual(16.0, events[0].EventEndSeconds); + Assert.AreEqual(1000, events[0].LowFrequencyHertz); + Assert.AreEqual(8000, events[0].HighFrequencyHertz); + Assert.AreEqual(5.0, events[0].Score); + + Assert.AreEqual(typeof(SpectralEvent), events[1].GetType()); + Assert.AreEqual(17.0, events[1].EventStartSeconds); + Assert.AreEqual(19.0, events[1].EventEndSeconds); + Assert.AreEqual(1000, events[1].LowFrequencyHertz); + Assert.AreEqual(8000, events[1].HighFrequencyHertz); + Assert.AreEqual(9.0, events[1].Score); + } + } +} \ No newline at end of file diff --git a/tests/Acoustics.Test/AudioAnalysisTools/Events/SpectralEventTest.cs b/tests/Acoustics.Test/AudioAnalysisTools/Events/SpectralEventTest.cs index 7e69edf34..7a8af9e59 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/Events/SpectralEventTest.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/Events/SpectralEventTest.cs @@ -4,6 +4,8 @@ namespace Acoustics.Test.AudioAnalysisTools.Events { + using System; + using System.Collections.Generic; using Acoustics.Shared.ImageSharp; using Acoustics.Test.Shared.Drawing; using Acoustics.Test.TestHelpers; @@ -67,5 +69,54 @@ public void DrawTest() // assert this.AssertImagesEqual(); } + + [TestMethod] + public void TestSonogramWithEventsOverlay() + { + // make a substitute sonogram image + var imageWidth = 100; + var imageHeight = 256; + var substituteSonogram = Drawing.NewImage(imageWidth, imageHeight, Color.Black); + + // set the time/freq scales + var segmentDuration = 10.0; //seconds + var nyquist = 11025; //Hertz + + // set a max score to normalize. + double maxScore = 10.0; + + // make a list of two events + var events = new List(); + var segmentStartTime = TimeSpan.FromSeconds(10); + var event1 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 11.0, eventEndRecordingRelative: 16.0, minFreq: 1000, maxFreq: 8000) + { + Score = 10.0, + ScoreRange = (0, maxScore), + Name = "Event1", + }; + + events.Add(event1); + var event2 = new SpectralEvent(segmentStartOffset: segmentStartTime, eventStartRecordingRelative: 17.0, eventEndRecordingRelative: 19.0, minFreq: 1000, maxFreq: 8000) + { + Score = 1.0, + ScoreRange = (0, maxScore), + Name = "Event2", + }; + events.Add(event2); + + // now add events into the spectrogram image with score. + var options = new EventRenderingOptions(new UnitConverters(segmentStartTime.TotalSeconds, segmentDuration, nyquist, imageWidth, imageHeight)); + foreach (var ev in events) + { + // because we are testing placement of box not text. + ev.Name = string.Empty; + substituteSonogram.Mutate(x => ev.Draw(x, options)); + } + + this.ActualImage = substituteSonogram; + var path = PathHelper.ResolveAssetPath("EventTests_SuperimposeEventsOnImage.png"); + this.ExpectedImage = Image.Load(path); + this.AssertImagesEqual(); + } } } diff --git a/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTests.cs index b78d9c2aa..809df9ddc 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTests.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTests.cs @@ -26,39 +26,15 @@ public class TrackTests /// Get a track that is diagonal, increasing one unit /// both in time and frequency for each subsequent point. /// - public static readonly Track TestTrack_TimePositive_FrequencyPositive = + private static readonly Track TestTrack_TimePositive_FrequencyPositive = new Track( NiceTestConverter, - TrackType.FowardTrack, + TrackType.ForwardTrack, (5, 5, 1), (6, 6, 2), (7, 7, 3), (8, 8, 4), (9, 9, 5)); - - public static readonly Track TestTrack_Whistle = - new Track( - NiceTestConverter, - TrackType.OneBinTrack, - (5, 5, 1), - (6, 5, 2), - (7, 5, 3), - (8, 5, 4), - (9, 5, 5)); - - public static readonly Track TestTrack_ChevronRight = - new Track( - NiceTestConverter, - TrackType.FowardTrack, - (5, 5, 1), - (6, 6, 2), - (7, 7, 3), - (8, 8, 4), - (9, 9, 5), - (8, 10, 6), - (7, 11, 7), - (6, 12, 8), - (5, 13, 9)); #pragma warning restore SA1310 // Field names should not contain underscore [TestMethod] diff --git a/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTestsDrawing.cs b/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTestsDrawing.cs index 31a952fe3..b13e749f8 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTestsDrawing.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/Events/Tracks/TrackTestsDrawing.cs @@ -8,6 +8,7 @@ namespace Acoustics.Test.AudioAnalysisTools.Events.Tracks using Acoustics.Test.TestHelpers; using global::AudioAnalysisTools; using global::AudioAnalysisTools.Events.Drawing; + using global::AudioAnalysisTools.Events.Tracks; using Microsoft.VisualStudio.TestTools.UnitTesting; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -23,13 +24,63 @@ public class TrackTestsDrawing : GeneratedImageTest public static readonly UnitConverters ScaledUnitConverters = new UnitConverters( segmentStartOffset: 60, - segmentDuration: ImageSize * 0.05, + segmentDuration: ImageSize * 0.1, nyquistFrequency: ImageSize * 10, imageWidth: ImageSize, imageHeight: ImageSize); public static readonly EventRenderingOptions Options = new EventRenderingOptions(ScaledUnitConverters); + /// + /// Each frame is 100 Hz, each bin is 0.1 seconds. + /// + public static readonly UnitConverters NiceTestConverter = + new UnitConverters( + segmentStartOffset: 60, + sampleRate: 1000, + frameSize: 100, + frameOverlap: 0.0); + +#pragma warning disable SA1310 // Field names should not contain underscore + /// + /// Get a track that is diagonal, increasing one unit + /// both in time and frequency for each subsequent point. + /// + public static readonly Track TestTrack_TimePositive_FrequencyPositive = + new Track( + NiceTestConverter, + TrackType.ForwardTrack, + (5, 5, 1), + (6, 6, 2), + (7, 7, 3), + (8, 8, 4), + (9, 9, 5)); + + public static readonly Track TestTrack_Whistle = + new Track( + NiceTestConverter, + TrackType.OneBinTrack, + (5, 5, 1), + (6, 5, 2), + (7, 5, 3), + (8, 5, 4), + (9, 5, 5)); + + public static readonly Track TestTrack_ChevronRight = + new Track( + NiceTestConverter, + TrackType.ForwardTrack, + (5, 5, 1), + (6, 6, 2), + (7, 7, 3), + (8, 8, 4), + (9, 9, 5), + (8, 10, 6), + (7, 11, 7), + (6, 12, 8), + (5, 13, 9)); +#pragma warning restore SA1310 // Field names should not contain underscore + private const int ImageSize = 15; [TestMethod("Test draw ↗")] @@ -41,11 +92,11 @@ public void TestDrawUpRight() ............... ............... ............... -.........R..... -........R...... -.......R....... -......R........ -.....R......... +.........G..... +........G...... +.......G....... +......G........ +.....G......... ............... ............... ............... @@ -55,7 +106,7 @@ public void TestDrawUpRight() this.ExpectedImage = TestImage.Create(ImageSize, ImageSize, Color.Black, specification); this.ActualImage = Drawing.NewImage(ImageSize, ImageSize, Color.Black); - this.ActualImage.Mutate(x => TrackTests.TestTrack_TimePositive_FrequencyPositive.Draw(x, Options)); + this.ActualImage.Mutate(x => TestTrack_TimePositive_FrequencyPositive.Draw(x, Options)); this.AssertImagesEqual(); } @@ -73,7 +124,7 @@ public void TestDrawRight() ............... ............... ............... -.....RRRRR..... +.....GGGGG..... ............... ............... ............... @@ -83,7 +134,7 @@ public void TestDrawRight() this.ExpectedImage = TestImage.Create(ImageSize, ImageSize, Color.Black, specification); this.ActualImage = Drawing.NewImage(ImageSize, ImageSize, Color.Black); - this.ActualImage.Mutate(x => TrackTests.TestTrack_Whistle.Draw(x, Options)); + this.ActualImage.Mutate(x => TestTrack_Whistle.Draw(x, Options)); this.AssertImagesEqual(); } @@ -93,15 +144,15 @@ public void TestDrawChevronRight() { var specification = @" ............... -.....R......... -......R........ -.......R....... -........R...... -.........R..... -........R...... -.......R....... -......R........ -.....R......... +.....G......... +......G........ +.......G....... +........G...... +.........G..... +........G...... +.......G....... +......G........ +.....G......... ............... ............... ............... @@ -111,7 +162,7 @@ public void TestDrawChevronRight() this.ExpectedImage = TestImage.Create(ImageSize, ImageSize, Color.Black, specification); this.ActualImage = Drawing.NewImage(ImageSize, ImageSize, Color.Black); - this.ActualImage.Mutate(x => TrackTests.TestTrack_TimePositive_FrequencyPositive.Draw(x, Options)); + this.ActualImage.Mutate(x => TestTrack_ChevronRight.Draw(x, Options)); this.AssertImagesEqual(); } diff --git a/tests/Acoustics.Test/TestHelpers/TestImage.cs b/tests/Acoustics.Test/TestHelpers/TestImage.cs index 2463a8c35..12307efc7 100644 --- a/tests/Acoustics.Test/TestHelpers/TestImage.cs +++ b/tests/Acoustics.Test/TestHelpers/TestImage.cs @@ -52,7 +52,19 @@ public static Image Create(int width, int height, Color color, string spe return new TestImage(width, height, specification, color).Finish(); } - public Point Cursor { get; private set; } + public static bool AddKnownColor(char symbol, Color color) + { + if (KnownColors.ContainsKey(symbol)) + { + return false; + } + + KnownColors.Add(symbol, color); + return true; + } + + public Point Cursor + { get; private set; } public TestImage FillPattern(string specification, Color? defaultBackground = null) { diff --git a/tests/Fixtures/AcousticEventTests_SuperimposeEventsOnImage.png b/tests/Fixtures/AcousticEventTests_SuperimposeEventsOnImage.png new file mode 100644 index 000000000..f5c3aaa79 --- /dev/null +++ b/tests/Fixtures/AcousticEventTests_SuperimposeEventsOnImage.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db09b16c1b9f94bbf5fe03b1f73c6a1f1da06c419867309ef1b1e1c08f3bd4a6 +size 700 diff --git a/tests/Fixtures/EventTests_SuperimposeEventsOnImage.png b/tests/Fixtures/EventTests_SuperimposeEventsOnImage.png index e02d405b7..f138a5eed 100644 --- a/tests/Fixtures/EventTests_SuperimposeEventsOnImage.png +++ b/tests/Fixtures/EventTests_SuperimposeEventsOnImage.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de2a6beaed6df83b2670f10a0eccb54f862d62ff46d97fd8dda7baac61cc55b2 -size 674 +oid sha256:38a818a9ce7e2c5e30eecea474c2c28c0fe24c303be8ccad12a0ff4597bdf512 +size 543