【问题标题】:Converting Pixels to Polygons将像素转换为多边形
【发布时间】:2012-04-10 21:00:58
【问题描述】:

我有一张卫星图像,我想获取所有果岭区域。 在实践中,我需要从 bmp 加载图像,选择一种颜色和容差并获得许多多边形,这些多边形是照片中的绿色区域。 我如何在 C# 中做到这一点? (我需要这个用于飞行模拟)

【问题讨论】:

  • 您可能需要一个for 循环,使用Bitmap.GetPixel 获取每个像素。
  • 每当我想到 Get/SetPixel 时,我都会想到等待……慢代码……

标签: c# image vector polygons


【解决方案1】:

好吧,第一步是确定给定像素是否在该区域内。我认为这很简单。然后,您可以创建“开”或“关”的像素区域。

然后您需要将像素转换为多边形。如何做到这一点取决于您需要的粒度。如果您想要高精度,您可以使用Marching Squares 从您的区域获取多边形。如果您需要简单的多边形,则需要更高级的方法来追踪边界。

【讨论】:

    【解决方案2】:

    嗯。听起来像是一种“魔杖”算法(来自具有该名称的 PhotoShop/PSP 中的控件,允许您单击一个像素以选择特定颜色阈值内的所有相邻像素)。

    因此,第一步是在位图上选择一个标识为“绿色”的像素,该像素应该是多边形的一部分。然后,您可以从该点递归地向左、向右、向上和向下移动,并测试该点的像素是否在您从原始像素颜色设置的阈值范围内。如果该点在阈值内且尚未在集合中,则将其添加到集合中,并继续遍历;如果该点不够“绿色”,或者已经被映射,则返回。有一些方法可以通过限制后续递归调用可以遍历的方向来限制“回溯”。例如,假设我们打了四个电话,向上、向下、向左和向右移动。从“原点”向左传输的呼叫只能从该点开始进一步向左或向上传输的呼叫。

    现在你有了一组像素,大致对应一组几何点。然后,您必须确定定义多边形边界的这些点的子集。这被称为计算这些点的“凸包”,维基百科有许多可以用 C# 实现的算法:http://en.wikipedia.org/wiki/Convex_hull_algorithms

    最容易理解的大概是Graham Scan:把所有的点排成一个列表,从第一个点(A)开始,画一条线到第二个点(B),然后判断一条线是否从B到第三点 (C) 将构成从 A 到 B 方向的“左转”或“右转”。如果是“左转”,则通过画线从 B 到 C 进行转弯,并且然后像以前一样将该线与从 C 到 D 的线进行比较。如果是“右转”,那么忘记 B 作为凸包的可能顶点,从 A 画到 C,然后检查 C 到 D 的线是否是左转。每当您看到“右转”时,请忽略定义线的三个点的当前“中间点”,而是在其他两个点之间画一条线。继续,从最后一个点环绕列表回到 A,直到这些点定义了一系列从最后一行的方向“左转”的线。这是点集的“凸包”,它可以在 NlogN 时间内对任何点列表完成。

    了解“凸包”就是这样;您永远无法从中获得凹形(如星星)。如果这很重要,您将需要调整算法以允许一些“右转”但不允许任何线段交叉。

    【讨论】:

    • 非常感谢!但是对于凸包,我只得到一个多边形。如何获得更多多边形?
    • 挑选更多位于该多边形之外的像素并重复整个过程。
    • 如果绿色区域不代表凸区域,则基于凸包算法的建议向量化将失败。此外,基于“限制后续递归调用可以遍历的方向”的“魔杖算法”在非凸区域上也失败了。
    【解决方案3】:

    使用 LockBits 并遍历每个字节(取决于像素格式 - 索引图像使用调色板,因此您需要先查询它以获得在容差范围内的调色板索引 - 对于非索引(和非 1bpp/16ppgreyscale)您可以直接访问颜色通道 - 请参阅GDI+ FAQ 以获得帮助)。 您范围内的每个彩色像素都可以直接写入另一个图像(即只有您想要的像素 - 其余像素填充不可见像素 - Alpha 0) - 或写入集合。我个人会先做前者。这非常快(如果您使用 LockBits)。然后是使用像素行走算法的边缘检测来计算“碎片”(如果您愿意,可以使用不规则多边形)。 AForge 库可能会在这里为您提供帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-23
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多