public async Task GeostationaryUnderlay() { var definition = SatelliteRegistry.Locate(Goes16DefinitionPrefix); Assert.NotNull(definition, "Unable to find satellite definition"); var options = new UnderlayProjectionOptions( ProjectionType.Geostationary, InterpolationType.NearestNeighbour, 5424, Constants.DefaultUnderlayPath, 1000); var underlay = await UnderlayService.GetUnderlayAsync(options, definition); underlay.Width.Should().Be(1000); underlay.Height.Should().Be(1000); // Retrieve cached underlay = await UnderlayService.GetUnderlayAsync(options, definition); underlay.Width.Should().Be(1000); underlay.Height.Should().Be(1000); // Verify changing options doesn't retrieve cached underlay options = new UnderlayProjectionOptions( ProjectionType.Geostationary, InterpolationType.NearestNeighbour, 5424, Constants.DefaultUnderlayPath, 1500); underlay = await UnderlayService.GetUnderlayAsync(options, definition); underlay.Width.Should().Be(1500); underlay.Height.Should().Be(1500); }
/// <summary> /// Optionally resizes the underlay based on the target height. /// </summary> private void Resize(UnderlayProjectionOptions options, Image <Rgba32> underlay) { if (options.TargetHeight == null) { return; } // Resize underlay to target image size var targetHeight = options.TargetHeight.Value; // Ensure correct aspect ratio var targetWidth = (int)Math.Round(underlay.Width / (float)underlay.Height * targetHeight); _logger.LogInformation("Resizing underlay to {width} x {height} px", targetWidth, targetHeight); underlay.Mutate(c => c.Resize(targetWidth, targetHeight)); }
public async Task EquirectangularUnderlay() { var definition = SatelliteRegistry.Locate(Goes16DefinitionPrefix); Assert.NotNull(definition, "Unable to find satellite definition"); var options = new UnderlayProjectionOptions( ProjectionType.Equirectangular, InterpolationType.NearestNeighbour, 5424, Constants.DefaultUnderlayPath); var underlay = await UnderlayService.GetUnderlayAsync(options, definition); underlay.Width.Should().Be(10848); underlay.Height.Should().Be(5424); }
public async Task EquirectangularUnderlayWithCrop() { var definition = SatelliteRegistry.Locate(Goes16DefinitionPrefix); Assert.NotNull(definition, "Unable to find satellite definition"); var options = new UnderlayProjectionOptions( ProjectionType.Equirectangular, InterpolationType.NearestNeighbour, 5424, Constants.DefaultUnderlayPath, latitudeCrop: new Range(Angle.FromDegrees(45), Angle.FromDegrees(-45)), longitudeCrop: new Range(Angle.FromDegrees(-100), Angle.FromDegrees(100))); var underlay = await UnderlayService.GetUnderlayAsync(options, definition); underlay.Width.Should().Be(10848); underlay.Height.Should().Be(2712); }
public override async Task <ExecutionResult> RunAsync(IStepExecutionContext context) { Guard.Against.Null(_options.GeostationaryRender, nameof(_options.GeostationaryRender)); Guard.Against.Null(Registration?.Image, nameof(Registration.Image)); var targetLongitude = _options.GeostationaryRender.Longitude; if (targetLongitude != null) { throw new InvalidOperationException("Equirectangular composition should be used used when target longitude is provided"); } // Get or generate projected underlay var underlayOptions = new UnderlayProjectionOptions( ProjectionType.Geostationary, _options.InterpolationType, _options.ImageSize, _options.UnderlayPath); _logger.LogInformation("Retrieving underlay"); var underlay = await _underlayService.GetUnderlayAsync(underlayOptions, Registration.Definition); _logger.LogInformation("Tinting and normalising IR imagery"); if (_options.AutoAdjustLevels) { Registration.Image.Mutate(c => c.HistogramEqualization()); } TargetImage = Registration.Image.Clone(); TargetImage.Tint(_options.Tint); _logger.LogInformation("Blending with underlay"); TargetImage.Mutate(c => c .Resize(_options.ImageSize, _options.ImageSize) .DrawImage(underlay, PixelColorBlendingMode.Screen, 1.0f)); return(ExecutionResult.Next()); }
/// <summary> /// Retrieves a full-colour underlay image with the target projection. Underlays are cached to disk to speed up /// computation. /// </summary> /// <param name="options">Underlay generation options</param> /// <param name="definition">Optional satellite definition, if projecting underlay to match a satellite IR image</param> /// <returns>projected underlay</returns> public async Task <Image <Rgba32> > GetUnderlayAsync(UnderlayProjectionOptions options, SatelliteDefinition?definition = null) { // Attempt to retrieve underlay from cache var cached = await _cache.GetUnderlayAsync(definition, options); if (cached != null) { return(cached); } // Load master equirectangular underlay image from disk var underlay = await Image.LoadAsync <Rgba32>(options.UnderlayPath); // Project to match satellite imagery var target = GetProjected(underlay, definition, options); Resize(options, target); // Register underlay in cache await _cache.SetUnderlayAsync(target, definition, options); return(target); }
/// <summary> /// Returns an underlay projected and optionally cropped. /// </summary> private Image <Rgba32> GetProjected(Image <Rgba32> underlay, SatelliteDefinition?definition, UnderlayProjectionOptions options) { switch (options.Projection) { case ProjectionType.Geostationary: if (definition == null) { throw new InvalidOperationException("Satellite definition must be provided for geostationary projection"); } // Project underlay to geostationary, based on the target satellite _logger.LogInformation("{definition:l0} Rendering geostationary underlay", definition.DisplayName); return(underlay.ToGeostationaryProjection(definition.Longitude, definition.Height, _options)); case ProjectionType.Equirectangular: // Optionally crop and offset to specified lat/long range if (options.CropSpecified) { Offset(underlay, options.LongitudeCrop !.Value); Crop(underlay, options.LatitudeCrop !.Value); } return(underlay); default: throw new ArgumentOutOfRangeException($"Unhandled projection type: {options.Projection}"); } }