【问题标题】:How to triangulate a concave polygon?如何对凹多边形进行三角剖分?
【发布时间】:2020-04-21 12:19:16
【问题描述】:

我刚刚开始使用图形编程并尝试使用实现 Delaunay 算法的 opencv 的 Subdiv2D 类对凹多边形进行三角剖分。

我的代码在下面进一步生成以下输出,其中红线标记了生成的三角形。到目前为止,一切都很好。然而,该算法还为多边形的凹面部分计算了一个三角形。

我在这里做错了什么以及如何防止这种行为?我没有找到可以传递给Subdiv2D 函数的任何形式的约束。

我能想到的一种方法是计算每个三角形的质心,然后测试它是否在多边形内。但是......这真的是这个算法的方法吗?

# -*- coding: utf-8 -*-
import numpy as np
import cv2

width = 800
height = 600
img = np.zeros((height,width,3), np.uint8)
pts = np.array([[100,50],[200,300],[700,200],[500,100],[400,150]], np.int32)
rect = (0, 0, width, height)

def rect_contains(rect, point) :
    if point[0] <rect[0] : 
        return False
    elif point[1] < rect[1] : 
        return False
    elif point[0] > rect[2] :
        return False
    elif point[1] > rect[3] : 
        return False
    return True

def draw_triangeles(rect, points, img) :
    subdiv = cv2.Subdiv2D()
    subdiv.initDelaunay(rect)

    for p in points:
        subdiv.insert((p[0], p[1]))

    triangles = subdiv.getTriangleList()

    for t in triangles:
        pt1 = (t[0], t[1])
        pt2 = (t[2], t[3])
        pt3 = (t[4], t[5])

        if rect_contains(rect, pt1) and rect_contains(rect, pt2) and rect_contains(rect, pt3) :
            cv2.line(img, pt1, pt2, (0,0,255), 2)
            cv2.line(img, pt2, pt3, (0,0,255), 2)
            cv2.line(img, pt3, pt1, (0,0,255), 2)

def draw_points(points, img):
    for p in points:
        cv2.circle(img, (p[0], p[1]), 2, (255,255,255), 2)

# Draw polygon    
cv2.fillPoly(img, [pts], (0, 255, 0))

# Draw result of triangulation
draw_triangeles(rect, pts, img)

# Draw vertices on top 
draw_points(pts, img)

#hull = cv2.convexHull(pts)
#cv2.polylines(img, [hull], True, (0, 255, 0))

cv2.imshow("image", img)
cv2.waitKey()
cv2.destroyAllWindows()

【问题讨论】:

  • 我认为标准算法是首先将凹多边形分解为多个凸多边形,然后分别对每个凸多边形进行三角剖分。例如,请参阅stackoverflow.com/questions/694108/…
  • 感谢您的回复。看来我对三角测量的用途有错误的理解。我的想法就是这样,将一个凹多边形分解成几个凹多边形(三角形)。
  • 您可以将任何n-gon三角化成n-2个三角形;为了效率(或至少简单),大多数算法都假设一个凸多边形。 (更准确地说,三角测量算法是为任意点集简单定义的,其凸包意味着特定的凸多边形。)
  • 你看过convex hull吗?

标签: python opencv triangulation delaunay


【解决方案1】:

第 27 行的triangles = subdiv.getTriangleList() 将生成 4 个三角形,包括不需要的三角形。

虽然不理想,但在第 32 行将 for t in triangles: 更改为 for t in triangles[:3]: 将绘制除最后一个(不需要的)三角形之外的所有三角形。

完整代码:

# -*- coding: utf-8 -*-
import numpy as np
import cv2

width = 800
height = 600
img = np.zeros((height,width,3), np.uint8)
pts = np.array([[100,50],[200,300],[700,200],[500,100],[400,150]], np.int32)
rect = (0, 0, width, height)

def rect_contains(rect, point) :
    if point[0] <rect[0] :
        return False
    elif point[1] < rect[1] :
        return False
    elif point[0] > rect[2] :
        return False
    elif point[1] > rect[3] :
        return False
    return True

def draw_triangeles(rect, points, img) :
    subdiv = cv2.Subdiv2D()
    subdiv.initDelaunay(rect)

    for p in points:
        subdiv.insert((p[0], p[1]))


    triangles = subdiv.getTriangleList()

    for t in triangles[:3]:
        pt1 = (t[0], t[1])
        pt2 = (t[2], t[3])
        pt3 = (t[4], t[5])

        if rect_contains(rect, pt1) and rect_contains(rect, pt2) and rect_contains(rect, pt3) :
            cv2.line(img, pt1, pt2, (0,0,255), 2)
            cv2.line(img, pt2, pt3, (0,0,255), 2)
            cv2.line(img, pt3, pt1, (0,0,255), 2)

def draw_points(points, img):
    for p in points:
        cv2.circle(img, (p[0], p[1]), 2, (255,255,255), 2)

# Draw polygon
cv2.fillPoly(img, [pts], (0, 255, 0))

# Draw result of triangulation
draw_triangeles(rect, pts, img)

# Draw vertices on top
draw_points(pts, img)

#hull = cv2.convexHull(pts)
#cv2.polylines(img, [hull], True, (0, 255, 0))

cv2.imshow("image", img)
cv2.waitKey()
cv2.destroyAllWindows()

虽然这样解决了问题,但并不理想。这个解决方案没有考虑更多的三角形,只解决了症状,而不是问题的根源。

【讨论】:

  • 感谢您的宝贵时间。不幸的是,这通常不能解决我的问题,也不能解决其他多边形,然后是我的代码中的问题。
  • 是的,我在写完答案后在 cmets 看到了你的交流。尽管如此,还是祝项目好运。
猜你喜欢
  • 2016-09-28
  • 2011-07-15
  • 2012-09-06
  • 2016-09-27
  • 2017-05-23
  • 1970-01-01
  • 2014-07-12
  • 2020-11-21
  • 2018-04-13
相关资源
最近更新 更多