예제 #1
0
        public void Test60Resolution()
        {
            var testBitmap = Image.Load <Rgba32>(PathHelper.ResolveAssetPath("1440px2.png"));
            var superTile  = new TimeOffsetSingleLayerSuperTile(
                TimeSpan.Zero,
                SpectrogramType.Index,
                60.Seconds(),
                testBitmap,
                TimeSpan.Zero);

            this.tiler.Tile(superTile);

            ////Trace.WriteLine(this.outputDirectory.FullName);
            ////Trace.WriteLine(this.outputDirectory.GetFiles().Length);
            var producedFiles = this.outputDirectory.GetFiles().OrderBy(x => x.Name).ToArray();

            Assert.AreEqual(6, producedFiles.Length);

            var expectedImages =
                new[]
            {
                "panojstile_005_004_000.png", "panojstile_005_005_000.png", "panojstile_005_000_000.png",
                "panojstile_005_001_000.png", "panojstile_005_002_000.png", "panojstile_005_003_000.png",
            }
            .OrderBy(x => x)
            .Select(args => PathHelper.ResolveAssetPath(args))
            .ToArray();
            var loadedImages = expectedImages.Select(Image.Load <Rgba32>).ToArray();

            for (int i = 0; i < loadedImages.Length; i++)
            {
                var producedImage = Image.Load <Rgba32>(producedFiles[i].FullName);
                Assert.That.ImageMatches(loadedImages[i], producedImage, message: $"Bitmaps were not equal {expectedImages[i]}, {producedFiles[i].Name}");
            }
        }
예제 #2
0
        public void EnsureReallyShortRecordingsWork()
        {
            var testBitmap = new Image <Rgba32>(2, 300);

            testBitmap.Mutate(graphics =>
            {
                graphics.Fill(Brushes.Solid(Color.Red), testBitmap.Bounds());
            });

            var superTile = new TimeOffsetSingleLayerSuperTile(TimeSpan.Zero, SpectrogramType.Index, 60.Seconds(), testBitmap, TimeSpan.Zero);

            this.tiler.Tile(superTile);

            var producedFiles = this.outputDirectory.GetFiles().OrderBy(x => x.Name).ToArray();

            Assert.AreEqual(1, producedFiles.Length);

            // produced image should have 180px of transparency, 2px of color, and then 118px of transparency
            var expected = new Image <Rgba32>(300, 300);

            expected.Mutate(graphics =>
            {
                graphics.Fill(Brushes.Solid(Color.Red), new Rectangle(180, 0, 2, 300));
            });

            var expectedImages = new[] { expected };

            for (int i = 0; i < expectedImages.Length; i++)
            {
                var producedImage = Image.Load <Rgba32>(producedFiles[i].FullName);
                Assert.That.ImageMatches(expectedImages[i], producedImage, message: $"Bitmaps were not equal {producedImage}, {producedFiles[i].Name}");
            }
        }
예제 #3
0
        public void EnsureReallyShortRecordingsWork()
        {
            var testBitmap = new Bitmap(2, 300);

            using (var graphics = Graphics.FromImage(testBitmap))
            {
                var graphicsUnit = GraphicsUnit.Pixel;
                graphics.FillRectangle(Brushes.Red, testBitmap.GetBounds(ref graphicsUnit));
            }

            var superTile = new TimeOffsetSingleLayerSuperTile(TimeSpan.Zero, SpectrogramType.Index, 60.Seconds(), testBitmap, TimeSpan.Zero);

            this.tiler.Tile(superTile);

            var producedFiles = this.outputDirectory.GetFiles();

            Assert.AreEqual(1, producedFiles.Length);

            // produced image should have 180px of transparency, 2px of color, and then 118px of transparency
            var expected = new Bitmap(300, 300);

            using (var graphics = Graphics.FromImage(expected))
            {
                graphics.FillRectangle(Brushes.Red, new Rectangle(180, 0, 2, 300));
            }

            var expectedImages = new[] { expected };

            for (int i = 0; i < expectedImages.Length; i++)
            {
                var producedImage = Image.FromFile(producedFiles[i].FullName);
                var areEqual      = BitmapEquals(expectedImages[i], (Bitmap)producedImage);
                Assert.IsTrue(areEqual, "Bitmaps were not equal {0}, {1}", expectedImages[i], producedFiles[i].Name);
            }
        }
예제 #4
0
        public void EnsureSameTileNotRenderedTwice()
        {
            var testBitmap = Image.Load <Rgba32>(PathHelper.ResolveAssetPath("Farmstay_ECLIPSE3_201_scale-1.0_supertile-1.png"));
            var superTile  = new TimeOffsetSingleLayerSuperTile(
                TimeSpan.Zero,
                SpectrogramType.Index,
                1.Seconds(),
                testBitmap,
                TimeSpan.FromHours(1));

            this.tiler.Tile(superTile);

            TestHelper.ExceptionMatches <DuplicateTileException>(
                () => { this.tiler.Tile(superTile); },
                "Tile 'panojstile_00000_00012_00000' has already been created");
        }
예제 #5
0
        private static void TileOutput(DirectoryInfo outputDirectory, string fileStem, string analysisTag, FileSegment fileSegment, Image <Rgb24> image)
        {
            const int TileHeight = 256;
            const int TileWidth  = 60;

            // seconds per pixel
            const double Scale = 60.0;
            TimeSpan     scale = Scale.Seconds();

            if (image.Height != TileHeight)
            {
                throw new InvalidOperationException("Expecting images exactly the same height as the defined tile height");
            }

            // if recording does not start on an absolutely aligned hour of the day
            // align it, then adjust where the tiling starts from, and calculate the offset for the super tile (the gap)
            var recordingStartDate = fileSegment.TargetFileStartDate.Value;

            // TODO: begin remove duplicate code
            var timeOfDay            = recordingStartDate.TimeOfDay;
            var previousAbsoluteHour = TimeSpan.FromSeconds(Math.Floor(timeOfDay.TotalSeconds / (Scale * TileWidth)) * (Scale * TileWidth));
            var gap              = timeOfDay - previousAbsoluteHour;
            var tilingStartDate  = recordingStartDate - gap;
            var tilingStartDate2 = ZoomTiledSpectrograms.GetPreviousTileBoundary(TileWidth, Scale, recordingStartDate);
            var padding          = recordingStartDate - tilingStartDate2;

            Debug.Assert(tilingStartDate == tilingStartDate2, "tilingStartDate != tilingStartDate2: these methods should be equivalent");

            // TODO: end remove duplicate code

            var tilingProfile = new AbsoluteDateTilingProfile(fileStem, analysisTag, tilingStartDate, TileHeight, TileWidth);

            // pad out image so it produces a whole number of tiles
            // this solves the asymmetric right padding of short audio files
            var width = (int)(Math.Ceiling(image.Width / Scale) * Scale);
            var tiler = new Tiler(outputDirectory, tilingProfile, Scale, width, 1.0, image.Height);

            // prepare super tile
            var tile = new TimeOffsetSingleLayerSuperTile(
                padding,
                SpectrogramType.Index,
                scale,
                image.CloneAs <Rgba32>(),
                fileSegment.SegmentStartOffset ?? TimeSpan.Zero);

            tiler.Tile(tile);
        }
예제 #6
0
        public void Test1Resolution()
        {
            var testBitmap = Image.Load <Rgba32>(PathHelper.ResolveAssetPath("Farmstay_ECLIPSE3_201_scale-1.0_supertile-1.png"));
            var superTile  = new TimeOffsetSingleLayerSuperTile(
                TimeSpan.Zero,
                SpectrogramType.Index,
                1.Seconds(),
                testBitmap,
                TimeSpan.FromHours(1));

            this.tiler.Tile(superTile);

            ////Debug.WriteLine(this.outputDirectory.FullName);
            ////Debug.WriteLine(this.outputDirectory.GetFiles().Length);
            var producedFiles = this.outputDirectory.GetFiles().OrderBy(x => x.Name).ToArray();

            Assert.AreEqual(12, producedFiles.Length);

            var expectedImages =
                new[]
            {
                "panojstile_000_012_000.png", "panojstile_000_013_000.png", "panojstile_000_014_000.png",
                "panojstile_000_015_000.png", "panojstile_000_016_000.png", "panojstile_000_017_000.png",
                "panojstile_000_018_000.png", "panojstile_000_019_000.png", "panojstile_000_020_000.png",
                "panojstile_000_021_000.png", "panojstile_000_022_000.png", "panojstile_000_023_000.png",
            }
            .OrderBy(x => x)
            .Select(args => PathHelper.ResolveAssetPath(args))
            .ToArray();

            var loadedImages = expectedImages.Select(Image.Load <Rgba32>).ToArray();

            for (int i = 0; i < loadedImages.Length; i++)
            {
                var producedImage = Image.Load <Rgba32>(producedFiles[i].FullName);
                var areEqual      = BitmapEquals(loadedImages[i], producedImage);
                Assert.IsTrue(areEqual, "Bitmaps were not equal {0}, {1}", expectedImages[i], producedFiles[i].Name);
            }
        }
예제 #7
0
        public void Test60Resolution()
        {
            var testBitmap = new Bitmap(PathHelper.ResolveAssetPath("1440px2.png"));
            var superTile  = new TimeOffsetSingleLayerSuperTile(
                TimeSpan.Zero,
                SpectrogramType.Index,
                60.Seconds(),
                testBitmap,
                TimeSpan.Zero);

            this.tiler.Tile(superTile);

            ////Debug.WriteLine(this.outputDirectory.FullName);
            ////Debug.WriteLine(this.outputDirectory.GetFiles().Length);
            var producedFiles = this.outputDirectory.GetFiles();

            Assert.AreEqual(6, producedFiles.Length);

            var expectedImages =
                new[]
            {
                "panojstile_005_004_000.png", "panojstile_005_005_000.png", "panojstile_005_000_000.png",
                "panojstile_005_001_000.png", "panojstile_005_002_000.png", "panojstile_005_003_000.png",
            }
            .OrderBy(x => x)
            .Select(args => PathHelper.ResolveAssetPath(args))
            .ToArray();
            var loadedImages = expectedImages.Select(Image.FromFile).ToArray();

            for (int i = 0; i < loadedImages.Length; i++)
            {
                var producedImage = Image.FromFile(producedFiles[i].FullName);
                var areEqual      = BitmapEquals((Bitmap)loadedImages[i], (Bitmap)producedImage);
                Assert.IsTrue(areEqual, "Bitmaps were not equal {0}, {1}", expectedImages[i], producedFiles[i].Name);
            }
        }
        public void TestLeftPaddingInLowerLayers()
        {
            const int TileWidth = 180;
            var       startDate = new DateTimeOffset(2014, 05, 29, 08, 13, 58, TimeSpan.FromHours(10));
            var       boundary  = ZoomTiledSpectrograms.GetPreviousTileBoundary(TileWidth, 0.1, startDate);
            var       padding   = startDate - boundary;

            var profile = new AbsoluteDateTilingProfile(
                "Filename",
                "Tile",
                boundary,
                256,
                TileWidth);

            var tiler = new Tiler(
                this.outputDirectory.ToDirectoryEntry(),
                profile,
                new SortedSet <double>()
            {
                60.0, 0.1
            },
                60.0,
                1440,
                new SortedSet <double>()
            {
                1, 1
            },
                1.0,
                256);

            var testBitmap = new Bitmap(1200, 256);

            using (var graphics = Graphics.FromImage(testBitmap))
            {
                var points = new[]
                {
                    new Point(0, 0), new Point(180, 256), new Point(360, 0), new Point(540, 256), new Point(720, 0),
                    new Point(900, 256), new Point(1080, 0), new Point(1260, 256),
                };
                graphics.DrawLines(
                    Pens.Red,
                    points);
            }

            var superTile = new TimeOffsetSingleLayerSuperTile(
                padding,
                SpectrogramType.Index,
                0.1.Seconds(),
                testBitmap,
                0.Seconds());

            tiler.Tile(superTile);

            ////Debug.WriteLine(this.outputDirectory.FullName);
            ////Debug.WriteLine(this.outputDirectory.GetFiles().Length);
            var actualFiles = this.outputDirectory.GetFiles().OrderBy(x => x.Name).ToArray();

            Assert.AreEqual(8, actualFiles.Length);

            var expectedFiles = new[]
            {
                "Filename__Tile_20140528T221348Z_0.1.png",
                "Filename__Tile_20140528T221406Z_0.1.png",
                "Filename__Tile_20140528T221424Z_0.1.png",
                "Filename__Tile_20140528T221442Z_0.1.png",
                "Filename__Tile_20140528T221500Z_0.1.png",
                "Filename__Tile_20140528T221518Z_0.1.png",
                "Filename__Tile_20140528T221536Z_0.1.png",
                "Filename__Tile_20140528T221554Z_0.1.png",
            };
            var expectedImages =
                expectedFiles
                .OrderBy(x => x)
                .Select((x, i) => testBitmap.Crop(new Rectangle((i * TileWidth) - 100, 0, TileWidth, 256)))
                .ToArray();

            for (var i = 0; i < expectedImages.Length; i++)
            {
                Assert.AreEqual(expectedFiles[i], actualFiles[i].Name);

                var expectedImage = expectedImages[i];
                var actualImage   = Image.FromFile(actualFiles[i].FullName);
                var areEqual      = TilerTests.BitmapEquals(expectedImage, (Bitmap)actualImage);
                Assert.IsTrue(areEqual, "Bitmaps were not equal {0}, {1}", expectedFiles[i], actualFiles[i]);
            }
        }
        /// <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);
        }
        /// <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);
        }
예제 #11
0
        public void TestLeftPaddingInLowerLayers()
        {
            const int TileWidth = 180;
            var       startDate = new DateTimeOffset(2014, 05, 29, 08, 13, 58, TimeSpan.FromHours(10));
            var       boundary  = ZoomTiledSpectrograms.GetPreviousTileBoundary(TileWidth, 0.1, startDate);
            var       padding   = startDate - boundary;

            var profile = new AbsoluteDateTilingProfile(
                "Filename",
                "Tile",
                boundary,
                256,
                TileWidth);

            var tiler = new Tiler(
                this.outputDirectory,
                profile,
                new SortedSet <double>()
            {
                60.0, 0.1
            },
                60.0,
                1440,
                new SortedSet <double>()
            {
                1, 1
            },
                1.0,
                256);

            var testBitmap = new Image <Rgba32>(1200, 256);

            testBitmap.Mutate(graphics =>
            {
                var points = new[]
                {
                    new PointF(0, 0), new Point(180, 256), new Point(360, 0), new Point(540, 256), new Point(720, 0),
                    new PointF(900, 256), new Point(1080, 0), new Point(1260, 256),
                };
                graphics.DrawLines(
                    new GraphicsOptions(),
                    Brushes.Solid(Color.Red),
                    1,
                    points);
            });

            var superTile = new TimeOffsetSingleLayerSuperTile(
                padding,
                SpectrogramType.Index,
                0.1.Seconds(),
                testBitmap,
                0.Seconds());

            tiler.Tile(superTile);

            ////Trace.WriteLine(this.outputDirectory.FullName);
            ////Trace.WriteLine(this.outputDirectory.GetFiles().Length);
            var actualFiles = this.outputDirectory.GetFiles().OrderBy(x => x.Name).ToArray();

            Assert.AreEqual(8, actualFiles.Length);

            var expectedFiles = new[]
            {
                "Filename__Tile_20140528T221348Z_0.1.png",
                "Filename__Tile_20140528T221406Z_0.1.png",
                "Filename__Tile_20140528T221424Z_0.1.png",
                "Filename__Tile_20140528T221442Z_0.1.png",
                "Filename__Tile_20140528T221500Z_0.1.png",
                "Filename__Tile_20140528T221518Z_0.1.png",
                "Filename__Tile_20140528T221536Z_0.1.png",
                "Filename__Tile_20140528T221554Z_0.1.png",
            };
            var expectedImages =
                expectedFiles
                .OrderBy(x => x)
                .Select((x, i) => testBitmap.CropInverse(new Rectangle((i * TileWidth) - 100, 0, TileWidth, 256)))
                .ToArray();

            for (var i = 0; i < expectedImages.Length; i++)
            {
                Assert.AreEqual(expectedFiles[i], actualFiles[i].Name);

                var expectedImage = expectedImages[i];
                var actualImage   = Image.Load <Rgba32>(actualFiles[i].FullName);
                Assert.That.ImageMatches(expectedImages[i], actualImage, message: $"Bitmaps were not equal {expectedImages[i]}, {actualFiles[i]}");
            }
        }