找到要裁剪的图像矩形区域

时间:2014-07-06 08:01:15

标签: c# image winforms crop

我的图像尺寸为(352 x 240)
enter image description here

我想裁剪白色区域(所选区域如下图所示) enter image description here

我使用此代码裁剪图片,

private static Image cropImage(Image img, Rectangle cropArea)
{
   Bitmap bmpImage = new Bitmap(img);
   Bitmap bmpCrop = bmpImage.Clone(cropArea,
   bmpImage.PixelFormat);
   return (Image)(bmpCrop);
}

但我找不到符合我需要的确切矩形区域!
如何查找所选区域的Rectangle值?
我只想裁剪这个区域!谢谢!

1 个答案:

答案 0 :(得分:2)

如果你想自己做,你当然可以。但是如何做到最好的细节很大程度上取决于你对源图像的确切了解程度。

以下是一些需要考虑的问题和决定:

  • 你对图像的尺寸有所了解吗
  • 你对图像的位置有所了解吗?它总是在右下角吗?
  • 你知道切角的大小吗?
  • 你知道颜色吗?
  • 你宁愿削减内部的一些像素,还是包括外面或中间的一些像素?

看看你的例子,你可以试试这个策略:

  • 首先,您可以在一定距离内水平移动图像,例如10或20片。
  • 在您观察到的每条横线上,收集像素变色的所有点
  • 然后你比较结果列表,看看中间是否有一些(!)同意
  • 这可以让你获得左右边界
  • 它还可以为您提供可以进行垂直扫描的区域
  • 然后重复进行垂直扫描以获得顶部和底部坐标。
  • 垂直扫描不必搜索矩形,它们可以从水平扫描结果的中间工作

为了实现这一点,你必须对你期望的颜色变化有所了解:是否会涉及平滑?如果是这样,您需要比较GetPixel颜色的结果...

此外,尺寸应该是近似已知的,否则您可能需要用更精细的网格重复整个过程。

编辑:使用评论中的信息可以做出一些假设(*)并使用这段代码来确定目标矩形。这些假设用于:

  • 确定两个扫描线范围,其中可以假设扫描到达目标体
  • 确定内部和外部颜色的两个像素

我使用colordistance函数和4个点列表和几个点击的平均值。变量blur适用于图像的值2-6。

List<Point> xPoints1 = new List<Point>();
List<Point> xPoints2 = new List<Point>();
List<Point> yPoints1 = new List<Point>();
List<Point> yPoints2 = new List<Point>();

Rectangle findRectangle()
{
    int xMax = pictureBox1.Image.Width; 
    int yMax = pictureBox1.Image.Height;

    // * we can asume that these lines hit the body
    int x0 = xMax * 3 / 4;
    int y0 = yMax * 3 / 4;

    using (Bitmap bmp = new Bitmap(pictureBox1.Image) )
    {
        // we can assume that these are the out- and inside colors
        Color col0 = bmp.GetPixel(9, 9);
        Color col1 = bmp.GetPixel(x0, y0);

        int blur = 4;
        int diff = colordistance(col0, col1) / blur;

        bool outside = true;
        // a few horizontal scans..
        for (int y = y0 - 20; y < y0 + 20; y += 4)
        {
          outside = true;
          for (int x = 0; x < xMax; x++)
          {
            Color c = bmp.GetPixel(x, y);

            if ( outside && colordistance(c, col0) > diff)
               { outside = !outside; xPoints1.Add(new Point(x, y)); }
            else if (!outside && colordistance(c, col1) > diff) 
               { outside = !outside; xPoints2.Add(new Point(x, y)); }
            }
        }              

        // a few vertical scans..
        for (int x = x0 - 20; x < x0 + 20; x += 4)
        {
           outside = true;
           for (int y = 0; y < yMax; y++)
           {
              Color c = bmp.GetPixel(x, y);
              if (outside && colordistance(c, col0) > diff) 
                  { outside = !outside; yPoints1.Add(new Point(x, y)); }
              else if (!outside && colordistance(c, col1) > diff) 
                  { outside = !outside; yPoints2.Add(new Point(x, y)); }
           }
        }

        int left   = (int)xPoints1.Average(p => p.X);
        int right  = (int)xPoints2.Average(p => p.X);
        int top    = (int)yPoints1.Average(p => p.Y);
        int bottom = (int)yPoints2.Average(p => p.Y);
        // if the target sits at the bottom we didn't find the edge
        if (bottom == 0) bottom = yMax;

        return = new Rectangle(left, top, right - left, bottom - top);

    }
}

int colordistance(Color c1, Color c2)
{
    return (int) Math.Sqrt((c1.R - c2.R) * (c1.R - c2.R) +
        (c1.G - c2.G) * (c1.G - c2.G) +
        (c1.B - c2.B) * (c1.B - c2.B));

}

注意:顶部和左侧值触及目标内部。底部(可能还有底部)撞到了外面。因此,您应该将前者或后者减少1个像素,具体取决于您的需要..!

编辑第一个版本的outside变量设置在错误的位置。校正。