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.
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;
}
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;
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With