求 3D 空间中一点到直线的垂直距离(向量)

问题描述 投票:0回答:4

受到答案here的启发,我想计算3D空间中从点到直线的垂直距离(以矢量格式而不只是幅度)。

上述方程确实给出了幅度。

import numpy as np
norm = np.linalg.norm

p1 = np.array([0,0,0])
p2 = np.array([10,0,3])

p3 = np.array([6, -3, 5])

ppDist = np.abs(norm(np.cross(p2-p1, p1-p3)))/norm(p2-p1)
print(ppDist) # 4.28888043816146
现实中的

ppDist
向量将是
(0.8807339448,3,-2.935779817)
,这样它的
norm()
就是
4.288880438

这是一个快速可视化 -

python numpy linear-algebra
4个回答
2
投票

求 P13 向量在 P12 上的投影,P13 与投影的向量差就是垂直向量。

P12 = p2-p1
P13 = p3-p1

proj_13over12 = np.dot(P13, P12)*P12/norm(P12)**2 # array([6.88073394, 0.        , 2.06422018])
perpendicular = proj_13over12 - P13

print(perpendicular) # [ 0.88073394  3.         -2.93577982]


0
投票
python
import numpy as np

def distance_point_to_line(p1, p2, p3):
    v = p2 - p1
    w = p3 - p1
    proj_w_v = np.dot(w, v) / np.dot(v, v) * v
    u = w - proj_w_v
    d = np.linalg.norm(u)
    p = p3 - u
    return d, p

0
投票

我将对 OP 的解决方案给出一个稍微改变的解决方案。这是因为在OP的解决方案中,他们所说的

proj_13over12
的含义缺失了。我们想要从投影中得到的实际上是位于由
p1
p2
定义的直线上的点,当将该点与
p3
连接时,它会创建一个垂直于该向量的向量。在
p1 = (0,0,0)
的特殊情况下,我们得到了结果,但当点移动时该值不会改变。例如,对于给定的点,垂直点位于
[6.88073394, 0., 2.06422018]
。但是,如果我们将所有点在每个方向上平移 1,我们应该得到一个平移相同量的垂直点,但我们没有。

import numpy as np
from numpy.linalg import norm

p1 = np.array([0, 0, 0]) + 1
p2 = np.array([10, 0, 3]) + 1
p3 = np.array([6, -3, 5]) + 1

P12 = p2-p1
P13 = p3-p1

proj_13over12 = np.dot(P13, P12)*P12/norm(P12)**2 
print(proj_13over12) # still [6.88073394, 0., 2.06422018]

我将使用一些对我来说更有意义的不同符号。首先,将 p1 连接到

p2
向量
将称为
v1
(对于向量 1),将
p1
连接到
p2
的向量将称为
v2
。投影的结果将称为
projv2_v1
(这在某种程度上反映了常见的表示法,其中投影到的向量是单词“proj”的下标)。垂直点称为
pperp

我们使用方程

v1 (v1 dot v2)/norm(v1)^2
计算投影,也可以写为
v1 (v1 dot v2)/(v1 dot v1)
。 (数学插曲:投影之所以有效,是因为
v1/norm(v1)
给出了
v1
方向上的单位向量,而
(v1 dot v2)/norm(v1)
给出了
v2
方向上
v1
向量的大小。)现在,在计算投影之后,
pperp
是通过添加
p1
来找到的(我们通过与
p1
求差来创建向量,本质上将所有内容平移到原点,因此这一步将平移回空间中的实际位置)。然后通过求连接
p1
pperp
的向量的范数来求出距离。通过这些变化,结果都有简单的物理解释。

import numpy as np
from numpy.linalg import norm

p1 = np.array([0,0,0])
p2 = np.array([10,0,3])
p3 = np.array([6, -3, 5])

v1 = p2 - p1
v2 = p3 - p1
projv2_v1 = np.dot(v1,v2)*v1/np.dot(v1, v1)
pperp = projv2_v1 + p1
print(pperp) # [6.88073394, 0., 2.06422018]
dist = norm(pperp - p3)
print(dist)  # 4.28888043816146

现在,如果我们像以前一样翻译所有点,我们会得到

pperp =  [7.88073394, 1., 3.06422018]
,这是有道理的,因为它也会被翻译相同的量。


0
投票

非常感谢@jared,它工作得很好,但我对这段代码有一个小问题。

我用一张图片和一个轮廓来表示菱形物体的4个点。

因为图片太大所以调整大小

frame = cv2.resize(img, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_AREA)

然后我得到3分:

P1 = [399,1656]
P2 = [2761,1601]
P3 = [647,918]

V1=[2362,-55]
V2=[248,-738]
PPERP = [664,1650]

一切都很完美,但是......当我使用原始尺寸时

frame = cv2.resize(img, None, fx=1.0, fy=1.0, interpolation=cv2.INTER_AREA)

我有结果了

P1 = [499,2071]
P2 = [3452,2001]
P3 = [809,1148]

V1=[2953,-70]
V2=[310,-923]
PPERP = [338,2063] #which is wrong

你能帮我解释一下为什么我在使用全尺寸图像后得到错误的结果吗?

附上小图来显示 p1、p2 和 p3 点。

© www.soinside.com 2019 - 2024. All rights reserved.