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}"); } }
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}"); } }
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); } }
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"); }
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); }
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); } }
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); }
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]}"); } }