using System; using System.Drawing; using FreeImageAPI; public class ImageDeskew { // Representation of a line in the image. private class HougLine { // Count of points in the line. public int Count; // Index in Matrix. public int Index; // The line is represented as all x,y that solve y*cos(alpha)-x*sin(alpha)=d public double Alpha; } // The range of angles to search for lines const double ALPHA_START = -20; const double ALPHA_STEP = 0.2; const int STEPS = 40 * 5; const double STEP = 1; // Precalculation of sin and cos. double[] _sinA; double[] _cosA; // Range of d double _min; int _count; // Count of points that fit in a line. int[] _hMatrix; // Calculate the skew angle of the image cBmp. public double GetSkewAngle (FreeImageBitmap image) { if (image.PixelFormat != System.Drawing.Imaging.PixelFormat.Format1bppIndexed) { image = image.GetColorConvertedInstance (FREE_IMAGE_COLOR_DEPTH.FICD_FORCE_GREYSCALE | FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER); } image.Save ("m:\\1.png"); // Hough Transformation Calc (image); // Top 20 of the detected lines in the image. HougLine[] hl = GetTop (20); // Average angle of the lines double sum = 0; int count = 0; for (int i = 0; i <= 19; i++) { sum += hl[i].Alpha; count += 1; } return sum / count; } // Calculate the Count lines in the image with most points. private HougLine[] GetTop (int count) { HougLine[] hl = new HougLine[count]; for (int i = 0; i <= count - 1; i++) { hl[i] = new HougLine (); } for (int i = 0; i <= _hMatrix.Length - 1; i++) { if (_hMatrix[i] > hl[count - 1].Count) { hl[count - 1].Count = _hMatrix[i]; hl[count - 1].Index = i; int j = count - 1; while (j > 0 && hl[j].Count > hl[j - 1].Count) { HougLine tmp = hl[j]; hl[j] = hl[j - 1]; hl[j - 1] = tmp; j -= 1; } } } for (int i = 0; i <= count - 1; i++) { int dIndex = hl[i].Index / STEPS; int alphaIndex = hl[i].Index - dIndex * STEPS; hl[i].Alpha = GetAlpha (alphaIndex); //hl[i].D = dIndex + _min; } return hl; } // Hough Transforamtion: private void Calc (FreeImageBitmap image) { int hMin = image.Height / 4; int hMax = image.Height * 3 / 4; Init (image); Scanline l1, l2; for (int y = hMin; y <= hMax; y++) { l1 = image.GetScanline (y - 1); l2 = image.GetScanline (y); for (int x = 1; x <= image.Width - 2; x++) { // Only lower edges are considered. if (l1[x] == FI1BIT.MinValue) { if (l2[x] == FI1BIT.MaxValue) { Calc (x, y); } } } } } // Calculate all lines through the point (x,y). private void Calc (int x, int y) { int alpha; for (alpha = 0; alpha <= STEPS - 1; alpha++) { double d = y * _cosA[alpha] - x * _sinA[alpha]; int calculatedIndex = (int)CalcDIndex (d); int index = calculatedIndex * STEPS + alpha; try { _hMatrix[index] += 1; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine (ex.ToString ()); } } } private double CalcDIndex (double d) { return Convert.ToInt32 (d - _min); } private void Init (FreeImageBitmap image) { // Precalculation of sin and cos. _cosA = new double[STEPS]; _sinA = new double[STEPS]; for (int i = 0; i < STEPS; i++) { double angle = GetAlpha (i) * Math.PI / 180.0; _sinA[i] = Math.Sin (angle); _cosA[i] = Math.Cos (angle); } // Range of d: _min = -image.Width; _count = (int)(2 * (image.Width + image.Height) / STEP); _hMatrix = new int[_count * STEPS]; } private static double GetAlpha (int index) { return ALPHA_START + index * ALPHA_STEP; } } //// AForge Image Processing Library //// AForge.NET framework //// http://www.aforgenet.com/framework/ //// //// Copyright © Andrew Kirillov, 2005-2010 //// andrew.kirillov@aforgenet.com //// //// Alejandro Pirola, 2008 //// alejamp@gmail.com //// //namespace PDFPatcher.Processor //{ // using System; // using System.Collections; // using System.Drawing; // using System.Drawing.Imaging; // using FreeImageAPI; // /// // /// Hough line. // /// // /// // /// Represents line of Hough Line transformation using // /// polar coordinates. // /// See Wikipedia // /// for information on how to convert polar coordinates to Cartesian coordinates. // /// // /// // /// Hough Line transformation does not provide // /// information about lines start and end points, only slope and distance from image's center. Using // /// only provided information it is not possible to draw the detected line as it exactly appears on // /// the source image. But it is possible to draw a line through the entire image, which contains the // /// source line (see sample code below). // /// // /// // /// Sample code to draw detected Hough lines: // /// // /// HoughLineTransformation lineTransform = new HoughLineTransformation( ); // /// // apply Hough line transofrm // /// lineTransform.ProcessImage( sourceImage ); // /// Bitmap houghLineImage = lineTransform.ToBitmap( ); // /// // get lines using relative intensity // /// HoughLine[] lines = lineTransform.GetLinesByRelativeIntensity( 0.5 ); // /// // /// foreach ( HoughLine line in lines ) // /// { // /// // get line's radius and theta values // /// int r = line.Radius; // /// double t = line.Theta; // /// // /// // check if line is in lower part of the image // /// if ( r < 0 ) // /// { // /// t += 180; // /// r = -r; // /// } // /// // /// // convert degrees to radians // /// t = ( t / 180 ) * Math.PI; // /// // /// // get image centers (all coordinate are measured relative // /// // to center) // /// int w2 = image.Width /2; // /// int h2 = image.Height / 2; // /// // /// double x0 = 0, x1 = 0, y0 = 0, y1 = 0; // /// // /// if ( line.Theta != 0 ) // /// { // /// // none-vertical line // /// x0 = -w2; // most left point // /// x1 = w2; // most right point // /// // /// // calculate corresponding y values // /// y0 = ( -Math.Cos( t ) * x0 + r ) / Math.Sin( t ); // /// y1 = ( -Math.Cos( t ) * x1 + r ) / Math.Sin( t ); // /// } // /// else // /// { // /// // vertical line // /// x0 = line.Radius; // /// x1 = line.Radius; // /// // /// y0 = h2; // /// y1 = -h2; // /// } // /// // /// // draw line on the image // /// Drawing.Line( sourceData, // /// new IntPoint( (int) x0 + w2, h2 - (int) y0 ), // /// new IntPoint( (int) x1 + w2, h2 - (int) y1 ), // /// Color.Red ); // /// } // /// // /// // /// To clarify meaning of and values // /// of detected Hough lines, let's take a look at the below sample image and // /// corresponding values of radius and theta for the lines on the image: // /// // /// // /// // /// // /// Detected radius and theta values (color in corresponding colors): // /// // /// Theta = 90, R = 125, I = 249; // /// Theta = 0, R = -170, I = 187 (converts to Theta = 180, R = 170); // /// Theta = 90, R = -58, I = 163 (converts to Theta = 270, R = 58); // /// Theta = 101, R = -101, I = 130 (converts to Theta = 281, R = 101); // /// Theta = 0, R = 43, I = 112; // /// Theta = 45, R = 127, I = 82. // /// // /// // /// // /// // /// // /// // /// // public class HoughLine : IComparable // { // /// // /// Line's slope - angle between polar axis and line's radius (normal going // /// from pole to the line). Measured in degrees, [0, 180). // /// // public readonly double Theta; // /// // /// Line's distance from image center, (−∞, +∞). // /// // /// // /// Negative line's radius means, that the line resides in lower // /// part of the polar coordinates system. This means that value // /// should be increased by 180 degrees and radius should be made positive. // /// // /// // public readonly short Radius; // /// // /// Line's absolute intensity, (0, +∞). // /// // /// // /// Line's absolute intensity is a measure, which equals // /// to number of pixels detected on the line. This value is bigger for longer // /// lines. // /// // /// The value may not be 100% reliable to measure exact number of pixels // /// on the line. Although these value correlate a lot (which means they are very close // /// in most cases), the intensity value may slightly vary. // /// // /// // public readonly short Intensity; // /// // /// Line's relative intensity, (0, 1]. // /// // /// // /// Line's relative intensity is relation of line's // /// value to maximum found intensity. For the longest line (line with highest intesity) the // /// relative intensity is set to 1. If line's relative is set 0.5, for example, this means // /// its intensity is half of maximum found intensity. // /// // /// // public readonly double RelativeIntensity; // /// // /// Initializes a new instance of the class. // /// // /// // /// Line's slope. // /// Line's distance from image center. // /// Line's absolute intensity. // /// Line's relative intensity. // /// // public HoughLine (double theta, short radius, short intensity, double relativeIntensity) { // Theta = theta; // Radius = radius; // Intensity = intensity; // RelativeIntensity = relativeIntensity; // } // /// // /// Compare the object with another instance of this class. // /// // /// // /// Object to compare with. // /// // /// A signed number indicating the relative values of this instance and value: 1) greater than zero - // /// this instance is greater than value; 2) zero - this instance is equal to value; // /// 3) greater than zero - this instance is less than value. // /// // /// The sort order is descending. // /// // /// // /// Object are compared using their intensity value. // /// // /// // public int CompareTo (object value) { // return (-Intensity.CompareTo (((HoughLine)value).Intensity)); // } // } // /// // /// Skew angle checker for scanned documents. // /// // /// // /// The class implements document's skew checking algorithm, which is based // /// on Hough line transformation. The algorithm // /// is based on searching for text base lines - black line of text bottoms' followed // /// by white line below. // /// // /// The routine supposes that a white-background document is provided // /// with black letters. The algorithm is not supposed for any type of objects, but for // /// document images with text. // /// // /// The range of angles to detect is controlled by property. // /// // /// The filter accepts 8 bpp grayscale images for processing. // /// // /// Sample usage: // /// // /// // create instance of skew checker // /// DocumentSkewChecker skewChecker = new DocumentSkewChecker( ); // /// // get documents skew angle // /// double angle = skewChecker.GetSkewAngle( documentImage ); // /// // create rotation filter // /// RotateBilinear rotationFilter = new RotateBilinear( -angle ); // /// rotationFilter.FillColor = Color.White; // /// // rotate image applying the filter // /// Bitmap rotatedImage = rotationFilter.Apply( documentImage ); // /// // /// // /// Initial image: // /// // /// Deskewed image: // /// // /// // /// // /// // /// // public class ImageDeskew // { // // Hough transformation: quality settings // private int stepsPerDegree; // private int houghHeight; // private double thetaStep; // private double maxSkewToDetect; // // Hough transformation: precalculated Sine and Cosine values // private double[] sinMap; // private double[] cosMap; // private bool needToInitialize = true; // // Hough transformation: Hough map // private short[,] houghMap; // private short maxMapIntensity = 0; // private int localPeakRadius = 4; // private ArrayList lines = new ArrayList (); // /// // /// Steps per degree, [1, 10]. // /// // /// // /// The value defines quality of Hough transform and its ability to detect // /// line slope precisely. // /// // /// Default value is set to 1. // /// // /// // public int StepsPerDegree { // get { return stepsPerDegree; } // set { // stepsPerDegree = Math.Max (1, Math.Min (10, value)); // needToInitialize = true; // } // } // /// // /// Maximum skew angle to detect, [0, 45] degrees. // /// // /// // /// The value sets maximum document's skew angle to detect. // /// Document's skew angle can be as positive (rotated counter clockwise), as negative // /// (rotated clockwise). So setting this value to 25, for example, will lead to // /// [-25, 25] degrees detection range. // /// // /// Scanned documents usually have skew in the [-20, 20] degrees range. // /// // /// Default value is set to 30. // /// // /// // public double MaxSkewToDetect { // get { return maxSkewToDetect; } // set { // maxSkewToDetect = Math.Max (0, Math.Min (45, value)); // needToInitialize = true; // } // } // /// // /// Minimum angle to detect skew in degrees. // /// // /// // /// The property is deprecated and setting it has not any effect. // /// Use property instead. // /// // [Obsolete ("The property is deprecated and setting it has not any effect. Use MaxSkewToDetect property instead.")] // public double MinBeta { // get { return (-maxSkewToDetect); } // set { } // } // /// // /// Maximum angle to detect skew in degrees. // /// // /// // /// The property is deprecated and setting it has not any effect. // /// Use property instead. // /// // [Obsolete ("The property is deprecated and setting it has not any effect. Use MaxSkewToDetect property instead.")] // public double MaxBeta { // get { return (maxSkewToDetect); } // set { } // } // /// // /// Radius for searching local peak value, [1, 10]. // /// // /// // /// The value determines radius around a map's value, which is analyzed to determine // /// if the map's value is a local maximum in specified area. // /// // /// Default value is set to 4. // /// // public int LocalPeakRadius { // get { return localPeakRadius; } // set { localPeakRadius = Math.Max (1, Math.Min (10, value)); } // } // /// // /// Initializes a new instance of the class. // /// // public ImageDeskew () { // StepsPerDegree = 10; // MaxSkewToDetect = 30; // } // /// // /// Get skew angle of the provided document image. // /// // /// // /// Document's image to get skew angle of. // /// // /// Returns document's skew angle. If the returned angle equals to -90, // /// then document skew detection has failed. // /// // /// Unsupported pixel format of the source image. // /// // public double GetSkewAngle (FreeImageBitmap image) { // return GetSkewAngle (image, new Rectangle (0, 0, image.Width, image.Height)); // } // /// // /// Get skew angle of the provided document image. // /// // /// // /// Document's image to get skew angle of. // /// Image's rectangle to process (used to exclude processing of // /// regions, which are not relevant to skew detection). // /// // /// Returns document's skew angle. If the returned angle equals to -90, // /// then document skew detection has failed. // /// // /// Unsupported pixel format of the source image. // /// // public double GetSkewAngle (FreeImageBitmap image, Rectangle rect) { // //image = image.GetColorConvertedInstance (FREE_IMAGE_COLOR_DEPTH.FICD_FORCE_GREYSCALE | FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP); // // init hough transformation settings // InitHoughMap (); // // get source image size // int width = image.Width; // int height = image.Height; // int halfWidth = width / 2; // int halfHeight = height / 2; // // make sure the specified rectangle recides with the source image // rect.Intersect (new Rectangle (0, 0, width, height)); // int startX = -halfWidth + rect.Left; // int startY = -halfHeight + rect.Top; // int stopX = width - halfWidth - (width - rect.Right); // int stopY = height - halfHeight - (height - rect.Bottom) - 1; // int offset = image.Stride - rect.Width; // // calculate Hough map's width // int halfHoughWidth = (int)Math.Sqrt (halfWidth * halfWidth + halfHeight * halfHeight); // int houghWidth = halfHoughWidth * 2; // houghMap = new short[houghHeight, houghWidth]; // #region do the job // //using (Bitmap bmp = image.ToBitmap ()) { // // BitmapData d = bmp.LockBits (new Rectangle (0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); // // unsafe { // // byte* src = (byte*)d.Scan0.ToPointer () + // // rect.Top * d.Stride + rect.Left; // // byte* srcBelow = src + d.Stride; // // // for each row // // for (int y = startY; y < stopY; y++) { // // // for each pixel // // for (int x = startX; x < stopX; x++, src++, srcBelow++) { // // // if current pixel is more black // // // and pixel below is more white // // if ((*src < 128) && (*srcBelow >= 128)) { // // // for each Theta value // // for (int theta = 0; theta < houghHeight; theta++) { // // int radius = (int)(cosMap[theta] * x - sinMap[theta] * y) + halfHoughWidth; // // if ((radius < 0) || (radius >= houghWidth)) // // continue; // // houghMap[theta, radius]++; // // } // // } // // } // // src += offset; // // srcBelow += offset; // // } // // } // //} // #endregion // Scanline src, srcBelow; // // for each row // for (int y = startY, l = height - 1; y < stopY; y++, l--) { // src = image.GetScanline (l - 1); // srcBelow = image.GetScanline (l); // // for each pixel // for (int x = startX, i = 0; x < stopX; x++, i++) { // // if current pixel is more black // // and pixel below is more white // if ((src[i] < 128) && (srcBelow[i] >= 128)) { // // for each Theta value // for (int theta = 0; theta < houghHeight; theta++) { // int radius = (int)(cosMap[theta] * x - sinMap[theta] * y) + halfHoughWidth; // if ((radius < 0) || (radius >= houghWidth)) // continue; // houghMap[theta, radius]++; // } // } // } // } // // find max value in Hough map // maxMapIntensity = 0; // for (int i = 0; i < houghHeight; i++) { // for (int j = 0; j < houghWidth; j++) { // if (houghMap[i, j] > maxMapIntensity) { // maxMapIntensity = houghMap[i, j]; // } // } // } // CollectLines ((short)(width / 10)); // // get skew angle // HoughLine[] hls = this.GetMostIntensiveLines (5); // double skewAngle = 0; // double sumIntensity = 0; // foreach (HoughLine hl in hls) { // if (hl.RelativeIntensity > 0.5) { // skewAngle += (hl.Theta * hl.RelativeIntensity); // sumIntensity += hl.RelativeIntensity; // } // } // if (hls.Length > 0) skewAngle = skewAngle / sumIntensity; // return skewAngle - 90.0; // } // // Get specified amount of lines with highest intensity // private HoughLine[] GetMostIntensiveLines (int count) { // // lines count // int n = Math.Min (count, lines.Count); // // result array // HoughLine[] dst = new HoughLine[n]; // lines.CopyTo (0, dst, 0, n); // return dst; // } // // Collect lines with intesities greater or equal then specified // private void CollectLines (short minLineIntensity) { // int maxTheta = houghMap.GetLength (0); // int maxRadius = houghMap.GetLength (1); // short intensity; // bool foundGreater; // int halfHoughWidth = maxRadius >> 1; // // clean lines collection // lines.Clear (); // // for each Theta value // for (int theta = 0; theta < maxTheta; theta++) { // // for each Radius value // for (int radius = 0; radius < maxRadius; radius++) { // // get current value // intensity = houghMap[theta, radius]; // if (intensity < minLineIntensity) // continue; // foundGreater = false; // // check neighboors // for (int tt = theta - localPeakRadius, ttMax = theta + localPeakRadius; tt < ttMax; tt++) { // // skip out of map values // if (tt < 0) // continue; // if (tt >= maxTheta) // break; // // break if it is not local maximum // if (foundGreater == true) // break; // for (int tr = radius - localPeakRadius, trMax = radius + localPeakRadius; tr < trMax; tr++) { // // skip out of map values // if (tr < 0) // continue; // if (tr >= maxRadius) // break; // // compare the neighboor with current value // if (houghMap[tt, tr] > intensity) { // foundGreater = true; // break; // } // } // } // // was it local maximum ? // if (!foundGreater) { // // we have local maximum // lines.Add (new HoughLine (90.0 - maxSkewToDetect + (double)theta / stepsPerDegree, (short)(radius - halfHoughWidth), intensity, (double)intensity / maxMapIntensity)); // } // } // } // lines.Sort (); // } // // Init Hough settings and map // private void InitHoughMap () { // if (needToInitialize) { // needToInitialize = false; // houghHeight = (int)(2 * maxSkewToDetect * stepsPerDegree); // thetaStep = (2 * maxSkewToDetect * Math.PI / 180) / houghHeight; // // precalculate Sine and Cosine values // sinMap = new double[houghHeight]; // cosMap = new double[houghHeight]; // double minTheta = 90.0 - maxSkewToDetect; // for (int i = 0; i < houghHeight; i++) { // sinMap[i] = Math.Sin ((minTheta * Math.PI / 180) + (i * thetaStep)); // cosMap[i] = Math.Cos ((minTheta * Math.PI / 180) + (i * thetaStep)); // } // } // } // } //} /*namespace PDFPatcher.Processor { using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using FreeImageAPI; //public class main //{ // public static void Main () { // string fnIn = "d:\\skewsample_in.tif"; // string fnOut = "d:\\skewsample_out.tif"; // Bitmap bmpIn = new Bitmap (fnIn); // ImageDeskew sk = new ImageDeskew (bmpIn); // double skewangle = sk.GetSkewAngle (); // Bitmap bmpOut = RotateImage (bmpIn, -skewangle); // bmpOut.Save (fnOut, ImageFormat.Tiff); // Interaction.MsgBox ("Skewangle: " + skewangle); // } // private static Bitmap RotateImage (Bitmap bmp, double angle) { // Graphics g = null; // Bitmap tmp = new Bitmap (bmp.Width, bmp.Height, PixelFormat.Format32bppRgb); // tmp.SetResolution (bmp.HorizontalResolution, bmp.VerticalResolution); // g = Graphics.FromImage (tmp); // try { // g.FillRectangle (Brushes.White, 0, 0, bmp.Width, bmp.Height); // g.RotateTransform ((float)angle); // g.DrawImage (bmp, 0, 0); // } // finally { // g.Dispose (); // } // return tmp; // } //} public class ImageDeskew { // Representation of a line in the image. public class HougLine { // Count of points in the line. public int Count; // Index in Matrix. public int Index; // The line is represented as all x,y that solve y*cos(alpha)-x*sin(alpha)=d public double Alpha; public double d; } // The Bitmap FreeImageBitmap cBmp; // The range of angles to search for lines double cAlphaStart = -20; double cAlphaStep = 0.2; int cSteps = 40 * 5; // Precalculation of sin and cos. double[] cSinA; double[] cCosA; // Range of d double cDMin; double cDStep = 1; int cDCount; // Count of points that fit in a line. int[] cHMatrix; public static double GetSkewAngle (FreeImageBitmap bmp) { return new ImageDeskew (bmp).GetSkewAngle (); } // Calculate the skew angle of the image cBmp. private double GetSkewAngle () { ImageDeskew.HougLine[] hl = null; int i = 0; double sum = 0; int count = 0; // Hough Transformation Calc (); // Top 20 of the detected lines in the image. hl = GetTop (20); // Average angle of the lines for (i = 0; i <= 19; i++) { sum += hl[i].Alpha; count += 1; } return sum / count; } // Calculate the Count lines in the image with most points. private HougLine[] GetTop (int Count) { HougLine[] hl = null; int i = 0; int j = 0; HougLine tmp = null; int AlphaIndex = 0; int dIndex = 0; hl = new HougLine[Count + 1]; for (i = 0; i <= Count - 1; i++) { hl[i] = new HougLine (); } for (i = 0; i <= cHMatrix.Length - 1; i++) { if (cHMatrix[i] > hl[Count - 1].Count) { hl[Count - 1].Count = cHMatrix[i]; hl[Count - 1].Index = i; j = Count - 1; while (j > 0 && hl[j].Count > hl[j - 1].Count) { tmp = hl[j]; hl[j] = hl[j - 1]; hl[j - 1] = tmp; j -= 1; } } } for (i = 0; i <= Count - 1; i++) { dIndex = hl[i].Index / cSteps; AlphaIndex = hl[i].Index - dIndex * cSteps; hl[i].Alpha = GetAlpha (AlphaIndex); hl[i].d = dIndex + cDMin; } return hl; } private ImageDeskew (FreeImageBitmap bmp) { cBmp = bmp; } // Hough Transforamtion: private void Calc () { int x = 0; int y = 0; int hMin = cBmp.Height / 4; int hMax = cBmp.Height * 3 / 4; Init (); for (y = hMin; y <= hMax; y++) { for (x = 1; x <= cBmp.Width - 2; x++) { // Only lower edges are considered. if (IsBlack (x, y)) { if (!IsBlack (x, y + 1)) { Calc (x, y); } } } } } // Calculate all lines through the point (x,y). private void Calc (int x, int y) { int alpha = 0; double d = 0; int dIndex = 0; int Index = 0; for (alpha = 0; alpha <= cSteps - 1; alpha++) { d = y * cCosA[alpha] - x * cSinA[alpha]; dIndex = (int)CalcDIndex (d); Index = dIndex * cSteps + alpha; try { cHMatrix[Index] += 1; } catch (Exception ex) { Debug.WriteLine (ex.ToString ()); } } } private double CalcDIndex (double d) { return Convert.ToInt32 (d - cDMin); } private bool IsBlack (int x, int y) { Color c = cBmp.GetPixel (x, y); double luminance = (c.R * 0.299) + (c.G * 0.587) + (c.B * 0.114); return luminance < 140; } private void Init () { int i = 0; double angle = 0; // Precalculation of sin and cos. cSinA = new double[cSteps]; cCosA = new double[cSteps]; for (i = 0; i <= cSteps - 1; i++) { angle = GetAlpha (i) * Math.PI / 180.0; cSinA[i] = Math.Sin (angle); cCosA[i] = Math.Cos (angle); } // Range of d: cDMin = -cBmp.Width; cDCount = (int)(2 * (cBmp.Width + cBmp.Height) / cDStep); cHMatrix = new int[cDCount * cSteps + 1]; } private double GetAlpha (int Index) { return cAlphaStart + Index * cAlphaStep; } } } */