关于python:如何计算方向轴?

How to calculate the axis of orientation?

以前,我根据解剖结构计算方向轴,例如爪中的脚趾。

enter image description here

但我发现,当我无法很好地区分脚趾或"鞋跟"(蓝色正方形)离得很远时,这不起作用。所以我决定寻找更好的选择,我决定尝试计算惯性轴。

这一页对如何计算它给出了很好的解释,但是我很难理解从质量中心(在我的例子中是压力)到某个角度的步骤。

enter image description here

解释可以归结为:enter image description here,它使用的是压力中心和一个p值,我不知道它是什么。

我可以使用matlab代码计算人的脚的轴,并尽我所能将其转换为python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
x = 0.508 # sensor size in the x-direction
y = 0.762 # sensor size in the y-direction
Ptot = 0 # total pressure
Px   = 0 # first order moment(x)
Py   = 0 # first order moment(y)
Pxx  = 0 # second order moment (y)
Pyy  = 0 # second order moment (x)
Pxy  = 0 # second order moment (xy)

for row in range(rows): # y-direction
    for col in range(cols): # x-direction
        if data[row,col] > 0.0: # If not zero
            temp = 1
        else:
            temp = 0
        Ptot = Ptot + temp # Add 1 for every sensor that is nonzero
        Px = Px   + (x * col + x / 2) * temp
        Py = Py   + (y * row + y / 2) * temp
        Pxx = Pxx + (x * y * y * y / 12 + x * y * (row * y + y / 2) * (row * y + y / 2) ) * temp
        Pyy = Pyy + (y * x * x * x / 12 + x * y * (col * x + x / 2) * (col * x + x / 2) ) * temp        
        Pxy = Pxy + (x * y * (row * y + y / 2) * (row * x + x / 2)) * temp

CoPY = Py / Ptot
CoPX = Px / Ptot
CoP = [CoPX, CoPY]

Ixx = Pxx - Ptot * self.x * self.y * CoPY * CoPY
Iyy = Pyy - Ptot * self.x * self.y * CoPX * CoPX
Ixy = Pxy - Ptot * self.x * self.y * CoPY * CoPX
angle = (math.atan(2 * Ixy / (Iyy - Ixx))) / 2

Ixp = Ixx * math.cos(angle) * math.cos(angle) + Iyy * math.sin(angle) * math.sin(angle) - 2 * Ixy * math.sin(angle) * math.cos(angle)
Iyp = Iyy * math.cos(angle) * math.cos(angle) + Ixx * math.sin(angle) * math.sin(angle) + 2 * Ixy * math.sin(angle) * math.cos(angle)
RotationMatrix = [[math.cos(angle), math.sin(angle)], [-math.sin(angle), math.cos(angle)]]

据我所知,旋转矩阵的sin(角度)和cos(角度)用来确定轴。但我真的不知道如何使用这些值来画出一个轴穿过爪并围绕它旋转。

知道我做错了什么和/或我该怎么解决吗?

如果有人觉得需要进行实验,这里有一个包含每个爪子压力数据的所有切片阵列的文件。对Clarfy来说:Walk_Sliced_Data是一个字典,它包含了测量的名称['ser_3'、'ser_2'、'sel_1'、'sel_2'、'ser_1'、'sel_3']。每个测量都包含另一个字典,[0,1,2,3,4,5,6,7,8,9,10](例如"sel_1"),表示提取的影响。


好吧,这里有一个实现与上面的代码做同样的事情(并以相关的角度旋转图像)。

但是,就你的爪子而言,我不确定它是否能像人类的脚一样工作。

首先,对于狗的爪,这种方式定义的"长"轴是沿着爪的宽度而不是爪的长度。只要它是一致的,这就没什么关系了,因为我们可以简单地用计算出的角度来旋转,而不是90度——计算出的角度。

然而,狗的爪子接近圆形的事实给了我们更多的问题。

基本上,这可能不会像对人类那样对狗有用。"长轴"的旋转由图像的第二个中心时刻形成的图像的协方差矩阵推导(我认为这是您上面的代码所做的),不太可能是对爪的方向的精确测量。

换言之,狗的爪子接近圆形,它们似乎把大部分重量都放在脚趾上,所以"后"脚趾的重量比这个计算中的字体要轻。正因为如此,我们得到的轴不会一直与"后"脚趾和前脚趾的位置有关系。(希望这有点道理……我是个可怕的作家…这就是为什么我要回答这个问题而不是写我应该写的论文…)

无论如何,足够的闲逛…下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import cPickle
import numpy as np
import matplotlib.pyplot as plt

from scipy import ndimage

def main():
    measurements = cPickle.load(open('walk_sliced_data', 'r'))
    plot(measurements['ser_1'].values())
    plt.show()

def raw_moment(data, iord, jord):
    nrows, ncols = data.shape
    y, x = np.mgrid[:nrows, :ncols]
    data = data * x**iord * y**jord
    return data.sum()

def intertial_axis(data):
    data_sum = data.sum()
    m10 = raw_moment(data, 1, 0)
    m01 = raw_moment(data, 0, 1)
    x_bar = m10 / data_sum
    y_bar = m01 / data_sum
    u11 = (raw_moment(data, 1, 1) - x_bar * m01) / data_sum
    u20 = (raw_moment(data, 2, 0) - x_bar * m10) / data_sum
    u02 = (raw_moment(data, 0, 2) - y_bar * m01) / data_sum
    angle = 0.5 * np.arctan(2 * u11 / (u20 - u02))
    return x_bar, y_bar, angle


def plot(impacts):
    def plot_subplot(pawprint, ax):
        x_bar, y_bar, angle = intertial_axis(pawprint)
        ax.imshow(pawprint)
        plot_bars(x_bar, y_bar, angle, ax)
        return angle

    fig1 = plt.figure()
    fig2 = plt.figure()
    for i, impact in enumerate(impacts[:9]):
        ax1 = fig1.add_subplot(3,3,i+1)
        ax2 = fig2.add_subplot(3,3,i+1)

        pawprint = impact.sum(axis=2)
        angle = plot_subplot(pawprint, ax1)

        pawprint = ndimage.rotate(pawprint, np.degrees(angle))
        plot_subplot(pawprint, ax2)

    fig1.suptitle('Original')
    fig2.suptitle('Rotated')

def plot_bars(x_bar, y_bar, angle, ax):
    def plot_bar(r, x_bar, y_bar, angle, ax, pattern):
        dx = r * np.cos(angle)
        dy = r * np.sin(angle)
        ax.plot([x_bar - dx, x_bar, x_bar + dx],
                [y_bar - dy, y_bar, y_bar + dy], pattern)
    plot_bar(1, x_bar, y_bar, angle + np.radians(90), ax, 'wo-')
    plot_bar(3, x_bar, y_bar, angle, ax, 'ro-')
    ax.axis('image')


if __name__ == '__main__':
    main()

在这些图中,中心点是图像的质心,红线定义"长"轴,白线定义"短"轴。

原始(未旋转)爪:enter image description here

旋转爪子:enter image description here

这里有一件事要注意…我只是绕着它的中心旋转图像。(同样,scipy.ndimage.rotate也适用于N-D阵列,就像它适用于二维阵列一样。您可以轻松地旋转原始的三维"随时间变化的爪印"阵列。)

如果你想围绕一个点旋转它(比如说,质心),并将这个点移动到新图像上的一个新位置,你可以通过几个技巧在Scipy的ndimage模块中很容易地做到这一点。如果你愿意,我可以举个例子。这个例子有点长,不过…