コード例 #1
0
        public static Image <Rgb24> DrawFrameSpectrogramAtScale(
            LdSpectrogramConfig config,
            SpectrogramZoomingConfig zoomingConfig,
            TimeSpan startTimeOfData,
            TimeSpan frameScale,
            double[,] frameData,
            IndexGenerationData indexGeneration,
            ImageChrome chromeOption)
        {
            // TODO:  the following normalisation bounds could be passed instead of using hard coded.
            double min = zoomingConfig.LowerNormalizationBoundForDecibelSpectrograms;
            double max = zoomingConfig.UpperNormalizationBoundForDecibelSpectrograms;

            //need to correctly orient the matrix for this method
            frameData = MatrixTools.MatrixRotate90Clockwise(frameData);

            // Get an unchromed image
            var spectrogramImage = ZoomFocusedSpectrograms.DrawStandardSpectrogramInFalseColour(frameData);

            if (chromeOption == ImageChrome.Without)
            {
                return(spectrogramImage);
            }

            int    nyquist      = indexGeneration.SampleRateResampled / 2;
            int    herzInterval = 1000;
            string title        = $"ZOOM SCALE={frameScale.TotalMilliseconds}ms/pixel ";
            var    titleBar     = ZoomFocusedSpectrograms.DrawTitleBarOfZoomSpectrogram(title, spectrogramImage.Width);

            spectrogramImage = ZoomFocusedSpectrograms.FrameZoomSpectrogram(
                spectrogramImage,
                titleBar,
                startTimeOfData,
                frameScale,
                config.XAxisTicInterval,
                nyquist,
                herzInterval);
            return(spectrogramImage);
        }
コード例 #2
0
        /// <summary>
        /// Assume that we are processing data for one minute only.
        ///     From this one minute of data, we produce images at three scales.
        ///     A one minute recording framed at 20ms should yield 3000 frames.
        ///     But to achieve this where sr= 22050 and frameSize=512, we need an overlap of 71 samples.
        ///     Consequently only 2999 frames returned per minute.
        ///     Therefore have to pad end to get 3000 frames.
        /// </summary>
        public static TimeOffsetSingleLayerSuperTile[] DrawSuperTilesFromSingleFrameSpectrogram(DirectoryInfo dataDir, LdSpectrogramConfig analysisConfig, Dictionary <string, IndexProperties> indexProperties, SpectrogramZoomingConfig zoomingConfig, int minute, double[] imageScales, string basename, IndexGenerationData indexGeneration, ImageChrome chromeOption, TimeSpan alignmentPadding)
        {
            string fileStem = basename;

            // string analysisType = analysisConfig.AnalysisType;
            TimeSpan indexScale = indexGeneration.IndexCalculationDuration;
            TimeSpan frameScale = TimeSpan.FromSeconds(zoomingConfig.SpectralFrameDuration);

            var expectedDataDurationInSeconds = (int)indexGeneration.MaximumSegmentDuration.Value.TotalSeconds;
            var expectedFrameCount            = (int)Math.Round(expectedDataDurationInSeconds / zoomingConfig.SpectralFrameDuration);

            string fileName        = fileStem + "_" + minute + "min.csv";
            string csvPath         = Path.Combine(dataDir.FullName, fileName);
            bool   skipHeader      = true;
            bool   skipFirstColumn = true;

            // read spectrogram into a list of frames
            List <double[]> frameList = CsvTools.ReadCSVFileOfDoubles(csvPath, skipHeader, skipFirstColumn);

            if (frameList == null)
            {
                LoggedConsole.WriteErrorLine(
                    "WARNING: METHOD DrawSuperTilesFromSingleFrameSpectrogram(): NO SPECTRAL DATA SUPPLIED");
                return(null);
            }

            PadEndOfListOfFrames(frameList, expectedFrameCount);
            TrimEndOfListOfFrames(frameList, expectedFrameCount);

            //// frame count will be one less than expected for the recording segment because of frame overlap
            //// Therefore pad the end of the list of frames with the last frame.
            // int frameDiscrepancy = expectedFrameCount - frameList.Count;
            // if (frameDiscrepancy > 0)
            // {
            // double[] frame = frameList[frameList.Count - 1];
            // for (int d = 0; d < frameDiscrepancy; d++)
            // {
            // frameList.Add(frame);
            // }
            // }
            var frameData = new TemporalMatrix("rows", MatrixTools.ConvertList2Matrix(frameList), frameScale);

            frameData.SwapTemporalDimension();                              // so the two data matrices have the same temporal dimension

            TimeSpan startTime       = indexGeneration.AnalysisStartOffset; // default = zero minute of day i.e. midnight
            TimeSpan startTimeOfData = startTime + TimeSpan.FromMinutes(minute);

            var str = new TimeOffsetSingleLayerSuperTile[imageScales.Length];

            // make the images
            for (int scale = 0; scale < imageScales.Length; scale++)
            {
                TimeSpan imageScale        = TimeSpan.FromSeconds(imageScales[scale]);
                var      compressionFactor =
                    (int)Math.Round(imageScale.TotalMilliseconds / frameData.DataScale.TotalMilliseconds);
                double columnDuration = imageScale.TotalSeconds;

                // int expectedFrameCount = (int)Math.Round(expectedDataDurationInSeconds / columnDuration);

                // ############## RESEARCH CHOICE HERE >>>>  compress spectrograms to correct scale using either max or average
                // Average appears to offer better contrast.
                // double[,] data = frameData.CompressMatrixInTemporalDirectionByTakingMax(imageScale);
                double[,] data = frameData.CompressMatrixInTemporalDirectionByTakingAverage(imageScale);

                var spectrogramImage = DrawFrameSpectrogramAtScale(
                    analysisConfig,
                    zoomingConfig,
                    startTimeOfData,
                    imageScale,
                    data,
                    indexGeneration,
                    chromeOption);

                str[scale] = new TimeOffsetSingleLayerSuperTile(
                    alignmentPadding,
                    SpectrogramType.Frame,
                    imageScale,
                    spectrogramImage.CloneAs <Rgba32>(),
                    startTimeOfData);
            }

            return(str);
        }
コード例 #3
0
        public static Image <Rgb24> DrawOneScaledIndexSpectrogramTile(
            LdSpectrogramConfig config,
            IndexGenerationData indexGenerationData,
            Dictionary <string, IndexProperties> indexProperties,
            TimeSpan startTime,
            TimeSpan dataScale,
            TimeSpan imageScale,
            int superTileImageWidth,
            Dictionary <string, double[, ]> spectra,
            string basename,
            ImageChrome chromeOption)
        {
            Contract.Requires(!spectra.IsNullOrEmpty());

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

            var analysisStartTime = indexGenerationData.RecordingStartDate.Value.TimeOfDay.Add(indexGenerationData.AnalysisStartOffset);

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

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

            TimeSpan endTime = startTime + imageDuration;

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

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

            if (chromeOption == ImageChrome.Without)
            {
                return(ldSpectrogram);
            }

            int nyquist = 22050 / 2;

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

            int hertzInterval = 1000;

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

            string title = $"ZOOM SCALE={imageScale.TotalSeconds}s/pixel";

            var titleBar = ZoomFocusedSpectrograms.DrawTitleBarOfZoomSpectrogram(title, ldSpectrogram.Width);

            startTime    += analysisStartTime;
            ldSpectrogram = ZoomFocusedSpectrograms.FrameZoomSpectrogram(
                ldSpectrogram,
                titleBar,
                startTime,
                imageScale,
                config.XAxisTicInterval,
                nyquist,
                hertzInterval);

            // create the base image
            var image = Drawing.NewImage(ldSpectrogram.Width, ldSpectrogram.Height, Color.DarkGray);

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

            image.Mutate(g1 =>
            {
                g1.DrawImage(ldSpectrogram, new Point(xOffset, 0), 1);
            });

            return(image);
        }
コード例 #4
0
        /// <summary>
        /// Draws FC index spectrograms for an entire row.
        /// </summary>
        public static TimeOffsetSingleLayerSuperTile[] DrawSuperTilesAtScaleFromIndexSpectrograms(
            LdSpectrogramConfig analysisConfig,
            Dictionary <string, IndexProperties> indexProperties,
            SpectrogramZoomingConfig zoomingConfig,
            TimeSpan imageScale,
            Dictionary <string, double[, ]> spectra,
            IndexGenerationData indexGeneration,
            string basename,
            ImageChrome chromeOption,
            TimeSpan alignmentPadding)
        {
            Contract.Requires(!spectra.IsNullOrEmpty(), "ERROR: NO SPECTRAL DATA SUPPLIED");

            // calculate source data duration from column count of arbitrary matrix
            TimeSpan dataScale = indexGeneration.IndexCalculationDuration;

            double[,] matrix = spectra.First().Value;
            TimeSpan sourceDataDuration = TimeSpan.FromSeconds(matrix.GetLength(1) * dataScale.TotalSeconds);

            int tileWidth      = zoomingConfig.TileWidth;
            int superTileWidth = zoomingConfig.SuperTileWidthDefault();
            var superTileCount =
                (int)Math.Ceiling(zoomingConfig.SuperTileCount(sourceDataDuration, imageScale.TotalSeconds));

            TimeSpan superTileDuration = TimeSpan.FromTicks(superTileWidth * imageScale.Ticks);

            // initialize the image array to return
            var superTiles = new TimeOffsetSingleLayerSuperTile[superTileCount];

            // sometimes the whole recording is not analyzed. In this case, jump the time index forward.
            TimeSpan startTime = indexGeneration.AnalysisStartOffset;

            // start the loop
            for (int t = 0; t < superTileCount; t++)
            {
                var image = DrawOneScaledIndexSpectrogramTile(
                    analysisConfig,
                    indexGeneration,
                    indexProperties,
                    startTime,
                    dataScale,
                    imageScale,
                    superTileWidth,
                    spectra,
                    basename,
                    chromeOption);

                superTiles[t] = new TimeOffsetSingleLayerSuperTile(
                    durationToPreviousTileBoundaryAtUnitScale: alignmentPadding,
                    spectrogramType: SpectrogramType.Index,
                    scale: imageScale,
                    image: image.CloneAs <Rgba32>(),
                    timeOffset: startTime);

                startTime += superTileDuration;
                if (startTime > sourceDataDuration)
                {
                    break;
                }
            }

            return(superTiles);
        }