我正在尝试制作扫描应用程序。该应用程序将扫描文档并将图像显示在图片框中。我面临的问题是图像(保存在扫描仪中的文档图像或说“真实”图像)显示在具有一些背景的另一个图像内(背景颜色也在变化)它看起来像这个图像。
我尝试了很多东西,但是没有给我一个完美的结果我用forge.net尝试过。这是我试过的代码。
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;
}
答案 0 :(得分:3)
我将您的代码更改为此并且运行良好。 感谢
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;
}
答案 1 :(得分:2)
我假设你总是拥有一个具有独特前景和背景的图像,并且你想要做一些像背景的热情作物。
在这种情况下,我会做类似于区域成长的事情。从可以保证背景像素的点开始。
获取另一个图像(或矩阵或其他),初始化为零,并将相应的像素值设置为1.如果任何相邻像素在原始图像的阈值范围内,则递归移动它们并设置其对应的像素值也是0。
那是:
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
现在,map应将所有背景像素设置为1,将forground设置为2.您可以更改此设置以允许多个对象和阈值等等。您可能希望阈值是值更改而不是绝对值。
然后只需找到min和max x和y,并将该范围内的像素存储到新图像中。
我希望这与你所需要的一致。
答案 2 :(得分:1)
您可以使用AForge.NET Image Processing
边缘检测器:http://www.aforgenet.com/framework/features/edge_detectors_filters.html
答案 3 :(得分:0)
Mostafa HK的代码为我工作。我使用此功能预处理YouTube缩略图(剥去黑边;这是一个常见问题),我确实需要对他的代码进行一些小修改:
1)摆脱了轮换(不确定是什么)
2)我将门槛从100降低到25.
3)克隆最终图像时,我从原始autoCropImage执行克隆而不是rotateImage(再次,不确定旋转的用途)。
我认为真正的秘诀是降低门槛。这减少了代码找到的矩形数量,现在我正在裁剪所有形式的缩略图(宽屏,顶部和底部为黑色,全屏,左侧和右侧为黑色)。
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;
}