【问题标题】:Find area given a set of points给定一组点查找区域
【发布时间】:2012-09-17 08:09:59
【问题描述】:

给定 x,y 坐标列表和已知宽度和高度,如何确定封闭区域的 NUMBER(在 C# 中)?

例如:

在这张图片中,定义了 5 个封闭区域

  1. 人脸 (1)
  2. 眼睛 (2)
  3. 鼻子 (1)
  4. 面部右侧 (1)

x,y 点列表可以是任何黑色像素,包括嘴巴。

【问题讨论】:

标签: c# image-processing geometry


【解决方案1】:

你可以使用这个简单的算法,基于使用辅助位图填充的思想:

// backColor is an INT representation of color at fillPoint in the beginning.
// result in pixels of enclosed shape.
private int GetFillSize(Bitmap b, Point fillPoint)
{
   int count = 0;
   Point p;
   Stack pixels = new Stack();
   var backColor = b.GetPixel(fillPoint.X, fillPoint.Y);
   pixels.Push(fillPoint);
   while (pixels.Count != 0)
   {
       count++;

       p = (Point)pixels.Pop();
       b.SetPixel(p.X, p.Y, backColor);

       if (b.GetPixel(p.X - 1, p.Y).ToArgb() == backColor)
           pixels.Push(new Point(p.X - 1, p.Y));

       if (b.GetPixel(p.X, p.Y - 1).ToArgb() == backColor)
           pixels.Push(new Point(p.X, p.Y - 1));

       if (b.GetPixel(p.X + 1, p.Y).ToArgb() == backColor)
           pixels.Push(new Point(p.X + 1, p.Y));

       if (b.GetPixel(p.X, p.Y + 1).ToArgb() == backColor)
           pixels.Push(new Point(p.X, p.Y + 1));
   }

   return count;
}

更新

上面的代码只适用于这个四重连接的封闭区域。以下代码适用于八元链接的封闭区域。

// offset points initialization.
Point[] Offsets = new Point[]
{
    new Point(-1, -1),
    new Point(-0, -1),
    new Point(+1, -1),
    new Point(+1, -0),
    new Point(+1, +1),
    new Point(+0, +1),
    new Point(-1, +1),
    new Point(-1, +0),
};

...

private int Fill(Bitmap b, Point fillPoint)
{
    int count = 0;
    Point p;
    Stack<Point> pixels = new Stack<Point>();
    var backColor = b.GetPixel(fillPoint.X, fillPoint.Y).ToArgb();
    pixels.Push(fillPoint);
    while (pixels.Count != 0)
    {
        count++;

        p = (Point)pixels.Pop();
        b.SetPixel(p.X, p.Y, Color.FromArgb(backColor));

        foreach (var offset in Offsets)
            if (b.GetPixel(p.X + offset.X, p.Y + offset.Y).ToArgb() == backColor)
                pixels.Push(new Point(p.X + offset.X, p.Y + offset.Y));
    }

    return count;
}

下面的图片清楚地说明了我的意思。也可以向偏移数组添加更多远点,以便能够填充有间隙的区域。

【讨论】:

  • 酷。这使我的模糊描述变得明确。我喜欢。
  • 很好,对我正在研究的另一个领域很有用,但是知道如何确定封闭区域的数量吗?
  • 您可以对每个非背景颜色(示例图像上的黑色)像素使用我的算法进行区域检测。每次填充后,将不会检测到该区域(因为它们将被填充),您将不得不增加找到的区域的数量。当然,这种方法适用于链接区域。因此,对于其他使用 OpenCV 的情况,@Jason Hermann 已回答。
  • @KvanTTT - 这适用于 2 或更大的像素宽度,但是,如果像素宽度为 1px,它总是返回为只有 1 个封闭区域。有没有办法修改上面的代码来处理这个问题?
【解决方案2】:

我在使用 OpenCV 方面取得了巨大成功。有一个 .net 库,名为 Emgu CV

这是一个涵盖 Emgu CV 替代品的问题:.Net (dotNet) wrappers for OpenCV?

该库包含用于识别轮廓和查找有关它们的属性的函数。您可以搜索 cvContourArea 以查找更多信息。

如果您正在寻找针对该特定问题的快速解决方案并希望编写自己的代码而不是重用其他代码,那么我没有可以提供的算法来做到这一点。对不起。

【讨论】:

    【解决方案3】:

    示例图片中有几个特殊情况。你必须决定如何处理它们。

    通常,您将从将光栅图像转换为一系列多边形开始。那么计算面积是一件相当琐碎的事情(见Servy的评论)

    特殊情况是脸部和嘴巴的一侧。两者都是开放的形状,而不是封闭的。你需要弄清楚如何关闭它们。

    【讨论】:

      【解决方案4】:

      我认为这归结为计算每个区域中(非黑色)像素的数量。如果您选择一个不是黑色的像素,请将其添加到HashSet&lt;&gt;,查看所选像素上方、下方、左侧和右侧的像素是否也是非黑色的。

      每当您发现 个非黑色像素(通过上/下/左/右),将它们添加到您的集合中。全部找到后,数一数。

      您所在地区的面积是count / (pixelWidthOfTotalDrawing * pixelHeightOfTotalDrawing) 乘以整个矩形的面积(取决于您想要的单位)。

      评论:我不认为这看起来像一个多边形。这就是为什么我想到了简单绘图软件的“填色”功能。

      【讨论】:

        猜你喜欢
        • 2016-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-24
        相关资源
        最近更新 更多