Rotate image using bicubic interpolation.

The class implements image rotation filter using bicubic interpolation algorithm. It uses bicubic kernel W(x) as described on Wikipedia (coefficient a is set to -0.5).

Rotation is performed in counterclockwise direction.

The filter accepts 8 bpp grayscale images and 24 bpp color images for processing.

Sample usage:

// create filter - rotate for 30 degrees keeping original image size RotateBicubic filter = new RotateBicubic( 30, true ); // apply the filter Bitmap newImage = filter.Apply( image );

Initial image:

Result image:

Inheritance: BaseRotateFilter
 public static Bitmap RotateBicubic(Bitmap bmp, int degree)
 {
     // create filter - rotate for 30 degrees keeping original image size
     RotateBicubic filter = new RotateBicubic(degree, true);
     // apply the filter
     Bitmap newImage = filter.Apply(bmp);
     return bmp;
 }
        public static Bitmap Find(Blob blob, BlobCounter blobCounter, FoundColorSpaces colorSpaces)
        {
            List<IntPoint> blobPoints = new List<IntPoint>();
            List<IntPoint> leftPoints, rightPoints;
            blobCounter.GetBlobsLeftAndRightEdges(blob, out leftPoints, out rightPoints);

            Bitmap bmp = new Bitmap(blob.Rectangle.Width, blob.Rectangle.Height, PixelFormat.Format24bppRgb);
            for (int c = 0; c < leftPoints.Count; c++)
            {
                IntPoint startLeft = leftPoints[c];
                IntPoint endRight = rightPoints[c];

                for (int x = startLeft.X; x <= endRight.X; x++)
                {
                    blobPoints.Add(new IntPoint(x - blob.Rectangle.Left, startLeft.Y - blob.Rectangle.Top));
                    bmp.SetPixel(x - blob.Rectangle.Left, startLeft.Y - blob.Rectangle.Top,
                        colorSpaces.OriginalColorSpace.GetPixel(x, startLeft.Y)); 
                }
            }

            double[,] aData = new double[blobPoints.Count, 2];
            double[,] eData = new double[blobPoints.Count, 2];
            double[] bData = new double[blobPoints.Count];

            double centroidX = 0;
            double centroidY = 0;
            double total = 0;
            for (int c = 0; c < blobPoints.Count; c++)
            {
                centroidX += blobPoints[c].X;
                centroidY += blobPoints[c].Y;

                total++;
            }

            centroidX /= total;
            centroidY /= total;

            for (int c = 0; c < blobPoints.Count; c++)
            {
                eData[c, 0] = blobPoints[c].X - centroidX;
                eData[c, 1] = blobPoints[c].Y - centroidY;

                aData[c, 0] = 1;
                aData[c, 1] = blobPoints[c].X;

                bData[c] = blobPoints[c].Y;
            }

            DenseMatrix E = DenseMatrix.OfArray(eData);
            DenseMatrix Eprime = (DenseMatrix)E.TransposeThisAndMultiply(E);
            DenseEvd eigen = new DenseEvd(Eprime);
            Vector<Complex> eigenValues = eigen.EigenValues();
            int maxIndex = 0;
            double max = 0.0;
            for (int c = 0; c < eigenValues.Count; c++)
            {
                double eigenvalue = eigenValues[c].Real;
                if (eigenvalue > max)
                {
                    max = eigenvalue;
                    maxIndex = c;
                }
            }
            Matrix<double> eigenVectors = eigen.EigenVectors();
            Vector<double> maxEigenVector = eigenVectors.Column(maxIndex);
            Matrix<double> xHat = DenseMatrix.OfColumns(2, 1, new List<Vector<double>>(new Vector<double>[] { maxEigenVector }));

            double radians = System.Math.Asin(xHat[0, 0]);
            double degrees = radians * (180 / System.Math.PI); 

            // Why doesn't this work?
            //DenseMatrix A = DenseMatrix.OfArray(aData);
            //DenseVector b = new DenseVector(bData);
            //Matrix<double> xHat = (A.TransposeThisAndMultiply(A).Inverse() * A.Transpose() * b).ToColumnMatrix();

            RotateBicubic rotate = new RotateBicubic(-degrees);
            bmp = rotate.Apply(bmp); 

            return bmp;
        }
        /// <summary>
        /// Rotate an image using trial and error until a best angle is found (measured by a vertical histogram).
        /// </summary>
        /// <param name="drawHistogramBarsBecauseTheyreCool"> 
        /// Saying TRUE here makes the image unusable, but you can save the image to a file and it looks cool with all the pretty histogram lines on it...
        /// </param>
        public void ResizeRotateCut(bool drawHistogramBarsBecauseTheyreCool)
        {
            try
            {
                Bitmap copy = new Bitmap(Image.Width, Image.Height, PixelFormat.Format24bppRgb);
                Graphics g = Graphics.FromImage(copy);
                g.DrawImage(Image, 0, 0, Image.Width, Image.Height);

                Bitmap rot;
                int best = copy.Height;
                double ang = 0.0;

                copy = copy.CropResize();

                for (double d = -45.0; d <= 45.0; d += 5.0)
                {
                    RotateBicubic r = new RotateBicubic(d);
                    r.FillColor = Color.White;
                    r.KeepSize = false;
                    rot = r.Apply(copy);

                    int hist = GetHistogram(rot, 7);

                    if (hist < best)
                    {
                        best = hist;
                        ang = d;
                    }

                    //Pen p1 = new Pen(new SolidBrush(Color.FromArgb(128, Color.Red)));
                    //Pen p2 = new Pen(new SolidBrush(Color.FromArgb(128, Color.LimeGreen)));
                    //Bitmap rot2 = new Bitmap(600, 600);
                    //using (Graphics g2 = Graphics.FromImage(rot2))
                    //{
                    //    g2.Clear(Color.White);
                    //    g2.DrawImage(rot, rot2.Width / 2 - rot.Width / 2, rot2.Height - rot.Height);
                    //    for (int x = 0; x < rot2.Width; x++)
                    //    {
                    //        int count = 0;
                    //        for (int y = 0; y < rot2.Height; y++)
                    //        {
                    //            if (rot2.GetPixel(x, y).Subtract(Color.White) > 10)
                    //            {
                    //                count++;
                    //            }
                    //        }
                    //        if (count > rot2.Height / 15)
                    //        {
                    //            double percent = (double)count / rot2.Height;
                    //            g2.DrawLine(p1, x, (int)((rot2.Height - 1) * (1.0 - percent)), x, rot2.Height - 1);
                    //        }
                    //        else
                    //        {
                    //            g2.DrawLine(p2, x, 0, x, rot2.Height - 1);
                    //        }
                    //    }
                    //    g2.DrawString(ang.ToString("0.00") + " degrees", new Font("Tahoma", 8.25f), Brushes.Black, new PointF(1.0f, 1.0f));
                    //}
                    //rot2.Save("zhist " + (90 - (45 + d)).ToString("00") + ".png");

                    GlobalMessage.SendMessage(rot);
                }

                RotateBicubic r2 = new RotateBicubic(ang);
                r2.FillColor = Color.White;
                r2.KeepSize = false;
                rot = r2.Apply(copy);

                GetHistogram(rot, 7);
                rot = rot.CropResize();

                if (drawHistogramBarsBecauseTheyreCool)
                {
                    Pen p1 = new Pen(new SolidBrush(Color.FromArgb(128, Color.Red)));
                    Pen p2 = new Pen(new SolidBrush(Color.FromArgb(128, Color.LimeGreen)));

                    using (Graphics g2 = Graphics.FromImage(rot))
                    {
                        for (int x = 0; x < rot.Width; x++)
                        {
                            int count = 0;
                            for (int y = 0; y < rot.Height; y++)
                            {
                                if (rot.GetPixel(x, y).Subtract(Color.White) > 10)
                                {
                                    count++;
                                }
                            }

                            if (count > rot.Height / 15)
                            {
                                double percent = (double)count / rot.Height;
                                g2.DrawLine(p1, x, (int)((rot.Height - 1) * (1.0 - percent)), x, rot.Height - 1);
                            }
                            else
                            {
                                g2.DrawLine(p2, x, 0, x, rot.Height - 1);
                            }
                        }

                        g2.DrawString(ang.ToString("0.00") + " degrees", new Font("Tahoma", 8.25f), Brushes.Black, new PointF(1.0f, 1.0f));
                    }
                }

                Image = rot;

                GlobalMessage.SendMessage(Image);
            }
            catch (Exception ex)
            {
                throw new ImageProcessingException("Error rotating an image to find the best vertical histogram.", ex);
            }
        }
Beispiel #4
0
 public static Bitmap rotate(this Bitmap bitmap, int degrees)
 {
     AForge.Imaging.Filters.RotateBicubic filter = new AForge.Imaging.Filters.RotateBicubic(degrees);
     return(filter.Apply(AForge.Imaging.Image.Clone(bitmap, PixelFormat.Format24bppRgb)));
 }
        private static UnmanagedImage RotateImage(KindleProfile profile, UnmanagedImage image)
        {
            if (image.Width > image.Height)
            {
                UnmanagedImage output;
                RotateBicubic filter = new RotateBicubic(90);

                output = filter.Apply(image);

                return output;
            }

            return image;
        }