296 lines
6.6 KiB
C#
296 lines
6.6 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
|
|
namespace AForge.Imaging;
|
|
|
|
public class DocumentSkewChecker
|
|
{
|
|
private int stepsPerDegree;
|
|
|
|
private int houghHeight;
|
|
|
|
private double thetaStep;
|
|
|
|
private double maxSkewToDetect;
|
|
|
|
private double[] sinMap;
|
|
|
|
private double[] cosMap;
|
|
|
|
private bool needToInitialize = true;
|
|
|
|
private short[,] houghMap;
|
|
|
|
private short maxMapIntensity;
|
|
|
|
private int localPeakRadius = 4;
|
|
|
|
private ArrayList lines = new ArrayList();
|
|
|
|
public int StepsPerDegree
|
|
{
|
|
get
|
|
{
|
|
return stepsPerDegree;
|
|
}
|
|
set
|
|
{
|
|
stepsPerDegree = System.Math.Max(1, System.Math.Min(10, value));
|
|
needToInitialize = true;
|
|
}
|
|
}
|
|
|
|
public double MaxSkewToDetect
|
|
{
|
|
get
|
|
{
|
|
return maxSkewToDetect;
|
|
}
|
|
set
|
|
{
|
|
maxSkewToDetect = System.Math.Max(0.0, System.Math.Min(45.0, value));
|
|
needToInitialize = true;
|
|
}
|
|
}
|
|
|
|
[Obsolete("The property is deprecated and setting it has not any effect. Use MaxSkewToDetect property instead.")]
|
|
public double MinBeta
|
|
{
|
|
get
|
|
{
|
|
return 0.0 - maxSkewToDetect;
|
|
}
|
|
set
|
|
{
|
|
}
|
|
}
|
|
|
|
[Obsolete("The property is deprecated and setting it has not any effect. Use MaxSkewToDetect property instead.")]
|
|
public double MaxBeta
|
|
{
|
|
get
|
|
{
|
|
return maxSkewToDetect;
|
|
}
|
|
set
|
|
{
|
|
}
|
|
}
|
|
|
|
public int LocalPeakRadius
|
|
{
|
|
get
|
|
{
|
|
return localPeakRadius;
|
|
}
|
|
set
|
|
{
|
|
localPeakRadius = System.Math.Max(1, System.Math.Min(10, value));
|
|
}
|
|
}
|
|
|
|
public DocumentSkewChecker()
|
|
{
|
|
StepsPerDegree = 10;
|
|
MaxSkewToDetect = 30.0;
|
|
}
|
|
|
|
public double GetSkewAngle(Bitmap image)
|
|
{
|
|
return GetSkewAngle(image, new Rectangle(0, 0, ((Image)image).Width, ((Image)image).Height));
|
|
}
|
|
|
|
public double GetSkewAngle(Bitmap image, Rectangle rect)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000b: Invalid comparison between Unknown and I4
|
|
if ((int)((Image)image).PixelFormat != 198659)
|
|
{
|
|
throw new UnsupportedImageFormatException("Unsupported pixel format of the source image.");
|
|
}
|
|
BitmapData val = image.LockBits(new Rectangle(0, 0, ((Image)image).Width, ((Image)image).Height), (ImageLockMode)1, (PixelFormat)198659);
|
|
try
|
|
{
|
|
return GetSkewAngle(new UnmanagedImage(val), rect);
|
|
}
|
|
finally
|
|
{
|
|
image.UnlockBits(val);
|
|
}
|
|
}
|
|
|
|
public double GetSkewAngle(BitmapData imageData)
|
|
{
|
|
return GetSkewAngle(new UnmanagedImage(imageData), new Rectangle(0, 0, imageData.Width, imageData.Height));
|
|
}
|
|
|
|
public double GetSkewAngle(BitmapData imageData, Rectangle rect)
|
|
{
|
|
return GetSkewAngle(new UnmanagedImage(imageData), rect);
|
|
}
|
|
|
|
public double GetSkewAngle(UnmanagedImage image)
|
|
{
|
|
return GetSkewAngle(image, new Rectangle(0, 0, image.Width, image.Height));
|
|
}
|
|
|
|
public unsafe double GetSkewAngle(UnmanagedImage image, Rectangle rect)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000b: Invalid comparison between Unknown and I4
|
|
if ((int)image.PixelFormat != 198659)
|
|
{
|
|
throw new UnsupportedImageFormatException("Unsupported pixel format of the source image.");
|
|
}
|
|
InitHoughMap();
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
int num = width / 2;
|
|
int num2 = height / 2;
|
|
rect.Intersect(new Rectangle(0, 0, width, height));
|
|
int num3 = -num + rect.Left;
|
|
int num4 = -num2 + rect.Top;
|
|
int num5 = width - num - (width - rect.Right);
|
|
int num6 = height - num2 - (height - rect.Bottom) - 1;
|
|
int num7 = image.Stride - rect.Width;
|
|
int num8 = (int)System.Math.Sqrt(num * num + num2 * num2);
|
|
int num9 = num8 * 2;
|
|
houghMap = new short[houghHeight, num9];
|
|
byte* ptr = (byte*)image.ImageData.ToPointer() + (nint)rect.Top * (nint)image.Stride + rect.Left;
|
|
byte* ptr2 = ptr + image.Stride;
|
|
for (int i = num4; i < num6; i++)
|
|
{
|
|
int num10 = num3;
|
|
while (num10 < num5)
|
|
{
|
|
if (*ptr < 128 && *ptr2 >= 128)
|
|
{
|
|
for (int j = 0; j < houghHeight; j++)
|
|
{
|
|
int num11 = (int)(cosMap[j] * (double)num10 - sinMap[j] * (double)i) + num8;
|
|
if (num11 >= 0 && num11 < num9)
|
|
{
|
|
houghMap[j, num11]++;
|
|
}
|
|
}
|
|
}
|
|
num10++;
|
|
ptr++;
|
|
ptr2++;
|
|
}
|
|
ptr += num7;
|
|
ptr2 += num7;
|
|
}
|
|
maxMapIntensity = 0;
|
|
for (int k = 0; k < houghHeight; k++)
|
|
{
|
|
for (int l = 0; l < num9; l++)
|
|
{
|
|
if (houghMap[k, l] > maxMapIntensity)
|
|
{
|
|
maxMapIntensity = houghMap[k, l];
|
|
}
|
|
}
|
|
}
|
|
CollectLines((short)(width / 10));
|
|
HoughLine[] mostIntensiveLines = GetMostIntensiveLines(5);
|
|
double num12 = 0.0;
|
|
double num13 = 0.0;
|
|
HoughLine[] array = mostIntensiveLines;
|
|
foreach (HoughLine houghLine in array)
|
|
{
|
|
if (houghLine.RelativeIntensity > 0.5)
|
|
{
|
|
num12 += houghLine.Theta * houghLine.RelativeIntensity;
|
|
num13 += houghLine.RelativeIntensity;
|
|
}
|
|
}
|
|
if (mostIntensiveLines.Length > 0)
|
|
{
|
|
num12 /= num13;
|
|
}
|
|
return num12 - 90.0;
|
|
}
|
|
|
|
private HoughLine[] GetMostIntensiveLines(int count)
|
|
{
|
|
int num = System.Math.Min(count, lines.Count);
|
|
HoughLine[] array = new HoughLine[num];
|
|
lines.CopyTo(0, array, 0, num);
|
|
return array;
|
|
}
|
|
|
|
private void CollectLines(short minLineIntensity)
|
|
{
|
|
int length = houghMap.GetLength(0);
|
|
int length2 = houghMap.GetLength(1);
|
|
int num = length2 >> 1;
|
|
lines.Clear();
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
for (int j = 0; j < length2; j++)
|
|
{
|
|
short num2 = houghMap[i, j];
|
|
if (num2 < minLineIntensity)
|
|
{
|
|
continue;
|
|
}
|
|
bool flag = false;
|
|
int k = i - localPeakRadius;
|
|
for (int num3 = i + localPeakRadius; k < num3; k++)
|
|
{
|
|
if (k < 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (k >= length || flag)
|
|
{
|
|
break;
|
|
}
|
|
int l = j - localPeakRadius;
|
|
for (int num4 = j + localPeakRadius; l < num4; l++)
|
|
{
|
|
if (l >= 0)
|
|
{
|
|
if (l >= length2)
|
|
{
|
|
break;
|
|
}
|
|
if (houghMap[k, l] > num2)
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!flag)
|
|
{
|
|
lines.Add(new HoughLine(90.0 - maxSkewToDetect + (double)i / (double)stepsPerDegree, (short)(j - num), num2, (double)num2 / (double)maxMapIntensity));
|
|
}
|
|
}
|
|
}
|
|
lines.Sort();
|
|
}
|
|
|
|
private void InitHoughMap()
|
|
{
|
|
if (needToInitialize)
|
|
{
|
|
needToInitialize = false;
|
|
houghHeight = (int)(2.0 * maxSkewToDetect * (double)stepsPerDegree);
|
|
thetaStep = 2.0 * maxSkewToDetect * System.Math.PI / 180.0 / (double)houghHeight;
|
|
sinMap = new double[houghHeight];
|
|
cosMap = new double[houghHeight];
|
|
double num = 90.0 - maxSkewToDetect;
|
|
for (int i = 0; i < houghHeight; i++)
|
|
{
|
|
sinMap[i] = System.Math.Sin(num * System.Math.PI / 180.0 + (double)i * thetaStep);
|
|
cosMap[i] = System.Math.Cos(num * System.Math.PI / 180.0 + (double)i * thetaStep);
|
|
}
|
|
}
|
|
}
|
|
}
|