26

I am trying to detect and crop a photo out of a blank page, at unknown random locations using AForge, following the article Here

I have downloaded a passport photo from google images and stuck in onto a white sheet:

enter image description here enter image description here

AForge gets the job done, However, there is a slight problem which i cannot figure out; the photos are being cropped wrong.

here is how the cropped photo looks after the processing:

enter image description here

Do you notice the white margins of the photo? as if the photo is tilted to leave white space on the sides.

Not only AForge doesnt recognize the quadrilateral of this photo to be a rectangle, but it also crops it wrong.

Here is my code which i took from the article and adjusted for cropping:

Bitmap bitmap = AForge.Imaging.Image.Clone(bmp, PixelFormat.Format24bppRgb);
BitmapData bitmapData = bitmap.LockBits(
    new Rectangle(0, 0, bitmap.Width, bitmap.Height),
    ImageLockMode.ReadWrite, bitmap.PixelFormat);
Invert invertFilter = new Invert();
invertFilter.ApplyInPlace(bitmapData);
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 50;
blobCounter.MinWidth = 50;
blobCounter.MaxHeight = 1500;
blobCounter.MaxWidth = 1500;
blobCounter.ProcessImage(bitmapData);
Blob[] blobs = blobCounter.GetObjectsInformation();
bitmap.UnlockBits(bitmapData);
if (blobs.Length == 1)
{
    List<IntPoint> corners;
    List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[0]);
    SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
    if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
    {
        if (corners.Count == 4)
        {
            int[] sides = new int[4];
            Math.Pow(corners[0].X - corners[1].X, 2);
            sides[0] = (int)Math.Sqrt(Math.Pow(corners[0].X - corners[1].X, 2) + Math.Pow(corners[0].Y - corners[1].Y, 2));
            sides[1] = (int)Math.Sqrt(Math.Pow(corners[2].X - corners[1].X, 2) + Math.Pow(corners[2].Y - corners[1].Y, 2));
            sides[2] = (int)Math.Sqrt(Math.Pow(corners[2].X - corners[3].X, 2) + Math.Pow(corners[2].Y - corners[3].Y, 2));
            sides[3] = (int)Math.Sqrt(Math.Pow(corners[0].X - corners[3].X, 2) + Math.Pow(corners[0].Y - corners[3].Y, 2));
            BaseQuadrilateralTransformationFilter qtb = new QuadrilateralTransformationBilinear(corners, sides.Min(), sides.Max());
            bitmap = qtb.Apply(bitmap);
        }
    }
}
bitmap = invertFilter.Apply(bitmap);

Id appreciate any input you can offer on this...

Banana
  • 7,424
  • 3
  • 22
  • 43
  • 4
    a trick I used to do in document imaging is to crank your "contrast" so that the image is pretty much black when you do the deskew then crop. You look pretty advanced, so I'm sure you already know that, but doesnt hurt. – Trey Jun 26 '18 at 12:22
  • 3
    I have a suspicion about integer precision. Check your warnings - are there any implicit casts from real number types to integer? – speciesUnknown Jun 28 '18 at 15:40

1 Answers1

2

You could try Math.Round before casting:

sides[0] = (int)Math.Round(Math.Sqrt(Math.Pow(corners[0].X - corners[1].X, 2) + Math.Pow(corners[0].Y - corners[1].Y, 2)));
            sides[1] = (int)Math.Round(Math.Sqrt(Math.Pow(corners[2].X - corners[1].X, 2) + Math.Pow(corners[2].Y - corners[1].Y, 2)));
            sides[2] = (int)Math.Round(Math.Sqrt(Math.Pow(corners[2].X - corners[3].X, 2) + Math.Pow(corners[2].Y - corners[3].Y, 2)));
            sides[3] = (int)Math.Round(Math.Sqrt(Math.Pow(corners[0].X - corners[3].X, 2) + Math.Pow(corners[0].Y - corners[3].Y, 2)));

Let me know if it helps.

hce
  • 1,107
  • 9
  • 25