2012-04-10 91 views
0

我有一个卫星图像,我想要得到所有的绿色区域。 在实践中,我需要从一个BMP加载图像,选择一种颜色和tollerance,并获得许多多边形是照片中的绿色区域。 我如何在C#中做到这一点? (我需要这个模拟飞行)将像素转换为多边形

+0

你可能需要一个'for'循环,用'Bitmap.GetPixel'获取每个像素。 – Matthew 2012-04-10 21:06:41

+1

每当我想到Get/SetPixel时,我都会想到等待......慢代码... – 2012-04-10 21:13:33

回答

1

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

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

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

最容易理解的可能是Graham Scan:将所有点排列在列表中,从第一个点(A)开始,向第二个(B)绘制一条线,然后确定从B到第三个点(C)将从A到B的方向构成“左转”或“右转”。如果它是“左转”,则从B画C到C画出转弯,然后将该行与以前的从C到D的行进行比较。如果它是一个“右转”,那么忘记B作为凸包的可能顶点,从A画到C,然后检查C到D的行是否是左转。无论何时你看到一个“右转弯”,都忽略了定义这些线的三个点的当前“中点”,而是在另外两个线之间追溯一条线。继续,从最后一点回到A列表,直到这些点定义了一系列从最后一行的方向开始“左转”的行。这是一组点的“凸包”,它可以在NlogN时间的任意点上完成。

明白一个“凸包”就是那个;你永远不会得到一个凹形(如星形)。如果这很重要,则需要对算法进行调整以允许“右转”,但不允许任何线段穿过。

+0

非常感谢!但使用凸包,我只能得到一个多边形。我如何获得更多的多边形? – 2012-04-11 12:57:51

+0

选取位于该多边形之外的更多像素并重复整个过程。 – KeithS 2012-04-11 14:00:23

0

那么,第一步是找出一个给定的像素是否在区域内。我认为这很简单。然后,您可以创建“开”或“关”的像素区域。

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

0

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