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);
        }
Esempio n. 2
0
        /// <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()