如何自动裁剪一张图片?

4
我正在尝试制作一个扫描应用程序。该应用程序将扫描文档并在图片框中显示图像。我遇到的问题是,图像(保存在扫描仪中的文档图像或说“真实”图像)显示在另一个带有背景的图像内(该背景颜色也在变化),如下所示:
enter image description here
我尝试了很多方法,但没有给我完美的结果,我用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;
    }

“没有完美的结果”离真正的问题还很遥远 - 我投票关闭。顺便说一下,我不会尝试使用GDI+这样的方式,最好使用像ImageMagick(http://www.imagemagick.org/script/index.php)这样的工具,或者对应的.NET API(http://imagemagick.codeplex.com/)来完成。 - Doc Brown
@DocBrown 非常有用,谢谢。我已经尝试了 AForge 而不是 ImageMagick。再次感谢。 - Rakesh
4个回答

4
我已经修改了您的代码,现在它可以正常运行。谢谢!
 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;
        }

3

我假设您始终拥有一个具有明显前景和背景的图像,并且希望对背景进行热切的剪裁。

在这种情况下,我会执行类似于区域增长的操作。从您可以保证是背景像素的点开始。

获取另一张图像(或矩阵或其他),初始化为零,并将相应的像素值设置为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

现在地图应该将所有背景像素设为1,前景设为2。您可以更改此设置以允许多个对象和阈值等。您可能希望阈值是值变化而不是绝对值。
然后,简单地找到最小和最大的x和y,并将该范围内的像素存储到新图像中。
希望这符合您的要求。

你说得对。这正是我需要的东西。你有在C#中实现它的任何想法吗? - Rakesh
点击这里了解像素操作。 点击这里了解裁剪。 如果您对C/C++/C#很熟悉,那么其他部分应该很容易翻译。 - Bill
好的,我会尝试您的解决方案,并在此更新。希望它能解决我的问题。谢谢Bill.. :-) - Rakesh

1

你可以使用EdgeDetector来查找书的边界: http://www.aforgenet.com/framework/features/edge_detectors_filters.html - Nickon

0

Mostafa HK的代码对我很有用。我正在使用此函数预处理YouTube缩略图(去除黑边,这是一个常见问题),并且我确实需要对他的代码进行一些小修正:

1)去掉了旋转(不确定那是干什么的)

2)将阈值从100降低到25。

3)在克隆最终图像时,我执行克隆原始autoCropImage而不是rotatedImage(同样不确定旋转是干什么的)。

我认为真正的秘密酱是降低阈值。这减少了代码找到的矩形数量,现在我可以正确地裁剪所有形式的缩略图(带有黑色顶部和底部的宽屏和带有黑色左侧和右侧的全屏)。

    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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接