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 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.
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;
}
You can use AForge.NET Image Processing
Edge detector: http://www.aforgenet.com/framework/features/edge_detectors_filters.html
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