Example #1
0
        /// <summary> Re-projects an image given a mapping function that maps target to source pixels. </summary>
        /// <param name="image">The image to re-project.</param>
        /// <param name="size">Determines the size of the resulting image.</param>
        /// <param name="targetToSource">Mapping function that maps target to source pixels.</param>
        public virtual Stream Reproject(Image image, Size size, Func <PointD, PointD> targetToSource)
        {
            // Determine the scale to use. The scale is used to virtually inflate the target rectangle to be filled when
            // re-projecting a single block. The scale specifies the lowest possible integer values that, multiplied with
            // width and height of the target image, would make the target image larger than the source image. Virtually,
            // the target image has to be larger than the source image for the interpolation filters to produce proper
            // results.

            var scale = new Size(
                Math.Max(1, (int)Math.Ceiling((double)image.Width / size.Width)),
                Math.Max(1, (int)Math.Ceiling((double)image.Height / size.Height))
                );

            // setup source and target image
            var source = ArgbImage.FromImage(image, ReprojectionOptions.InterpolationMode);
            var target = new ArgbImage(size);

            // divide into blocks and re-project each block
            GetBlocks(size).ForEach(ReprojectionOptions.DegreeOfParallelism, block =>
            {
                Reproject(source, target, block, targetToSource, scale);
            });

            return(target.Stream);
        }
Example #2
0
        /// <summary>
        /// Performs a scaled linear re-projection into the specified target block.
        /// <br/>
        /// Uses the given mapping function only to determine the corresponding corner points in the source image,
        /// uses a linear interpolation to determine intermediate points.
        /// </summary>
        /// <param name="source">The image to be re-projected.</param>
        /// <param name="target">The resulting image to be filled.</param>
        /// <param name="block">The block being targeted.</param>
        /// <param name="transformTargetToSource">Mapping function that maps target to source pixels.</param>
        /// <param name="scale">A factor to apply when re-projecting the block. See code comments in Reproject method above, where this parameter is set up.</param>
        private static void ScaledReprojection(ArgbImage source, ArgbImage target, ReprojectionBlock block, Func <PointD, PointD> transformTargetToSource, Size scale)
        {
            // determine the number of sections of the scaled block
            var nx = (block.X1 - block.X0 + 1) * scale.Width - 1;
            var ny = (block.Y1 - block.Y0 + 1) * scale.Height - 1;

            // Interpolators for upper and lower line of block
            var upper = InterpolationData.Create(transformTargetToSource(block.LeftTop), transformTargetToSource(block.RightTop), nx);
            var lower = InterpolationData.Create(transformTargetToSource(block.LeftBottom), transformTargetToSource(block.RightBottom), nx);

            // total number of color components collected in a color block due to scaling
            var colorBlockSize = (uint)(scale.Width * scale.Height);

            for (var x = block.X0; x <= block.X1; ++x)
            {
                // setup scale.Width interpolators for interpolating points on the line
                // defined through upper+n and lower+n, with n=0..(scale.Width-1)

                var sourcePoint = new InterpolationData[scale.Width];

                for (var xsub = 0; xsub < scale.Width; ++xsub)
                {
                    sourcePoint[xsub] = InterpolationData.Create(upper++, lower++, ny);
                }

                for (var y = block.Y0; y <= block.Y1; ++y)
                {
                    // storage for color components
                    uint a, r, g, b;
                    a = r = g = b = colorBlockSize >> 2;

                    // collect color components of subpixels.
                    // In the inner loop, we'll step our sourcePoint interpolators.
                    for (var ysub = 0; ysub < scale.Height; ++ysub)
                    {
                        for (var xsub = 0; xsub < scale.Width; ++sourcePoint[xsub], ++xsub)
                        {
                            var color = source[sourcePoint[xsub].x, sourcePoint[xsub].y];

                            a += (color >> 24) & 0xff;
                            r += (color >> 16) & 0xff;
                            g += (color >> 8) & 0xff;
                            b += color & 0xff;
                        }
                    }

                    // average the collected color components and set the target pixel
                    target[x, y] =
                        ((a / colorBlockSize) << 24) |
                        ((r / colorBlockSize) << 16) |
                        ((g / colorBlockSize) << 8) |
                        (b / colorBlockSize);
                }
            }
        }
Example #3
0
        /// <summary>
        /// Performs a unscaled linear re-projection into the specified target block.
        /// <br/>
        /// Uses the given mapping function only to determine the corresponding corner points in the source image,
        /// uses a linear interpolation to determine intermediate points.
        /// </summary>
        /// <param name="source">The image to be re-projected.</param>
        /// <param name="target">The resulting image to be filled.</param>
        /// <param name="block">The block being targeted.</param>
        /// <param name="transformTargetToSource">Mapping function that maps target to source pixels.</param>
        private static void UnscaledReprojection(ArgbImage source, ArgbImage target, ReprojectionBlock block, Func <PointD, PointD> transformTargetToSource)
        {
            // Interpolators for upper and lower line of block
            var upper = InterpolationData.Create(transformTargetToSource(block.LeftTop), transformTargetToSource(block.RightTop), block.X1 - block.X0);
            var lower = InterpolationData.Create(transformTargetToSource(block.LeftBottom), transformTargetToSource(block.RightBottom), block.X1 - block.X0);

            for (var x = block.X0; x <= block.X1; ++x, ++upper, ++lower)
            {
                // interpolator for points on the current line defined through upper and lower
                var sourcePoint = InterpolationData.Create(upper, lower, block.Y1 - block.Y0);

                for (var y = block.Y0; y <= block.Y1; ++y, ++sourcePoint)
                {
                    target[x, y] = source[sourcePoint.x, sourcePoint.y];
                }
            }
        }
Example #4
0
        /// <summary>
        /// Performs a scaled linear re-projection into the specified target block.
        /// <br/>
        /// Uses the given mapping function only to determine the corresponding corner points in the source image,
        /// uses a linear interpolation to determine intermediate points.
        /// </summary>
        /// <param name="source">The image to be re-projected.</param>
        /// <param name="target">The resulting image to be filled.</param>
        /// <param name="block">The block being targeted.</param>
        /// <param name="transformTargetToSource">Mapping function that maps target to source pixels.</param>
        /// <param name="scaleY">A factor to apply when re-projecting the block. See code comments in Reproject method above, where this parameter is set up.</param>
        private static void VerticallyScaledReprojection(ArgbImage source, ArgbImage target, ReprojectionBlock block, Func <PointD, PointD> transformTargetToSource, int scaleY)
        {
            // determine the number of sections of the scaled block
            var nx = block.X1 - block.X0;
            var ny = (block.Y1 - block.Y0 + 1) * scaleY - 1;

            // Interpolators for upper and lower line of block
            var upper = InterpolationData.Create(transformTargetToSource(block.LeftTop), transformTargetToSource(block.RightTop), nx);
            var lower = InterpolationData.Create(transformTargetToSource(block.LeftBottom), transformTargetToSource(block.RightBottom), nx);

            // total number of color components collected in a color block due to scaling
            var colorBlockSize = (uint)scaleY;

            for (var x = block.X0; x <= block.X1; ++x, ++upper, ++lower)
            {
                // setup interpolator for interpolating points on the line defined through upper and lower

                var sourcePoint = InterpolationData.Create(upper, lower, ny);

                for (var y = block.Y0; y <= block.Y1; ++y)
                {
                    // storage for color components
                    uint a, r, g, b;
                    a = r = g = b = colorBlockSize >> 2;

                    // collect color components of sub pixels.
                    // In the inner loop, we'll step our sourcePoint interpolators.
                    for (var ysub = 0; ysub < scaleY; ++ysub, ++sourcePoint)
                    {
                        var color = source[sourcePoint.x, sourcePoint.y];

                        a += (color >> 24) & 0xff;
                        r += (color >> 16) & 0xff;
                        g += (color >> 8) & 0xff;
                        b += color & 0xff;
                    }

                    // average the collected color components and set the target pixel
                    target[x, y] =
                        ((a / colorBlockSize) << 24) |
                        ((r / colorBlockSize) << 16) |
                        ((g / colorBlockSize) << 8) |
                        (b / colorBlockSize);
                }
            }
        }
Example #5
0
 /// <summary>
 /// Performs a linear re-projection into the specified target block.
 /// <br/>
 /// Uses the given mapping function only to determine the corresponding corner points in the source image,
 /// uses a linear interpolation to determine intermediate points.
 /// </summary>
 /// <param name="source">The image to be re-projected.</param>
 /// <param name="target">The resulting image to be filled.</param>
 /// <param name="block">The block being targeted.</param>
 /// <param name="transformTargetToSource">Mapping function that maps target to source pixels.</param>
 /// <param name="scale">A factor to apply when re-projecting the block. See code comments in Reproject method above, where this parameter is set up.</param>
 protected virtual void Reproject(ArgbImage source, ArgbImage target, ReprojectionBlock block, Func <PointD, PointD> transformTargetToSource, Size scale)
 {
     try
     {
         if (scale.Width != 1)
         {
             ScaledReprojection(source, target, block, transformTargetToSource, scale);
         }
         else
         {
             if (scale.Height == 1)
             {
                 // use optimized reprojection when scale values are both set to "1" (= unscaled)
                 UnscaledReprojection(source, target, block, transformTargetToSource);
             }
             else
             {
                 // use optimized reprojection when scale.Width is set to "1" (vertical scaling)
                 VerticallyScaledReprojection(source, target, block, transformTargetToSource, scale.Height);
             }
         }
     }
     catch (Components.Projections.TransformationException)
     {
         // ignore transformation exceptions; the given block will simply remain empty.
         //
         // seen transformation exceptions to happen in Proj4.cs with the transformation returning error code -14.
         // This is probably caused by coordinates exceeding the limits; See
         //
         // proj-4.8.0\src\pj_strerrno.c
         //   ...
         //   "latitude or longitude exceeded limits",	/* -14 */
         //   ...
         //
         // proj-4.8.0\src\pj_transform.c
         //   ...
         //   if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io], x + io, y + io, z + io ) != 0 ) {
         //     ret_errno = -14;
         //   ...
     }
 }