【问题标题】:Python - is there a way to identify the directionality of angles?Python - 有没有办法识别角度的方向性?
【发布时间】:2020-12-17 17:51:17
【问题描述】:

在下图中,显示了所谓的泪珠状 DNA 分子。对我来说,这个 DNA 弯曲角度的分布非常有趣。红色显示了由skimage.morphology.skeletonize 产生的跟踪。 在我的程序中,跟踪被表示为一个 numpy-array:numpy-array 中的每个条目都是一个 float64 元组,对应于图像中跟踪点的 x 和 y 坐标。所以如果我申请np.diff(trace, axis=0),我会得到我想要在向量中分析的片段。

问题:现在,我现在如何计算两个后续线段之间的角度。但是,如果角度是顺时针或逆时针方向,我现在不知道。例如,在某一时刻,DNA 向左弯曲,因此当 DNA 向右弯曲时所测得的角度会有所不同,大多数情况下都是这样。有什么办法可以解决这个问题?

到目前为止我的想法: 我想对每个段进行插值,然后检查下一段是否位于插值线的下方或上方,指示顺时针与逆时针的角度。但这似乎很难实现,而且由于我是初学者,任何输入将不胜感激!

【问题讨论】:

    标签: python numpy scikit-image angle


    【解决方案1】:

    我认为叉积 np.cross 会在这里为您提供帮助。对于一个简单的三角形,首先逆时针,然后顺时针,这可能看起来像这样(可以优化,为了清晰起见,让它更长)。角度输出是向量之间的夹角,方向遵循右手定则:编辑:添加了一条方向变化的曲线,添加了图形(逆时针方向的注释):

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.path import Path
    
    def drangl(vsgi, vsgi1):
        '''sin(theta)=|axb|/(|a||b|)'''
        return np.arcsin(np.cross(vsgi, vsgi1)/np.linalg.norm(vsgi)/np.linalg.norm(vsgi1))
    
    print('going around the traingle counter-clockwise and clockwise:\n')
    
    trace = np.array([(0.,0.), (10.,-1.), (5.,10.), (0.,0.)])
    vsegs = np.diff(trace, axis=0)
    
    for iv in [0,1,-1]: # counter-clockwise
        print(f'ctr-cl: {iv:d} {drangl(vsegs[iv], vsegs[iv+1]):2.2f}')
    for iv in [-1,1,0]: # clockwise
        print(f'cw: {iv:d} {drangl(vsegs[iv], vsegs[iv+1]):2.2f}')
        
    print('\nnow with direction change in the path:\n')
    
    trace = np.array([(0.,0.), (10.,-1.), (9., 5.), (12., 5.), (5.,10.), (0.,0.)])
    vsegs = np.diff(trace, axis=0)
        
    for iv in [0,1,2,3,-1]: # counter-clockwise
        print(f'ctr-cl: {iv:d} {drangl(vsegs[iv], vsegs[iv+1]):2.2f}')
    for iv in [-1,3,2,1,0]: # clockwise
        print(f'cw: {iv:d} {drangl(vsegs[iv], vsegs[iv+1]):2.2f}')
        
    codes = [
        Path.MOVETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.CLOSEPOLY,
    ]
    
    path = Path(trace, codes)
    fig, ax = plt.subplots()
    patch = patches.PathPatch(path, facecolor='white', lw=2)
    ax.add_patch(patch)
    ax.set_xlim(-1, 13)
    ax.set_ylim(-2, 11)
    ax.annotate('turns right', xy=(9, 5), xytext=(5, 5),
                arrowprops=dict(facecolor='black', shrink=0.05),
                )
    ax.annotate('turns left', xy=(12, 5), xytext=(10, 10),
                arrowprops=dict(facecolor='black', shrink=0.05),
                )
    plt.show()
    

    产生

    逆时针和顺时针绕着火车转:

    ctr-cl: 0 1.04
    ctr-cl: 1 0.89
    ctr-cl: -1 1.21
    cw: -1 1.21
    cw: 1 0.89
    cw: 0 1.04
    
    now with direction change in the path:
    
    ctr-cl: 0 1.31
    ctr-cl: 1 -1.41
    ctr-cl: 2 0.62
    ctr-cl: 3 1.41
    ctr-cl: -1 1.21
    cw: -1 1.21
    cw: 3 1.41
    cw: 2 0.62
    cw: 1 -1.41
    cw: 0 1.31
    

    符号变化现在指示曲线改变方向的位置。

    【讨论】:

    • 你为什么计算np.arcsin而不是np.arccos
    • 我用 |axb|=|a| |b| sin(theta) 其中 theta 是 a 和 b 之间的包围角,但我猜结果向量的方向对您的问题很重要。
    • 如果你穿过两个向量迈出一步,这个符号就会发挥作用(想象一个向量加法的三角形:你沿着两条边走,得到结果向量)。添加是可交换的,但是您可以通过叉积来识别向左或向右的“手性”,它会切换符号(如上例所示:绝对角度值相同,但符号是倒置的)。也许看看en.wikipedia.org/wiki/Right-hand_rule
    • 啊,是的:只要你向右走,seg(i-1) 和 seg(i) 的叉积总是有相同的符号。如果它切换符号,则表明最后一段向左转。角度的问题在于它们不是以 2*pi 为底的,但正如您正确评论的那样,它们是定向的。
    • 是的。我认为它是大多数三角函数的默认值。祝你好运,你会成功的,这是一个有趣的问题。如果您遇到问题,请在问题中发布一些数据。
    猜你喜欢
    • 2011-12-06
    • 1970-01-01
    • 2017-10-25
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多