public int getRegNumOfSheet(System.Drawing.Image image, XML.OMREnums.OMRSheet sheet, string OMRSheetFile, bool readInvalidRegNum) //parameters - panel1.BackgroundImage, OMREnums.OMRSheet.A550, "sheets.xml", false { Rectangle[] Blocks = new Rectangle[] //stores a set of four integers that represent the location & size of a rectangle { XML.OMRSheetReader.GetSheetPropertyLocation(OMRSheetFile, sheet, XML.OMREnums.OMRProperty.RegNumBlock), }; List <Bitmap[]> bmps = new List <Bitmap[]>(); //list of bitmap objects, bitmap - pixel data for graphics image and its attributes bmps.Add(SliceOMarkBlock(image, Blocks[0], 3)); //image = panel1.BackgroundImage, location of reg no block, slices = 3 digits for reg no //fill the bitmap array with bitmap images of slice images of reg no block //SliceOMarkBlock method returns 3 sliced bitmap images of reg no block, those bitmap images are added to bmps list int regNum = 0, multiplier = 100; foreach (Bitmap[] blk in bmps) { foreach (Bitmap line in blk)//line = line containing numbers from 0 to 9 { try { int num = rateSlice(line, 10) - 1; // if (num < 1 && !readInvalidRegNum) { throw new Exception("Invalid Reg. No."); } else { if (num < 0) { num = 0; } regNum += num * multiplier; multiplier /= 10; } } catch (Exception e) { MessageBox.Show("Image is too noisy"); } } } return(regNum); }
/// <summary> /// Reads all the selected options on paper in one call /// </summary> /// <param name="image">Exctracted Sheet.</param> /// <param name="sheet">Type of printed sheet</param> /// <param name="OMRSheetFile">XML sheet address</param> /// <returns></returns> public List <List <int> > getScoreOfSheet(System.Drawing.Image image, XML.OMREnums.OMRSheet sheet, string OMRSheetFile) { List <List <int> > scores = new List <List <int> >(); //number of blocks depend upon type of sheet selected Rectangle[] Blocks = new Rectangle[ XML.OMRSheetReader.GetSheetPropertyInt(OMRSheetFile, sheet, XML.OMREnums.OMRProperty.NumOfBlocks) ]; // Read block location from XML file for selected sheet for (int i = 1; i <= Blocks.Length; i++) { Blocks[i - 1] = XML.OMRSheetReader.GetSheetPropertyLocation(OMRSheetFile, sheet, (XML.OMREnums.OMRProperty)i); } // slice the blocks into lines inside them and record as bitmap List <Bitmap[]> bmps = new List <Bitmap[]>(); for (int i = 0; i < 4; i++) { bmps.Add(SliceOMarkBlock(image, Blocks[i], 10)); scores.Add(new List <int>()); } int bn = 0; // read selected option of sliced line foreach (Bitmap[] blk in bmps) { foreach (Bitmap line in blk) { scores[bn].Add(rateSlice(line, 5)); } bn++; } return(scores); }
public int getRegNumOfSheet(System.Drawing.Image image, XML.OMREnums.OMRSheet sheet, string OMRSheetFile, bool readInvalidRegNum) { Rectangle[] Blocks = new Rectangle[] { XML.OMRSheetReader.GetSheetPropertyLocation(OMRSheetFile, sheet, XML.OMREnums.OMRProperty.RegNumBlock), }; List <Bitmap[]> bmps = new List <Bitmap[]>(); bmps.Add(SliceOMarkBlock(image, Blocks[0], 3)); int regNum = 0, multiplier = 100; foreach (Bitmap[] blk in bmps) { foreach (Bitmap line in blk) { int num = rateSlice(line, 10) - 1; if (num < 1 && !readInvalidRegNum) { throw new Exception("Invalid Reg. No."); } else { if (num < 0) { num = 0; } regNum += num * multiplier; multiplier /= 10; } } } return(regNum); }
/// <summary> /// Detects, wrapps and crops out OMR sheet from flattened camera/scanner image. /// Flattened image is got by using method, private Bitmap flatten(Bitmap bmp, int fillint, int contint); /// </summary> /// <param name="bitmap">Bitmap image to process</param> /// <param name="basicImage">Backup image in case extraction fails</param> /// <param name="minBlobWidHei">Pre-configured variable, to be queried from XML reader</param> /// <param name="fillint">Pre-configured int, to be queried from XML reader</param> /// <param name="contint">Pre-configured int, to be queried from XML reader</param> /// <param name="OMRSheets">Sheets XML File Address</param> /// <param name="tb">Textbox to give in'process details on</param> /// <param name="panel1">Panel to draw in-process changes on.</param> /// <param name="giveFB">True when In- Process Feedback is required.</param> /// <param name="sheet">Type of sheet from OMREnums</param> /// <returns>Cropped OMR sheet (if detected) from camera/scanner image.</returns> private Bitmap ExtractPaperFromFlattened(Bitmap bitmap, Bitmap basicImage, int minBlobWidHei, int fillint, int contint, string OMRSheets, ref TextBox tb, ref Panel panel1, bool giveFB, XML.OMREnums.OMRSheet sheet) { // lock image, Bitmap itself takes much time to be processed BitmapData bitmapData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); // step 2 - locating objects BlobCounter blobCounter = new BlobCounter(); blobCounter.FilterBlobs = true; blobCounter.MinHeight = minBlobWidHei; // both these variables have to be given when calling the blobCounter.MinWidth = minBlobWidHei; // method, the can also be queried from the XML reader using OMREnums blobCounter.ProcessImage(bitmapData); Blob[] blobs = blobCounter.GetObjectsInformation(); bitmap.UnlockBits(bitmapData); Graphics g = Graphics.FromImage(bitmap); Pen yellowPen = new Pen(Color.Yellow, 2); // create pen in case image extraction failes and we need to preview the //blobs that were detected Rectangle[] rects = blobCounter.GetObjectsRectangles(); Blob[] blobs2 = blobCounter.GetObjects(bitmap, false); //Detection of paper lies within the presence of crossmark printed on the corneres of printed sheet. // First, detect left edge. System.Drawing.Image compImg = System.Drawing.Image.FromFile("lc.jpg"); // lc.jpg = Mirrored image sample as located on the corner of printed sheet UnmanagedImage compUMImg = UnmanagedImage.FromManagedImage((Bitmap)compImg); // this helps filtering out much smaller and much larger blobs depending upon the size of image. // can be queried from XML Reader double minbr = XML.OMRSheetReader.getProcessVariableD(OMRSheets, sheet, XML.OMREnums.OMRImageProcessVariables.MinBlobRatio); double maxbr = XML.OMRSheetReader.getProcessVariableD(OMRSheets, sheet, XML.OMREnums.OMRImageProcessVariables.MaxBlobRatio); List <IntPoint> quad = new List <IntPoint>(); // Store sheet corner locations (if anyone is detected ) if (giveFB) { showTimeStamp("Left edge detection started.", ref tb); } try { foreach (Blob blob in blobs2) { if ( ((double)blob.Area) / ((double)bitmap.Width * bitmap.Height) > minbr && ((double)blob.Area) / ((double)bitmap.Width * bitmap.Height) < maxbr && blob.Rectangle.X < (bitmap.Width) / 4) // filters oout very small or very larg blobs { if ((double)blob.Rectangle.Width / blob.Rectangle.Height < 1.4 && (double)blob.Rectangle.Width / blob.Rectangle.Height > .6) // filters out blobs having insanely wrong aspect ratio { compUMImg = UnmanagedImage.FromManagedImage(ImageUtilities.ResizeImage(compImg, blob.Rectangle.Width, blob.Rectangle.Height)); if (isSame(blob.Image, compUMImg)) { g.DrawRectangle(yellowPen, blob.Rectangle); quad.Add(new IntPoint((int)blob.CenterOfGravity.X, (int)blob.CenterOfGravity.Y)); } } } } } catch (ArgumentException) { MessageBox.Show("No Blobs"); } if (giveFB) { showTimeStamp("Left edge detection finished.", ref tb); } try { // Sort out the list in right sequence, UpperLeft,LowerLeft,LowerRight,upperRight if (quad[0].Y > quad[1].Y) { IntPoint tp = quad[0]; quad[0] = quad[1]; quad[1] = tp; } } catch { } compImg = System.Drawing.Image.FromFile("rc.jpg"); compUMImg = UnmanagedImage.FromManagedImage((Bitmap)compImg); if (giveFB) { showTimeStamp("Right edge detection started.", ref tb); // jusst like left edge detection } try { foreach (Blob blob in blobs2) { if ( ((double)blob.Area) / ((double)bitmap.Width * bitmap.Height) > minbr && ((double)blob.Area) / ((double)bitmap.Width * bitmap.Height) < maxbr && blob.Rectangle.X > (bitmap.Width * 3) / 4) { if ((double)blob.Rectangle.Width / blob.Rectangle.Height < 1.4 && (double)blob.Rectangle.Width / blob.Rectangle.Height > .6) { compUMImg = UnmanagedImage.FromManagedImage(ImageUtilities.ResizeImage(compImg, blob.Rectangle.Width, blob.Rectangle.Height)); if (isSame(blob.Image, compUMImg)) { g.DrawRectangle(yellowPen, blob.Rectangle); quad.Add(new IntPoint((int)blob.CenterOfGravity.X, (int)blob.CenterOfGravity.Y)); } } } } } catch (ArgumentException) { MessageBox.Show("No Blobs"); } if (giveFB) { showTimeStamp("Right edge detection finished.", ref tb); } try { if (quad[2].Y < quad[3].Y) { IntPoint tp = quad[2]; quad[2] = quad[3]; quad[3] = tp; } } catch { } yellowPen.Dispose(); g.Dispose(); //Again, filter out if wrong blobs pretended to our blobs. if (quad.Count == 4) { if (((double)quad[1].Y - (double)quad[0].Y) / ((double)quad[2].Y - (double)quad[3].Y) < .75 || ((double)quad[1].Y - (double)quad[0].Y) / ((double)quad[2].Y - (double)quad[3].Y) > 1.25) { quad.Clear(); // clear if, both edges have insanely wrong lengths } else if (quad[0].X > bitmap.Width / 2 || quad[1].X > bitmap.Width / 2 || quad[2].X < bitmap.Width / 2 || quad[3].X < bitmap.Width / 2) { quad.Clear(); // clear if, sides appear to be "wrong sided" } } if (quad.Count != 4) // sheet not detected, reccurrsive call. { if (contint <= 60) //try altering the contrast correction on both sides of numberline { if (contint >= 0) { contint += 5; contint *= -1; return(ExtractOMRSheet(basicImage, fillint, contint, OMRSheets, ref panel1, ref tb, giveFB, sheet)); } else { contint *= -1; contint += 10; return(ExtractOMRSheet(basicImage, fillint, contint, OMRSheets, ref panel1, ref tb, giveFB, sheet)); } } else // contrast correction yeilded no result { MessageBox.Show("Extraction Failed."); return(basicImage); } } else // sheet found { IntPoint tp2 = quad[3]; quad[3] = quad[1]; quad[1] = tp2; //sort the edges for wrap operation QuadrilateralTransformation wrap = new QuadrilateralTransformation(quad); wrap.UseInterpolation = false; //perspective wrap only, no binary. Rectangle sr = XML.OMRSheetReader.GetSheetPropertyLocation(OMRSheets, sheet, XML.OMREnums.OMRProperty.SheetSize); wrap.AutomaticSizeCalculaton = false; wrap.NewWidth = sr.Width; wrap.NewHeight = sr.Height; wrap.Apply(basicImage).Save("LastImg.jpg", ImageFormat.Jpeg); // creat file backup for future use. return(wrap.Apply(basicImage)); // wrap } }
private Bitmap ExtractOMRSheet(Bitmap basicImage, int fillint, int contint, string OMRSpecsSheetAddress, ref Panel panel1, ref TextBox textBox1, bool giveFB, XML.OMREnums.OMRSheet sheet) { ts = new TimeSpan(DateTime.Now.Ticks); System.Drawing.Image flattened = (System.Drawing.Image)flatten(basicImage, fillint, contint); if (giveFB) { showTimeStamp("Flatting Started", ref textBox1); panel1.BackgroundImage = flattened; showTimeStamp("Flattened", ref textBox1); panel1.Invalidate(); Application.DoEvents(); showTimeStamp("OMR Extraction Started", ref textBox1); } return(ExtractPaperFromFlattened(new Bitmap(flattened), basicImage, 3, fillint, contint, OMRSpecsSheetAddress, ref textBox1, ref panel1, giveFB, sheet)); }
/// <summary> /// Extracts image and gives "In-Process" feebback on referenced panel and text box /// </summary> /// <param name="SmallCameraImage">any small image, as smaller as 3MP is recomended and enough clear. Bigger images take alot of time to be processed</param> /// <param name="OMRSpecsSheetAddress">XML sheet specification file</param> /// <param name="panel1"></param> /// <param name="textBox1"></param> /// <returns></returns> public Bitmap ExtractOMRSheet(Bitmap SmallCameraImage, string OMRSpecsSheetAddress, ref Panel panel1, ref TextBox textBox1, XML.OMREnums.OMRSheet sheet) { return(ExtractOMRSheet(SmallCameraImage, 0, 0, OMRSpecsSheetAddress, ref panel1, ref textBox1, true, sheet)); }
/// <summary> /// Extracts Images from smallSize CameraImage, No feed Back given during process /// </summary> /// <param name="SmallCameraImage"></param> /// <param name="OMRSpecsSheetAddress"></param> /// <returns>Formated, Right sized OMR Sheet</returns> public Bitmap ExtractOMRSheet(Bitmap SmallCameraImage, string OMRSpecsSheetAddress, XML.OMREnums.OMRSheet sheet) { Panel p = new Panel(); TextBox t = new TextBox(); t.Text = ""; return(ExtractOMRSheet(SmallCameraImage, 0, 0, OMRSpecsSheetAddress, ref p, ref t, false, sheet)); }