/// <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 } }
public Bitmap ExtractPaperFromFlattened(Bitmap bitmap, Bitmap basicImage, int minBlobWidHei, int fillint, int contint) { // 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. // lc.jpg = Mirrored image sample as located on the corner of printed sheet // this helps filtering out much smaller and much larger blobs depending upon the size of image. // can be queried from XML Reader List <IntPoint> quad = new List <IntPoint>(); // Store sheet corner locations (if anyone is detected ) if (blobs2.GetLength(0) < 4 && contint == 0) { lExtractResult = ExtractResults.FAILED; return(basicImage); } 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 { cb1 = UnmanagedImage.FromManagedImage(ImageUtilities.ResizeImage(iMarkLeft, blob.Rectangle.Width, blob.Rectangle.Height)); if (isSame(blob.Image, cb1)) { quad.Add(new IntPoint((int)blob.CenterOfGravity.X, (int)blob.CenterOfGravity.Y)); } } } } } catch (ArgumentException) { lExtractResult = ExtractResults.NOBLOB; } 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 { } 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) { cb2 = UnmanagedImage.FromManagedImage(ImageUtilities.ResizeImage(iMarkRight, blob.Rectangle.Width, blob.Rectangle.Height)); if (isSame(blob.Image, cb2)) { quad.Add(new IntPoint((int)blob.CenterOfGravity.X, (int)blob.CenterOfGravity.Y)); } } } } } catch (ArgumentException) { lExtractResult = ExtractResults.NOBLOB; } try { if (quad[2].Y < quad[3].Y) { IntPoint tp = quad[2]; quad[2] = quad[3]; quad[3] = tp; } } catch { } 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)); } else { contint *= -1; contint += 10; return(ExtractOMRSheet(basicImage, fillint, contint)); } } else // contrast correction yeilded no result { lExtractResult = ExtractResults.FAILED; return(basicImage); } } else // sheet found { IntPoint tp2 = quad[3]; quad[3] = quad[1]; quad[1] = tp2; if (!CheckSheetAR(quad)) { lExtractResult = ExtractResults.INVALIDAR; return(basicImage); } //sort the edges for wrap operation QuadrilateralTransformation wrap = new QuadrilateralTransformation(quad); wrap.UseInterpolation = false; //perspective wrap only, no binary. wrap.AutomaticSizeCalculaton = false; wrap.NewWidth = tSheetSize.Width; wrap.NewHeight = tSheetSize.Height; lExtractResult = ExtractResults.OK; //wrap.Apply(basicImage);//.Save("LastImg.jpg", ImageFormat.Jpeg); // creat file backup for future use. return(wrap.Apply(basicImage)); // wrap } }