Example #1
0
        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);
        }
Example #2
0
        /// <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));
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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());
        }
Example #6
0
        /// <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);
        }
Example #7
0
        /// <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}");
            }
        }