/// <summary> /// Derives false colour varying-resolution multi-index spectrograms from provided spectral indices. /// </summary> private static void GenerateIndexSpectrogramTiles(double[] indexScales, LdSpectrogramConfig ldsConfig, Dictionary <string, IndexProperties> filteredIndexProperties, SpectrogramZoomingConfig zoomConfig, Dictionary <string, double[, ]> spectra, IndexGenerationData indexGenerationData, string fileStem, TilingProfile tilingProfile, Tiler tiler, TimeSpan alignmentPadding) { // TOP MOST ZOOMED-OUT IMAGES Log.Info("Begin drawwing zooming indec spectrograms"); foreach (double scale in indexScales) { Log.Info("Starting scale: " + scale); if (indexGenerationData.RecordingDuration.TotalSeconds < scale) { Log.Warn($"Skipping scale step {scale} because recording duration ({indexGenerationData.RecordingDuration}) is less than 1px of scale"); continue; } // TODO: eventual optimisation, remove concept of super tiles // TODO: optimisation, cache aggregation layers (currently every layer is reaggregated from base level) TimeSpan imageScale = TimeSpan.FromSeconds(scale); var superTiles = DrawSuperTilesAtScaleFromIndexSpectrograms( ldsConfig, filteredIndexProperties, zoomConfig, imageScale, spectra, indexGenerationData, fileStem, tilingProfile.ChromeOption, alignmentPadding); // tile images as we go Log.Debug("Writing index tiles for " + scale); tiler.TileMany(superTiles); Log.Debug("Completed writing index tiles for " + scale); } }
private static void GenerateStandardSpectrogramTiles( Dictionary <string, double[, ]> spectra, IndexGenerationData indexGeneration, LdSpectrogramConfig ldsConfig, Dictionary <string, IndexProperties> filteredIndexProperties, SpectrogramZoomingConfig zoomConfig, double[] standardScales, string fileStem, TilingProfile namingPattern, Tiler tiler, TimeSpan alignmentPadding) { Log.Info("START DRAWING ZOOMED-IN FRAME SPECTROGRAMS"); TimeSpan dataDuration = TimeSpan.FromTicks(spectra["PMN"].GetLength(1) * indexGeneration.IndexCalculationDuration.Ticks); TimeSpan duration = indexGeneration.RecordingDuration; Contract.Requires( (dataDuration - duration).Absolute() < indexGeneration.IndexCalculationDuration, "The expected amount of data was not supplied"); var minuteCount = (int)Math.Ceiling(dataDuration.TotalMinutes); // window the standard spectrogram generation so that we can provide adjacent supertiles to the // tiler, so that bordering / overlapping tiles (for cases where tile size != multiple of supertile size) // don't render partial tiles (i.e. bad/partial rendering of image) // this is the function generator // use of Lazy means results will only be evaluated once // and only when needed. This is useful for sliding window. Lazy <TimeOffsetSingleLayerSuperTile[]> GenerateStandardSpectrogramGenerator(int minuteToLoad) { return(new Lazy <TimeOffsetSingleLayerSuperTile[]>( () => { Log.Info("Starting generation for minute: " + minuteToLoad); var superTilingResults = DrawSuperTilesFromSingleFrameSpectrogram( null /*inputDirectory*/, //TODO:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ldsConfig, filteredIndexProperties, zoomConfig, minuteToLoad, standardScales, fileStem, indexGeneration, namingPattern.ChromeOption, alignmentPadding); return superTilingResults; })); } Lazy <TimeOffsetSingleLayerSuperTile[]> previous = null; Lazy <TimeOffsetSingleLayerSuperTile[]> current = null; Lazy <TimeOffsetSingleLayerSuperTile[]> next = null; for (int minute = 0; minute < minuteCount; minute++) { Log.Trace("Starting loop for minute" + minute); // shift each value back previous = current; current = next ?? GenerateStandardSpectrogramGenerator(minute); next = minute + 1 < minuteCount?GenerateStandardSpectrogramGenerator(minute + 1) : null; // for each scale level of the results for (int i = 0; i < current.Value.Length; i++) { // finally tile the output Log.Debug("Begin tile production for minute: " + minute); tiler.Tile(previous?.Value[i], current.Value[i], next?.Value[i]); Log.Debug("Begin tile production for minute: " + minute); } } }