예제 #1
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));
            }
        }