你的位置:首页 > ASP.net教程

[ASP.net教程]一种从纹理图片提取多边形的方法


很久在这里写博客。很多时候匹配纹理图片和多边形匹配,手工设置往往非常繁琐,于是写了一段从纹理图片提取边缘多边形的代码。但这份代码只能提取“实心”的多边形,并且只支持了一个多边形。当然如果需要可以扩展使之能够提取多个多边形。基本思路如下:

1、快速填充纹理中被设为透明的部分。并获得一个边缘种子。

2、利用边缘种子快速检索边缘。

3、简化边缘。

到这里似乎问题解决了,但测试发现一个问题,由于快速边缘检索时将种子周围的点入栈而没有方向,导致最终闭合时一些点会不按顺时针或逆时针被添加到列表。为了解决这个问题,还需要进行边缘排序,而边缘排序之后,还需要再次简化:

4、对简化的边缘排序。

5、简化边缘。

当然,如果边缘排序算法效率更高,可以得到检索的结果后进行排序并简化,这样简化边缘只需要运行一次。

这里仅列出边缘简化和排序算法。其他代码在之前的文章中已经发过了。

 1   '简化边缘 2   Private Function EdgeSimple(edge As List(Of Point)) As List(Of Point) 3     Dim tmp As New List(Of Point) 4     Dim result As New List(Of Point) 5     '把前两点复制到结尾 6     If edge.Count < 3 Then Return result 7     tmp.AddRange(edge) 8     tmp.Add(edge(0)) 9     tmp.Add(edge(1))10     '遍历整个数组,每三个点判定是否共线,若不共线则把中间点添加到返回值11     Dim v1, v2 As Vector212     For i As Integer = 0 To edge.Count - 113       v1 = New Vector2(tmp(i).X - tmp(i + 1).X, tmp(i).Y - tmp(i + 1).Y)14       v2 = New Vector2(tmp(i + 2).X - tmp(i + 1).X, tmp(i + 2).Y - tmp(i + 1).Y)15       v1.Normalize()16       v2.Normalize()17       If Vector2.Dot(v1, v2) + 1 > 0.00001F Then18         result.Add(tmp(i + 1))19       End If20     Next21     Return result22   End Function23 24   '边缘排序25   Private Sub EdgeSort(edge As List(Of Point))26     Dim op As Point = GetOrigin(edge)27     Dim tmp As Point28     For i As Integer = 0 To edge.Count - 229       For j As Integer = 0 To edge.Count - i - 230         If PointCmp(edge(j), edge(j + 1), op) Then31           tmp = edge(j)32           edge(j) = edge(j + 1)33           edge(j + 1) = tmp34         End If35       Next36     Next37   End Sub38 39 40 41   Private Function PointCmp(a As Point, b As Point, op As Point) As Boolean42     If a.X >= 0 AndAlso b.X < 0 Then Return True43     If a.X = 0 AndAlso b.X = 0 Then Return a.Y > b.Y44     Dim det As Integer = (a.X - op.X) * (b.Y - op.Y) - (b.X - op.X) * (a.Y - op.Y)45     If det = 0 Then46       Dim d1 As Double = (a.X - op.X) * (a.X - op.X) + (a.Y - op.Y) * (a.Y - op.Y)47       Dim d2 As Double = (b.X - op.X) * (b.X - op.Y) + (b.Y - op.Y) * (b.Y - op.Y)48       Return d1 > d249     Else50       Return det < 051     End If52   End Function