Exemplo n.º 1
0
        [DataRow(0.1, 35990)] // at this scale 10 pixels are missing... image is padded by 0 px, and misisng 10px
        public void TestImagesHaveCorrectLength(double renderScale, int expectedWidth)
        {
            // this value just represents a 'render as much as you can until this limit' threshold
            const int ImageWidth = 1024;

            var dataScale  = 0.1.Seconds();
            var imageScale = renderScale.Seconds();

            var recordingDuration = 3599.Seconds();

            // we simulate rendering the last tile at each resolution
            var tileDuration  = imageScale.Multiply(ImageWidth);
            var numberOfTiles = (int)Math.Floor(recordingDuration.TotalSeconds / tileDuration.TotalSeconds);
            var startTime     = tileDuration.Multiply(numberOfTiles);

            // 1 second short of an hour - this is the test case
            var endTime = recordingDuration;

            var config = new LdSpectrogramConfig()
            {
                // same color map to reduce memory stress for test
                ColorMap1 = SpectrogramConstants.RGBMap_BGN_PMN_EVN,
                ColorMap2 = SpectrogramConstants.RGBMap_BGN_PMN_EVN,
            };

            var generationData = new IndexGenerationData()
            {
                IndexCalculationDuration = dataScale,
                FrameLength       = 512,
                FrameStep         = 0,
                RecordingDuration = recordingDuration,
            };
            var indexProperties =
                IndexProperties.GetIndexProperties(PathHelper.ResolveConfigFile("IndexPropertiesConfig.yml"));

            // create some fake spectra
            int duration = (int)(recordingDuration.TotalSeconds / dataScale.TotalSeconds);
            var spectra  = new Dictionary <string, double[, ]>();

            foreach (var key in config.GetKeys())
            {
                var values = new double[256, duration].Fill(indexProperties[key].DefaultValue);
                spectra.Add(key, values);
            }

            string basename = "abc";

            var image = ZoomCommon.DrawIndexSpectrogramCommon(
                config,
                generationData,
                indexProperties,
                startTime,
                endTime,
                dataScale,
                imageScale,
                ImageWidth,
                spectra,
                basename);

            // since we just asked for a fragment of the image at the end,
            // the expected width is just for that last fragment
            var lastWidth = expectedWidth - (numberOfTiles * ImageWidth);

            Assert.That.ImageIsSize(lastWidth, 256, image);

            Image <Rgb24> bitmap = (Image <Rgb24>)image;

            // test output for debugging
            //image.Save("./" + renderScale + ".png");
            Assert.That.ImageRegionIsColor(new Rectangle(0, 0, lastWidth, 256), Color.Black, bitmap, 0);
        }
        /// <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);
        }
        [DataRow(0.1, 35990)] // at this scale 10 pixels are missing... image is padded by 0 px, and misisng 10px
        public void TestImagesHaveCorrectLength(double renderScale, int expectedWidth)
        {
            // this value just represents a 'render as much as you can until this limit' threshold
            const int ImageWidth = 1024;

            var dataScale  = 0.1.Seconds();
            var imageScale = renderScale.Seconds();

            var recordingDuration = 3599.Seconds();

            // we simulate rendering the last tile at each resolution
            var tileDuration  = imageScale.Multiply(ImageWidth);
            var numberOfTiles = (int)Math.Floor(recordingDuration.TotalSeconds / tileDuration.TotalSeconds);
            var startTime     = tileDuration.Multiply(numberOfTiles);

            // 1 second short of an hour - this is the test case
            var endTime = recordingDuration;

            var config         = new LdSpectrogramConfig();
            var generationData = new IndexGenerationData()
            {
                IndexCalculationDuration = dataScale,
                FrameLength       = 512,
                FrameStep         = 0,
                RecordingDuration = recordingDuration,
            };
            var indexProperties =
                IndexProperties.GetIndexProperties(PathHelper.ResolveConfigFile("IndexPropertiesConfig.yml"));

            // create some fake spectra
            int duration = (int)(recordingDuration.TotalSeconds / dataScale.TotalSeconds);
            var spectra  = new Dictionary <string, double[, ]>();

            foreach (var key in SpectralIndexValues.GetKeys())
            {
                spectra.Add(key, new double[256, duration]);
                var bgnKey = nameof(SpectralIndexValues.BGN);
                if (key == bgnKey)
                {
                    spectra[bgnKey].Fill(indexProperties[bgnKey].DefaultValue);
                }

                // due to a bug in DrawRgbColourMatrix the ACI calculation ends up being NaN.
                // This we fill one of our other spectra to a non-zero value to get the black colour we desire
                // Bug reference: https://github.com/QutEcoacoustics/audio-analysis/issues/154
                var sumKey = nameof(SpectralIndexValues.SUM);
                if (key == sumKey)
                {
                    // this forces ACI calculation to 0 / 1 instead of 0 / 0
                    spectra[sumKey].Fill(1.0);
                }
            }

            string basename = "abc";

            var image = ZoomCommon.DrawIndexSpectrogramCommon(
                config,
                generationData,
                indexProperties,
                startTime,
                endTime,
                dataScale,
                imageScale,
                ImageWidth,
                spectra,
                basename);

            // since we just asked for a fragment of the image at the end,
            // the expected width is just for that last fragment
            var lastWidth = expectedWidth - (numberOfTiles * ImageWidth);

            Assert.That.ImageIsSize(lastWidth, 256, image);

            Bitmap bitmap = (Bitmap)image;

            // test output for debugging
            //image.Save("./" + renderScale + ".png");
            Assert.That.ImageRegionIsColor(new Rectangle(0, 0, lastWidth, 256), Color.Black, bitmap, 0);
        }