Exemplo n.º 1
0
        /// <summary>
        /// Fits the <see cref="Image"/> into the area of specified dimensions.
        /// </summary>
        /// <param name="width">The width, in pixels, of the required image.</param>
        /// <param name="height">The height, in pixels, of the required image.</param>
        /// <param name="options">The scaling options.</param>
        /// <returns>
        /// A new scaled <see cref="Image"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// The operation cannot be performed on the image with current color depth.
        /// </exception>
        /// <remarks>
        /// This method modifies the current <see cref="Image"/> by resizing and inflating it when necessary.
        /// The resulting image should be <paramref name="width"/> x <paramref name="height"/> in size.
        /// </remarks>
        public Image FitToSize(int width, int height, ScalingOptions options)
        {
            Image dst = this;

            // if image is bigger than required, crop black area first
            // try to preserve black area relative position within the image
            if (dst.Width > width || dst.Height > height)
            {
                Rectangle blackArea = dst.BlackArea();
                if (!blackArea.IsEmpty && blackArea != dst.Bounds)
                {
                    ////dst = dst.Crop(blackArea);

                    if (blackArea.Height < height)
                    {
                        int dy = Core.MinMax.Min((height - blackArea.Height) / 2, blackArea.Y, dst.Height - blackArea.Bottom);
                        blackArea.Inflate(0, dy, 0, height - blackArea.Height - dy);
                    }

                    if (width > 0 && blackArea.Width < width)
                    {
                        int dx = Core.MinMax.Min((width - blackArea.Width) / 2, blackArea.X, dst.Width - blackArea.Right);
                        blackArea.Inflate(dx, 0, width - blackArea.Width - dx, 0);
                    }

                    blackArea.Intersect(dst.Bounds);
                    if (blackArea != dst.Bounds)
                    {
                        dst = dst.Crop(blackArea);
                    }
                }
            }

            if (dst.Width > width || dst.Height > height)
            {
                double horizontalFactor = (double)width / dst.Width;
                double verticalFactor   = (double)height / dst.Height;
                double scaleFactor      = Core.MinMax.Min(horizontalFactor, verticalFactor);

                int newWidth  = (int)((dst.Width * scaleFactor) + 0.5f);
                int newHeight = (int)((dst.Height * scaleFactor) + 0.5f);

                if (dst.Width != newWidth || dst.Height != newHeight)
                {
                    dst.ScaleToSize(dst, newWidth, newHeight, options);
                }
            }

            if (dst.Width < width || dst.Height < height)
            {
                int dx = width - dst.Width;
                int dy = height - dst.Height;
                dst = dst.Inflate(dx / 2, dy / 2, dx - (dx / 2), dy - (dy / 2), BorderType.BorderConst, dst.WhiteColor);
            }

            return(dst != this ? dst : dst.Copy(null, true));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Randomly distorts the specified image that contains a single character.
        /// </summary>
        /// <param name="image">The image to distort.</param>
        /// <param name="width">The sample width, in pixels.</param>
        /// <param name="height">The sample height, in pixels.</param>
        /// <param name="shift">The value that indicates whether the bitmap should be shifted randomly.</param>
        /// <param name="rotate">The value that indicates whether the bitmap should be rotated randomly.</param>
        /// <param name="scale">The value that indicates whether the bitmap should be scale randomly.</param>
        /// <param name="crop">The value that indicates whether the bitmap should be cropped randomly.</param>
        /// <returns>
        /// The sequence of <see cref="Imaging.Image"/> objects that contains the distorted images.
        /// </returns>
        public IEnumerable <Genix.Imaging.Image> Distort(
            Genix.Imaging.Image image,
            int width,
            int height,
            bool shift,
            bool rotate,
            bool scale,
            bool crop)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }

            if (image.BitsPerPixel == 8)
            {
                image.OtsuNormalizeBackground(image);
            }

            if (!image.IsAllWhite())
            {
                // rotate image randomly
                if (rotate)
                {
                    double angle = (width > 0 ? 18 : 3) * this.normalDistribution.Generate();
                    image.Rotate(image, angle, BorderType.BorderConst, image.WhiteColor);
                }

                // reduce image size to black area if bigger than requested
                ////image = image.CropBlackArea(1, 1);
                if ((width > 0 && image.Width > width) || image.Height > height)
                {
                    Rectangle blackArea = image.BlackArea();
                    if (!blackArea.IsEmpty && blackArea != image.Bounds)
                    {
                        blackArea.Inflate(1, 1);
                        blackArea.Intersect(image.Bounds);

                        if (blackArea.Height < height)
                        {
                            int dy = MinMax.Min((height - blackArea.Height) / 2, blackArea.Y, image.Height - blackArea.Bottom);
                            blackArea.Inflate(0, dy, 0, height - blackArea.Height - dy);
                        }

                        if (width > 0 && blackArea.Width < width)
                        {
                            int dx = MinMax.Min((width - blackArea.Width) / 2, blackArea.X, image.Width - blackArea.Right);
                            blackArea.Inflate(dx, 0, width - blackArea.Width - dx, 0);
                        }

                        blackArea.Intersect(image.Bounds);
                        if (blackArea != image.Bounds)
                        {
                            image = image.Crop(blackArea);
                        }
                    }
                }

                // scale down if bigger than needed
                if (width > 0)
                {
                    if (image.Width > width || image.Height > height)
                    {
                        double horizontalFactor = (double)width / image.Width;
                        double verticalFactor   = (double)height / image.Height;
                        double scaleFactor      = Math.Min(horizontalFactor, verticalFactor);

                        image.Scale(image, scaleFactor, new ScalingOptions());
                    }
                }
                else
                {
                    if (image.Height > height)
                    {
                        double scaleFactor = (double)height / image.Height;
                        image.Scale(image, scaleFactor, new ScalingOptions());
                    }
                }

                // scale down image randomly
                if (scale)
                {
                    if (width > 0)
                    {
                        int newWidth = image.Width - Math.Abs(this.Random(-width / 4, width / 4));
                        if (newWidth <= 0)
                        {
                            newWidth = 1;
                        }

                        int newHeight = image.Height - Math.Abs(this.Random(-height / 4, height / 4));
                        if (newHeight <= 0)
                        {
                            newHeight = 1;
                        }

                        image.ScaleToSize(image, newWidth, newHeight, new ScalingOptions());
                    }
                    else
                    {
                        int newWidth = image.Width + this.Random(-image.Width / 10, image.Width / 10);
                        if (newWidth <= 0)
                        {
                            newWidth = 1;
                        }

                        int newHeight = image.Height - Math.Abs(this.Random(-height / 4, height / 4));
                        if (newHeight <= 0)
                        {
                            newHeight = 1;
                        }

                        image.ScaleToSize(image, newWidth, newHeight, new ScalingOptions());

                        double angle = 0.5 * this.normalDistribution.Generate();
                        image = image.Inflate(image.Height, 0, image.Height, 0, BorderType.BorderConst, image.WhiteColor);
                        image = image.Shear(angle);

                        Rectangle blackArea = image.BlackArea();
                        int       left      = Math.Max(blackArea.Left - 1, 0);
                        int       right     = Math.Min(blackArea.Right + 1, image.Width);
                        image = image.Crop(left, 0, right - left, image.Height);
                    }
                }
            }

            // increase image size to fit the requested size
            if (width > 0)
            {
                if (image.Width < width || image.Height < height)
                {
                    int dx = width - image.Width;
                    int dy = height - image.Height;

                    int offsetx = dx / 2;
                    int offsety = dy / 2;
                    if (shift)
                    {
                        offsetx = this.Random(0, dx);
                        offsety = this.Random(0, dy);
                    }

                    image = image.Inflate(offsetx, offsety, dx - offsetx, dy - offsety, BorderType.BorderConst, image.WhiteColor);
                }
            }
            else
            {
                // pad with empty space on the right to reduce width granularity
                int newWidth = ((image.Width + 15) / 16) * 16;

                // increase image size to fit the requested size
                if (image.Width < newWidth || image.Height < height)
                {
                    int dx = newWidth - image.Width;
                    int dy = height - image.Height;

                    int offsetx = dx / 2;
                    int offsety = dy / 2;
                    if (shift)
                    {
                        offsetx = this.Random(0, dx);
                        offsety = this.Random(0, dy);
                    }

                    image = image.Inflate(offsetx, offsety, dx - offsetx, dy - offsety, BorderType.BorderConst, image.WhiteColor);
                }
            }

            yield return(image);

            if (crop)
            {
                int oldWidth  = image.Width;
                int oldHeight = image.Height;
                int inflatex  = image.Width / 8;
                int inflatey  = image.Height / 8;
                image = image.Inflate(inflatex, inflatey, inflatex, inflatey, BorderType.BorderConst, image.WhiteColor);

                yield return(image.Crop(0, 0, oldWidth, oldHeight));

                yield return(image.Crop(2 * inflatex, 0, oldWidth, oldHeight));

                yield return(image.Crop(0, 2 * inflatey, oldWidth, oldHeight));

                yield return(image.Crop(2 * inflatex, 2 * inflatey, oldWidth, oldHeight));
            }
        }