public static void Execute(Arguments arguments) { if (arguments == null) { arguments = Dev(); } string title = "# FIND OTHER ACOUSTIC EVENTS LIKE THIS"; string date = "# DATE AND TIME: " + DateTime.Now; Log.WriteLine(title); Log.WriteLine(date); Log.Verbosity = 1; Log.WriteIfVerbose("# Recording =" + arguments.Source); //the recording to be scanned Log.WriteIfVerbose("# Template list =" + arguments.Config); //the path to a file containing the paths to template locations, one template per line Log.WriteIfVerbose("# Output folder =" + arguments.Output); //name of output dir var allEvents = new List <AcousticEvent>(); var scoresList = new List <double[]>(); var thresholdList = new List <double>(); //i: GET RECORDING AudioRecording recording = new AudioRecording(arguments.Source.FullName); //if (recording.SampleRate != 22050) recording.ConvertSampleRate22kHz(); // THIS METHOD CALL IS OBSOLETE int sr = recording.SampleRate; //ii: MAKE SONOGRAM Log.WriteLine("Start sonogram."); SonogramConfig sonoConfig = new SonogramConfig(); //default values config sonoConfig.SourceFName = recording.BaseName; sonoConfig.WindowOverlap = FeltFrameOverlap; // set default value sonoConfig.DoMelScale = false; sonoConfig.NoiseReductionType = NoiseReductionType.Standard; AmplitudeSonogram basegram = new AmplitudeSonogram(sonoConfig, recording.WavReader); SpectrogramStandard sonogram = new SpectrogramStandard(basegram); //spectrogram has dim[N,257] Log.WriteLine("Signal: Duration={0}, Sample Rate={1}", sonogram.Duration, sr); Log.WriteLine("Frames: Size={0}, Count={1}, Duration={2:f1}ms, Overlap={5:f0}%, Offset={3:f1}ms, Frames/s={4:f1}", sonogram.Configuration.WindowSize, sonogram.FrameCount, (sonogram.FrameDuration * 1000), (sonogram.FrameStep * 1000), sonogram.FramesPerSecond, FeltFrameOverlap * 100); //iii: Get zip paths and the results Tuple List <string> zipList = FileTools.ReadTextFile(arguments.Config.FullName); Tuple <SpectrogramStandard, List <AcousticEvent>, double[]> results = null; //set up the results Tuple foreach (string zipPath in zipList) { if (zipPath.StartsWith("#")) { continue; // commented line } if (zipPath.Length < 2) { continue; // empty line } //i: get params file ZipFile.ExtractToDirectory(arguments.Output.FullName, zipPath); string zipName = Path.GetFileNameWithoutExtension(zipPath); string[] parts = zipName.Split('_'); string paramsPath = Path.Combine(arguments.Output.FullName, parts[0] + "_" + parts[1] + "_Params.txt"); string id = parts[0] + "_" + parts[1]; Log.WriteIfVerbose("################################################### " + id + " ########################################################"); //ii: READ PARAMETER VALUES FROM INI FILE var config = new ConfigDictionary(paramsPath); Dictionary <string, string> dict = config.GetTable(); //Dictionary<string, string>.KeyCollection keys = dict.Keys; //int DRAW_SONOGRAMS = Int32.Parse(dict[FeltTemplate_Create.key_DRAW_SONOGRAMS]); //options to draw sonogram dict[FeltTemplate_Create.key_DECIBEL_THRESHOLD] = "4.0"; dict[FeltTemplate_Create.key_MIN_DURATION] = "0.02"; if (zipName.EndsWith("binaryTemplate")) { string templatePath = Path.Combine(arguments.Output.FullName, id + "_binary.bmp"); double[,] templateMatrix = FindMatchingEvents.ReadImage2BinaryMatrixDouble(templatePath); results = FELTWithBinaryTemplate(sonogram, dict, templateMatrix, TimeSpan.Zero); } else if (zipName.EndsWith("trinaryTemplate")) { string templatePath = Path.Combine(arguments.Output.FullName, id + "_trinary.bmp"); double[,] templateMatrix = FindMatchingEvents.ReadImage2TrinaryMatrix(templatePath); results = FELTWithBinaryTemplate(sonogram, dict, templateMatrix, TimeSpan.Zero); } else if (zipName.EndsWith("syntacticTemplate")) { string templatePath = Path.Combine(arguments.Output.FullName, id + "_spr.txt"); char[,] templateMatrix = FindMatchingEvents.ReadTextFile2CharMatrix(templatePath); results = FELTWithSprTemplate(sonogram, dict, templateMatrix, TimeSpan.Zero); } else { Log.WriteLine("ERROR! UNKNOWN TEMPLATE: Zip file has unrecognised suffix:" + zipName); continue; } //get results sonogram = results.Item1; var matchingEvents = results.Item2; var scores = results.Item3; double matchThreshold = double.Parse(dict[FeltTemplate_Create.key_DECIBEL_THRESHOLD]); Log.WriteLine("# Finished detecting events like target: " + id); Log.WriteLine("# Matching Event Count = " + matchingEvents.Count); Log.WriteLine(" @ threshold = {0:f2}", matchThreshold); // accumulate results allEvents.AddRange(matchingEvents); scoresList.Add(scores); thresholdList.Add(matchThreshold); //v: write events count to results info file. double sigDuration = sonogram.Duration.TotalSeconds; string fname = arguments.Source.Name; string str = string.Format("{0}\t{1}\t{2}", fname, sigDuration, matchingEvents.Count); StringBuilder sb = AcousticEvent.WriteEvents(matchingEvents, str); FileTools.WriteTextFile("opPath", sb.ToString()); } // foreach (string zipPath in zipList) Log.WriteLine("\n\n\n##########################################################"); Log.WriteLine("# Finished detecting events"); Log.WriteLine("# Event Count = " + allEvents.Count); foreach (AcousticEvent ae in allEvents) { Log.WriteLine("# Event name = {0} ############################", ae.Name); Log.WriteLine("# Event time = {0:f2} to {1:f2} (frames {2}-{3}).", ae.TimeStart, ae.TimeEnd, ae.Oblong.RowTop, ae.Oblong.RowBottom); Log.WriteLine("# Event score= {0:f2}.", ae.Score); } int percentOverlap = 50; allEvents = PruneOverlappingEvents(allEvents, percentOverlap); Log.WriteLine("\n##########################################################"); Log.WriteLine("# Finished pruning events"); Log.WriteLine("# Event Count = " + allEvents.Count); WriteEventNames(allEvents); //WriteScoreAverages2Console(scoresList); //draw images of sonograms int DRAW_SONOGRAMS = 2; FileInfo opImagePath = arguments.Output.CombineFile(Path.GetFileNameWithoutExtension(arguments.Source.Name) + "_matchingEvents.png"); if (DRAW_SONOGRAMS == 2) { DrawSonogram(sonogram, opImagePath, allEvents, thresholdList, scoresList); } else if ((DRAW_SONOGRAMS == 1) && (allEvents.Count > 0)) { DrawSonogram(sonogram, opImagePath, allEvents, thresholdList, scoresList); } Log.WriteLine("# FINISHED passing all templates over recording:- " + arguments.Source.Name); }
/// <summary> /// Wraps up the resources into a template.ZIP file /// and then runs a test on the source recording. /// </summary> public static void Execute(Arguments arguments) { if (arguments == null) { arguments = Dev(); } string title = "# EDIT TEMPLATE."; string date = "# DATE AND TIME: " + DateTime.Now; Log.WriteLine(title); Log.WriteLine(date); //ZIP THE OUTPUT FILES const bool ZipOutput = true; FileInfo iniPath = arguments.Config; string[] nameComponents = (Path.GetFileNameWithoutExtension(iniPath.Name)).Split('_'); string targetName = nameComponents[0] + "_" + nameComponents[1]; //i: Set up the file names DirectoryInfo outputDir = iniPath.Directory; FileInfo targetImagePath = outputDir.CombineFile(targetName + "_target.png"); // input image file FileInfo binaryOpPath = outputDir.CombineFile(targetName + "_binary.bmp"); FileInfo trinaryOpPath = outputDir.CombineFile(targetName + "_trinary.bmp"); FileInfo sprOpPath = outputDir.CombineFile(targetName + "_spr.txt"); // syntactic pattern recognition file //additional files to be zipped up with template FileInfo targetPath = outputDir.CombineFile(targetName + "_target.txt"); FileInfo targetNoNoisePath = outputDir.CombineFile(targetName + "_targetNoNoise.txt"); FileInfo noisePath = outputDir.CombineFile(targetName + "_noise.txt"); //ii: READ PARAMETER VALUES FROM INI FILE var config = new ConfigDictionary(iniPath); Dictionary <string, string> dict = config.GetTable(); string sourceFile = dict[FeltTemplate_Create.key_SOURCE_RECORDING]; string sourceDir = dict[FeltTemplate_Create.key_SOURCE_DIRECTORY]; double dB_Threshold = double.Parse(dict[FeltTemplate_Create.key_DECIBEL_THRESHOLD]); double maxTemplateIntensity = double.Parse(dict[FeltTemplate_Create.key_TEMPLATE_MAX_INTENSITY]); int neighbourhood = int.Parse(dict[FeltTemplate_Create.key_DONT_CARE_NH]); //the do not care neighbourhood int lineLength = int.Parse(dict[FeltTemplate_Create.key_LINE_LENGTH]); double templateThreshold = dB_Threshold / maxTemplateIntensity; int bitmapThreshold = (int)(255 - (templateThreshold * 255)); Log.WriteLine("#################################### WRITE THE BINARY TEMPLATE ##################################"); Bitmap bitmap = ImageTools.ReadImage2Bitmap(targetImagePath.FullName); var binaryBmp = Image2BinaryBitmap(bitmap, bitmapThreshold); binaryBmp.Save(binaryOpPath.FullName); Log.WriteLine("#################################### WRITE THE TRINARY TEMPLATE ##################################"); var trinaryBmp = Image2TrinaryBitmap(binaryBmp, neighbourhood); trinaryBmp.Save(trinaryOpPath.FullName); Log.WriteLine("#################################### WRITE THE SPR TEMPLATE ##################################"); double[,] matrix = ImageTools.GreyScaleImage2Matrix(bitmap); matrix = DataTools.MatrixRotate90Clockwise(matrix); //rows=time cols=freq. //ImageTools.DrawMatrix(matrix, @"C:\SensorNetworks\Output\FELT_LewinsRail1\SPR_output1.bmp"); //int smallLengthThreshold = 10; //var tuple = SPT.doSPT(matrix, templateThreshold, smallLengthThreshold); //matrix = tuple.Item1; //ImageTools.DrawMatrix(matrix, @"C:\SensorNetworks\Output\FELT_LewinsRail1\SPR_output2.bmp"); char[,] spr = SprTools.Target2SymbolicTracks(matrix, templateThreshold, lineLength); FileTools.WriteMatrix2File(spr, sprOpPath.FullName); var tuple1 = FindMatchingEvents.Execute_One_Spr_Match(spr, matrix, templateThreshold); double sprScore = tuple1.Item1; double dBScore = sprScore * maxTemplateIntensity; Log.WriteLine("#################################### WRITE THE OSCILATION TEMPLATE ##################################"); double[,] target = FileTools.ReadDoubles2Matrix(targetPath.FullName); // oscillations in time double[,] rotatedtarget = DataTools.MatrixRotate90Clockwise(target); var colSums = DataTools.GetColumnsAverages(rotatedtarget); double[] periods = Oscillations2010.PeriodicityAnalysis(colSums); // frame periodicity LoggedConsole.WriteLine("Periodicity (sec) = {0:f3}, {1:f3}, {2:f3}", periods[0] * FeltTemplates_Use.FeltFrameOffset, periods[1] * FeltTemplates_Use.FeltFrameOffset, periods[2] * FeltTemplates_Use.FeltFrameOffset); //double oscilFreq = indexOfMaxValue / dctDuration * 0.5; //Times 0.5 because index = Pi and not 2Pi // oscillations in freq i.e. harmonics colSums = DataTools.GetColumnsAverages(target); periods = Oscillations2010.PeriodicityAnalysis(colSums); LoggedConsole.WriteLine("Periodicity (Hz) = {0:f0}, {1:f0}, {2:f0}.", periods[0] * FeltTemplates_Use.FeltFreqBinWidth, periods[1] * FeltTemplates_Use.FeltFreqBinWidth, periods[2] * FeltTemplates_Use.FeltFreqBinWidth); //double oscilFreq = indexOfMaxValue / dctDuration * 0.5; //Times 0.5 because index = Pi and not 2Pi //FileTools.WriteMatrix2File(spr, sprOpPath); // ZIP THE OUTPUT Log.WriteLine("#################################### ZIP THE TEMPLATES ##################################"); if (ZipOutput == true) { var filenames = new[] { iniPath, targetImagePath, binaryOpPath, targetPath, targetNoNoisePath, noisePath }; string biOutZipFile = outputDir + targetName + "_binaryTemplate.zip"; //FileTools.ZipFiles(filenames, biOutZipFile); filenames = new[] { iniPath, targetImagePath, trinaryOpPath, targetPath, targetNoNoisePath, noisePath }; string triOutZipFile = outputDir + targetName + "_trinaryTemplate.zip"; //FileTools.ZipFiles(filenames, triOutZipFile); filenames = new[] { iniPath, targetImagePath, sprOpPath, targetPath, targetNoNoisePath, noisePath }; string sprOutZipFile = outputDir + targetName + "_syntacticTemplate.zip"; //FileTools.ZipFiles(filenames, sprOutZipFile); // Zipping files can be done by using standard .NET 4.6 System.IO.Compression // however, this code hasn't been used in years and I've opted to just comment out the lines above throw new NotImplementedException("Zipping template files intentionally broken"); } Log.WriteLine("\n\n#################################### TEST THE EXTRACTED EVENT ON SOURCE FILE ##################################"); //vi: TEST THE EVENT ON ANOTHER FILE //felt "C:\SensorNetworks\WavFiles\Canetoad\DM420010_128m_00s__130m_00s - Toads.mp3" C:\SensorNetworks\Output\FELT_CaneToad\FELT_CaneToad_Params.txt events.txt //string testRecording = @"C:\SensorNetworks\WavFiles\Gecko\Suburban_March2010\geckos_suburban_104.mp3"; //string testRecording = @"C:\SensorNetworks\WavFiles\Gecko\Suburban_March2010\geckos_suburban_18.mp3"; //string testRecording = @"C:\SensorNetworks\WavFiles\Currawongs\Currawong_JasonTagged\West_Knoll_Bees_20091102-170000.mp3"; //string testRecording = @"C:\SensorNetworks\WavFiles\Curlew\Curlew2\Top_Knoll_-_St_Bees_20090517-210000.wav"; string listOpDir = "C:\\SensorNetworks\\Output\\FELT_templateList\\"; string templateListPath = listOpDir + "templateTestList.txt"; var list = new List <string>(); list.Add("#" + outputDir + targetName + "_binaryTemplate.zip"); list.Add("#" + outputDir + targetName + "_trinaryTemplate.zip"); list.Add("#" + outputDir + targetName + "_syntacticTemplate.zip"); FileTools.Append2TextFile(templateListPath, list); //write the template.ZIP file //TEST THE TEMPLATE ON SOURCE FILE //string[] arguments = new string[3]; /* * var args = new FeltTemplates_Use.Arguments() * { * Source = "", * arguments[0] = sourceDir + "\\" + sourceFile; * arguments[1] = templateListPath; * arguments[2] = listOpDir; * * }*/ //FeltTemplates_Use.Dev(arguments); Log.WriteLine("# Finished everything!"); }
} // FELTWithBinaryTemplate() /// <summary> /// Scans a recording given a dicitonary of parameters and a syntactic template /// Template has a different orientation to others. /// </summary> /// <param name="sonogram"></param> /// <param name="dict"></param> /// <param name="templateMatrix"></param> /// <param name="segmentStartOffset"></param> /// <param name="recording"></param> /// <param name="templatePath"></param> /// <returns></returns> public static Tuple <SpectrogramStandard, List <AcousticEvent>, double[]> FELTWithSprTemplate(SpectrogramStandard sonogram, Dictionary <string, string> dict, char[,] templateMatrix, TimeSpan segmentStartOffset) { //i: get parameters from dicitonary string callName = dict[FeltTemplate_Create.key_CALL_NAME]; bool doSegmentation = bool.Parse(dict[FeltTemplate_Create.key_DO_SEGMENTATION]); double smoothWindow = double.Parse(dict[FeltTemplate_Create.key_SMOOTH_WINDOW]); //before segmentation int minHz = int.Parse(dict[FeltTemplate_Create.key_MIN_HZ]); int maxHz = int.Parse(dict[FeltTemplate_Create.key_MAX_HZ]); double minDuration = double.Parse(dict[FeltTemplate_Create.key_MIN_DURATION]); //min duration of event in seconds double dBThreshold = double.Parse(dict[FeltTemplate_Create.key_DECIBEL_THRESHOLD]); // = 9.0; // dB threshold dBThreshold = 4.0; int binCount = (int)(maxHz / sonogram.FBinWidth) - (int)(minHz / sonogram.FBinWidth) + 1; Log.WriteLine("Freq band: {0} Hz - {1} Hz. (Freq bin count = {2})", minHz, maxHz, binCount); //ii: TEMPLATE INFO double templateDuration = templateMatrix.GetLength(0) / sonogram.FramesPerSecond; Log.WriteIfVerbose("Template duration = {0:f3} seconds or {1} frames.", templateDuration, templateMatrix.GetLength(0)); Log.WriteIfVerbose("Min Duration: " + minDuration + " seconds"); //iii: DO SEGMENTATION double segmentationThreshold = 2.0; // Standard deviations above backgorund noise double maxDuration = double.MaxValue; // Do not constrain maximum length of events. var tuple1 = AcousticEvent.GetSegmentationEvents((SpectrogramStandard)sonogram, doSegmentation, segmentStartOffset, minHz, maxHz, smoothWindow, segmentationThreshold, minDuration, maxDuration); var segmentEvents = tuple1.Item1; //iv: Score sonogram for events matching template //############################################################################################################################################# var tuple2 = FindMatchingEvents.Execute_Spr_Match(templateMatrix, sonogram, segmentEvents, minHz, maxHz, dBThreshold); //var tuple2 = FindMatchingEvents.Execute_StewartGage(target, dynamicRange, (SpectralSonogram)sonogram, segmentEvents, minHz, maxHz, minDuration); //var tuple2 = FindMatchingEvents.Execute_SobelEdges(target, dynamicRange, (SpectralSonogram)sonogram, segmentEvents, minHz, maxHz, minDuration); //var tuple2 = FindMatchingEvents.Execute_MFCC_XCOR(target, dynamicRange, sonogram, segmentEvents, minHz, maxHz, minDuration); var scores = tuple2.Item1; //############################################################################################################################################# //v: PROCESS SCORE ARRAY //scores = DataTools.filterMovingAverage(scores, 3); LoggedConsole.WriteLine("Scores: min={0:f4}, max={1:f4}, threshold={2:f2}dB", scores.Min(), scores.Max(), dBThreshold); //Set (scores < 0.0) = 0.0; for (int i = 0; i < scores.Length; i++) { if (scores[i] < 0.0) { scores[i] = 0.0; } } //vi: EXTRACT EVENTS List <AcousticEvent> matchEvents = AcousticEvent.ConvertScoreArray2Events(scores, minHz, maxHz, sonogram.FramesPerSecond, sonogram.FBinWidth, dBThreshold, minDuration, maxDuration, segmentStartOffset); foreach (AcousticEvent ev in matchEvents) { ev.FileName = sonogram.Configuration.SourceFName; ev.Name = sonogram.Configuration.CallName; } // Edit the events to correct the start time, duration and end of events to match the max score and length of the template. AdjustEventLocation(matchEvents, callName, templateDuration, sonogram.Duration.TotalSeconds); return(Tuple.Create(sonogram, matchEvents, scores)); } // FELTWithSprTemplate()