我在OMR项目中工作,我们正在使用C#。当我们来扫描答案纸时,图像会歪斜。我们怎么能纠正他们?
答案 0 :(得分:9)
VB.Net代码可用here,但是因为你要求C#这里是他们的Deskew类的C#翻译(注意:Binarize(严格来说没有必要,但工作得更好)和Rotate是练习留给用户)。
public class Deskew
{
// 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 Bitmap
Bitmap _internalBmp;
// 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;
public Bitmap DeskewImage(Bitmap image, int type, int binarizeThreshold)
{
Size oldSize = image.Size;
_internalBmp = BitmapFunctions.Resize(image, new Size(1000, 1000), true, image.PixelFormat);
Binarize(_internalBmp, binarizeThreshold);
return Rotate(image, GetSkewAngle());
}
// Calculate the skew angle of the image cBmp.
private double GetSkewAngle()
{
// Hough Transformation
Calc();
// 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()
{
int hMin = _internalBmp.Height / 4;
int hMax = _internalBmp.Height * 3 / 4;
Init();
for (int y = hMin; y <= hMax; y++)
{
for (int x = 1; x <= _internalBmp.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;
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 bool IsBlack(int x, int y)
{
Color c = _internalBmp.GetPixel(x, y);
double luminance = (c.R * 0.299) + (c.G * 0.587) + (c.B * 0.114);
return luminance < 140;
}
private void Init()
{
// 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 = -_internalBmp.Width;
_count = (int)(2 * (_internalBmp.Width + _internalBmp.Height) / STEP);
_hMatrix = new int[_count * STEPS];
}
private static double GetAlpha(int index)
{
return ALPHA_START + index * ALPHA_STEP;
}
}
答案 1 :(得分:2)
扫描文档始终倾斜平均[-10; +10]度角。
使用霍夫变换很容易对它们进行校正,就像Lou Franco说的那样。此变换可检测图像上的几个角度的线条。您只需在文档水平线上选择相应的一个,然后旋转它。
尝试隔离与文档水平线对应的像素(例如,底部有白色像素的黑色像素)。
运行Hough变换。不要忘记在C#中使用“不安全”模式,通过使用指针来固定整个图像的过程。
就像二进制文档上的魅力一样(很容易扩展到灰度级文档)
答案 2 :(得分:1)
免责声明:我在Atalasoft工作,DotImage Document Imaging可以使用几行代码执行此操作。
Deskew是一个艺术术语,描述了你想要做的事情。正如Ben Voigt所说,它在技术上是旋转,而不是倾斜 - 但是,如果你搜索,你会发现自动偏移校正下的算法。
执行此操作的常规方法是在图像中执行hough transform to look for the prevalent lines。使用普通文档时,其中许多文档将与纸张的两侧正交。
答案 3 :(得分:0)
你确定它是“倾斜”而不是“旋转”(旋转保持角度,倾斜没有)。