如何使用 Python 和 DLib 找到线的左侧或右侧的点?

Posted

技术标签:

【中文标题】如何使用 Python 和 DLib 找到线的左侧或右侧的点?【英文标题】:how to find a point is on left or right side of line using Python and DLib? 【发布时间】:2020-11-02 23:47:49 【问题描述】:

我正在尝试在 Dlib/OpenCV/Numpy/Scipy 中查找现有 API,以找出一个点在线的左侧或右侧。

import dlib
a = dlib.point(0, 0)
b = dlib.point(20, 20)
line = dlib.line(a, b)
dlib.distance_to_line(line, dlib.point((-50, 4))) # provides absolute distance. 

寻找解决方案

一个简单的 API,告诉它在一行的左侧/右侧。

example 
dlib.where_is_the_point(line, dlib.point((-50, 4)) # if returns negative means left side.

我目前的解决方案

我写了一个数学来找到一个点是左侧还是右侧。所以下面的函数返回一个d,基于d的符号我可以判断它是左还是右。一种硬编码的方式,不喜欢下面的解决方案。

    def where_it_is(self, target: Point):
        d = (target.x - self.p1[0]) * (self.p2[1] - self.p1[1]) - (target.y - self.p1[1]) * (self.p2[0] - self.p1[0])
        return d

【问题讨论】:

【参考方案1】:

我希望您在 Math StackExchange 上参考这一点:https://math.stackexchange.com/questions/274712/calculate-on-which-side-of-a-straight-line-is-a-given-point-located。简单来说,假设你有三个点:一个表示线开始的点,一个表示线结束的点和一个查询点,你可以计算这三个点之间的叉积并检查符号结果。事实上,Stack Overflow 上的这个答案使用它来确定一个点是否在一条线的左侧:How to tell whether a point is to the right or left side of a line。

我们可以使用此行为来帮助定义一个点是在左侧还是右侧,并且可以根据您使用 Python 和 DLib 的事实进行调整。因此,如果叉积的符号为正,则该点位于线的左侧。如果符号为负,则该点位于该线的右侧。如果叉积为 0,则该点在直线上共线。由于数值不精确,与 0 进行精确比较是非常危险的,因为在大多数情况下,很少会得到精确的 0,因此与精确的 0 进行比较可能会给您错误的结果。因此,您需要查看该值是否小于一个小的阈值,例如1e-9 用于共线检查。

对于您的示例行,请注意它本质上是y = x,因此我们绝对可以定义应该出现在该行左侧和右侧的众所周知的点。

因此:

def where_it_is(line, point):
    aX = line.p1.x
    aY = line.p1.y
    bX = line.p2.x
    bY = line.p2.y
    cX = point.x
    cY = point.y

    val = ((bX - aX)*(cY - aY) - (bY - aY)*(cX - aX))
    thresh = 1e-9
    if val >= thresh:
        return "left"
    elif val <= -thresh:
        return "right"
    else:
        return "point is on the line"

测试一下:

import dlib

a = dlib.point(0, 0)
b = dlib.point(20, 20)
line = dlib.line(a, b)

pt1 = dlib.point(2, -2) # Should appear on the right
pt2 = dlib.point(5, 10) # Should appear on the left
pt3 = dlib.point(2, 2) # Point should be collinear

print(where_it_is(line, pt1))
print(where_it_is(line, pt2))
print(where_it_is(line, pt3))

我已将点定义为在线的左侧、右侧和共线。我们得到:

In [40]: %paste
print(where_it_is(line, pt1))
print(where_it_is(line, pt2))
print(where_it_is(line, pt3))

## -- End pasted text --
right
left
point is on the line

【讨论】:

谢谢,我无法理解为什么我们需要阈值以及如何确定阈值,因为我试图在边缘设备(如 Nano、TX2)上运行此代码。是否有任何经验法则或者我们可以使用1e-9 作为标准值? 阈值是因为浮点精度。具体来说,与完全零进行比较是非常危险的,因此您通常使用一个小的常数来代替。这里没有规则,但它通常是一个很小的值,您预计不会对您的计算产生重大影响。 1e-9 只是我选择的一个值。

以上是关于如何使用 Python 和 DLib 找到线的左侧或右侧的点?的主要内容,如果未能解决你的问题,请参考以下文章

无法安装 DLIB [Debian 7] [Python 2.7]

无法在 Python 3.6 中运行 dlib 模块

如何线上部署用python基于dlib写的人脸识别算法

人脸识别算法虹软arcface和Dlib对比

如何在 mac 上为 python 安装 dlib?

如何在 Windows 10 上为 python 3.6 安装 dlib?