简体   繁体   English

寻找直线和轮廓的交点

[英]Finding intersection between straight line and contour

I am trying to find the intersection point of a straight(dashed red) with the contour-line highlighted in red(see plot).我试图找到一条直线(红色虚线)与以红色突出显示的轮廓线的交点(见图)。 I used .get_paths in the second plot to isolate said contour line form the others(second plot).我在第二个图中使用 .get_paths 将所述等高线与其他(第二个图)隔离。

I have looked at a contour intersection problem, How to find all the intersection points between two contour-set in an efficient way , and have tried to use it as a base but have not been able to reproduce anything useful.我看过一个轮廓相交问题, 如何以有效的方式找到两个轮廓集之间的所有交点,并试图将其用作基础,但未能重现任何有用的东西。

http://postimg.org/image/hz01fouvn/ http://postimg.org/image/hz01fouvn/

http://postimg.org/image/m6utofwb7/ http://postimg.org/image/m6utofwb7/

Does any one have any ideas?有没有人有任何想法?

relevant functions to recreate plot,重新创建绘图的相关功能,

#for contour 
def p_0(num,t) :
    esc_p = np.sum((((-1)**n)*(np.exp(t)**n)*((math.factorial(n)*((n+1)**0.5))**-1)) for n in range(1,num,1))
    return esc_p+1

tau = np.arange(-2,3,0.1)
r=[]

p1 = p_0(51,tau)
p2 = p_0(51,tau)

for i in p1:
    temp_r=i/p2
    r.append(temp_r)

x,y= np.meshgrid(tau,tau)
cs = plt.contour(x, y, np.log(r),50,colors='k')
whichContour =20
pa = CS.collections[whichContour].get_paths()[0]
v = pa.vertices
xx = v[:, 0]
yy = v[:, 1]
plt.plot(xx, yy, 'r-', label='Crossing contour')

#straight line 
p=0.75
logp = (np.log(p*np.exp(tau)))
plt.plot(tau,logp)

Current attempt,目前的尝试,

import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import math

def intercepting_line() :
matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'

#fake data

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10.0 * (Z2 - Z1)

#plot
cs = plt.contour(X,Y,Z)
whichContour = 2 # change this to find the right contour lines

#get the vertices to calculate an intercept with a line
p = cs.collections[whichContour].get_paths()[0]
#see: http://matplotlib.org/api/path_api.html#module-matplotlib.path
v = p.vertices
xx = v[:, 0]
yy = v[:, 1]

#this shows the innermost ring now
plt.plot(xx, yy, 'r--', label='inner ring')

#fake line
x = np.arange(-2, 3.0, 0.1)
y=lambda x,m:(m*x)
y=y(x,0.9)
lineMesh = np.meshgrid(x,y)
plt.plot(x,y,'r' ,label='line')

#get the intercepts, two in this case 
x, y = find_intersections(v, lineMesh[1])
print x
print y
#plot the intercepting points
plt.plot(x[0], y[0], 'bo', label='first intercept')
#plt.plot(x[1], y[1], 'rs', label='second intercept')
plt.legend(shadow=True, fancybox=True, numpoints=1, loc='best')
plt.show()

#now we need to calculate the intercept of the vertices and whatever line
#this is pseudo code but works in case of two intercepting contour vertices

def find_intersections(A, B):
# min, max and all for arrays
amin = lambda x1, x2: np.where(x1<x2, x1, x2)
amax = lambda x1, x2: np.where(x1>x2, x1, x2)
aall = lambda abools: np.dstack(abools).all(axis=2)
slope = lambda line: (lambda d: d[:,1]/d[:,0])(np.diff(line, axis=0))

x11, x21 = np.meshgrid(A[:-1, 0], B[:-1, 0])
x12, x22 = np.meshgrid(A[1:, 0], B[1:, 0])
y11, y21 = np.meshgrid(A[:-1, 1], B[:-1, 1])
y12, y22 = np.meshgrid(A[1:, 1], B[1:, 1])
m1, m2 = np.meshgrid(slope(A), slope(B))
m1inv, m2inv = 1/m1, 1/m2

yi = (m1*(x21-x11-m2inv*y21) + y11)/(1 - m1*m2inv)
xi = (yi - y21)*m2inv + x21

xconds = (amin(x11, x12) < xi, xi <= amax(x11, x12),
          amin(x21, x22) < xi, xi <= amax(x21, x22) )
yconds = (amin(y11, y12) < yi, yi <= amax(y11, y12),
          amin(y21, y22) < yi, yi <= amax(y21, y22) )

return xi[aall(xconds)], yi[aall(yconds)]

At the moment it finds intersecting points but only where the line is uniform, the main reason why I cannot find a solution here is that I dont understand the original authors train of thinking here,目前它找到了相交点,但只在线条一致的地方,我在这里找不到解决方案的主要原因是我不明白原作者在这里的思路,

yi = (m1*(x21-x11-m2inv*y21) + y11)/(1 - m1*m2inv)
xi = (yi - y21)*m2inv + x21     

Use shapely can find the intersection point, than use the point as the init guess value for fsolve() to find the real solution:使用shapely可以找到交点,而不是使用该点作为fsolve()的初始猜测值来找到真正的解决方案:

#for contour 
def p_0(num,t) :
    esc_p = np.sum((((-1)**n)*(np.exp(t)**n)*((math.factorial(n)*((n+1)**0.5))**-1)) for n in range(1,num,1))
    return esc_p+1

tau = np.arange(-2,3,0.1)

x,y= np.meshgrid(tau,tau)
cs = plt.contour(x, y, np.log(p_0(51, y)/p_0(51, x)),[0.2],colors='k')

p=0.75
logp = (np.log(p*np.exp(tau)))
plt.plot(tau,logp)

from shapely.geometry import LineString
v1 = cs.collections[0].get_paths()[0].vertices

ls1 = LineString(v1)
ls2 = LineString(np.c_[tau, logp])
points = ls1.intersection(ls2)
x, y = points.x, points.y

from scipy import optimize

def f(p):
    x, y = p
    e1 = np.log(0.75*np.exp(x)) - y
    e2 = np.log(p_0(51, y)/p_0(51, x)) - 0.2
    return e1, e2

x2, y2 = optimize.fsolve(f, (x, y))

plt.plot(x, y, "ro")
plt.plot(x2, y2, "gx")

print x, y
print x2, y2

Here is the output:这是输出:

0.273616328952 -0.0140657435002
0.275317387697 -0.0123646847549

and the plot:和情节:

在此处输入图片说明

See your contour lines as polylines and plug the vertex coordinates into the implicit line equation (F(P) = aX + bY + c = 0).将轮廓线视为折线并将顶点坐标插入隐式线方程 (F(P) = aX + bY + c = 0)。 Every change of sign is an intersection, computed by solving 2x2 linear equations.符号的每次变化都是一个交集,通过求解 2x2 线性方程来计算。 You need no sophisticated solver.您不需要复杂的求解器。

If you need to detect the contour lines simultaneously, it is not much more complicated: consider the section of the terrain by a vertical plane through the line.如果需要同时检测等高线,也不是很复杂:考虑通过该线的垂直平面的地形截面。 You will obtain altitudes by linear interpolation along the edges of the grid tiles that are crossed.您将通过沿交叉的网格图块边缘的线性插值获得高度。 Finding the intersections with the grid is closely related to the Bresenham line drawing algorithm.寻找与网格的交点与 Bresenham 画线算法密切相关。

Then what you get is a profile, ie a function of a single variable.那么你得到的是一个配置文件,即单个变量的函数。 Locating the intersections with the horizontal planes (iso-values) is also done by detecting changes of sign.定位与水平面(等值)的交点也是通过检测符号的变化来完成的。

This is a way that I used to solve this problem这是我用来解决这个问题的一种方法

def straight_intersection(straight1, straight2):
    p1x = straight1[0][0]
    p1y = straight1[0][1]
    p2x = straight1[1][0]
    p2y = straight1[1][1]
    p3x = straight2[0][0]
    p3y = straight2[0][1]
    p4x = straight2[1][0]
    p4y = straight2[1][1]
    x = p1y * p2x * p3x - p1y * p2x * p4x - p1x * p2y * p4x + p1x * p2y * p3x - p2x * p3x * p4y + p2x * p3y * p4x + p1x * p3x * p4y - p1x * p3y * p4x
    x = x / (p2x * p3y - p2x * p4y - p1x * p3y + p1x * p4y + p4x * p2y - p4x * p1y - p3x * p2y + p3x * p1y)
    y = ((p2y - p1y) * x + p1y * p2x - p1x * p2y) / (p2x - p1x)
    return (x, y)

While this question is old now, i want to share my answer for this problem for future generations to come.虽然这个问题现在已经很老了,但我想为子孙后代分享我对这个问题的回答。 Actually, there is two more solutions i found to this problem that is relatively efficient.实际上,对于这个问题,我发现了另外两个相对有效的解决方案。

First solution is using pointPolygonTest in opencv recursively like that.第一个解决方案是在 opencv 中递归地使用pointPolygonTest

# Enumerate the line segment points between 2 points
for pt in zip(*line(*p1, *p2)):
    if cv2.pointPolygonTest(conts[0], pt, False) == 0:  # If the point is on the contour
        return pt

Second solution , you can simply draw the contour and line and make a np.logical_and() to get the answer第二种解决方案,您可以简单地绘制轮廓和线条并制作一个np.logical_and()来获得答案

blank = np.zeros((1000, 1000))
blank_contour = drawContour(blank.copy(), cnt[0], 0, 1, 1)
blank_line = cv2.line(blank.copy(), line[0], line[1], 1, 1)
intersections = np.logical_and(blank_contour, black_line)

points = np.where(intersections == 1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM