Skip to content

Commit

Permalink
Stub out initial recogniser files for NSW DPI project
Browse files Browse the repository at this point in the history
Also added a generic recogniser template snippet that helps generate the boiler plate.
  • Loading branch information
atruskie committed Apr 9, 2021
1 parent 17a6c1c commit 7f29c61
Show file tree
Hide file tree
Showing 23 changed files with 783 additions and 267 deletions.
18 changes: 10 additions & 8 deletions src/Acoustics.Shared/Meta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,16 @@ public static class Meta

private static Assembly[] ourAssemblies;

public static string BinaryName(bool isSelfContained)
{
var extension = isSelfContained ? string.Empty : ".dll";
return AppConfigHelper.IsWindows ? Name : "AnalysisPrograms" + extension;
}

public static string Organization { get; } = "QUT";

public static string Website { get; } = "http://research.ecosounds.org/";
public static string Website { get; } = "https://ap.qut.ecoacoustics.info/";

public static string OrganizationTag => CopyrightSymbol + " " + NowYear + " " + Organization;

public static string Repository { get; } = "https://github.com/QutBioacoustics/audio-analysis";

public static string DebuggingHelp => GetDocsUrl("technical/debugging.html");

internal static Assembly[] QutAssemblies
{
get
Expand All @@ -64,9 +60,15 @@ internal static Assembly[] QutAssemblies
}
}

public static string BinaryName(bool isSelfContained)
{
var extension = isSelfContained ? string.Empty : ".dll";
return AppConfigHelper.IsWindows ? Name : "AnalysisPrograms" + extension;
}

public static string GetDocsUrl(string page)
{
return $"{Repository}/blob/master/docs/{page}";
return $"{Website}/{page}";
}

public static IEnumerable<TypeInfo> GetTypesFromQutAssemblies<T>()
Expand Down
48 changes: 48 additions & 0 deletions src/AnalysisBase/Citation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// <copyright file="Citation.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 AnalysisBase
{
using System;
using System.Collections.Generic;
using Acoustics.Shared;

public record Citation(IReadOnlyCollection<Author> Authors, string Title, string Project, string Uri);

public record Author(string FirstName, string LastName, string Affiliation, params string[] OtherNames);

public interface ICiteable
{
public IReadOnlyCollection<Citation> Citations => Array.Empty<Citation>();
}

public static class Bibliography
{
public static Author Anthony => new Author("Anthony", "Truskinger", "QUT Ecoacoustics");

public static Author Michael => new Author("Michael", "Towsey", "QUT Ecoacoustics");

public static Author Paul => new Author("Paul", "Roe", "QUT Ecoacoustics");

public static Author Kristen => new Author("Kristen", "Thompson", "NSW DPI");

public static Author Brad => new Author("Brad", "Law", "NSW DPI");

public static IReadOnlyCollection<Author> BuiltByAnthony => new[] { Anthony, Kristen, Michael, Paul, Brad };

public static IReadOnlyCollection<Author> BuiltByMichael => new[] { Michael, Kristen, Anthony, Paul, Brad };

public static Citation NswDpiRecognisersProject => new Citation(
Array.Empty<Author>(),
string.Empty,
"Recogniser project with NSW DPI: grant xxxx",
string.Empty);

public static Citation QutEcoacousticsProject => new Citation(
Array.Empty<Author>(),
string.Empty,
$"Recognizers devdeloped for various projects by {Meta.GroupName}",
Meta.Website);
}
}
2 changes: 1 addition & 1 deletion src/AnalysisBase/IAnalyser2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace AnalysisBase
/// This is a strong typed version of <c>IAnalyser</c> intentionally removed from the old inheritance tree.
/// DO NOT MODIFY THIS FILE UNLESS INSTRUCTED TO!.
/// </summary>
public interface IAnalyser2
public interface IAnalyser2 : ICiteable, IHasStatus
{
/// <summary>
/// Gets the name to display for the analysis.
Expand Down
18 changes: 18 additions & 0 deletions src/AnalysisBase/IHasStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IAnalyser2.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>
// <summary>
// Interface a compatible analysis must implement.
// This is a strong typed version of <c>IAnalyser</c> intentionally removed from the old inheritance tree.
// DO NOT MODIFY THIS FILE UNLESS INSTRUCTED TO!
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace AnalysisBase
{
public interface IHasStatus
{
public Status Status => Status.Unknown;
}
}
24 changes: 24 additions & 0 deletions src/AnalysisBase/Status.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IAnalyser2.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>
// <summary>
// Interface a compatible analysis must implement.
// This is a strong typed version of <c>IAnalyser</c> intentionally removed from the old inheritance tree.
// DO NOT MODIFY THIS FILE UNLESS INSTRUCTED TO!
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace AnalysisBase
{
public enum Status
{
Unknown = 0,
InDevelopment,
Alpha,
Beta,
Maintained,
Unmaintained,
Retired,
}
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
2 changes: 1 addition & 1 deletion src/AnalysisPrograms/Production/MainEntryUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ internal static void AttachDebugger(DebugOptions options)
var prompt =
$@"Do you wish to debug?
Attach now or press [Y] and [ENTER] to attach. Press [N] or [ENTER] to continue.
See {Meta.GetDocsUrl("debugging.md")} for help.";
See {Meta.DebuggingHelp} for help.";

var response = Prompt.GetYesNo(
prompt,
Expand Down
90 changes: 47 additions & 43 deletions src/AnalysisPrograms/Recognizers/Base/RecognizerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,12 @@ namespace AnalysisPrograms.Recognizers.Base

public abstract class RecognizerBase : AbstractStrongAnalyser, IEventRecognizer
{
public class RecognizerConfig : AnalyzerConfig
{
public RecognizerConfig()
{
this.Loaded += config =>
{
var file = ConfigFile.Resolve(this.HighResolutionIndicesConfig ?? "Towsey.Acoustic.HiResIndicesForRecognisers.yml");
var indicesConfig = ConfigFile.Deserialize<AcousticIndices.AcousticIndicesConfig>(file);
this.HighResolutionIndices = indicesConfig;
};
}

public string HighResolutionIndicesConfig { get; set; }

public AcousticIndices.AcousticIndicesConfig HighResolutionIndices { get; private set; }
}

public abstract string Author { get; }

public abstract string SpeciesName { get; }

public abstract string CommonName { get; }

public override string Identifier => this.Author + "." + this.SpeciesName;

public override string DisplayName => this.SpeciesName;
Expand All @@ -65,6 +50,42 @@ public RecognizerConfig()
AnalysisTargetSampleRate = AppConfigHelper.DefaultTargetSampleRate,
};

public static Image<Rgb24> DrawDebugImage(BaseSonogram sonogram, List<AcousticEvent> events, List<Plot> scores, double[,] hits)
{
const bool doHighlightSubband = false;
const bool add1KHzLines = true;
var image = new Image_MultiTrack(sonogram.GetImage(doHighlightSubband, add1KHzLines, doMelScale: false));

image.AddTrack(ImageTrack.GetTimeTrack(sonogram.Duration, sonogram.FramesPerSecond));
if (scores != null)
{
foreach (var plot in scores)
{
// assumes data normalised in 0,1
image.AddTrack(ImageTrack.GetNamedScoreTrack(plot.data, 0.0, 1.0, plot.threshold, plot.title));
}
}

if (hits != null)
{
image.OverlayRainbowTransparency(hits);
}

if (events.Count > 0)
{
// set colour for the events
foreach (var ev in events)
{
ev.BorderColour = AcousticEvent.DefaultBorderColor;
ev.ScoreColour = AcousticEvent.DefaultScoreColor;
}

image.AddEvents(events, sonogram.NyquistFrequency, sonogram.Configuration.FreqBinCount, sonogram.FramesPerSecond);
}

return image.GetImage().CloneAs<Rgb24>();
}

public override AnalyzerConfig ParseConfig(FileInfo file)
{
return ConfigFile.Deserialize<RecognizerConfig>(file);
Expand Down Expand Up @@ -411,38 +432,21 @@ IndexCalculateResult[] Callback()
return new Lazy<IndexCalculateResult[]>(Callback, LazyThreadSafetyMode.ExecutionAndPublication);
}

public static Image<Rgb24> DrawDebugImage(BaseSonogram sonogram, List<AcousticEvent> events, List<Plot> scores, double[,] hits)
public class RecognizerConfig : AnalyzerConfig
{
const bool doHighlightSubband = false;
const bool add1KHzLines = true;
var image = new Image_MultiTrack(sonogram.GetImage(doHighlightSubband, add1KHzLines, doMelScale: false));

image.AddTrack(ImageTrack.GetTimeTrack(sonogram.Duration, sonogram.FramesPerSecond));
if (scores != null)
public RecognizerConfig()
{
foreach (var plot in scores)
this.Loaded += config =>
{
image.AddTrack(ImageTrack.GetNamedScoreTrack(plot.data, 0.0, 1.0, plot.threshold, plot.title)); //assumes data normalised in 0,1
}
var file = ConfigFile.Resolve(this.HighResolutionIndicesConfig ?? "Towsey.Acoustic.HiResIndicesForRecognisers.yml");
var indicesConfig = ConfigFile.Deserialize<AcousticIndices.AcousticIndicesConfig>(file);
this.HighResolutionIndices = indicesConfig;
};
}

if (hits != null)
{
image.OverlayRainbowTransparency(hits);
}

if (events.Count > 0)
{
foreach (var ev in events) // set colour for the events
{
ev.BorderColour = AcousticEvent.DefaultBorderColor;
ev.ScoreColour = AcousticEvent.DefaultScoreColor;
}

image.AddEvents(events, sonogram.NyquistFrequency, sonogram.Configuration.FreqBinCount, sonogram.FramesPerSecond);
}
public string HighResolutionIndicesConfig { get; set; }

return image.GetImage().CloneAs<Rgb24>();
public AcousticIndices.AcousticIndicesConfig HighResolutionIndices { get; private set; }
}
}
}
85 changes: 85 additions & 0 deletions src/AnalysisPrograms/Recognizers/Birds/NinoxConnivens.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// <copyright file="NinoxConnivens.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 AnalysisPrograms.Recognizers.Birds
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using Acoustics.Shared.ConfigFile;
using AnalysisBase;
using AnalysisPrograms.Recognizers.Base;
using AudioAnalysisTools.Indices;
using AudioAnalysisTools.WavTools;
using log4net;

/// <summary>
/// A recognizer for the Barking Owl, https://en.wikipedia.org/wiki/Barking_owl.
/// The barking owl (Ninox connivens), also known as the winking owl, is a nocturnal bird species native to mainland Australia
/// and partsof Papua New Guinea and the Moluccas. They are a medium-sized brown owl and have a characteristic voice with
/// calls ranging from a barking dog noise to a shrill human-like howl of great intensity.
/// This recognizer has been trained on good quality calls provided by NSW DPI by Brad Law and Kristen Thompson.
/// </summary>
public class NinoxConnivens : RecognizerBase
{
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

public override string Author => Bibliography.Anthony.LastName;

public override string SpeciesName => "NinoxConnivens";

public override string CommonName => "Barking owl";

public Status Status => Status.InDevelopment;

public override string Description => $"Acoustic event recognizer for the {this.CommonName}.";

public IReadOnlyCollection<Citation> Citations => new[] {
Bibliography.NswDpiRecognisersProject with {
Authors = Bibliography.BuiltByAnthony,
Title = this.Description,
},
};

public override AnalyzerConfig ParseConfig(FileInfo file)
{
RuntimeHelpers.RunClassConstructor(typeof(NinoxConnivensConfig).TypeHandle);
var config = ConfigFile.Deserialize<NinoxConnivensConfig>(file);

// validation of configs can be done here
GenericRecognizer.ValidateProfileTagsMatchAlgorithms(config.Profiles, file);
return config;
}

public override RecognizerResults Recognize(
AudioRecording audioRecording,
Config configuration,
TimeSpan segmentStartOffset,
Lazy<IndexCalculateResult[]> getSpectralIndexes,
DirectoryInfo outputDirectory,
int? imageWidth)
{
var genericConfig = (NinoxConnivensConfig)configuration;
var recognizer = new GenericRecognizer();

// Use the generic recognizers to find all generic events.
RecognizerResults combinedResults = recognizer.Recognize(
audioRecording,
genericConfig,
segmentStartOffset,
getSpectralIndexes,
outputDirectory,
imageWidth);

return combinedResults;
}

public class NinoxConnivensConfig : GenericRecognizer.GenericRecognizerConfig
{
}
}
}
6 changes: 4 additions & 2 deletions src/AnalysisPrograms/Recognizers/Birds/NinoxStrenua.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace AnalysisPrograms.Recognizers
/// Its conservation status is "threatened".
/// This recognizer has been trained on good quality calls provided by NSW DPI by Brad Law and Kristen Thompson.
/// </summary>
internal class NinoxStrenua : RecognizerBase
public class NinoxStrenua : RecognizerBase
{
private static readonly ILog PowerfulOwlLog = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

Expand All @@ -36,13 +36,15 @@ internal class NinoxStrenua : RecognizerBase

public override string Description => "[ALPHA] Detects acoustic events for the Australian Powerful Owl.";

public override string CommonName => "Powerful Owl";

public override AnalyzerConfig ParseConfig(FileInfo file)
{
RuntimeHelpers.RunClassConstructor(typeof(NinoxStrenuaConfig).TypeHandle);
var config = ConfigFile.Deserialize<NinoxStrenuaConfig>(file);

// validation of configs can be done here
GenericRecognizer.ValidateProfileTagsMatchAlgorithms(config.Profiles, file);
ValidateProfileTagsMatchAlgorithms(config.Profiles, file);
return config;
}

Expand Down
Loading

0 comments on commit 7f29c61

Please sign in to comment.