ScanFree






3.22/5 (7投票s)
一个程序,可以对扫描的纸质试卷进行评分。
为什么选择 ScanFree?
一群开发者启动了 dnnScanFree 项目,希望创建开源软件,让其他人能够创建免费且廉价的测试程序。 他们的想法是,如果存在可靠且廉价的测量学生进步的方法,就能帮助学生。 这群开发者对发现像这样的免费程序并不存在感到震惊。
这个项目还处于早期阶段,但目前已经完成足够的内容,对其他开发者来说是有用的。 该程序将对扫描的纸质试卷进行评分。
背景
Christian Graus 撰写了一系列关于图像处理的精彩 CodeProject 文章。 在他的文章中,他解释了如何快速可靠地处理图像。 没有必要涵盖他如此专业地涵盖的内容,因此建议您阅读他的原始文章以了解图像操作的基本概念。 他涵盖了重要的点,例如为什么使用指针而不是 GetPixel
和 SetPixel
。
程序
首先,使用一种方法将每个像素变成黑色或白色。 接下来,使用以下方法确定起始点。 这只是查找一起找到的第一个两个黑色像素。
private Point LocateStartingPoint(Bitmap b)
{
Point tmpStartingPoint = new Point(0, 0);
bool boolBreakOut = false;
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.ReadWrite, b.PixelFormat);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - (b.Width) * 3;
int nWidth = (b.Width) * 3;
for (int y = 0; y < (b.Height); ++y)
{
for (int x = 0; x < nWidth; ++x)
{
if (
((byte)p[0] == (byte)0)
& (x > 10 & y > 10)
& (x < b.Width + 10 & y < b.Height + 10)
)
{
// See if the next one is black also
++p;
if ((byte)p[0] == (byte)0)
{
tmpStartingPoint = new Point((x / 3), y);
boolBreakOut = true;
break;
}
// It wasn't black so move back
--p;
}
++p;
}
if (boolBreakOut)
{
break;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return tmpStartingPoint;
}
一旦找到起始点,就可以简单地计算出答案块并循环遍历它们。 FindAnswerBlocks
是用于循环遍历答案块和每个块中每个答案的方法。 CountBlackPixelsInRectangle
是一个简单的方法,用于计算每个正方形中的黑色像素数量。 如果一个正方形有超过 1000 个黑色像素,则认为它被标记为答案。
private string FindAnswerBlocks()
{
string strSelectedAnswers = "";
// Find answer blocks
int intX = 499;
int intY = 209;
for (int i = 1; i <= 8; i++)
{
Point AnswerBlock = new Point(StartingPoint.X + intX, StartingPoint.Y + intY);
DrawARectangle(m_Bitmap, AnswerBlock, 480, 65, Color.Red);
// Find answers in answer block
int intX2 = StartingPoint.X + intX;
for (int ii = 1; ii <= 5; ii++)
{
Point Answer = new Point(intX2, AnswerBlock.Y);
DrawARectangle(m_Bitmap, Answer, 90, 62, Color.Blue);
int intCount = CountBlackPixelsInRectangle(m_Bitmap, Answer.X, Answer.Y, 90,
62);
if (intCount > 1000)
{
strSelectedAnswers = strSelectedAnswers + Environment.NewLine +
String.Format("Answer
Block: {0} | Answer: {1} ", i, ii);
}
intX2 = intX2 + 97;
}
intY = intY + 68;
}
return strSelectedAnswers;
}
关注点
仍然有很多工作要做。 框现在太大了,应该比较每个答案,而不是使用一组预期的像素。 但是,该代码应该为其他开发者提供一个起点。