Click here to Skip to main content
Licence BSD
First Posted 10 Mar 2008
Views 16,926
Downloads 357
Bookmarked 40 times

ScanFree

By | 10 Mar 2008 | Article
A program that will grade a test from a scanned sheet of paper.

dnnScanFree_Source

Why ScanFree?

A group of developers started the dnnScanFree project in hopes of creating Open Source software that would allow others to create free and inexpensive testing programs. The idea is that school children can be helped if there are reliable inexpensive methods to measure their progress. The group of developers were alarmed when they discovered that free programs such as this did not exist.

This project is in the early stages, yet enough has been completed so far to be useful to other developers. The program will grade a test from a scanned sheet of paper.

Background

Christian Graus has written a great series of CodeProject articles on image processing. In his articles, he has explained how to process images quickly and reliably. There is no point covering what he so expertly covered, so it is recommended that you read his original articles to understand the basic concepts of image manipulation. He covers important points such as why pointers are used rather than GetPixel and SetPixel.

The Program

First, a method is used to turn each pixel into black or white. Next, the following method is used to determine a starting point. This simply looks for the first two black pixels that are found together.

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; 

}

Once the starting point is found, it is a simple calculation to find the answer blocks and loop through them. FindAnswerBlocks is the method used to loop through the answer blocks and each answer in each block. CountBlackPixelsInRectangle is a simple method that counts the number of black pixels in each square. If a square has more than 1000 black pixels, then it is considered to be marked as an answer.

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

Points of Interest

There is still a lot more work that needs to be done. The boxes are currently too big, and each answer should be compared rather than using a set number of expected pixels. However, the code should provide a starting point for other developers.

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

defwebserver

Software Developer (Senior)
http://ADefWebserver.com
United States United States

Member

Michael Washington is a Microsoft Silverlight MVP. He is a Silverlight developer and an ASP.NET, C#, and Visual Basic programmer.
 
He is a DotNetNuke Core member and has been involved with DotNetNuke for over 4 years. He is the Co-Author of Building Websites with DotNetNuke (4 and 5).
 
He is one of the founding members of The Open Light Group (http://openlightgroup.net).
 
He is the founder of http://LightSwitchHelpWebsite.com
 
He has a son, Zachary and resides in Los Angeles with his wife Valerie.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralHelp PinmemberGrim Re@p3r10:42 10 Apr '08  
Hey Michael i need your help in doing a task which is similar to this what you have done in this scan free application.
Basically i am trying to make an application to read specific data on an image. I have done the reading part through OCR now the problem i am facing is that i just have to read information given in a label on the image so first of all i have to locate that label. I have decided to do is to design a label like putting a black pixels small square of lets suppose 20,20 on top left and 10,10 on right bottom of the label. With this i can identify from where the label is starting and ending and after identifying i will crop that area to apply OCR on it.
Do you think this trick is gonna work? if you have any other idea so please tell me because i am trying to make this application from past 6 months and have not succeeded yet i will really appreciate if you can help me in doing this Thanx.
GeneralRe: Help Pinmemberdefwebserver13:19 10 Apr '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120529.1 | Last Updated 10 Mar 2008
Article Copyright 2008 by defwebserver
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid