4

I am trying to make a scanning application. That application will scan the document and will display image in a picture box. The problem I am facing is image (Documents image which kept in the scanner or say ‘real ’image) is displaying inside another image with some background (That background color is also changing) its look like this image.
enter image description here
I have tried lot of things but nothing giving me a perfect result I tried it with a forge.net. Here is the code I have tried.

public static System.Drawing.Image AforgeAutoCrop(Bitmap selectedImage)
    {
        Bitmap autoCropImage = null;
    try
    {

        autoCropImage = selectedImage;
        // create grayscale filter (BT709)
        Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
        Bitmap grayImage = filter.Apply(autoCropImage);
        // create instance of skew checker
        DocumentSkewChecker skewChecker = new DocumentSkewChecker();
        // get documents skew angle
        double angle = skewChecker.GetSkewAngle(grayImage);
        // create rotation filter
        RotateBilinear rotationFilter = new RotateBilinear(-angle);
        rotationFilter.FillColor = Color.White;
        // rotate image applying the filter
        Bitmap rotatedImage = rotationFilter.Apply(grayImage);
        new ContrastStretch().ApplyInPlace(grayImage);
        new Threshold(100).ApplyInPlace(grayImage);
        BlobCounter bc = new BlobCounter();
        bc.FilterBlobs = true;
        // bc.MinWidth = 500;
        //bc.MinHeight = 500;
        bc.ProcessImage(grayImage);
        Rectangle[] rects = bc.GetObjectsRectangles();
        MemoryStream writeName = new MemoryStream();
        if (rects.Length == 0)
        {
            System.Windows.Forms.MessageBox.Show("No rectangle found in image ");
        }
        else if (rects.Length == 1)
        {
            Bitmap cropped = new Crop(rects[0]).Apply(autoCropImage);
            autoCropImage = cropped;
           // pictureBox1.Image = cropped;
        }
        else if (rects.Length > 1)
        {
            // get largets rect
            Console.WriteLine("Using largest rectangle found in image ");
            var r2 = rects.OrderByDescending(r => r.Height * r.Width).ToList();
            //var r2 = rects.OrderByDescending(r => r.Height < 1500 && r.Width < 1000).ToList();
            Bitmap cropped = new Crop(r2[0]).Apply(autoCropImage);

            Graphics gr = Graphics.FromImage(cropped);
            gr.DrawRectangles(new Pen(Color.Red), rects);
            autoCropImage = cropped;
           // pictureBox1.Image = cropped;

        }
        else
        {
            Console.WriteLine("Huh? on image ");
        }
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

    return autoCropImage;
    }
j0k
  • 22,600
  • 28
  • 79
  • 90
Rakesh
  • 2,730
  • 10
  • 39
  • 65
  • "No perfect result" is very far from beeing a real question - voting to close. By the way, I would not try something like that using GDI+, better utilize a tool like ImageMagick (http://www.imagemagick.org/script/index.php) for it, or the corresponding .NET API (http://imagemagick.codeplex.com/) – Doc Brown Aug 02 '12 at 14:29
  • @DocBrown its very useful thank you. I have tried AForge instead of ImageMagick. Thanks again. – Rakesh Aug 02 '12 at 15:06

4 Answers4

4

i changed your code to this and works well. thanks

 public static System.Drawing.Image AforgeAutoCrop(Bitmap selectedImage)
        {
            Bitmap autoCropImage = null;
            try
            {

                autoCropImage = selectedImage;
                // create grayscale filter (BT709)
                Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
                Bitmap grayImage = filter.Apply(autoCropImage);
                // create instance of skew checker
                DocumentSkewChecker skewChecker = new DocumentSkewChecker();
                // get documents skew angle
                double angle = skewChecker.GetSkewAngle(grayImage);
                // create rotation filter
                RotateBilinear rotationFilter = new RotateBilinear(-angle);
                rotationFilter.FillColor = Color.White;
                // rotate image applying the filter
                Bitmap rotatedImage = rotationFilter.Apply(grayImage);
                new ContrastStretch().ApplyInPlace(rotatedImage);
                new Threshold(100).ApplyInPlace(rotatedImage);
                BlobCounter bc = new BlobCounter();
                bc.FilterBlobs = true;
                // bc.MinWidth = 500;
                //bc.MinHeight = 500;
                bc.ProcessImage(rotatedImage);
                Rectangle[] rects = bc.GetObjectsRectangles();

                if (rects.Length == 0)
                {
                    System.Windows.Forms.MessageBox.Show("No rectangle found in image ");
                }
                else if (rects.Length == 1)
                {
                    autoCropImage = rotatedImage.Clone(rects[0], rotatedImage.PixelFormat); ;
                }
                else if (rects.Length > 1)
                {
                    // get largets rect
                    Console.WriteLine("Using largest rectangle found in image ");
                    var r2 = rects.OrderByDescending(r => r.Height * r.Width).ToList();
                    autoCropImage = rotatedImage.Clone(r2[1], rotatedImage.PixelFormat);
                }
                else
                {
                    Console.WriteLine("Huh? on image ");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return autoCropImage;
        }
mostafa hk
  • 61
  • 4
3

I assume you always have an image with a distinct foreground and background, and you want to do something like a zealous crop of the background.

In this case I would do something similar to region growning. Start at a point where you can be guaranteed a background pixel.

Get another image (or matrix or whatever), initialized to zeros, and set the corresponding pixel value to 1. If any neighboring pixels are within a threshold value in the original image, move to them recursively and set their corresponding pixel values to 0 as well.

That is:

map = 0's, size of image
function f(x,y,image,map)
    if map(x,y) is not  0
        return
    if pixel value at image(x,y)<T
        map(x,y) = 1;
        for all neighbors of x,y
           function([neighbor coordinates],image,map)
    else
        map(x,y) = 2;
 end

Now map should have all background pixels as 1 and forground as 2. You can change this to allow multiple objects and thresholds and so forth. You might want threshold to be a value change rather than an absolute value.

Then simply find the min and max x and y and store the pixels in that range to a new image.

I hope this was along the lines of what you need.

Bill
  • 698
  • 1
  • 5
  • 22
  • you are correct. This is something what i required. do you have any idea to do this in c#. – Rakesh Aug 03 '12 at 06:37
  • Look [here](http://stackoverflow.com/questions/190385/how-to-manipulate-images-at-pixel-level-in-c) for pixel manipulation. Look [here](http://stackoverflow.com/questions/734930/how-to-crop-an-image-using-c) for cropping. The rest should be fairly simple to translate to C/C++/C# if you are familiar enough with them. – Bill Aug 06 '12 at 17:32
  • Ok i will try your solution and will updated here. Hoping it will solve my probs ..Thanks Bill..:-) – Rakesh Aug 06 '12 at 18:41
1

You can use AForge.NET Image Processing
Edge detector: http://www.aforgenet.com/framework/features/edge_detectors_filters.html

Nickon
  • 9,652
  • 12
  • 64
  • 119
  • So u can use EdgeDetector to find borders of your book: http://www.aforgenet.com/framework/features/edge_detectors_filters.html – Nickon Aug 02 '12 at 14:30
0

Mostafa HK's code worked for me. I'm using this function to pre-process YouTube thumbnails (to strip the black edges; a common problem), and I did have to make a couple of minor corrections to his code:

1) got rid of the rotation (not sure what that was for)

2) I lowered the threshold from 100 to 25.

3) When cloning the final image, I perform the clone off the original autoCropImage and not the rotatedImage (again, not sure what the rotation was for).

I think the real secret sauce was lowering the threshold. This reduced the number of rectangles the code was finding, and now I am properly cropping all forms of thumbnails (widescreen with black on the top and bottom AND fullscreen with black on the left and right).

    public static System.Drawing.Image AforgeAutoCrop(Bitmap selectedImage)
    {
        Bitmap autoCropImage = null;
        try
        {

            autoCropImage = selectedImage;
            // create grayscale filter (BT709)
            Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
            Bitmap grayImage = filter.Apply(autoCropImage);
            // create instance of skew checker
            DocumentSkewChecker skewChecker = new DocumentSkewChecker();
            // get documents skew angle
            double angle = 0; // skewChecker.GetSkewAngle(grayImage);
            // create rotation filter
            RotateBilinear rotationFilter = new RotateBilinear(-angle);
            rotationFilter.FillColor = Color.White;
            // rotate image applying the filter
            Bitmap rotatedImage = rotationFilter.Apply(grayImage);
            new ContrastStretch().ApplyInPlace(rotatedImage);
            new Threshold(25).ApplyInPlace(rotatedImage);
            BlobCounter bc = new BlobCounter();
            bc.FilterBlobs = true;
            // bc.MinWidth = 500;
            //bc.MinHeight = 500;
            bc.ProcessImage(rotatedImage);
            Rectangle[] rects = bc.GetObjectsRectangles();

            if (rects.Length == 0)
            {
                // CAN'T CROP
            }
            else if (rects.Length == 1)
            {
                autoCropImage = autoCropImage.Clone(rects[0], autoCropImage.PixelFormat); ;
            }
            else if (rects.Length > 1)
            {
                // get largets rect
                Console.WriteLine("Using largest rectangle found in image ");
                var r2 = rects.OrderByDescending(r => r.Height * r.Width).ToList();
                autoCropImage = autoCropImage.Clone(r2[0], autoCropImage.PixelFormat);
            }
            else
            {
                Console.WriteLine("Huh? on image ");
            }
        }
        catch (Exception ex)
        {
            //MessageBox.Show(ex.Message);
            //CAN'T CROP
        }

        return autoCropImage;
    }

https://stackoverflow.com/search?q=youtube+thumbnail+crop

Community
  • 1
  • 1
Frog Pr1nce
  • 730
  • 9
  • 8