Skip to content

Commit

Permalink
Getting track drawing to work after merge.
Browse files Browse the repository at this point in the history
Issue #297
  • Loading branch information
towsey committed Apr 16, 2020
1 parent b5d0400 commit f537c36
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 49 deletions.
8 changes: 4 additions & 4 deletions src/Acoustics.Shared/Interval.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@ public override int GetHashCode()
/// <returns>
/// String representation.
/// </returns>
public override string ToString()
{
return this.ToString(false);
}
//public override string ToString(string v)
//{
// return this.ToString(false);
//}

/// <summary>
/// Gets string representation of the Interval.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class HorizontalTrackParameters : CommonParameters
/// This method returns spectral peak tracks enclosed in acoustic events.
/// It averages dB log values incorrectly but it is faster than doing many log conversions.
/// </summary>
public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetSpectralPeakTracks(
public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetFowardTracks(
SpectrogramStandard sonogram,
int minHz,
int maxHz,
Expand All @@ -52,7 +52,6 @@ public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetSpectr
double binWidth = nyquist / (double)binCount;
int minBin = (int)Math.Round(minHz / binWidth);
int maxBin = (int)Math.Round(maxHz / binWidth);
int bandwidthBinCount = maxBin - minBin + 1;

var converter = new UnitConverters(
segmentStartOffset: segmentStartOffset.TotalSeconds,
Expand All @@ -61,10 +60,10 @@ public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetSpectr
frameOverlap: sonogram.Configuration.WindowOverlap);

//Find all spectral peaks and place in peaks matrix
var peaks = new double[frameCount, bandwidthBinCount];
var peaks = new double[frameCount, binCount];
for (int row = 0; row < frameCount; row++)
{
for (int col = minBin - 1; col < maxBin - 1; col++)
for (int col = minBin + 1; col < maxBin - 1; col++)
{
if (sonogramData[row, col] < decibelThreshold)
{
Expand All @@ -80,7 +79,7 @@ public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetSpectr
}
}

var tracks = TrackExtractor.GetHorizontalTracks(peaks, minDuration, maxDuration, decibelThreshold, converter);
var tracks = TrackExtractor.GetFowardTracks(peaks, minDuration, maxDuration, decibelThreshold, converter);

// initialise tracks as events and get the combined intensity array.
// list of accumulated acoustic events
Expand All @@ -96,7 +95,9 @@ public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetSpectr
events.Add(ae);

// fill the intensity array
var startRow = ae.Oblong.ColumnLeft;
//var startRow = ae.Oblong.ColumnLeft;
//var amplitudeTrack = track.GetAmplitudeOverTimeFrames();
var startRow = converter.FrameFromStartTime(track.StartTimeSeconds);
var amplitudeTrack = track.GetAmplitudeOverTimeFrames();
for (int i = 0; i < amplitudeTrack.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetVertic
var sonogramData = sonogram.Data;
int frameCount = sonogramData.GetLength(0);
int binCount = sonogramData.GetLength(1);
var frameDuration = sonogram.FrameDuration;
var frameStep = sonogram.FrameStep;

double binWidth = nyquist / (double)binCount;
Expand Down Expand Up @@ -93,10 +92,9 @@ public static (List<AcousticEvent> Events, double[] CombinedIntensity) GetVertic
}

//NOTE: the Peaks matrix is same size as the sonogram.
var tracks = TrackExtractor.GetVerticalTracks(peaks, maxBin, minBandwidthHertz, maxBandwidthHertz, decibelThreshold, converter);
var tracks = TrackExtractor.GetVerticalTracks(peaks, minBin, maxBin, minBandwidthHertz, maxBandwidthHertz, decibelThreshold, converter);

// initialise tracks as events and get the combined intensity array.
// list of accumulated acoustic events
var events = new List<AcousticEvent>();
var temporalIntensityArray = new double[frameCount];
foreach (var track in tracks)
Expand Down
2 changes: 1 addition & 1 deletion src/AnalysisPrograms/Recognizers/GenericRecognizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public override RecognizerResults Recognize(
else if (profileConfig is HorizontalTrackParameters tp)
{
double[] decibelArray;
(acousticEvents, decibelArray) = HorizontalTrackParameters.GetSpectralPeakTracks(
(acousticEvents, decibelArray) = HorizontalTrackParameters.GetFowardTracks(
sonogram,
tp.MinHertz.Value,
tp.MaxHertz.Value,
Expand Down
68 changes: 49 additions & 19 deletions src/AudioAnalysisTools/Events/Tracks/Track.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ namespace AudioAnalysisTools.Events.Tracks

public enum TrackType
{
Whistle,
HorizontalTrack,
VerticalTrack,
Click,
HorizontalTrack, // Sounds like single tone whistle. Each track point advances one time step. All points remain in the same frequency bin.
FowardTrack, // Sounds like fluctuating tone/chirp. Each track point advances one time step. Points may move up or down two frequency bins.
UpwardTrack, // Sounds like whip. Each track point ascends one frequency bin. Points may move forwards or back one frame step.
VerticalTrack, // Sounds like click. Each track point ascends one frequency bin. All points remain in the same time frame.
}

public class Track : ITrack
Expand Down Expand Up @@ -52,6 +52,8 @@ public Track(
}
}

public TrackType trackType { get; }

public int PointCount => this.Points.Count;

public double StartTimeSeconds => this.converter.SegmentStartOffset + this.Points.Min(x => x.Seconds.Minimum);
Expand Down Expand Up @@ -101,6 +103,38 @@ public void SetPoint(int frame, int bin, double amplitude)
this.Points.Add(point);
}

/// <summary>
/// Does a sanity check on the conversion of frame/bins to real values and back again.
/// </summary>
/// <param name="frame">The frame number.</param>
/// <param name="bin">The freq bin number.</param>
public string CheckPoint(int frame, int bin)
{
var secondsStart = this.converter.GetStartTimeInSecondsOfFrame(frame);
var hertzLow = this.converter.GetHertzFromFreqBin(bin);
double amplitude = 1.0; // a filler.

var point = new SpectralPoint(
(secondsStart, secondsStart + this.converter.SecondsPerFrame),
(hertzLow, hertzLow + this.converter.HertzPerFreqBin),
amplitude);

var outFrame = this.converter.FrameFromStartTime(point.Seconds.Minimum);
var outBin = this.converter.GetFreqBinFromHertz(point.Hertz.Minimum);
var info = new string($"In frame:{frame}, In bin:{bin}, SecondsStart:{point.Seconds.Minimum.ToString("0.000")}, HertzLow:{point.Hertz.Minimum:F3}, Out frame:{outFrame}, Out bin: {outBin}");

if (frame != outFrame || bin != outBin)
{
LoggedConsole.WriteWarnLine("WARNING" + info);
}
else
{
LoggedConsole.WriteLine(info);
}

return info;
}

/// <summary>
/// Returns an array that has the same number of time frames as the track.
/// Each element contains the highest frequency (Hertz) for that time frame.
Expand Down Expand Up @@ -174,30 +208,26 @@ public double[] GetAmplitudeOverTimeFrames()
/// The sorted collection is then used as a set of points to connect lines to.
/// </remarks>
public void Draw(IImageProcessingContext graphics, EventRenderingOptions options)
{
((IPointData)this).DrawPointsAsPath(graphics, options);
}

/*
public void DrawTrack<T>(Image<T> imageToReturn, double framesPerSecond, double freqBinWidth)
where T : unmanaged, IPixel<T>
{
switch (this.trackType)
{
case SpectralTrackType.VerticalTrack:
this.DrawVerticalTrack(imageToReturn);
case TrackType.UpwardTrack:
((IPointData)this).DrawPointsAsPath(graphics, options);
break;
case TrackType.HorizontalTrack:
((IPointData)this).DrawPointsAsPath(graphics, options);
break;
case SpectralTrackType.HorizontalTrack:
this.DrawHorizontalTrack(imageToReturn, framesPerSecond, freqBinWidth);
case TrackType.VerticalTrack:
((IPointData)this).DrawPointsAsPath(graphics, options);
break;
case SpectralTrackType.Whistle:
this.DrawWhistle(imageToReturn, framesPerSecond, freqBinWidth);
case TrackType.FowardTrack:
((IPointData)this).DrawPointsAsPath(graphics, options);
break;
default:
this.DrawDefaultTrack(imageToReturn, framesPerSecond, freqBinWidth);
//((IPointData)this).DrawPointsAsPath(graphics, options);
((IPointData)this).DrawPointsAsFill(graphics, options);
break;
}
}
*/
}
}
22 changes: 15 additions & 7 deletions src/AudioAnalysisTools/Events/Tracks/TrackExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace AudioAnalysisTools.Events.Tracks

public static class TrackExtractor
{
public static List<Track> GetHorizontalTracks(double[,] peaks, double minDuration, double maxDuration, double threshold, UnitConverters converter)
public static List<Track> GetFowardTracks(double[,] peaks, double minDuration, double maxDuration, double threshold, UnitConverters converter)
{
int frameCount = peaks.GetLength(0);
int bandwidthBinCount = peaks.GetLength(1);
Expand Down Expand Up @@ -121,25 +121,30 @@ public static Track GetHorizontalTrack(double[,] peaks, int startRow, int startB
}

track.SetPoint(row, bin, maxValue);

// next line is for debug purposes
var info = track.CheckPoint(row, bin);
}

return track;
}

public static List<Track> GetVerticalTracks(double[,] peaks, int maxBin, double minBandwidthHertz, double maxBandwidthHertz, double threshold, UnitConverters converter)
public static List<Track> GetVerticalTracks(double[,] peaks, int minBin, int maxBin, double minBandwidthHertz, double maxBandwidthHertz, double threshold, UnitConverters converter)
{
int frameCount = peaks.GetLength(0);
int bandwidthBinCount = peaks.GetLength(1);

var tracks = new List<Track>();

// Look for possible track starts and initialise as track.
// Cannot include edge rows & columns because of edge effects.
// Each row is a time frame which is a spectrum. Each column is a frequency bin
for (int row = 0; row < frameCount; row++)
{
for (int col = 3; col < bandwidthBinCount - 3; col++)
for (int col = minBin; col < maxBin; col++)
{
if (peaks[row, col] < threshold)
{
continue;
}

// Visit each spectral peak in order. Each may be start of possible track
var track = GetVerticalTrack(peaks, row, col, maxBin, threshold, converter);

Expand All @@ -166,7 +171,7 @@ public static Track GetVerticalTrack(double[,] peaks, int startRow, int startBin
for (int bin = startBin; bin < maxBin - 1; bin++)
{
// Avoid row edge effects.
if (row < 2 || row > peaks.GetLength(0) - 3)
if (row < 1 || row > peaks.GetLength(0) - 1)
{
// arrived back at start of recording or end of recording.
// The track has come to end
Expand Down Expand Up @@ -219,6 +224,9 @@ public static Track GetVerticalTrack(double[,] peaks, int startRow, int startBin
}

track.SetPoint(row, bin, maxValue);

// next line is for debug purposes
var info = track.CheckPoint(row, bin);
}

return track;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ public void TestHarmonicsAlgorithm()
}

[TestMethod]
public void TestSpectralPeakTracksAlgorithm()
public void TestFowardsTrackAlgorithm()
{
// Set up the recognizer parameters.
var windowSize = 512;
Expand Down Expand Up @@ -349,7 +349,7 @@ public void TestSpectralPeakTracksAlgorithm()
var plots = new List<Plot>();
double[] dBArray;
List<AcousticEvent> acousticEvents;
(acousticEvents, dBArray) = HorizontalTrackParameters.GetSpectralPeakTracks(
(acousticEvents, dBArray) = HorizontalTrackParameters.GetFowardTracks(
spectrogram,
minHertz,
maxHertz,
Expand Down Expand Up @@ -385,7 +385,7 @@ public void TestSpectralPeakTracksAlgorithm()

// DEBUG PURPOSES COMMENT NEXT LINE
var outputDirectory = new DirectoryInfo("C:\\temp");
GenericRecognizer.SaveDebugSpectrogram(allResults, null, outputDirectory, "track");
GenericRecognizer.SaveDebugSpectrogram(allResults, null, outputDirectory, "FowardsTrack");

Assert.AreEqual(23, allResults.Events.Count);

Expand Down Expand Up @@ -495,10 +495,10 @@ public void TestClickAlgorithm()
}

/// <summary>
/// This tests the vertical tracks recognizer on the same artifical spectrogram as used for spectral tracks and harmonics.
/// Tests the upwards-track recognizer on the same artifical spectrogram as used for fowards-tracks and harmonics.
/// </summary>
[TestMethod]
public void TestVerticalTrackAlgorithm()
public void TestUpwardsTrackAlgorithm()
{
// Set up the recognizer parameters.
var windowSize = 512;
Expand Down Expand Up @@ -579,14 +579,14 @@ public void TestVerticalTrackAlgorithm()
var @event = allResults.Events[0];
Assert.AreEqual(10.0, @event.EventStartSeconds, 0.1);
Assert.AreEqual(10.1, @event.EventEndSeconds, 0.1);
Assert.AreEqual(6460, @event.LowFrequencyHertz);
Assert.AreEqual(10724, @event.HighFrequencyHertz);
Assert.AreEqual(6450, @event.LowFrequencyHertz);
Assert.AreEqual(10750, @event.HighFrequencyHertz);

@event = allResults.Events[1];
Assert.AreEqual(11.0, @event.EventStartSeconds, 0.1);
Assert.AreEqual(11.24, @event.EventEndSeconds, 0.1);
Assert.AreEqual(6460, @event.LowFrequencyHertz);
Assert.AreEqual(7278, @event.HighFrequencyHertz);
Assert.AreEqual(6450, @event.LowFrequencyHertz);
Assert.AreEqual(7310, @event.HighFrequencyHertz);

// do a SECOND TEST of the vertical tracks
minHertz = 500;
Expand Down

0 comments on commit f537c36

Please sign in to comment.