Skip to content

Commit

Permalink
Add testing capcability to the Build/Make templates.
Browse files Browse the repository at this point in the history
Issue #252 Add testing capcability to the Build/Make templates.
Testing requires two additional arguments to BuildModel.Execute but the arguments and the testing are optional. Testing not done if two additional arguments are not provided.
  • Loading branch information
towsey committed Nov 21, 2019
1 parent d9db4ae commit e095850
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 9 deletions.
89 changes: 82 additions & 7 deletions src/AnalysisPrograms/ContentDescription/BuildModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,32 @@ namespace AnalysisPrograms.ContentDescription
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using Acoustics.Shared;
using AnalysisPrograms.Production.Arguments;
using AnalysisPrograms.Production.Validation;
using AudioAnalysisTools.ContentDescriptionTools;
using McMaster.Extensions.CommandLineUtils;

using TowseyLibrary;

/// <summary>
/// THis class builds/makes a set of content description templates.
/// Templates are initially defined manually in a YAML file. Each template in a YAML file is called a "manifest".
/// The array of manifests in a yml file is used to calculate an array of "functional templates" in a json file.
/// The json file is generated automatically from the information provided in the manifests.yml file.
/// A template manifest contains the "provenance" of the template (i.e. details of the recordings, source locations etc used to make the functional template.
/// It also contains the information required to calculate the template definition.
/// The core of a functional template is its definition, which is stored as a dictionary of spectral indices.
/// The functional template also contains information required to scan new recordings with the template definition.
///
/// IMPORTANT NOTE: At current time (Nov, 2019) Functional Templates are made by reading csv files containing pre-calculated spectral indices.
/// In addition, the Functional Templates can subsequently be tested (this is optional) by reading csv files of spectral indices.
/// The first two FileInfo arguments in the arguments list are compulsory and templates cannot be made without them.
/// Arguments 3 and 4 are optional. They must be provided for testing the templates. Testing also requires files of pre-calculated spectral indices.
/// TODO: Refactor the code so that functional templates can be made and tested reading directly from .wav recordings files.
/// </summary>
public class BuildModel
{
public const string CommandName = "BuildContentDescriptionModel";
Expand All @@ -39,15 +58,22 @@ public class Arguments : SubCommandBase
[LegalFilePath]
public FileInfo TemplateDefinitions { get; set; }

/*
[Argument(
2,
Description = "A directory to write output to")]
[Required]
[DirectoryExistsOrCreate(createIfNotExists: true)]
Description = "Optional argument: Path to a txt file containing list of pre-calculated test data files.")]
//[Required]
[FileExists]
[LegalFilePath]
public FileInfo ListOfTestIndexFiles { get; set; }

[Argument(
3,
Description = "Optional argument: Image of LDFC spectrogram consistent with the data-files listed in previous argument.")]
//[Required]
//[DirectoryExistsOrCreate(createIfNotExists: true)]
[FileExists]
[LegalFilePath]
public virtual DirectoryInfo Output { get; set; }
*/
public virtual FileInfo ImageOfLdfcSpectrogram { get; set; }

public override Task<int> Execute(CommandLineApplication app)
{
Expand Down Expand Up @@ -135,6 +161,55 @@ public static void Execute(Arguments arguments)
// No need to move the backup because serializing over-writes the current templates file.
var opTemplatesFile = new FileInfo(functionalTemplatesFilePath);
Json.Serialise(opTemplatesFile, newTemplateList.ToArray());

if (arguments.ListOfTestIndexFiles != null)
{
TestTemplates(arguments.ListOfTestIndexFiles, opTemplatesFile, arguments.ImageOfLdfcSpectrogram);
}
}

public static void TestTemplates(FileInfo listOfIndexFiles, FileInfo templatesFile, FileInfo imageOfLdfcSpectrogram)
{
var contentDictionary = ContentSignatures.ContentDescriptionOfMultipleRecordingFiles(listOfIndexFiles, templatesFile);

// Write the results to a csv file
var outputDirectory = templatesFile.DirectoryName;
var filePath = Path.Combine(outputDirectory ?? throw new InvalidOperationException("Output directory does not exist."), "AcousticSignatures.csv");
FileTools.WriteDictionaryAsCsvFile(contentDictionary, filePath);

// get content description plots and use to examine score distributions.
var contentPlots = ContentSignatures.GetPlots(contentDictionary);
var images = GraphsAndCharts.DrawPlotDistributions(contentPlots);
var plotsImage = ImageTools.CombineImagesVertically(images);
var path1 = Path.Combine(outputDirectory, "ScoreDistributions.png");
plotsImage.Save(path1);

// Attach plots to LDFC spectrogram and write to file
var imageList = new List<Image>();
if (imageOfLdfcSpectrogram != null)
{
var ldfcSpectrogram = Image.FromFile(imageOfLdfcSpectrogram.FullName);
imageList.Add(ldfcSpectrogram);
}

if (contentPlots != null)
{
int plotHeight = 30;
foreach (var plot in contentPlots)
{
var imageOfPlot = plot.DrawAnnotatedPlot(plotHeight);
imageList.Add(imageOfPlot);
}
}

if (imageList.Count != 0)
{
var opImage = ImageTools.CombineImagesVertically(imageList);
var path2 = Path.Combine(outputDirectory, templatesFile.BaseName() + ".TestOfTemplates.png");
opImage.Save(path2);
}

//Console.WriteLine("# Finished test of content description templates");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ public class ContentSignatures
public static Dictionary<string, double[]> ContentDescriptionOfMultipleRecordingFiles(FileInfo listOfIndexFiles, FileInfo templatesFile)
{
// TODO: inline this method into AnalysisPrograms.ContentDescription.UseModel.Analyse
// ASSUMPTION: total length in minutes of all the recordings
const int totalMinutesDurationOverAllRecordings = 1440;
const int startMinute = 0;

// Read in all the prepared templates
Expand Down

0 comments on commit e095850

Please sign in to comment.