Skip to content

Commit

Permalink
Fixes unit tests
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
atruskie committed May 12, 2020
1 parent 10df97a commit 59b256e
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 154 deletions.
19 changes: 11 additions & 8 deletions src/AudioAnalysisTools/Events/Drawing/EventDrawer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,32 @@ public static class EventDrawer
/// </summary>
/// <param name="event">The event for which to draw the score indicator.</param>
/// <param name="graphics">The image context to draw to.</param>
/// <param name="options">The event rendering optons to use.</param>
/// <param name="options">The event rendering options to use.</param>
public static void DrawScoreIndicator(this SpectralEvent @event, IImageProcessingContext graphics, EventRenderingOptions options)
{
if (!options.DrawScore)
{
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ public EventRenderingOptions(UnitConverters converters)

public bool DrawScore { get; set; } = true;

/// <summary>
/// TODO Set this false for present time because text not drawing well.
/// </summary>
// TODO: Renable. Currently set to false because text not drawing well.
public bool DrawLabel { get; set; } = false;
}
}
11 changes: 3 additions & 8 deletions src/AudioAnalysisTools/Events/Interfaces/IPointData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/AudioAnalysisTools/Scales/LinearScale.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ public class LinearScale
/// <summary>
/// Initializes a new instance of the <see cref="LinearScale"/> class.
/// </summary>
/// <remakrs>
/// <remarks>
/// Should be able to handle mapping a domain where x1 ≤ x &lt; x2
/// to a range where y1 > y ≥ y2 (an inverted mapping).
/// </remakrs>
/// </remarks>
/// <param name="domain">The range to consider the domain (the input).</param>
/// <param name="range">The range to consider the range (the output).</param>
public LinearScale((double Low, double High) domain, (double Low, double High) range)
Expand Down Expand Up @@ -82,7 +82,7 @@ public double ToMagnitude(double xMagnitude)
/// <returns>The equivalent domain value.</returns>
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;
Expand Down
2 changes: 1 addition & 1 deletion src/AudioAnalysisTools/Tracks/ForwardTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public static List<Track> 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.
Expand Down
2 changes: 1 addition & 1 deletion src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public static List<Track> 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.
Expand Down
4 changes: 2 additions & 2 deletions src/AudioAnalysisTools/Tracks/Track.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public enum TrackType
/// Each track point advances one time step.
/// Points may move up or down two frequency bins.
/// </summary>
FowardTrack,
ForwardTrack,

/// <summary>
/// Sounds like whip.
Expand Down Expand Up @@ -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:
Expand Down
99 changes: 23 additions & 76 deletions tests/Acoustics.Test/AudioAnalysisTools/AcousticEventTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,102 +19,51 @@ namespace Acoustics.Test.AudioAnalysisTools
[TestClass]
public class AcousticEventTests : GeneratedImageTest<Rgb24>
{
[TestMethod]
public void TestEventMerging()
{
// make a list of three events
var events = new List<SpectralEvent>();
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<EventCommon>().ToList());
events = newEvents.Cast<SpectralEvent>().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<SpectralEvent>();
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<AcousticEvent>();
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<Rgb24>(path);

// BUG: this asset is faulty. See https://github.com/QutEcoacoustics/audio-analysis/issues/300#issuecomment-601537263
this.ExpectedImage = Image.Load<Rgb24>(
PathHelper.ResolveAssetPath("AcousticEventTests_SuperimposeEventsOnImage.png"));

this.AssertImagesEqual();
}
}
Expand Down
14 changes: 10 additions & 4 deletions tests/Acoustics.Test/AudioAnalysisTools/Events/BlobEventTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,17 @@ public void DrawTest()
";
var p = PixelOperations<Rgb24>.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
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// <copyright file="CompositeEventTests.cs" company="QutEcoacoustics">
// 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).
// </copyright>

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<Rgb24>
{
[TestMethod]
public void TestEventMerging()
{
// make a list of three events
var events = new List<SpectralEvent>();
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<EventCommon>().ToList());
events = newEvents.Cast<SpectralEvent>().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);
}
}
}
Loading

0 comments on commit 59b256e

Please sign in to comment.