Skip to content

Commit

Permalink
Set up new classes to recognise acoustic types
Browse files Browse the repository at this point in the history
Issue #252 Set up separate class for determining amount of each type of acoustic content. Add new class to hold visualization methods. Having difficulty with writing strings to image so play around with ImageTrack.cs but cannot fix problem.
Set up BaseContent.cs class with eventual intention to do inheritance.
  • Loading branch information
towsey committed Sep 10, 2019
1 parent c2ec082 commit 2e4c4c1
Show file tree
Hide file tree
Showing 12 changed files with 412 additions and 199 deletions.
20 changes: 13 additions & 7 deletions src/AnalysisPrograms/Sandpit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace AnalysisPrograms
using AnalyseLongRecordings;
using AudioAnalysisTools;
using AudioAnalysisTools.ContentDescriptionTools;
using AudioAnalysisTools.ContentDescriptionTools.ContentTypes;
using AudioAnalysisTools.DSP;
using AudioAnalysisTools.Indices;
using AudioAnalysisTools.LongDurationSpectrograms;
Expand Down Expand Up @@ -175,16 +176,21 @@ public static void ContentDescriptionDev()
};

//PREPARE STRONG WIND TEMPLATE
//var dir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez02\Towsey.Acoustic");
//var ipDir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez02\Towsey.Acoustic");
//string baseName = "SM304256_0+1_20151114_011652";
//var path2 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "StrongWindTemplate1.csv");
//WindContent.WriteStrongWindTemplateToFile(dictionary, path2);
//var opDir = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "StrongWindTemplate1.csv");
//WindStrong1.WriteStrongWindTemplateToFile(dictionary, path2);

//PREPARE LIGHT WIND TEMPLATE
//var ipDir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez03\Towsey.Acoustic");
//var opDir = new DirectoryInfo(@"C:\Ecoacoustics\Output\ContentDescription");
//WindLight1.WriteTemplateToFile(ipDir, opDir);

//PREPARE LIGHT RAIN TEMPLATE
//var dir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez08\Towsey.Acoustic");
//var ipDir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez08\Towsey.Acoustic");
//string baseName = "SM304256_0+1_20151114_071652";
//var dictionary = ContentDescription.ReadIndexMatrices(dir, baseName);
//var path2 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "LightRainTemplate1.csv");
//var opDir = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "LightRainTemplate1.csv");
//RainContent.WriteLightRainTemplateToFile(dictionary, path2);

var contentPlots = ContentDescription.ContentDescriptionOfMultipleRecordingFiles(directories, baseNames);
Expand All @@ -198,8 +204,8 @@ public static void ContentDescriptionDev()
// ContentDescription.GetRandomNumberArray(ldfcSpectrogram.Width),
//};

var image = ContentDescription.DrawLdfcSpectrogramWithContentScoreTracks(ldfcSpectrogram, contentPlots);
var path1 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "Testing__2Maps.CONTENT3.png");
var image = ContentVisualization.DrawLdfcSpectrogramWithContentScoreTracks(ldfcSpectrogram, contentPlots);
var path1 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "Testing__2Maps.CONTENT4.png");
image.Save(path1);
}

Expand Down
9 changes: 7 additions & 2 deletions src/AudioAnalysisTools/AudioAnalysisTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,14 @@
<Compile Include="BirdClefExperiment1.cs" />
<Compile Include="ChannelIntegrity.cs" />
<Compile Include="ContentDescriptionTools\ContentDescription.cs" />
<Compile Include="ContentDescriptionTools\ContentTypes\BaseContentType.cs" />
<Compile Include="ContentDescriptionTools\ContentTypes\RainLight1.cs" />
<Compile Include="ContentDescriptionTools\ContentTypes\RainHeavy2.cs" />
<Compile Include="ContentDescriptionTools\ContentTypes\WindLight1.cs" />
<Compile Include="ContentDescriptionTools\ContentVisualization.cs" />
<Compile Include="ContentDescriptionTools\DescriptionResult.cs" />
<Compile Include="ContentDescriptionTools\RainContent.cs" />
<Compile Include="ContentDescriptionTools\WindContent.cs" />
<Compile Include="ContentDescriptionTools\ContentTypes\RainHeavy1.cs" />
<Compile Include="ContentDescriptionTools\ContentTypes\WindStrong1.cs" />
<Compile Include="CrossCorrelation.cs" />
<Compile Include="DSP\Clipping.cs" />
<Compile Include="DSP\DSP_Filters.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace AudioAnalysisTools.ContentDescriptionTools
using System.Linq;
using Acoustics.Shared;
using Acoustics.Shared.Csv;
using AudioAnalysisTools.ContentDescriptionTools.ContentTypes;
using AudioAnalysisTools.DSP;
using AudioAnalysisTools.LongDurationSpectrograms;
using AudioAnalysisTools.StandardSpectrograms;
Expand Down Expand Up @@ -172,19 +173,21 @@ public static List<DescriptionResult> AnalyseMinutes(Dictionary<string, double[,
var descriptionResult = new DescriptionResult(elapsedMinutes + i);

// now send indices to various content searches
descriptionResult.AddDescription(WindContent.GetStrongWindContent(oneMinuteOfIndices));
descriptionResult.AddDescription(WindContent.GetLightWindContent(oneMinuteOfIndices));
descriptionResult.AddDescription(RainContent.GetStrongRainContent(oneMinuteOfIndices));
descriptionResult.AddDescription(RainContent.GetLightRainContent(oneMinuteOfIndices));
descriptionResult.AddDescription(WindStrong1.GetContent(oneMinuteOfIndices));
descriptionResult.AddDescription(WindLight1.GetContent(oneMinuteOfIndices));
descriptionResult.AddDescription(RainLight1.GetContent(oneMinuteOfIndices));

// yet to do following
//descriptionResult.AddDescription(RainHeavy1.GetContent(oneMinuteOfIndices));
//descriptionResult.AddDescription(RainHeavy2.GetContent(oneMinuteOfIndices));

results.Add(descriptionResult);
}

return results;
}

public static Dictionary<string, double[]> GetIndicesForOneMinute(Dictionary<string, double[,]> allIndices,
int rowId)
public static Dictionary<string, double[]> GetIndicesForOneMinute(Dictionary<string, double[,]> allIndices, int rowId)
{
var opIndices = new Dictionary<string, double[]>();

Expand Down Expand Up @@ -259,46 +262,6 @@ public static double[] ConvertDictionaryToVector(Dictionary<string, double[]> di
return list.ToArray();
}

public static void DrawNormalisedIndexMatrices(DirectoryInfo dir, string baseName, Dictionary<string, double[,]> dictionary)
{
var list = new List<Image>();
foreach (string key in IndexNames)
{
var bmp = ImageTools.DrawReversedMatrixWithoutNormalisation(dictionary[key]);

// need to rotate spectrogram to get correct orientation.
bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);

// draw grid lines and add axis scales
var xAxisPixelDuration = TimeSpan.FromSeconds(60);
var fullDuration = TimeSpan.FromTicks(xAxisPixelDuration.Ticks * bmp.Width);
var freqScale = new FrequencyScale(11025, 512, 1000);
SpectrogramTools.DrawGridLinesOnImage((Bitmap)bmp, TimeSpan.Zero, fullDuration, xAxisPixelDuration, freqScale);
const int trackHeight = 20;
var recordingStartDate = default(DateTimeOffset);
var timeBmp = ImageTrack.DrawTimeTrack(fullDuration, recordingStartDate, bmp.Width, trackHeight);
var array = new Image[2];
array[0] = bmp;
array[1] = timeBmp;
var image = ImageTools.CombineImagesVertically(array);

// add a header to the spectrogram
var header = new Bitmap(image.Width, 20);
Graphics g = Graphics.FromImage(header);
g.Clear(Color.LightGray);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawString(key, new Font("Tahoma", 9), Brushes.Black, 4, 4);
list.Add(ImageTools.CombineImagesVertically(new List<Image>(new[] { header, image })));
}

// save the image - the directory for the path must exist
var path = Path.Combine(dir.FullName, baseName + "__Towsey.Acoustic.GreyScaleImages.png");
var indexImage = ImageTools.CombineImagesInLine(list);
indexImage?.Save(path);
}

public static Dictionary<string, Plot> ConvertResultsToPlots(List<DescriptionResult> results, int plotLength, int plotStart)
{
var plots = new Dictionary<string, Plot>();
Expand Down Expand Up @@ -372,34 +335,6 @@ public static List<Plot> ConvertPlotDictionaryToPlotList(Dictionary<string, Plot
return list;
}

public static Image DrawLdfcSpectrogramWithContentScoreTracks(Image ldfcSpectrogram, List<Plot> contentScores)
{
int trackHeight = 30;
int width = ldfcSpectrogram.Width;
var imageList = new List<Image>
{
ldfcSpectrogram,
};

foreach (var plot in contentScores)
{
var track = new ImageTrack(TrackType.scoreArrayNamed, plot.data)
{
Name = plot.title,
ScoreMin = 0.0, // plot.data.Min(),
ScoreMax = 1.0, // plot.data.Max(),
Height = trackHeight,
topOffset = 0,
ScoreThreshold = plot.threshold,
};
var bmp = new Bitmap(width, trackHeight);
imageList.Add(track.DrawNamedScoreArrayTrack(bmp));
}

Image bmp3 = ImageTools.CombineImagesVertically(imageList);
return bmp3;
}

/// <summary>
/// used for experimental purposes.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <copyright file="WindStrong1.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 AudioAnalysisTools.ContentDescriptionTools.ContentTypes
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TowseyLibrary;

public abstract class BaseContentType
{
public const int ReductionFactor = 16;

public virtual string Name() => "Something";

public static Dictionary<string, double[]> GetTemplate(Dictionary<string, double[,]> dictionaryOfIndices)
{
var windIndices = ContentDescription.AverageIndicesOverMinutes(dictionaryOfIndices, 23, 27);
var reducedIndices = ContentDescription.ReduceIndicesByFactor(windIndices, ReductionFactor);
return reducedIndices;
}

public static void WriteTemplateToFile(Dictionary<string, double[,]> dictionaryOfIndices, string path)
{
var template = GetTemplate(dictionaryOfIndices);
FileTools.WriteDictionaryToFile(template, path);
}

// get dummy data
//var rn = new RandomNumber(DateTime.Now.Second + (int)DateTime.Now.Ticks + 333);
//var distance = rn.GetDouble();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// <copyright file="RainHeavy1.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 AudioAnalysisTools.ContentDescriptionTools.ContentTypes
{
using System;
using System.Collections.Generic;
using TowseyLibrary;

public class RainHeavy1
{
public const string Name = "HeavyRain1";
private const int ReductionFactor = 16;

private static Dictionary<string, double[]> StrongRainTemplate = new Dictionary<string, double[]>
{
["ACI"] = new[] { 0.076, 0.046, 0.167, 0.360, 0.426, 0.443, 0.545, 0.595, 0.564, 0.612, 0.659, 0.570, 0.542, 0.520, 0.485, 0.485 },
["ENT"] = new[] { 0.065, 0.061, 0.176, 0.289, 0.249, 0.255, 0.296, 0.292, 0.262, 0.386, 0.462, 0.262, 0.222, 0.243, 0.217, 0.205 },
["EVN"] = new[] { 0.136, 0.009, 0.022, 0.051, 0.072, 0.092, 0.109, 0.150, 0.175, 0.176, 0.193, 0.155, 0.171, 0.135, 0.109, 0.133 },
["BGN"] = new[] { 0.366, 0.249, 0.181, 0.148, 0.122, 0.111, 0.106, 0.105, 0.104, 0.111, 0.111, 0.111, 0.105, 0.100, 0.090, 0.048 },
["PMN"] = new[] { 0.182, 0.076, 0.243, 0.459, 0.470, 0.501, 0.592, 0.651, 0.625, 0.699, 0.792, 0.599, 0.572, 0.550, 0.490, 0.488 },
};

public static KeyValuePair<string, double> GetRainContent(Dictionary<string, double[]> oneMinuteOfIndices)
{
var reducedIndices = ContentDescription.ReduceIndicesByFactor(oneMinuteOfIndices, ReductionFactor);
var oneMinuteVector = ContentDescription.ConvertDictionaryToVector(reducedIndices);
var templateVector = ContentDescription.ConvertDictionaryToVector(StrongRainTemplate);

//Get Euclidian distance and normalise the distance
var distance = DataTools.EuclidianDistance(templateVector, oneMinuteVector);
distance /= Math.Sqrt(templateVector.Length);

// get dummy data
//var rn = new RandomNumber(DateTime.Now.Second + (int)DateTime.Now.Ticks + 333);
//var distance = rn.GetDouble();

return new KeyValuePair<string, double>(Name, 1 - distance);
}

//THESE ARE SPECIFIC BOUNDS FOR PREPARING THIS TEMPLATE
private const int StartRowId = 23;
private const int EndRowId = 27;

public static Dictionary<string, double[]> GetTemplate(Dictionary<string, double[,]> dictionaryOfIndices)
{
var windIndices = ContentDescription.AverageIndicesOverMinutes(dictionaryOfIndices, StartRowId, EndRowId);
var reducedIndices = ContentDescription.ReduceIndicesByFactor(windIndices, ReductionFactor);
return reducedIndices;
}

public static void WriteTemplateToFile(Dictionary<string, double[,]> dictionaryOfIndices, string path)
{
var template = GetTemplate(dictionaryOfIndices);
FileTools.WriteDictionaryToFile(template, path);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// <copyright file="RainHeavy2.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 AudioAnalysisTools.ContentDescriptionTools.ContentTypes
{
using System;
using System.Collections.Generic;
using TowseyLibrary;

public class RainHeavy2
{
public const string Name = "HeavyRain2";
private const int ReductionFactor = 16;

private static Dictionary<string, double[]> StrongRainTemplate = new Dictionary<string, double[]>
{
["ACI"] = new[] { 0.076, 0.046, 0.167, 0.360, 0.426, 0.443, 0.545, 0.595, 0.564, 0.612, 0.659, 0.570, 0.542, 0.520, 0.485, 0.485 },
["ENT"] = new[] { 0.065, 0.061, 0.176, 0.289, 0.249, 0.255, 0.296, 0.292, 0.262, 0.386, 0.462, 0.262, 0.222, 0.243, 0.217, 0.205 },
["EVN"] = new[] { 0.136, 0.009, 0.022, 0.051, 0.072, 0.092, 0.109, 0.150, 0.175, 0.176, 0.193, 0.155, 0.171, 0.135, 0.109, 0.133 },
["BGN"] = new[] { 0.366, 0.249, 0.181, 0.148, 0.122, 0.111, 0.106, 0.105, 0.104, 0.111, 0.111, 0.111, 0.105, 0.100, 0.090, 0.048 },
["PMN"] = new[] { 0.182, 0.076, 0.243, 0.459, 0.470, 0.501, 0.592, 0.651, 0.625, 0.699, 0.792, 0.599, 0.572, 0.550, 0.490, 0.488 },
};

public static KeyValuePair<string, double> GetStrongRainContent(Dictionary<string, double[]> oneMinuteOfIndices)
{
var reducedIndices = ContentDescription.ReduceIndicesByFactor(oneMinuteOfIndices, ReductionFactor);
var oneMinuteVector = ContentDescription.ConvertDictionaryToVector(reducedIndices);
var templateVector = ContentDescription.ConvertDictionaryToVector(StrongRainTemplate);

//Get Euclidian distance and normalise the distance
var distance = DataTools.EuclidianDistance(templateVector, oneMinuteVector);
distance /= Math.Sqrt(templateVector.Length);

// get dummy data
//var rn = new RandomNumber(DateTime.Now.Second + (int)DateTime.Now.Ticks + 333);
//var distance = rn.GetDouble();

return new KeyValuePair<string, double>(Name, 1 - distance);
}

//THESE ARE SPECIFIC BOUNDS FOR PREPARING THIS TEMPLATE
private const int StartRowId = 32;
private const int EndRowId = 36;

/// <summary>
/// string baseName = "SM304256_0+1_20151114_071652".
/// </summary>
public static Dictionary<string, double[]> GetTemplate(Dictionary<string, double[,]> dictionaryOfIndices)
{
var windIndices = ContentDescription.AverageIndicesOverMinutes(dictionaryOfIndices, StartRowId, EndRowId);
var reducedIndices = ContentDescription.ReduceIndicesByFactor(windIndices, ReductionFactor);
return reducedIndices;
}

public static void WriteTemplateToFile(Dictionary<string, double[,]> dictionaryOfIndices, string path)
{
var template = GetTemplate(dictionaryOfIndices);
FileTools.WriteDictionaryToFile(template, path);
}
}
}
Loading

0 comments on commit 2e4c4c1

Please sign in to comment.