指向多边形光线投射算法

时间:2014-12-09 21:01:46

标签: python algorithm computer-science corner-detection

给定一个大小为M的矩阵,N和一个点列表形成一个多边形,我需要返回一个二进制矩阵,它标记多边形内的所有点。这是代码:使用水平线扫描,与多边形相交并将交点之间的所有点标记为真。

import cv2
import math
import numpy as np

def getABC(x1, y1, x2, y2):
    A = y2 - y1
    B = x1 - x2
    C = A*x1 + B*y1
    return (A, B, C)

def polygon(M, N, poly):
    """
    Return a mask matrix
    Where points inside the polygon is 1, outside is 0
    """
    out = np.zeros((M, N)). astype(bool)

    n = len(poly)
    for i in range(M):

        # horizontal scanning
        intersection_x = i
        intersection_y = []

        # check through all edges
        for edge in range(n + 1):
            v1_x, v1_y = poly[edge % n]
            v2_x, v2_y = poly[(edge + 1) % n]

        v1_x = int(v1_x)
        v1_y = int(v1_y)
        v2_x = int(v2_x)
        v2_y = int(v2_y)

            assert (v1_x <= M and v2_x <= M and v1_y <= N and v2_y <= N)

            A1, B1, C1 = getABC(v1_x, v1_y, v2_x, v2_y)
            A2 = 1
            B2 = 0
            C2 = i

            # find intersection
            if intersection_x >= min(v1_x, v2_x) and intersection_x <= max(v1_x, v2_x):
                det = A1*B2 - A2*B1
                if (det != 0):
                    tmp = (A1 * C2 - A2 * C1)/det
                    intersection_y.append(math.ceil(tmp))

        intersection_y = sorted(list(set(intersection_y)))



        if len(intersection_y) > 1:
            for k in range(1, len(intersection_y), 2):
                out[intersection_y[k - 1]:intersection_y[k], intersection_x] = True

    return out

if __name__ == "__main__":
out = polygon(512, 512,         
    [[
      321.929203539823, 
      414.4070796460177
    ], 
    [
      164.74414597854175, 
      512.0
    ], 
    [
      0.0, 
      509.9846825337252
    ], 
    [
      0.0, 
      221.4867256637168
    ], 
    [
      170.60176991150445, 
      2.902654867256672
    ], 
    [
      320.1592920353982, 
      91.39823008849561
    ], 
    [
      271.4867256637168, 
      201.1327433628319
    ], 
    [
      348.4778761061947, 
      228.56637168141594
    ], 
    [
      359.98230088495575, 
      302.9026548672567
    ], 
    [
      220.15929203539824, 
      329.4513274336283
    ]])

    cv2.imwrite("polygon.png", out * 255)

在角落的情况下执行错误,例如上面的输入将生成:

enter image description here

我无法解决此问题。根据交叉点的数量,我将分配l0-l1 l2-l3 l4-l5或l1-l2 l3-l4 l5-l6为真。

1 个答案:

答案 0 :(得分:1)

您可以通过应用以下算法进行修复:
1.如果一条线与其内部的边相交(而不是在其中一个端点),则始终保持交叉点 2.如果一条直线与一个端点的边相交,当且仅当它是边的左端(x坐标较小)时,保持它。
3.如果边缘是垂直的,则忽略它。

之后,只需对点进行排序,而不删除重复项。