/// <summary>
        /// Joins summary indices csv files together.
        /// This method merges ALL the passed files of acoustic indices
        /// It is assumed you are concatenating a sequence of consecutive short recordings.
        /// </summary>
        public static List <SummaryIndexValues> ConcatenateAllSummaryIndexFiles(
            FileInfo[] summaryIndexFiles,
            DirectoryInfo opDir,
            IndexGenerationData indexGenerationData,
            string outputFileBaseName)
        {
            var indexResolution = indexGenerationData.IndexCalculationDuration;

            var summaryIndices = IndexMatrices.ConcatenateSummaryIndexFilesWithTimeCheck(summaryIndexFiles, indexResolution);

            if (summaryIndices.Count == 0)
            {
                LoggedConsole.WriteErrorLine("WARNING: LDSpectrogramStitching.ConcatenateAllSummaryIndexFiles(): Empty List of SUMMARY indices returned!");
                return(null);
            }

            // check length of data and make adjustments if required.
            // NOTHING done with this info at the moment. Could be used to truncate data to 24 hours.
            //int totalRowMinutes = (int)Math.Round(summaryIndices.Count() * indexResolution.TotalMinutes);

            // write out the list of data file names to JSON file.
            var arrayOfFileNames = summaryIndices.Select(x => x.FileName).ToArray();
            var path             = FilenameHelpers.AnalysisResultPath(opDir, outputFileBaseName, "FileNames", "json");

            Json.Serialise(new FileInfo(path), arrayOfFileNames);

            return(summaryIndices);
        }
Exemple #2
0
        public void CompressIndexSpectrogramsAcceptsRoundingFuncTest()
        {
            var spectra = new Dictionary <string, double[, ]> {
                { "Test", new double[, ] {
                      { 1, 2, 3, 4, 5 }
                  } },
            };

            // the default rounding func (when param omitted) is floor
            var result = IndexMatrices.CompressIndexSpectrograms(
                spectra,
                TimeSpan.FromSeconds(60),
                TimeSpan.FromSeconds(30));

            Assert.AreEqual(2, result.First().Value.Length);

            result = IndexMatrices.CompressIndexSpectrograms(
                spectra,
                TimeSpan.FromSeconds(60),
                TimeSpan.FromSeconds(30),
                Math.Ceiling);

            Assert.AreEqual(3, result.First().Value.Length);

            result = IndexMatrices.CompressIndexSpectrograms(
                spectra,
                TimeSpan.FromSeconds(60),
                TimeSpan.FromSeconds(30),
                d => Math.Round(d, MidpointRounding.AwayFromZero));

            Assert.AreEqual(3, result.First().Value.Length);
        }
Exemple #3
0
        public void CompressIndexSpectrogramsBasicAverageTest()
        {
            // testing an average that occurs with three windows, each of 5 values,
            // with the last window being two values too long
            var someSpectra = new double[256, 13].ForEach((i, j) => i);
            var spectra     = new Dictionary <string, double[, ]> {
                { "I_DO_NOT_EXIST", someSpectra },
            };
            var compressed = IndexMatrices.CompressIndexSpectrograms(
                spectra,
                5.Seconds(),
                1.Seconds(),
                d => Math.Round(d, MidpointRounding.AwayFromZero));

            var compressedSpectra = compressed["I_DO_NOT_EXIST"];
            var average           = compressedSpectra.Average();

            Assert.AreEqual(127.5, average, $"Expected total average to be -100 but it was {average}");

            // and make sure every value is as we expect
            for (int j = 0; j < compressedSpectra.LastColumnIndex(); j++)
            {
                Assert.AreEqual(127.5, compressedSpectra.GetColumn(j).Average());
            }
        }
Exemple #4
0
        public void CompressIndexSpectrogramsFillsAllValuesTest(double renderScale, int dataSize, string key)
        {
            var someSpectra = new double[256, dataSize].Fill(-100);
            var spectra     = new Dictionary <string, double[, ]> {
                { key, someSpectra },
            };
            var compressed = IndexMatrices.CompressIndexSpectrograms(
                spectra,
                renderScale.Seconds(),
                0.1.Seconds(),
                d => Math.Round(d, MidpointRounding.AwayFromZero));

            // ReSharper disable once CompareOfFloatsByEqualityOperator (We are testing exact values)
            if (renderScale == 0.1)
            {
                // in cases where the scales are equal, the method should short circuit and
                // just return the same matrix.
                Assert.AreEqual(spectra, compressed);
            }

            var compressedSpectra = compressed[key];
            var average           = compressedSpectra.Average();

            // this test is specifically testing whether the last column has the correct value
            var lastColumn        = MatrixTools.GetColumn(compressedSpectra, compressedSpectra.LastColumnIndex());
            var lastColumnAverage = lastColumn.Average();

            Assert.AreEqual(-100, lastColumnAverage, 0.0000000001, $"Expected last column to have value -100 but it was {lastColumnAverage:R}");

            Assert.AreEqual(-100, average, 0.0000000001, $"Expected total average to be -100 but it was {average:R}");
        }
Exemple #5
0
        public void TestReadSpectralIndices()
        {
            var testSpectra = PathHelper.ResolveAssetPath("20160725_203006_continuous1__Towsey.Acoustic.ACI.csv");

            var dir = PathHelper.TestResources.ToDirectoryEntry();

            var matrix = IndexMatrices.ReadSpectralIndices(
                dir,
                "20160725_203006_continuous1",
                "Towsey.Acoustic",
                new[] { "ACI" })
                         .Single()
                         .Value;

            Assert.AreEqual(256, matrix.GetLength(0));
            Assert.AreEqual(30, matrix.GetLength(1));

            Assert.AreEqual(0.462924678189025, matrix[255, 0]);
            Assert.AreEqual(0.42779069684277, matrix[254, 0]);
            Assert.AreEqual(0.46412042529103, matrix[255, 1]);
            Assert.AreEqual(0.444650614488611, matrix[254, 1]);

            var matrix2 = IndexMatrices.ReadSpectrogram(testSpectra.ToFileInfo(), out var binCount);

            matrix2 = MatrixTools.MatrixRotate90Anticlockwise(matrix2);

            var actualEnumerator = matrix2.GetEnumerator();

            foreach (var expected in matrix)
            {
                actualEnumerator.MoveNext();

                Assert.AreEqual(expected, (double)actualEnumerator.Current, 1E-14, $"delta: {expected - (double)actualEnumerator.Current}");
            }
        }
Exemple #6
0
        public static Dictionary <string, double[]> ConvertToDictionaryOfSummaryIndices(List <SummaryIndexValues> summaryIndices)
        {
            // Now add in derived indices i.e. NCDI etc
            // Decided NOT to do this anymore
            // dictionaryOfSummaryIndices = IndexMatrices.AddDerivedIndices(dictionaryOfSummaryIndices);

            // Put SUMMARY indices into dictionary. TODO need to generalise the following method
            // ################# WARNING: THIS METHOD ONLY GETS A "HARD CODED" LIST OF SUMMARY INDICES. See the method.
            var dictionaryOfSummaryIndices = IndexMatrices.GetDictionaryOfSummaryIndices(summaryIndices);

            // return the dictionary - it will be used later to produce an index tracks image.
            return(dictionaryOfSummaryIndices);
        }
Exemple #7
0
        public void CompressIndexSpectrogramsTest()
        {
            var spectra = new Dictionary <string, double[, ]> {
                { "Test", new double[, ] {
                      { 1, 2, 3, 4 }
                  } },
            };

            Assert.ThrowsException <ArgumentException>(
                () => IndexMatrices.CompressIndexSpectrograms(
                    spectra,
                    TimeSpan.FromSeconds(60),
                    TimeSpan.FromSeconds(80)));
        }
Exemple #8
0
        /// <summary>
        /// Compress high resolution indices - intended to be used when summarizing results.
        /// Summarize method not yet written.
        /// </summary>
        /// <param name="analysisResults"></param>
        /// <param name="indexResults"></param>
        /// <param name="highResolutionParsedConfiguration"></param>
        private void SummarizeHighResolutionIndices(
            AnalysisResult2 analysisResults,
            IndexCalculateResult[] indexResults,
            AcousticIndices.AcousticIndicesConfig highResolutionParsedConfiguration)
        {
            // NOW COMPRESS THE HI-RESOLUTION SPECTRAL INDICES TO LOW RES
            double   lowResolution = highResolutionParsedConfiguration.GetDoubleOrNull("LowResolution") ?? 60.0;
            TimeSpan imageScale    = TimeSpan.FromSeconds(lowResolution);
            TimeSpan dataScale     = highResolutionParsedConfiguration.IndexCalculationDuration.Seconds();

            var dictionaryOfSpectra = indexResults.Select(icr => icr.SpectralIndexValues).ToArray().ToTwoDimensionalArray(SpectralIndexValues.CachedSelectors, TwoDimensionalArray.Rotate90ClockWise);

            var spectralSelection = IndexMatrices.CompressIndexSpectrograms(dictionaryOfSpectra, imageScale, dataScale);

            // check that have not compressed matrices to zero length
            double[,] matrix = spectralSelection.First().Value;
            if (matrix.GetLength(0) == 0 || matrix.GetLength(1) == 0)
            {
                LoggedConsole.WriteErrorLine("WARNING: SPECTRAL INDEX MATRICES compressed to zero length!!!!!!!!!!!!!!!!!!!!!!!!");
            }

            // Place LOW RESOLUTION SPECTRAL INDICES INTO analysisResults before returning.
            //int windowLength = (int?)highResolutionConfig[AnalysisKeys.FrameLength] ?? IndexCalculate.DefaultWindowSize;
            var indexProperties = highResolutionParsedConfiguration.IndexProperties;

            SpectralIndexValues.CheckExistenceOfSpectralIndexValues(indexProperties);

            // Init a new spectral indices class and populate it with spectral indices
            var spectrums = SpectralIndexValues.ImportFromDictionary(spectralSelection);

            for (int i = 0; i < spectrums.Length; i++)
            {
                spectrums[i].ResultStartSeconds     = (analysisResults.SegmentStartOffset + TimeSpan.FromSeconds(i * lowResolution)).TotalSeconds;
                spectrums[i].SegmentDurationSeconds = imageScale.TotalSeconds;
                spectrums[i].FileName = ((SegmentSettings <object>)analysisResults.SegmentSettings).Segment.SourceMetadata.Identifier;
            }

            // assign to the analysis result
            analysisResults.SpectralIndices = spectrums;

            // TODO TODO TODO
            // ALSO NEED TO COMPRESS THE analysisResults.SummaryIndices To LOW RESOLUTION
            //var summaryIndexValues = new SummaryIndexValues();
            //summaryIndexValues.BackgroundNoise = ETC;
            // ETC
            //var summaryiv = new SummaryIndexValues[1];
            //summaryiv[0] = summaryIndexValues;
            //analysisResults.SummaryIndices = summaryiv;
        }
Exemple #9
0
        public void TestReadSpectrogram()
        {
            var testSpectra = PathHelper.ResolveAssetPath("20160725_203006_continuous1__Towsey.Acoustic.ACI.csv");

            var matrix = IndexMatrices.ReadSpectrogram(testSpectra.ToFileInfo(), out var binCount);

            Assert.AreEqual(30, matrix.GetLength(0));
            Assert.AreEqual(256, matrix.GetLength(1));
            Assert.AreEqual(256, binCount);

            Assert.AreEqual(0.462924678189025, matrix[0, 0]);
            Assert.AreEqual(0.42779069684277, matrix[0, 1]);
            Assert.AreEqual(0.46412042529103, matrix[1, 0]);
            Assert.AreEqual(0.444650614488611, matrix[1, 1]);
        }
        // ##############################################################################################################
        // ######################### METHODS FOR STITCHING TNC - EDDIE GAME's DATA
        // ######################### CONCATENATE EVERYTHING

        /// <summary>
        /// RECENT METHOD TO CONCATENATE Spectral INDEX.CSV FILES - August 2015. Revised Septermber 2016
        /// Was written to deal with  EDDIE GAME PNG data where the files to be concatenated are all in one top level directory.
        /// This method merges all files of spectral indices in the passed directories.
        /// The total length of the concatenated files can exceed 24 hours - limited by memory!
        /// </summary>
        public static Dictionary <string, double[, ]> ConcatenateAllSpectralIndexFiles(DirectoryInfo[] directories, string[] keys, IndexGenerationData indexGenerationData)
        {
            string analysisType = "Towsey.Acoustic";
            var    dictionaryOfSpectralIndices = IndexMatrices.GetSpectralIndexFilesAndConcatenate(directories, analysisType, keys, indexGenerationData, true);

            if (dictionaryOfSpectralIndices.Count == 0)
            {
                LoggedConsole.WriteErrorLine("WARNING from method LDSpectrogramStitching.ConcatenateSpectralIndexFiles() !!!");
                LoggedConsole.WriteErrorLine("        An empty dictionary of spectral indices was returned !!! ");
                return(null);
            }

            // now add in derived indices i.e. POW, NCDI etc
            // dictionaryOfSpectralIndices = IndexMatrices.AddDerivedIndices(dictionaryOfSpectralIndices);
            return(dictionaryOfSpectralIndices);
        }
        private static (Dictionary <string, double[, ]>, Dictionary <string, IndexProperties>) LoadSpectra(
            AnalysisIoInputDirectory io,
            string analysisTag,
            string fileStem,
            Dictionary <string, IndexProperties> indexProperties)
        {
            indexProperties = InitialiseIndexProperties.FilterIndexPropertiesForSpectralOnly(indexProperties);
            string[] keys = indexProperties.Keys.ToArray();

            Dictionary <string, double[, ]> spectra = IndexMatrices.ReadSpectralIndices(
                io.InputBase,
                fileStem,
                analysisTag,
                keys);

            return(spectra, indexProperties);
        }
        /// <summary>
        /// ONLY Use this concatenation method when you want to concatenate the files for a fixed single day.
        /// The files to be concatenated must be somewhere in the subdirectory structure of the passed list of data directories
        /// Read them into a dictionary
        /// MOST RECENT METHOD TO CONCATENATE Spectral INDEX.CSV FILES - Early September 2015.
        /// It is designed to deal with Yvonne's case where want to concatenate files distributed over arbitrary directories.
        /// It only merges files for the passed fixed date. i.e only 24 hours
        /// </summary>
        public static void DrawSpectralIndexFiles(
            Dictionary <string, double[, ]> dictionary,
            LdSpectrogramConfig sgConfig,
            IndexGenerationData indexGenerationData,
            FileInfo indexPropertiesConfigFileInfo,
            DirectoryInfo opDir,
            SiteDescription siteDescription,
            FileInfo sunriseDataFile          = null,
            List <GapsAndJoins> segmentErrors = null)
        {
            // derive new indices such as sqrt(PMN), NCDI etc -- main reason for this is to view what their distributions look like.
            dictionary = IndexMatrices.AddDerivedIndices(dictionary);

            // Calculate the index distribution statistics and write to a json file. Also save as png image
            if (indexGenerationData.RecordingStartDate != null)
            {
                DateTimeOffset dto        = (DateTimeOffset)indexGenerationData.RecordingStartDate;
                string         dateString = $"{dto.Year}{dto.Month:D2}{dto.Day:D2}";
                string         opFileStem = $"{siteDescription.SiteName}_{dateString}";

                var indexDistributions = IndexDistributions.WriteSpectralIndexDistributionStatistics(dictionary, opDir, opFileStem);

                //SummaryIndexBase[] summaryIndices = null;
                string analysisType = "Towsey.Acoustic";

                Tuple <Image, string>[] tuple = LDSpectrogramRGB.DrawSpectrogramsFromSpectralIndices(
                    opDir, // topLevelDirectories[0], // this should not be required but it is - because things have gotten complicated !
                    opDir,
                    sgConfig,
                    indexPropertiesConfigFileInfo,
                    indexGenerationData,
                    opFileStem,
                    analysisType,
                    dictionary,
                    null, //summaryIndices,
                    indexDistributions,
                    siteDescription,
                    sunriseDataFile,
                    segmentErrors,
                    ImageChrome.With);
            }
        }
        public static (Dictionary <string, double[, ]>, Dictionary <string, IndexProperties>) LoadSpectra(
            AnalysisIoInputDirectory io,
            string analysisTag,
            string fileStem,
            LdSpectrogramConfig config,
            Dictionary <string, IndexProperties> indexProperties)
        {
            var keys = config.GetKeys().Distinct();

            // add two necessary keys for zooming
            keys = keys.ToList().Append("SUM");
            keys = keys.ToList().Append("DIF");

            //add following matrix for possible subsequent BNG combination matrix.
            string comboIndexID = "RHZ";

            keys = keys.ToList().Append(comboIndexID);

            var relevantIndexProperties = keys.ToDictionary(x => x, x => indexProperties[x]);

            Dictionary <string, double[, ]> spectra = IndexMatrices.ReadSpectralIndices(
                io.InputBase,
                fileStem,
                analysisTag,
                keys.ToArray());

            /*
             * // THE FOLLOWING IDEA TO MAKE A COMBINED MATRIX OF BGN and RHZ was rejected.
             * // Anthony was concerned that the BGN matrix alone was not conveying much information at high resolutions.
             * // The idea was to combine another matrix with the BGN matrix.
             * // I tried three combinations, BGN-RHZ, BGN-OSC and BGN-SPT. None of them appeard to provide additional useful information at high resolution.
             * // The problem is that at high resolution, i.e. approaching 0.1s for an analysis unit, there are not many orthogonal features in a single frequency bin.
             * // Make a BNG COMBINATION Spectral matrix.
             * //var comboMatrix = MatrixTools.MaxOfTwoMatrices(spectra["BNG"], spectra["RHZ"]);
             * var comboMatrix = MatrixTools.AddMatricesWeightedSum(spectra["BGN"], 1.0, spectra[comboIndexID], 10.0);
             * spectra["BGN"] = comboMatrix;
             */

            return(spectra, relevantIndexProperties);
        }
Exemple #14
0
        public void CompressIndexSpectrogramsFillsAllValuesTest(double renderScale, int dataSize)
        {
            var bgnSpectra = new double[256, dataSize].Fill(-100);
            var spectra    = new Dictionary <string, double[, ]> {
                { "BGN", bgnSpectra },
            };
            var compressed = IndexMatrices.CompressIndexSpectrograms(
                spectra,
                renderScale.Seconds(),
                0.1.Seconds(),
                d => Math.Round(d, MidpointRounding.AwayFromZero));

            var bgn     = compressed["BGN"];
            var average = bgn.Average();

            // this test is specifically testing whether the last column has the correct value
            var lastColumn = MatrixTools.GetColumn(bgn, bgn.LastColumnIndex());

            Assert.AreEqual(-100, lastColumn.Average());

            Assert.AreEqual(-100, average);
        }
Exemple #15
0
        public void TestWriteReadSpectrogram()
        {
            var random      = TestHelpers.Random.GetRandom();
            var testSpectra = random.NextMatrix(100, 50);

            var testFile = this.outputDirectory.CombineFile("test.matrix.csv");

            Csv.WriteMatrixToCsv(testFile, testSpectra);

            var matrix = IndexMatrices.ReadSpectrogram(testFile, out var binCount);

            Assert.AreEqual(100, matrix.GetLength(0));
            Assert.AreEqual(50, matrix.GetLength(1));
            Assert.AreEqual(50, binCount);

            var actualEnumerator = matrix.GetEnumerator();

            foreach (var expected in testSpectra)
            {
                actualEnumerator.MoveNext();

                Assert.AreEqual(expected, (double)actualEnumerator.Current, 1E-14, $"delta: {expected - (double)actualEnumerator.Current}");
            }
        }
Exemple #16
0
        } // method DrawRidgeSpectrograms()

        public static Image DrawRidgeSpectrograms(DirectoryInfo inputDirectory, FileInfo ipConfig, string fileStem, double scale, Dictionary <string, double[, ]> spectra = null)
        {
            string analysisType = AcousticIndices.TowseyAcoustic;

            //double backgroundFilter = 0.0; // 0.0 means small values are removed.
            double backgroundFilter = 0.75;  // 0.75 means small values are accentuated.
            var    dataScale        = TimeSpan.FromSeconds(scale);

            Dictionary <string, IndexProperties> indexProperties = IndexProperties.GetIndexProperties(ipConfig);

            string[] keys = SpectralPeakTracks.GetDefaultRidgeKeys();

            // read the csv files of the indices in keys array
            if (spectra == null)
            {
                //C:\SensorNetworks\Output\BIRD50\Training\ID0001\Towsey.Acoustic\ID0001__Towsey.Acoustic.ACI
                spectra = IndexMatrices.ReadSpectralIndices(inputDirectory, fileStem, analysisType, keys);
            }

            var cs1 = new LDSpectrogramRGB(minuteOffset: TimeSpan.Zero, xScale: dataScale, sampleRate: 22050, frameWidth: 512, colorMap: null)
            {
                FileName                 = fileStem,
                BackgroundFilter         = backgroundFilter,
                IndexCalculationDuration = dataScale,
            };

            // set the relevant dictionary of index properties
            cs1.SetSpectralIndexProperties(indexProperties);
            cs1.SpectrogramMatrices = spectra;
            if (cs1.GetCountOfSpectrogramMatrices() == 0)
            {
                LoggedConsole.WriteLine("WARNING:  " + fileStem + ":   No spectrogram matrices in the dictionary. Spectrogram files do not exist?");
                return(null);
            }
            else if (cs1.GetCountOfSpectrogramMatrices() < keys.Length)
            {
                LoggedConsole.WriteLine("WARNING:  " + fileStem + ":   Missing indices in the dictionary. Some files do not exist?");
                return(null);
            }

            var stringFont = Drawing.Tahoma8;

            // constants for labels
            Color[]       color       = { Color.Blue, Color.Green, Color.Red, Color.Orange, Color.Purple };
            int           labelYvalue = 3;
            int           labelIndex  = 0;
            Image <Rgb24> ridges      = null;

            foreach (string key in keys)
            {
                Image <Rgb24> greyScaleImage = (Image <Rgb24>)cs1.DrawGreyscaleSpectrogramOfIndex(key);
                var           pixelWidth     = greyScaleImage.Width;

                int height = greyScaleImage.Height;
                ridges.Mutate(g2 =>
                {
                    if (ridges == null)
                    {
                        ridges = new Image <Rgb24>(pixelWidth, height);
                        g2.Clear(Color.White);
                    }

                    g2.DrawText(key, stringFont, color[labelIndex], new PointF(0, labelYvalue));
                });
                labelYvalue += 10;

                //g1.DrawLine(new Pen(Color.Black, 1), 0, 0, width, 0);//draw upper boundary
                //g1.DrawLine(new Pen(Color.Black, 1), 0, 1, width, 1);//draw upper boundary

                // transfer greyscale image to colour image
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < pixelWidth; x++)
                    {
                        var col = greyScaleImage[x, y];
                        if (col.G < 150)
                        {
                            ridges[x, y] = color[labelIndex];
                        }
                    }
                }

                labelIndex += 1;
            } //foreach key

            return(ridges);
        } // method DrawRidgeSpectrograms()
Exemple #17
0
        } // method DrawAggregatedSpectrograms()

        public static Image <Rgb24> DrawGrayScaleSpectrograms(Arguments arguments, string fileStem, TimeSpan dataScale, Dictionary <string, double[, ]> spectra = null)
        {
            // default values
            int sampleRate = 22050;
            int frameWidth = 512;

            //double backgroundFilter = 0.0; // 0.0 means small values are removed.
            double backgroundFilter = 0.75;  // 0.75 means small values are accentuated.
            string analysisType     = AcousticIndices.TowseyAcoustic;

            string[] keys           = LDSpectrogramRGB.GetArrayOfAvailableKeys();
            var      inputDirectory = arguments.InputDataDirectory;
            Dictionary <string, IndexProperties> indexProperties = IndexProperties.GetIndexProperties(arguments.IndexPropertiesConfig.ToFileInfo());

            if (spectra == null)
            {
                spectra = IndexMatrices.ReadSpectralIndices(inputDirectory.ToDirectoryInfo(), fileStem, analysisType, keys);
            }

            // note: the spectra are oriented as per visual orientation, i.e. xAxis = time frames
            //int frameCount = spectra[keys[0]].GetLength(1);
            var cs1 = new LDSpectrogramRGB(minuteOffset: TimeSpan.Zero, xScale: dataScale, sampleRate: sampleRate, frameWidth: frameWidth, colorMap: null)
            {
                FileName                 = fileStem,
                BackgroundFilter         = backgroundFilter,
                IndexCalculationDuration = dataScale,
            };

            cs1.SetSpectralIndexProperties(indexProperties); // set the relevant dictionary of index properties
            cs1.SpectrogramMatrices = spectra;
            if (cs1.GetCountOfSpectrogramMatrices() == 0)
            {
                LoggedConsole.WriteLine("WARNING:  " + fileStem + ":   No spectrogram matrices in the dictionary. Spectrogram files do not exist?");
                return(null);
            }

            var list       = new List <Image <Rgb24> >();
            var stringFont = Drawing.Arial14;

            foreach (string key in keys)
            {
                var image = cs1.DrawGreyscaleSpectrogramOfIndex(key);

                int width  = 70;
                int height = image.Height;
                var label  = new Image <Rgb24>(width, height);
                label.Mutate(g1 =>
                {
                    g1.Clear(Color.Gray);
                    g1.DrawText(key, stringFont, Color.Black, new PointF(4, 30));
                    g1.DrawLine(new Pen(Color.Black, 1), 0, 0, width, 0); //draw upper boundary
                    g1.DrawLine(new Pen(Color.Black, 1), 0, 1, width, 1); //draw upper boundary
                });
                var imagearray    = new[] { label, image };
                var labelledImage = ImageTools.CombineImagesInLine(imagearray);
                list.Add(labelledImage);
            } //foreach key

            var combinedImage = ImageTools.CombineImagesVertically(list);

            return(combinedImage);
        } // method DrawGrayScaleSpectrograms()
Exemple #18
0
        public static void DrawStackOfZoomedSpectrograms(DirectoryInfo inputDirectory, DirectoryInfo outputDirectory, ZoomParameters common, TimeSpan focalTime, int imageWidth, string analysisType)
        {
            var zoomConfig = common.SpectrogramZoomingConfig;
            LdSpectrogramConfig ldsConfig = common.SpectrogramZoomingConfig.LdSpectrogramConfig;

            var distributions   = common.IndexDistributions;
            var indexGeneration = common.IndexGenerationData;

            string fileStem = common.OriginalBasename;

            TimeSpan dataScale = indexGeneration.IndexCalculationDuration;

            // ####################### DERIVE ZOOMED OUT SPECTROGRAMS FROM SPECTRAL INDICES

            string[] keys            = { "ACI", "BGN", "CVR", "DIF", "ENT", "EVN", "PMN", "POW", "RHZ", "RVT", "RPS", "RNG", "SUM", "SPT" };
            var      indexProperties = InitialiseIndexProperties.FilterIndexPropertiesForSpectralOnly(zoomConfig.IndexProperties);
            Dictionary <string, double[, ]> spectra = IndexMatrices.ReadSpectralIndices(inputDirectory, fileStem, analysisType, keys);

            Stopwatch sw = Stopwatch.StartNew();

            // standard scales in seconds per pixel.
            double[] imageScales = { 60, 24, 12, 6, 2, 1, 0.6, 0.2 };
            if (zoomConfig.SpectralIndexScale != null)
            {
                imageScales = zoomConfig.SpectralIndexScale;
            }

            sw = Stopwatch.StartNew();
            int scaleCount = imageScales.Length;
            var imageList  = new List <Image>();

            for (int i = 0; i < scaleCount; i++)
            {
                var imageScale = TimeSpan.FromSeconds(imageScales[i]);
                var image      = DrawIndexSpectrogramAtScale(ldsConfig, indexGeneration, indexProperties, focalTime, dataScale, imageScale, imageWidth, spectra, fileStem);
                if (image != null)
                {
                    imageList.Add(image);
                    string name = $"{fileStem}_FocalZoom_min{focalTime.TotalMinutes:f1}_scale{imageScales[i]}.png";
                    image.Save(Path.Combine(outputDirectory.FullName, name));
                }
            }

            sw.Stop();
            LoggedConsole.WriteLine("Finished spectrograms derived from spectral indices. Elapsed time = " + sw.Elapsed.TotalSeconds + " seconds");

            // ####################### DERIVE ZOOMED IN SPECTROGRAMS FROM STANDARD SPECTRAL FRAMES
            int[] compressionFactor = { 8, 4, 2, 1 };
            int   compressionCount  = compressionFactor.Length;

            sw = Stopwatch.StartNew();
            double   frameStepInSeconds = indexGeneration.FrameStep / (double)indexGeneration.SampleRateResampled;
            TimeSpan frameScale         = TimeSpan.FromTicks((long)Math.Round(frameStepInSeconds * 10000000));

            if (zoomConfig.SpectralFrameScale != null)
            {
                imageScales = zoomConfig.SpectralFrameScale;

                // TODO: CONVERT IMAGE scales into Compression factors.
                compressionCount  = imageScales.Length;
                compressionFactor = new int[compressionCount];
                compressionFactor[compressionCount - 1] = 1;
                double denom = imageScales[compressionCount - 1];

                for (int i = 0; i < compressionCount - 1; i++)
                {
                    compressionFactor[i] = (int)Math.Round(imageScales[i] / denom);
                }
            }

            int      maxCompression   = compressionFactor[0];
            TimeSpan maxImageDuration = TimeSpan.FromTicks(maxCompression * imageWidth * frameScale.Ticks);

            TimeSpan halfMaxImageDuration = TimeSpan.FromMilliseconds(maxImageDuration.TotalMilliseconds / 2);
            TimeSpan startTimeOfMaxImage  = TimeSpan.Zero;

            if (focalTime != TimeSpan.Zero)
            {
                startTimeOfMaxImage = focalTime - halfMaxImageDuration;
            }

            TimeSpan startTimeOfData = TimeSpan.FromMinutes(Math.Floor(startTimeOfMaxImage.TotalMinutes));

            List <double[]> frameData = ReadFrameData(inputDirectory, fileStem, startTimeOfMaxImage, maxImageDuration, zoomConfig, indexGeneration.MaximumSegmentDuration.Value);

            // get the index data to add into the
            // TimeSpan imageScale1 = TimeSpan.FromSeconds(0.1);
            double[,] indexData = spectra["POW"];

            // make the images
            for (int i = 0; i < compressionCount; i++)
            {
                int factor = compressionFactor[i];
                var image  = DrawFrameSpectrogramAtScale(ldsConfig, indexGeneration, startTimeOfData, factor, frameData, indexData, focalTime, frameScale, imageWidth);
                if (image != null)
                {
                    imageList.Add(image);
                }
            }

            sw.Stop();
            LoggedConsole.WriteLine("Finished spectrograms derived from standard frames. Elapsed time = " + sw.Elapsed.TotalSeconds + " seconds");

            // combine the images into a stack
            Image  combinedImage = ImageTools.CombineImagesVertically(imageList);
            string fileName      = $"{fileStem}_FocalZOOM_min{focalTime.TotalMinutes:f1}.png";

            combinedImage.Save(Path.Combine(outputDirectory.FullName, fileName));
        }
Exemple #19
0
        public void TestAnalyzeSr64000Recording()
        {
            int    sampleRate = 64000;
            double duration   = 420; // signal duration in seconds = 7 minutes

            int[]  harmonics     = { 500, 1000, 2000, 4000, 8000 };
            var    recording     = DspFilters.GenerateTestRecording(sampleRate, duration, harmonics, WaveType.Cosine);
            string recordingName = "TemporaryRecording2";
            var    recordingPath = this.outputDirectory.CombineFile(recordingName + ".wav");

            WavWriter.WriteWavFileViaFfmpeg(recordingPath, recording.WavReader);

            var fst       = FreqScaleType.Linear125Octaves7Tones28Nyquist32000;
            var freqScale = new FrequencyScale(fst);

            /*
             * // draw the signal as spectrogram just for debugging purposes
             * // but can only draw a two minute spectrogram when sr=64000 - change duration above.
             * duration = 120; // if drawing sonogram, then set signal duration = 2 minutes
             * var sonogram = OctaveFreqScale.ConvertRecordingToOctaveScaleSonogram(recording, fst);
             * var sonogramImage = sonogram.GetImageFullyAnnotated(sonogram.GetImage(), "SPECTROGRAM", freqScale.GridLineLocations);
             * var outputImagePath = this.outputDirectory.CombineFile("SignalSpectrogram_OctaveFreqScale.png");
             * sonogramImage.Save(outputImagePath.FullName);
             */

            // Now need to rewrite the config file with new parameter settings
            var configPath = PathHelper.ResolveConfigFile("Towsey.Acoustic.yml");

            // Convert the Config config to IndexCalculateConfig class and merge in the unnecesary parameters.
            //Config configuration = Yaml.Deserialise(configPath);
            //IndexCalculateConfig config = IndexCalculateConfig.GetConfig(configuration, false);

            // because of difficulties in dealing with Config config files, just edit the text file!!!!!
            var configLines = File.ReadAllLines(configPath.FullName);

            configLines[configLines.IndexOf(x => x.StartsWith("IndexCalculationDuration: "))] = "IndexCalculationDuration: 15.0";

            //configLines[configLines.IndexOf(x => x.StartsWith("BgNoiseBuffer: "))] = "BgNoiseBuffer: 5.0";
            configLines[configLines.IndexOf(x => x.StartsWith("FrequencyScale: Linear"))] = "FrequencyScale: " + fst;

            // the is the only octave scale currently functioning for IndexCalculate class
            configLines[configLines.IndexOf(x => x.StartsWith("FrameLength"))]    = $"FrameLength: {freqScale.WindowSize}";
            configLines[configLines.IndexOf(x => x.StartsWith("ResampleRate: "))] = "ResampleRate: 64000";

            // write the edited Config file to temporary output directory
            var newConfigPath = this.outputDirectory.CombineFile("Towsey.Acoustic.yml");

            File.WriteAllLines(newConfigPath.FullName, configLines);

            PathHelper.ResolveConfigFile("IndexPropertiesConfig.yml").CopyTo(this.outputDirectory.CombineFile("IndexPropertiesConfig.yml").FullName);

            var arguments = new AnalyseLongRecording.Arguments
            {
                Source        = recordingPath,
                Config        = newConfigPath.FullName,
                Output        = this.outputDirectory,
                MixDownToMono = true,
                Parallel      = !Debugger.IsAttached,
            };

            AnalyseLongRecording.Execute(arguments);

            var resultsDirectory = this.outputDirectory.Combine("Towsey.Acoustic");
            var listOfFiles      = resultsDirectory.EnumerateFiles().ToArray();

            Assert.AreEqual(19, listOfFiles.Length);

            var csvCount = listOfFiles.Count(f => f.Name.EndsWith(".csv"));

            Assert.AreEqual(15, csvCount);

            var jsonCount = listOfFiles.Count(f => f.Name.EndsWith(".json"));

            Assert.AreEqual(2, jsonCount);

            var pngCount = listOfFiles.Count(f => f.Name.EndsWith(".png"));

            Assert.AreEqual(2, pngCount);

            var bgnFile = resultsDirectory.CombineFile(recordingName + "__Towsey.Acoustic.BGN.csv");

            double[,] actualBgn = Csv.ReadMatrixFromCsv <double>(bgnFile, TwoDimensionalArray.None);

            var expectedSpectrumFile = PathHelper.ResolveAsset("LongDuration", "BgnMatrix.OctaveScale.csv");

            // uncomment the following line when first produce the array
            // bgnFile.CopyTo(expectedSpectrumFile.FullName);

            // compare actual BGN file with expected file.
            var expectedBgn = Csv.ReadMatrixFromCsv <double>(expectedSpectrumFile, TwoDimensionalArray.None);

            CollectionAssert.That.AreEqual(expectedBgn, actualBgn, 0.000_000_001);

            var array = MatrixTools.GetRow(actualBgn, 0);

            Assert.AreEqual(28, actualBgn.RowLength());
            Assert.AreEqual(256, array.Length);

            // draw array just to check peaks are in correct places - just for debugging purposes
            var ldsBgnSpectrumFile = this.outputDirectory.CombineFile("Spectrum2.png");

            GraphsAndCharts.DrawGraph(array, "LD BGN SPECTRUM Octave", ldsBgnSpectrumFile);

            // ##########################################
            // SECOND part of test is to create the LD spectrograms because they are not created when IndexCalcDuration < 60 seconds
            // first read in the index generation data
            var icdPath         = resultsDirectory.CombineFile(recordingName + "__IndexGenerationData.json");
            var indexConfigData = Json.Deserialize <IndexGenerationData>(icdPath);

            var indexPropertiesConfig = PathHelper.ResolveConfigFile("IndexPropertiesConfig.yml");

            var ldSpectrogramConfigFile = PathHelper.ResolveConfigFile("SpectrogramFalseColourConfig.yml");
            var ldSpectrogramConfig     = LdSpectrogramConfig.ReadYamlToConfig(ldSpectrogramConfigFile);

            ldSpectrogramConfig.FreqScale = fst.ToString();

            // finally read in the dictionary of spectra
            string analysisType        = "Towsey.Acoustic";
            var    keys                = LDSpectrogramRGB.GetArrayOfAvailableKeys();
            var    dictionaryOfSpectra = IndexMatrices.ReadSpectralIndices(resultsDirectory, recordingName, analysisType, keys);

            LDSpectrogramRGB.DrawSpectrogramsFromSpectralIndices(
                inputDirectory: resultsDirectory,
                outputDirectory: resultsDirectory,
                ldSpectrogramConfig: ldSpectrogramConfig,
                indexPropertiesConfigPath: indexPropertiesConfig,
                indexGenerationData: indexConfigData,
                basename: recordingName,
                analysisType: analysisType,
                indexSpectrograms: dictionaryOfSpectra);

            // test number of images - should now be 23
            listOfFiles = resultsDirectory.EnumerateFiles().ToArray();
            pngCount    = listOfFiles.Count(f => f.Name.EndsWith(".png"));
            Assert.AreEqual(22, pngCount);

            var twoMapsImagePath = resultsDirectory.CombineFile(recordingName + "__2Maps.png");
            var twoMapsImage     = Image.Load <Rgb24>(twoMapsImagePath.FullName);

            // image is (7*4) * 652
            Assert.AreEqual(28, twoMapsImage.Width);
            Assert.AreEqual(652, twoMapsImage.Height);
        }
Exemple #20
0
        } // method DrawAggregatedSpectrograms()

        public static Image DrawGrayScaleSpectrograms(Arguments arguments, string fileStem, TimeSpan dataScale, Dictionary <string, double[, ]> spectra = null)
        {
            int sampleRate = 22050;
            int frameWidth = 512;

            //double backgroundFilter = 0.0; // 0.0 means small values are removed.
            double backgroundFilter = 0.75;  // 0.75 means small values are accentuated.
            string analysisType     = AcousticIndices.TowseyAcoustic;

            string[] keys = LDSpectrogramRGB.GetArrayOfAvailableKeys();

            //LoggedConsole.WriteLine("# Spectrogram Config      file: " + arguments.SpectrogramConfigPath);
            //LoggedConsole.WriteLine("# Index Properties Config file: " + arguments.IndexPropertiesConfig);
            var inputDirectory = arguments.InputDataDirectory;
            Dictionary <string, IndexProperties> indexProperties = IndexProperties.GetIndexProperties(arguments.IndexPropertiesConfig.ToFileInfo());

            if (spectra == null)
            {
                //C:\SensorNetworks\Output\BIRD50\Training\ID0001\Towsey.Acoustic\ID0001__Towsey.Acoustic.ACI
                spectra = IndexMatrices.ReadSpectralIndices(inputDirectory.ToDirectoryInfo(), fileStem, analysisType, keys);
            }

            // note: the spectra are oriented as per visual orientation, i.e. xAxis = time frames
            //int frameCount = spectra[keys[0]].GetLength(1);
            var cs1 = new LDSpectrogramRGB(minuteOffset: TimeSpan.Zero, xScale: dataScale, sampleRate: sampleRate, frameWidth: frameWidth, colourMap: null)
            {
                FileName                 = fileStem,
                BackgroundFilter         = backgroundFilter,
                IndexCalculationDuration = dataScale,
            };

            cs1.SetSpectralIndexProperties(indexProperties); // set the relevant dictionary of index properties
            cs1.SpectrogramMatrices = spectra;
            if (cs1.GetCountOfSpectrogramMatrices() == 0)
            {
                LoggedConsole.WriteLine("WARNING:  " + fileStem + ":   No spectrogram matrices in the dictionary. Spectrogram files do not exist?");
                return(null);
            }

            List <Image> list       = new List <Image>();
            Font         stringFont = new Font("Arial", 14);

            foreach (string key in keys)
            {
                var image = cs1.DrawGreyscaleSpectrogramOfIndex(key);

                int width  = 70;
                int height = image.Height;
                var label  = new Bitmap(width, height);
                var g1     = Graphics.FromImage(label);
                g1.Clear(Color.Gray);
                g1.DrawString(key, stringFont, Brushes.Black, new PointF(4, 30));
                g1.DrawLine(new Pen(Color.Black), 0, 0, width, 0); //draw upper boundary
                g1.DrawLine(new Pen(Color.Black), 0, 1, width, 1); //draw upper boundary

                Image[] imagearray    = { label, image };
                var     labelledImage = ImageTools.CombineImagesInLine(imagearray);
                list.Add(labelledImage);
            } //foreach key

            var combinedImage = ImageTools.CombineImagesVertically(list.ToArray());

            return(combinedImage);
        } // method DrawGrayScaleSpectrograms()
        public static void ConcatenateDays()
        {
            DirectoryInfo parentDir      = new DirectoryInfo(@"C:\SensorNetworks\Output\Frommolt");
            DirectoryInfo dataDir        = new DirectoryInfo(parentDir + @"\AnalysisOutput\mono");
            var           imageDirectory = new DirectoryInfo(parentDir + @"\ConcatImageOutput");

            //string indexPropertiesConfig = @"C:\Work\GitHub\audio-analysis\AudioAnalysis\AnalysisConfigFiles\IndexPropertiesConfigHiRes.yml";
            DateTimeOffset?startDate          = new DateTimeOffset(2012, 03, 29, 0, 0, 0, TimeSpan.Zero);
            DateTimeOffset?endDate            = new DateTimeOffset(2012, 06, 20, 0, 0, 0, TimeSpan.Zero);
            var            timeSpanOffsetHint = new TimeSpan(01, 0, 0);

            //string fileSuffix = @"2Maps.png";
            //string fileSuffix = @"ACI-ENT-EVN.png";
            // WARNING: POW was removed in December 2018
            string fileSuffix = @"BGN-POW-EVN.png";

            TimeSpan totalTimespan = (DateTimeOffset)endDate - (DateTimeOffset)startDate;
            int      dayCount      = totalTimespan.Days + 1; // assume last day has full 24 hours of recording available.

            bool verbose = true;

            if (verbose)
            {
                LoggedConsole.WriteLine("\n# Start date = " + startDate.ToString());
                LoggedConsole.WriteLine("# End   date = " + endDate.ToString());
                LoggedConsole.WriteLine(string.Format("# Elapsed time = {0:f1} hours", dayCount * 24));
                LoggedConsole.WriteLine("# Day  count = " + dayCount + " (inclusive of start and end days)");
                LoggedConsole.WriteLine("# Time Zone  = " + timeSpanOffsetHint.ToString());
            }

            //string dirMatch = "Monitoring_Rosin_2012*T*+0200_.merged.wav.channel_0.wav";
            string stem     = "Monitoring_Rosin_2012????T??0000+0200_.merged.wav.channel_";
            string dirMatch = stem + "?.wav";

            DirectoryInfo[] subDirectories = dataDir.GetDirectories(dirMatch, SearchOption.AllDirectories);

            string format   = "yyyyMMdd";
            string startDay = ((DateTimeOffset)startDate).ToString(format);

            //string fileMatch = stem + "?__" + fileSuffix;
            //FileInfo[] files = IndexMatrices.GetFilesInDirectories(subDirectories, fileMatch);

            // Sort the files by date and return as a dictionary: sortedDictionaryOfDatesAndFiles<DateTimeOffset, FileInfo>
            //var sortedDictionaryOfDatesAndFiles = FileDateHelpers.FilterFilesForDates(files, timeSpanOffsetHint);

            //following needed if a day is missing.
            int defaultDayWidth  = 20;
            int defaultDayHeight = 300;

            Brush brush      = Brushes.White;
            Font  stringFont = new Font("Tahoma", 12);

            var list = new List <Image>();

            // loop over days
            for (int d = 0; d < dayCount; d++)
            {
                Console.WriteLine(string.Format("Day {0} of {1} days", d, dayCount));
                var    thisday = ((DateTimeOffset)startDate).AddDays(d);
                string date    = thisday.ToString(format);

                stem = "Monitoring_Rosin_" + date + "T??0000+0200_.merged.wav.channel_";
                string     fileMatch = stem + "?__" + fileSuffix;
                FileInfo[] files     = IndexMatrices.GetFilesInDirectories(subDirectories, fileMatch);
                if (files.Length == 0)
                {
                    Bitmap   gapImage = new Bitmap(defaultDayWidth, defaultDayHeight);
                    Graphics g5       = Graphics.FromImage(gapImage);
                    g5.Clear(Color.Gray);
                    g5.DrawString("Day", stringFont, brush, new PointF(2, 5));
                    g5.DrawString("missing", stringFont, brush, new PointF(2, 35));
                    list.Add(gapImage);

                    continue;
                }

                // Sort the files by date and return as a dictionary: sortedDictionaryOfDatesAndFiles<DateTimeOffset, FileInfo>
                //var sortedDictionaryOfDatesAndFiles = FileDateHelpers.FilterFilesForDates(files, timeSpanOffsetHint);

                Image image = ConcatenateFourChannelImages(files, imageDirectory, fileSuffix, date);

                defaultDayHeight = image.Height;
                list.Add(image);
            }

            Image combinedImage = ImageTools.CombineImagesInLine(list);

            Bitmap   labelImage1 = new Bitmap(combinedImage.Width, 24);
            Graphics g1          = Graphics.FromImage(labelImage1);

            g1.Clear(Color.Black);
            g1.DrawString(fileSuffix, stringFont, brush, new PointF(2, 2));

            //labelImage1.Save(Path.Combine(imageDirectory.FullName, suffix1));

            Graphics g = Graphics.FromImage(combinedImage);

            g.DrawImage(labelImage1, 0, 0);
            string fileName = string.Format(startDay + "." + fileSuffix);

            combinedImage.Save(Path.Combine(imageDirectory.FullName, fileName));
        }
        public static Image DrawIndexSpectrogramCommon(
            LdSpectrogramConfig config,
            IndexGenerationData indexGenerationData,
            Dictionary <string, IndexProperties> indexProperties,
            TimeSpan startTime,
            TimeSpan endTime,
            TimeSpan dataScale,
            TimeSpan imageScale,
            int imageWidth,
            Dictionary <string, double[, ]> spectra,
            string basename)
        {
            double scalingFactor = Math.Round(imageScale.TotalMilliseconds / dataScale.TotalMilliseconds);

            Contract.Requires(scalingFactor >= 1.0, $"Compression scale `{scalingFactor}`is invalid");

            // calculate data duration from column count of abitrary matrix
            //TimeSpan dataDuration = TimeSpan.FromSeconds(matrix.GetLength(1) * dataScale.TotalSeconds);
            int columnCount = spectra.FirstValue().GetLength(1);

            var startIndex = (int)(startTime.Ticks / dataScale.Ticks);
            var endIndex   = (int)(endTime.Ticks / dataScale.Ticks);

            Contract.Ensures(endIndex <= columnCount);

            // extract subset of target data
            var spectralSelection = new Dictionary <string, double[, ]>();

            foreach (string key in spectra.Keys)
            {
                var matrix   = spectra[key];
                int rowCount = matrix.GetLength(0);

                spectralSelection[key] = MatrixTools.Submatrix(matrix, 0, startIndex, rowCount - 1, endIndex - 1);
                Contract.Ensures(
                    spectralSelection[key].GetLength(1) == (endTime - startTime).Ticks / dataScale.Ticks,
                    "The expected number of frames should be extracted.");
            }

            // compress spectrograms to correct scale
            if (scalingFactor > 1)
            {
                // we add rounding to the compression so that fractional pixels get rendered
                spectralSelection = IndexMatrices.CompressIndexSpectrograms(
                    spectralSelection,
                    imageScale,
                    dataScale,
                    d => Math.Round(d, MidpointRounding.AwayFromZero));
            }
            else
            {
                // this else is unnecessary - completely defensive code
                Contract.Ensures(scalingFactor == 1);
            }

            // check that have not compressed matrices to zero length
            if (spectralSelection.FirstValue().GetLength(0) == 0 || spectralSelection.FirstValue().GetLength(1) == 0)
            {
                throw new InvalidOperationException("Spectral matrices compressed to zero size");
            }

            // DEFINE the DEFAULT colour maps for the false-colour spectrograms
            // Then obtain values from spectrogramDrawingConfig. NOTE: WE REQUIRE LENGTH = 11 chars.
            string colorMap1 = "ACI-ENT-EVN";

            if (config.ColorMap1 != null && config.ColorMap1.Length == 11)
            {
                colorMap1 = config.ColorMap1;
            }

            string colorMap2 = "BGN-PMN-EVN";

            if (config.ColorMap2 != null && config.ColorMap2.Length == 11)
            {
                colorMap2 = config.ColorMap2;
            }

            double backgroundFilterCoeff = indexGenerationData.BackgroundFilterCoeff;

            // double  colourGain = (double?)configuration.ColourGain ?? SpectrogramConstants.COLOUR_GAIN;  // determines colour saturation
            var cs1 = new LDSpectrogramRGB(config, indexGenerationData, colorMap1)
            {
                FileName         = basename,
                BackgroundFilter = backgroundFilterCoeff,
            };

            cs1.SetSpectralIndexProperties(indexProperties); // set the relevant dictionary of index properties
            cs1.LoadSpectrogramDictionary(spectralSelection);

            // set up piecewise linear function to determine colour weights
            var    logResolution   = Math.Log(imageScale.TotalMilliseconds, 2);
            double upperResolution = Math.Log(32768, 2);
            double lowerResolution = Math.Log(256, 2);
            double range           = upperResolution - lowerResolution;
            double blendWeight1;

            if (logResolution >= upperResolution)
            {
                blendWeight1 = 1.0;
            }
            else if (logResolution <= lowerResolution)
            {
                blendWeight1 = 0.0;
            }
            else
            {
                blendWeight1 = (logResolution - lowerResolution) / range;
            }

            double blendWeight2 = 1 - blendWeight1;

            //else if (imageScaleInMsPerPixel > 2000)
            //{
            //    blendWeight1 = 0.7;
            //    blendWeight2 = 0.3;
            //}
            //else if (imageScaleInMsPerPixel > 1000)
            //{
            //    blendWeight1 = 0.3;
            //    blendWeight2 = 0.7;
            //}
            //else if (imageScaleInMsPerPixel > 500)
            //{
            //    // > 0.5 seconds
            //    blendWeight1 = 0.2;
            //    blendWeight2 = 0.8;
            //}
            //else if (imageScaleInMsPerPixel > 300)
            //{
            //    // > 0.5 seconds
            //    blendWeight1 = 0.1;
            //    blendWeight2 = 0.9;
            //}

            var ldfcSpectrogram = cs1.DrawBlendedFalseColourSpectrogram(colorMap1, colorMap2, blendWeight1, blendWeight2);

            if (ldfcSpectrogram == null)
            {
                throw new InvalidOperationException("Null Image returned from DrawBlendedFalseColourSpectrogram");
            }

            return(ldfcSpectrogram);
        }
Exemple #23
0
        public static void Execute(Arguments arguments)
        {
            var inputDirs = arguments.InputDataDirectories.Select(FileInfoExtensions.ToDirectoryInfo);
            var output    = arguments.OutputDirectory.ToDirectoryInfo();

            string date = "# DATE AND TIME: " + DateTime.Now;

            LoggedConsole.WriteLine("\n# DRAW an EASY IMAGE from consecutive days of SUMMARY INDICES in CSV files.");
            LoggedConsole.WriteLine("#    IT IS ASSUMED THAT THE CSV files are already concatenated into 24 hour files.");
            LoggedConsole.WriteLine(date);
            LoggedConsole.WriteLine("# Summary Index.csv files are in directories:");
            foreach (DirectoryInfo dir in inputDirs)
            {
                LoggedConsole.WriteLine("    {0}", dir.FullName);
            }

            LoggedConsole.WriteLine("# Output directory: " + output);
            if (arguments.StartDate == null)
            {
                LoggedConsole.WriteLine("# Start date = NULL (No argument provided). Will revise start date ....");
            }
            else
            {
                LoggedConsole.WriteLine("# Start date = " + arguments.StartDate.ToString());
            }

            if (arguments.EndDate == null)
            {
                LoggedConsole.WriteLine("# End   date = NULL (No argument provided). Will revise end date ....");
            }
            else
            {
                LoggedConsole.WriteLine("# End   date = " + arguments.EndDate.ToString());
            }

            LoggedConsole.WriteLine("# FILE FILTER = " + arguments.FileFilter);
            LoggedConsole.WriteLine();

            // PATTERN SEARCH FOR SUMMARY INDEX FILES.
            //string pattern = "*__Towsey.Acoustic.Indices.csv";
            FileInfo[] csvFiles = IndexMatrices.GetFilesInDirectories(inputDirs.ToArray(), arguments.FileFilter);

            //LoggedConsole.WriteLine("# Subdirectories Count = " + subDirectories.Length);
            LoggedConsole.WriteLine("# SummaryIndexFiles.csv Count = " + csvFiles.Length);

            if (csvFiles.Length == 0)
            {
                LoggedConsole.WriteErrorLine("\n\nWARNING from method DrawEasyImage.Execute():");
                LoggedConsole.WriteErrorLine("        No SUMMARY index files were found.");
                LoggedConsole.WriteErrorLine("        RETURNING EMPTY HANDED!");
                return;
            }

            // Sort the files by date and return as a dictionary: sortedDictionaryOfDatesAndFiles<DateTimeOffset, FileInfo>
            //var sortedDictionaryOfDatesAndFiles = LDSpectrogramStitching.FilterFilesForDates(csvFiles, arguments.TimeSpanOffsetHint);

            // calculate new start date if passed value = null.
            DateTimeOffset?startDate = arguments.StartDate;
            DateTimeOffset?endDate   = arguments.EndDate;

            TimeSpan totalTimespan = (DateTimeOffset)endDate - (DateTimeOffset)startDate;
            int      dayCount      = totalTimespan.Days + 1; // assume last day has full 24 hours of recording available.

            LoggedConsole.WriteLine("\n# Start date = " + startDate.ToString());
            LoggedConsole.WriteLine("# End   date = " + endDate.ToString());
            LoggedConsole.WriteLine(string.Format("# Elapsed time = {0:f1} hours", dayCount * 24));
            LoggedConsole.WriteLine("# Day  count = " + dayCount + " (inclusive of start and end days)");
            LoggedConsole.WriteLine("# Time Zone  = " + arguments.TimeSpanOffsetHint.ToString());

            // create top level output directory if it does not exist.
            DirectoryInfo opDir = output;

            if (!opDir.Exists)
            {
                opDir.Create();
            }

            // SET UP DEFAULT SITE LOCATION INFO    --  DISCUSS IWTH ANTHONY
            // The following location data is used only to draw the sunrise/sunset tracks on images.
            double?latitude        = null;
            double?longitude       = null;
            var    siteDescription = new SiteDescription();

            siteDescription.SiteName  = arguments.FileStemName;
            siteDescription.Latitude  = latitude;
            siteDescription.Longitude = longitude;

            // the following required if drawing the index images
            FileInfo indexPropertiesConfig = null;

            // require IndexGenerationData and indexPropertiesConfig for drawing
            //indexGenerationData = IndexGenerationData.GetIndexGenerationData(csvFiles[0].Directory);
            indexPropertiesConfig = arguments.IndexPropertiesConfig.ToFileInfo();
            Dictionary <string, IndexProperties>    listOfIndexProperties = IndexProperties.GetIndexProperties(indexPropertiesConfig);
            Tuple <List <string>, List <double[]> > tuple = CsvTools.ReadCSVFile(csvFiles[0].FullName);
            var names = tuple.Item1;

            // default EASY indices
            int    redID = 3; // backgroundNoise
            int    grnID = 5; // avSNROfActiveframes
            int    bluID = 7; // events per second
            string rep   = @"bgn-avsnr-evn";

            // ACI Ht Hpeaks EASY indices
            if (false)
            {
                redID = 11;  // ACI
                grnID = 12;  // Ht

                //bluID = 13;  // HavgSp
                //bluID = 14;  // Hvariance
                //bluID = 15;  // Hpeaks
                bluID = 16;  // Hcov

                //bluID = 7;  // SPT
                rep = @"aci-ht-hcov";

                //rep = @"aci-ht-spt";
            }

            // LF, MF, HF
            if (true)
            {
                redID = 10;  // LF
                grnID = 9;   // MF
                bluID = 8;   // HF
                rep   = @"lf-mf-hf";
            }

            IndexProperties redIndexProps = listOfIndexProperties[names[redID]];
            IndexProperties grnIndexProps = listOfIndexProperties[names[grnID]];
            IndexProperties bluIndexProps = listOfIndexProperties[names[bluID]];

            int dayPixelHeight = 4;
            int rowCount       = (dayPixelHeight * dayCount) + 35; // +30 for grid lines
            int colCount       = 1440;
            var bitmap         = new Image <Rgb24>(colCount, rowCount);
            var colour         = Color.Yellow;
            int currentRow     = 0;
            var oneDay         = TimeSpan.FromHours(24);
            int graphWidth     = colCount;
            int trackHeight    = 20;
            var stringFont     = Drawing.Arial8;

            string[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

            // for drawing the y-axis scale
            int scaleWidth = trackHeight + 7;
            var yAxisScale = new Image <Rgb24>(scaleWidth, rowCount + (2 * trackHeight));

            yAxisScale.Mutate(g =>
            {
                g.Clear(Color.Black);

                // loop over days
                for (int d = 0; d < dayCount; d++)
                {
                    var thisday = ((DateTimeOffset)startDate).AddDays(d);

                    if (thisday.Day == 1)
                    {
                        int nextRow = currentRow + 1;
                        for (int c = 0; c < colCount; c++)
                        {
                            bitmap[c, currentRow] = Color.Gray;
                            bitmap[c, nextRow]    = Color.Gray;
                        }

                        for (int c = 0; c < scaleWidth; c++)
                        {
                            yAxisScale[c, currentRow + trackHeight] = Color.Gray;
                            yAxisScale[c, nextRow + trackHeight]    = Color.Gray;
                        }

                        string month = monthNames[thisday.Month - 1];
                        if (thisday.Month == 1) // January
                        {
                            g.DrawText(thisday.Year.ToString(), stringFont, Color.White,
                                       new PointF(0, nextRow + trackHeight + 1));  //draw time
                            g.DrawText(month, stringFont, Color.White,
                                       new PointF(1, nextRow + trackHeight + 11)); //draw time
                        }
                        else
                        {
                            g.DrawText(month, stringFont, Color.White,
                                       new PointF(1, nextRow + trackHeight + 1)); //draw time
                        }

                        currentRow += 2;
                    }

                    // get the exact date and time
                    LoggedConsole.WriteLine($"READING DAY {d + 1} of {dayCount}:   {thisday.ToString()}");

                    // CREATE DAY LEVEL OUTPUT DIRECTORY for this day
                    string dateString = $"{thisday.Year}{thisday.Month:D2}{thisday.Day:D2}";

                    tuple      = CsvTools.ReadCSVFile(csvFiles[d].FullName);
                    var arrays = tuple.Item2;

                    var redArray = arrays[redID];
                    var grnArray = arrays[grnID];
                    var bluArray = arrays[bluID];

                    // NormaliseMatrixValues the indices
                    redArray = DataTools.NormaliseInZeroOne(redArray, redIndexProps.NormMin, redIndexProps.NormMax);
                    grnArray = DataTools.NormaliseInZeroOne(grnArray, grnIndexProps.NormMin, grnIndexProps.NormMax);
                    bluArray = DataTools.NormaliseInZeroOne(bluArray, bluIndexProps.NormMin, bluIndexProps.NormMax);

                    for (int c = 0; c < colCount; c++)
                    {
                        for (int r = 0; r < dayPixelHeight; r++)
                        {
                            //transformedValue = Math.Sqrt(redArray[c]);
                            var transformedValue = redArray[c] * redArray[c];
                            int redVal           = (int)Math.Round(transformedValue * 255);
                            if (redVal < 0)
                            {
                                redVal = 0;
                            }
                            else if (redVal > 255)
                            {
                                redVal = 255;
                            }

                            //transformedValue = Math.Sqrt(grnArray[c]);
                            transformedValue = grnArray[c] * grnArray[c]; // square the value
                            int grnVal       = (int)Math.Round(transformedValue * 255);
                            if (grnVal < 0)
                            {
                                grnVal = 0;
                            }
                            else if (grnVal > 255)
                            {
                                grnVal = 255;
                            }

                            //transformedValue = Math.Sqrt(bluArray[c]);
                            transformedValue = bluArray[c] * bluArray[c]; // square the value
                            int bluVal       = (int)Math.Round(transformedValue * 255);
                            if (bluVal < 0)
                            {
                                bluVal = 0;
                            }
                            else if (bluVal > 255)
                            {
                                bluVal = 255;
                            }

                            bitmap[c, currentRow + r] = Color.FromRgb((byte)redVal, (byte)grnVal, (byte)bluVal);
                        }
                    } // over all columns

                    currentRow += dayPixelHeight;

                    if (thisday.Day % 7 == 0)
                    {
                        for (int c = 0; c < colCount; c++)
                        {
                            bitmap[c, currentRow] = Color.Gray;
                        }

                        currentRow++;
                    }
                } // over days
            });
            // draw on civil dawn and dusk lines
            int startdayOfYear = ((DateTimeOffset)startDate).DayOfYear;
            int endDayOfYear   = ((DateTimeOffset)endDate).DayOfYear;

            SunAndMoon.AddSunRiseSetLinesToImage(bitmap, arguments.BrisbaneSunriseDatafile.ToFileInfo(), startdayOfYear, endDayOfYear, dayPixelHeight);

            // add the time scales
            Image <Rgb24> timeBmp1      = ImageTrack.DrawTimeRelativeTrack(oneDay, graphWidth, trackHeight);
            var           imageList     = new [] { timeBmp1, bitmap, timeBmp1 };
            Image <Rgb24> compositeBmp1 = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);

            imageList = new [] { yAxisScale, compositeBmp1 };
            Image <Rgb24> compositeBmp2 = (Image <Rgb24>)ImageTools.CombineImagesInLine(imageList);

            // indices used for image
            string        indicesDescription = $"{redIndexProps.Name}|{grnIndexProps.Name}|{bluIndexProps.Name}";
            string        startString        = $"{startDate.Value.Year}/{startDate.Value.Month}/{startDate.Value.Day}";
            string        endString          = $"{endDate.Value.Year}/{endDate.Value.Month}/{endDate.Value.Day}";
            string        title    = $"EASY:   {arguments.FileStemName}    From {startString} to {endString}                          Indices: {indicesDescription}";
            Image <Rgb24> titleBar = ImageTrack.DrawTitleTrack(compositeBmp2.Width, trackHeight, title);

            imageList     = new [] { titleBar, compositeBmp2 };
            compositeBmp2 = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);
            var outputFileName = Path.Combine(opDir.FullName, arguments.FileStemName + "." + rep + ".EASY.png");

            compositeBmp2.Save(outputFileName);
        } // Execute()
Exemple #24
0
        } //Execute()

        public static Output GetInstanceRepresentations(Arguments arguments)
        {
            LoggedConsole.WriteLine("1. Read in all Instances and do feature extraction");

            //################################### FEATURE WEIGHTS
            //TRY DIFFERENT WEIGHTINGS assuming following "SPT,RHZ,RVT,RPS,RNG";
            bool doDeltaFeatures = false;

            double[] weights      = { 1.0, 1.0, 0.8, 0.7, 0.7 };
            double[] deltaWeights = { 1.0, 1.0, 0.8, 0.7, 0.7, 0.5, 0.4, 0.4, 0.2, 0.2 };
            if (doDeltaFeatures)
            {
                weights = deltaWeights;
            }

            //MAX-POOLING for SPECTRAL REDUCTION
            // frequency bins used to reduce dimensionality of the 256 spectral values.
            int startBin  = 8;
            int maxOf2Bin = 117;
            int maxOf3Bin = 160;
            int endBin    = 200;

            double[] testArray = new double[256];
            for (int i = 0; i < testArray.Length; i++)
            {
                testArray[i] = i;
            }

            double[] reducedArray          = MaxPoolingLimited(testArray, startBin, maxOf2Bin, maxOf3Bin, endBin);
            int      reducedSpectralLength = reducedArray.Length;

            LoggedConsole.WriteLine("     Reduced spectral length = " + reducedSpectralLength);
            int instanceCount = arguments.InstanceCount;
            int speciesCount  = arguments.SpeciesCount;

            // READ IN THE SPECIES LABELS FILE AND SET UP THE DATA
            string[] fileID    = new string[instanceCount];
            int[]    speciesID = new int[speciesCount];
            ReadGlotinsSpeciesLabelFile(arguments.SpeciesLabelsFile, instanceCount, out fileID, out speciesID);

            // INIT array of species counts
            int[] instanceNumbersPerSpecies = new int[speciesCount];

            // INIT array of frame counts
            int[] frameNumbersPerInstance = new int[instanceCount];

            // initialise species description matrix
            var keyArray = FEATURE_KEYS.Split(',');

            int totalFeatureCount = keyArray.Length * reducedArray.Length;

            Console.WriteLine("    Total Feature Count = " + totalFeatureCount);

            if (doDeltaFeatures)
            {
                totalFeatureCount *= 2;
                LoggedConsole.WriteLine("    Total Delta Feature Count = " + totalFeatureCount);
            }

            // one matrix row per species
            double[,] instanceFeatureMatrix = new double[instanceCount, totalFeatureCount];

            // loop through all all instances
            for (int j = 0; j < instanceCount; j++)
            {
                LoggedConsole.Write(".");
                int frameCount = 0;

                // get the spectral index files
                int speciesLabel = speciesID[j];

                // dictionary to store feature spectra for instance.
                var aggreDictionary = new Dictionary <string, double[]>();

                // dictionary to store delta spectra for instance.
                var deltaDictionary = new Dictionary <string, double[]>();

                foreach (string key in keyArray)
                {
                    string   name = string.Format("{0}_Species{1:d2}.{2}.csv", fileID[j], speciesLabel, key);
                    FileInfo file = new FileInfo(Path.Combine(arguments.InputDataDirectory.FullName, name));

                    if (file.Exists)
                    {
                        int binCount;
                        double[,] matrix = IndexMatrices.ReadSpectrogram(file, out binCount);

                        // create or get the array of spectral values.
                        double[] aggregateArray = new double[reducedSpectralLength];
                        double[] deltaArray     = new double[reducedSpectralLength];

                        double[] ipVector = MatrixTools.GetRow(matrix, 0);
                        ipVector     = DataTools.SubtractValueAndTruncateToZero(ipVector, arguments.BgnThreshold);
                        reducedArray = MaxPoolingLimited(ipVector, startBin, maxOf2Bin, maxOf3Bin, endBin);
                        double[] previousArray = reducedArray;

                        // transfer spectral values to array.
                        int rowCount = matrix.GetLength(0);

                        //rowCount = (int)Math.Round(rowCount * 0.99); // ###################### USE ONLY 99% of instance
                        //if (rowCount > 1200) rowCount = 1200;
                        for (int r = 1; r < rowCount; r++)
                        {
                            ipVector     = MatrixTools.GetRow(matrix, r);
                            ipVector     = DataTools.SubtractValueAndTruncateToZero(ipVector, arguments.BgnThreshold);
                            reducedArray = MaxPoolingLimited(ipVector, startBin, maxOf2Bin, maxOf3Bin, endBin);

                            for (int c = 0; c < reducedSpectralLength; c++)
                            {
                                aggregateArray[c] += reducedArray[c];

                                // Calculate the DELTA values TWO OPTIONS ##################################################
                                double delta = Math.Abs(reducedArray[c] - previousArray[c]);

                                //double delta = reducedArray[c] - previousArray[c];
                                //if (delta < 0.0)  delta = 0.0;
                                //double delta = previousArray[c]; //previous array - i.e. do not calculate delta
                                deltaArray[c] += delta;
                            }

                            previousArray = reducedArray;
                        }

                        aggreDictionary[key] = aggregateArray;
                        deltaDictionary[key] = deltaArray;
                        frameCount           = rowCount;
                    } //if (file.Exists)
                }     //foreach (string key in keyArray)

                instanceNumbersPerSpecies[speciesLabel - 1]++;
                frameNumbersPerInstance[j] += frameCount;

                // create the matrix of instance descriptions which consists of concatenated vectors
                // j = index of instance ID = row number
                int featureID = 0;
                foreach (string key in keyArray)
                {
                    int featureOffset = featureID * reducedSpectralLength;
                    for (int c = 0; c < reducedSpectralLength; c++)
                    {
                        // TWO OPTIONS: SUM OR AVERAGE ######################################
                        //instanceFeatureMatrix[j, featureOffset + c] = dictionary[key][c];
                        instanceFeatureMatrix[j, featureOffset + c] = aggreDictionary[key][c] / frameCount;
                    }

                    featureID++;
                }

                if (doDeltaFeatures)
                {
                    foreach (string key in keyArray)
                    {
                        int featureOffset = featureID * reducedSpectralLength;
                        for (int c = 0; c < reducedSpectralLength; c++)
                        {
                            // TWO OPTIONS: SUM OR AVERAGE ######################################
                            //instanceFeatureMatrix[j, featureOffset + c] = dictionary[key][c];
                            instanceFeatureMatrix[j, featureOffset + c] = deltaDictionary[key][c] / frameCount;
                        }

                        featureID++;
                    }
                } // if doDeltaFeatures
            }     // end for loop j over all instances

            LoggedConsole.WriteLine("Done!");

            LoggedConsole.WriteLine("\nSum of species number array = " + instanceNumbersPerSpecies.Sum());
            LoggedConsole.WriteLine("Sum of  frame  number array = " + frameNumbersPerInstance.Sum());
            bool   addLineNumbers            = true;
            string countsArrayOutputFilePath = Path.Combine(arguments.OutputDirectory.FullName, "BirdClef50_training_Counts.txt");

            FileTools.WriteArray2File(instanceNumbersPerSpecies, addLineNumbers, countsArrayOutputFilePath);

            // Initialise output data arrays
            Output output = new Output();

            output.FileID    = fileID;
            output.SpeciesID = speciesID;
            output.InstanceNumbersPerSpecies = instanceNumbersPerSpecies;
            output.ReducedSpectralLength     = reducedSpectralLength;

            // INIT array of frame counts
            output.FrameNumbersPerInstance = frameNumbersPerInstance;

            // matrix: each row= one instance;  each column = one feature
            output.InstanceFeatureMatrix = instanceFeatureMatrix;

            output.Weights = weights;

            return(output);
        } // GetInstanceRepresentations()