受到答案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
求 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]
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
我将对 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]
,这是有道理的,因为它也会被翻译相同的量。
非常感谢@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 点。