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>
        /// This method can add in absolute time if you want.
        /// Currently commented out - see below.
        /// </summary>
        public static Image <Rgb24> DrawIndexSpectrogramAtScale(
            LdSpectrogramConfig config,
            IndexGenerationData indexGenerationData,
            Dictionary <string, IndexProperties> indexProperties,
            TimeSpan focalTime,
            TimeSpan dataScale,
            TimeSpan imageScale,
            int imageWidth,
            Dictionary <string, double[, ]> spectra,
            string basename)
        {
            if (spectra == null)
            {
                LoggedConsole.WriteLine("WARNING: NO SPECTRAL DATA SUPPLIED");
                return(null);
            }

            // check that scalingFactor >= 1.0
            double scalingFactor = Math.Round(imageScale.TotalMilliseconds / dataScale.TotalMilliseconds);

            if (scalingFactor < 1.0)
            {
                LoggedConsole.WriteLine("WARNING: Scaling Factor < 1.0");
                return(null);
            }

            Dictionary <string, IndexProperties> dictIp = indexProperties;

            dictIp = InitialiseIndexProperties.FilterIndexPropertiesForSpectralOnly(dictIp);

            // calculate start time by combining DatetimeOffset with minute offset.
            TimeSpan sourceMinuteOffset = indexGenerationData.AnalysisStartOffset;

            if (indexGenerationData.RecordingStartDate.HasValue)
            {
                DateTimeOffset dto = (DateTimeOffset)indexGenerationData.RecordingStartDate;
                sourceMinuteOffset = dto.TimeOfDay + sourceMinuteOffset;
            }

            // calculate data duration from column count of abitrary matrix
            var kvp    = spectra.First();
            var matrix = kvp.Value;

            //var matrix = spectra["ACI"]; // assume this key will always be present!!
            TimeSpan dataDuration = TimeSpan.FromSeconds(matrix.GetLength(1) * dataScale.TotalSeconds);

            TimeSpan recordingStartTime = TimeSpan.Zero; // default = zero minute of day i.e. midnight

            recordingStartTime = indexGenerationData.RecordingStartDate.Value.TimeOfDay.Add(indexGenerationData.AnalysisStartOffset);

            TimeSpan offsetTime        = TimeSpan.Zero;
            TimeSpan imageDuration     = TimeSpan.FromTicks(imageWidth * imageScale.Ticks);
            TimeSpan halfImageDuration = TimeSpan.FromTicks(imageWidth * imageScale.Ticks / 2);
            TimeSpan startTime         = TimeSpan.Zero;

            if (focalTime != TimeSpan.Zero)
            {
                startTime = focalTime - halfImageDuration;
            }

            if (startTime < TimeSpan.Zero)
            {
                offsetTime = TimeSpan.Zero - startTime;
                startTime  = TimeSpan.Zero;
            }

            TimeSpan endTime = imageDuration;

            if (focalTime != TimeSpan.Zero)
            {
                endTime = focalTime + halfImageDuration;
            }

            if (endTime > dataDuration)
            {
                endTime = dataDuration;
            }

            TimeSpan spectrogramDuration = endTime - startTime;
            int      spectrogramWidth    = (int)(spectrogramDuration.Ticks / imageScale.Ticks);

            // get the plain unchromed spectrogram
            var ldfcSpectrogram = ZoomCommon.DrawIndexSpectrogramCommon(
                config,
                indexGenerationData,
                indexProperties,
                startTime,
                endTime,
                dataScale,
                imageScale,
                imageWidth,
                spectra,
                basename);

            if (ldfcSpectrogram == null)
            {
                LoggedConsole.WriteLine("WARNING: NO SPECTROGRAM AT SCALE " + imageScale);
                return(null);
            }

            // now chrome spectrogram
            ldfcSpectrogram.Mutate(g2 =>
            {
                // draw red line at focus time
                if (focalTime != TimeSpan.Zero)
                {
                    Pen pen = new Pen(Color.Red, 1);
                    TimeSpan focalOffset = focalTime - startTime;
                    int x1 = (int)(focalOffset.Ticks / imageScale.Ticks);
                    g2.DrawLine(pen, x1, 0, x1, ldfcSpectrogram.Height);
                }
            });

            // draw the title bar
            int nyquist = 22050 / 2; // default

            if (indexGenerationData.SampleRateResampled > 0)
            {
                nyquist = indexGenerationData.SampleRateResampled / 2;
            }

            int herzInterval = 1000;

            if (config != null)
            {
                herzInterval = config.YAxisTicInterval;
            }

            string title = $"SCALE={imageScale.TotalSeconds}s/px.  Duration={spectrogramDuration} ";

            //add chrome
            // NEXT LINE USED ONLY IF WANT ABSOLUTE TIME
            //startTime += recordingStartTime;
            var titleBar = DrawTitleBarOfZoomSpectrogram(title, ldfcSpectrogram.Width);

            ldfcSpectrogram = FrameZoomSpectrogram(
                ldfcSpectrogram,
                titleBar,
                startTime,
                imageScale,
                config.XAxisTicInterval,
                nyquist,
                herzInterval);

            // create the base canvas image on which to centre the focal image
            var image = Drawing.NewImage(imageWidth, ldfcSpectrogram.Height, Color.DarkGray);

            int xOffset = (int)(offsetTime.Ticks / imageScale.Ticks);

            image.Mutate(g1 => g1.DrawImage(ldfcSpectrogram, new Point(xOffset, 0), 1));
            return(image);
        }
Example #3
0
        /// <summary>
        /// This method used to construct slices out of implicit 3-D spectrograms.
        /// As of December 2014 it contains hard coded variables just to get it working.
        /// </summary>
        public static void Main(Arguments arguments)
        {
            if (!arguments.OutputDir.Exists)
            {
                arguments.OutputDir.Create();
            }

            const string title   = "# READ LD data table files to prepare a 3D Spectrogram";
            string       dateNow = "# DATE AND TIME: " + DateTime.Now;

            LoggedConsole.WriteLine(title);
            LoggedConsole.WriteLine(dateNow);
            LoggedConsole.WriteLine("# Index    Properties: " + arguments.IndexPropertiesConfig.Name);
            LoggedConsole.WriteLine("# Input     directory: " + arguments.InputDir.Name);

            //LoggedConsole.WriteLine("# SonogramConfig:   " + arguments.SonoConfig.Name);
            LoggedConsole.WriteLine("# Table     directory: " + arguments.TableDir.Name);
            LoggedConsole.WriteLine("# Output    directory: " + arguments.OutputDir.Name);
            LoggedConsole.WriteLine("# Analysis SampleRate: " + arguments.SampleRate);
            LoggedConsole.WriteLine("# Analysis  FrameSize: " + arguments.FrameSize);

            bool verbose = arguments.Verbose;

            // 1. set up the necessary files
            DirectoryInfo inputDirInfo     = arguments.InputDir;
            DirectoryInfo dataTableDirInfo = arguments.TableDir;
            DirectoryInfo opDir            = arguments.OutputDir;

            // FileInfo configFile = arguments.SonoConfig;
            FileInfo indexPropertiesConfig = arguments.IndexPropertiesConfig;
            FileInfo sunriseSetData        = arguments.BrisbaneSunriseDatafile;
            int      sampleRate            = arguments.SampleRate;
            int      frameSize             = arguments.FrameSize;
            int      nyquistFreq           = sampleRate / 2;
            int      freqBinCount          = frameSize / 2;
            double   freqBinWidth          = nyquistFreq / (double)freqBinCount;

            // 2. convert spectral indices to a data table - need only do this once
            // ### IMPORTANT ######################################################################################################################
            // Uncomment the next line when converting spectral indices to a data table for the first time.
            // It calls method to read in index spectrograms and combine all the info into one index table per day
            //SpectralIndicesToAndFromTable.ReadAllSpectralIndicesAndWriteToDataTable(indexPropertiesConfig, inputDirInfo, dataTableDirInfo);

            // ############ use next seven lines to obtain slices at constant DAY OF YEAR
            string key           = KeyDayOfYear;
            int    step          = 1;
            int    firstIndex    = 71;
            int    maxSliceCount = TotalDaysInYear + 1;
            var    xInterval     = TimeSpan.FromMinutes(60); // one hour intervals = 60 pixels
            int    rowId         = 3;                        // FreqBin
            int    colId         = 2;                        // MinOfDay

            // ############ use next seven lines to obtain slices at constant FREQUENCY
            //string key = keyFreqBin;
            //int step = 100;
            //int firstIndex = 0;
            //int maxSliceCount = nyquistFreq;
            //var XInterval = TimeSpan.FromMinutes(60);
            //int rowID = 1; // DayOfYear
            //int colID = 2; // MinOfDay

            // ############ use next seven lines to obtain slices at constant MINUTE OF DAY
            //string key = keyMinOfDay;
            //int step = 5;
            //int firstIndex = 0;
            //int maxSliceCount = LDSpectrogram3D.Total_Minutes_In_Day;
            //var XInterval = TimeSpan.FromDays(30.4); // average days per month
            //int rowID = 3; // FreqBin
            //int colID = 1; // DayOfYear

            // These are the column names and order in the csv data strings.
            // Year, DayOfYear, MinOfDay, FreqBin, ACI, AVG, BGN, CVR, TEN, VAR
            string colorMap = "ACI-TEN-CVR";
            int    redId    = 4; // ACI
            int    grnId    = 8; // TEN
            int    bluId    = 7; // CVR
            int    year     = 2013;

            for (int sliceId = firstIndex; sliceId < maxSliceCount; sliceId += step)
            {
                // DEFINE THE SLICE
                //sliceID = 300; // Herz
                int arrayId = sliceId;
                if (key == "FreqBin")
                {
                    arrayId = (int)Math.Round(sliceId / freqBinWidth);
                }

                var fileStem = string.Format("SERF_2013_" + key + "_{0:d4}", arrayId);

                // 3. Read a data slice from the data table files
                List <string> data;
                var           outputFileName = $"{fileStem}.csv";
                var           path           = Path.Combine(opDir.FullName, outputFileName);
                if (File.Exists(path))
                {
                    data = FileTools.ReadTextFile(path);
                }
                else
                {
                    if (key == KeyDayOfYear)
                    {
                        data = GetDaySlice(dataTableDirInfo, year, arrayId);
                    }
                    else
                    {
                        data = GetDataSlice(dataTableDirInfo, key, arrayId);
                    }

                    FileTools.WriteTextFile(path, data);
                }

                // 4. Read the yaml file describing the Index Properties
                Dictionary <string, IndexProperties> dictIp = IndexProperties.GetIndexProperties(indexPropertiesConfig);
                dictIp = InitialiseIndexProperties.FilterIndexPropertiesForSpectralOnly(dictIp);

                // 5. Convert data slice to image
                string[]        indexNames = colorMap.Split('-');
                IndexProperties ipRed      = dictIp[indexNames[0]];
                IndexProperties ipGrn      = dictIp[indexNames[1]];
                IndexProperties ipBlu      = dictIp[indexNames[2]];
                Image <Rgb24>   image      = GetImageSlice(key, data, rowId, colId, redId, grnId, bluId, ipRed, ipGrn, ipBlu, freqBinCount);

                // 6. frame the image and save
                image = Frame3DSpectrogram(image, key, arrayId, year, colorMap, xInterval, nyquistFreq, sliceId, sunriseSetData);

                // 7. save the image
                outputFileName = $"{fileStem}.png";
                path           = Path.Combine(opDir.FullName, outputFileName);
                image.Save(path);
            } // end loop through slices
        }     // end Main()
Example #4
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));
        }