65.9K
CodeProject 正在变化。 阅读更多。
Home

ScanFree

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.22/5 (7投票s)

2008年3月10日

BSD

2分钟阅读

viewsIcon

32256

downloadIcon

619

一个程序,可以对扫描的纸质试卷进行评分。

dnnScanFree_Source

为什么选择 ScanFree?

一群开发者启动了 dnnScanFree 项目,希望创建开源软件,让其他人能够创建免费且廉价的测试程序。 他们的想法是,如果存在可靠且廉价的测量学生进步的方法,就能帮助学生。 这群开发者对发现像这样的免费程序并不存在感到震惊。

这个项目还处于早期阶段,但目前已经完成足够的内容,对其他开发者来说是有用的。 该程序将对扫描的纸质试卷进行评分。

背景

Christian Graus 撰写了一系列关于图像处理的精彩 CodeProject 文章。 在他的文章中,他解释了如何快速可靠地处理图像。 没有必要涵盖他如此专业地涵盖的内容,因此建议您阅读他的原始文章以了解图像操作的基本概念。 他涵盖了重要的点,例如为什么使用指针而不是 GetPixelSetPixel

程序

首先,使用一种方法将每个像素变成黑色或白色。 接下来,使用以下方法确定起始点。 这只是查找一起找到的第一个两个黑色像素。

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;
}

关注点

仍然有很多工作要做。 框现在太大了,应该比较每个答案,而不是使用一组预期的像素。 但是,该代码应该为其他开发者提供一个起点。

© . All rights reserved.