一种从纹理图片提取多边形的方法

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

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 Vector2
12         For i As Integer = 0 To edge.Count - 1
13             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 Then
18                 result.Add(tmp(i + 1))
19             End If
20         Next
21         Return result
22     End Function
23 
24     '边缘排序
25     Private Sub EdgeSort(edge As List(Of Point))
26         Dim op As Point = GetOrigin(edge)
27         Dim tmp As Point
28         For i As Integer = 0 To edge.Count - 2
29             For j As Integer = 0 To edge.Count - i - 2
30                 If PointCmp(edge(j), edge(j + 1), op) Then
31                     tmp = edge(j)
32                     edge(j) = edge(j + 1)
33                     edge(j + 1) = tmp
34                 End If
35             Next
36         Next
37     End Sub
38 
39 
40 
41     Private Function PointCmp(a As Point, b As Point, op As Point) As Boolean
42         If a.X >= 0 AndAlso b.X < 0 Then Return True
43         If a.X = 0 AndAlso b.X = 0 Then Return a.Y > b.Y
44         Dim det As Integer = (a.X - op.X) * (b.Y - op.Y) - (b.X - op.X) * (a.Y - op.Y)
45         If det = 0 Then
46             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 > d2
49         Else
50             Return det < 0
51         End If
52     End Function

 

posted @ 2016-09-20 15:09  zcsor~流浪dè风  Views(756)  Comments(0Edit  收藏  举报