【问题标题】:How to auto crop an image?如何自动裁剪图像?
【发布时间】:2012-07-31 13:00:28
【问题描述】:

我正在尝试制作扫描应用程序。该应用程序将扫描文档并在图片框中显示图像。我面临的问题是图像(保存在扫描仪中的文档图像或说“真实”图像)显示在另一个具有某些背景的图像中(该背景颜色也在变化)它看起来像这个图像。

我尝试了很多东西,但没有给我一个完美的结果,我用 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 (imagemagick.org/script/index.php) 之类的工具,或者相应的 .NET API (imagemagick.codeplex.com)
  • @DocBrown 非常有用,谢谢。我试过 AForge 而不是 ImageMagick。再次感谢。

标签: c# image-processing crop


【解决方案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

现在地图应该将所有背景像素设置为 1,前景设置为 2。您可以更改此设置以允许多个对象和阈值等等。您可能希望阈值是一个值变化而不是一个绝对值。

然后只需找到最小和最大 x 和 y 并将该范围内的像素存储到新图像中。

我希望这符合您的需要。

【讨论】:

  • 你是对的。这是我需要的。你有什么想法在 C# 中做到这一点。
  • 查看here 进行像素操作。查看here 进行裁剪。如果您对它们足够熟悉,其余部分应该很容易转换为 C/C++/C#。
  • 好的,我会试试你的解决方案,并会在这里更新。希望它能解决我的问题..谢谢比尔..:-)
【解决方案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;
        }

【讨论】:

    【解决方案4】:

    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;
        }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-18
      • 1970-01-01
      • 2012-07-18
      • 2023-03-10
      • 1970-01-01
      • 2013-09-13
      • 2012-10-01
      相关资源
      最近更新 更多