目标:
我正在编写代码来计算两个3D向量之间的夹角(足够容易)。但是,矢量是根据在单独程序中执行的数据对齐来定义的。更精确地说,对齐程序会获取体积并根据常见功能对齐它们。这些特征实际上是一条很粗的白线,在嘈杂的灰度图像中会出现一条较小的线。
使用遮罩,我分别对齐粗细的白线,然后使用已知的旋转将其放回原图像中应有的位置,然后我可以算出它们之间的角度(几千张图像) )。
当前问题:
虽然我相当有信心这可以奏效,但我想通过创建一些示例数据并通过比对程序然后通过我的代码运行它来对其进行测试。
使用以下代码在numpy中轻松制作充满随机灰度数字的3D numpy数组:
def RandomNoise():
NoiseArray = np.random.normal(0,1,(100,100,100))
return NoiseArray
然后我需要以某种方式插入一条粗的白线,然后从其中心以随机角度插入一条较小的白线。我想我可以在整个3D空间中将一条粗白线添加为一个平面,并将其保持在同一位置。我只是想将较细的白线以任意角度放置。我曾考虑过将其定义为向量,并对其应用随机旋转,记录旋转,然后在数组中将其渲染为圆柱,但是我不知道该怎么做。
编辑:为弄清楚“粗”白线本质上只是Z上整个3D空间的白色平面,x和y的高度已定义(例如,在100,100,100阵列中为20个像素)。然后,“细”白线是一个要定义半径的圆柱(例如,在100,100,100阵列中为10个像素),我想以不同的角度从白平面出来,因此它应该在较粗白线上的一端“枢轴化”
我正想将这个白色圆柱体定义为向量,然后使用旋转矩阵在绘制3D数组之前对其应用随机旋转。
任何帮助将不胜感激。
谢谢
编辑:要求的草图
答案 0 :(得分:2)
从您的问题出发,并不是完全确定各行之间如何对齐,但是我将为您提供以下小脚本,无论如何它们都应作为起点。对于旋转,您可以使用scipy软件包中的rotate
。
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import rotate
np.random.seed(181003)
N = 100 # Number of images.
m, n = 100, 100 # row and column dimension.
test = np.random.uniform(0, 1, (N, m, n))
def create_bars(d):
"""Parameter d indicates thickness of the bar in number of rows"""
bars = np.zeros((N, m, n), dtype=float)
bars[:, m//2 - d : m//2 + d, :] = np.random.uniform(0.95, 1.0, (N, 2*d, n))
for i, angle in enumerate(np.random.uniform(0, 180, N)): # Angle in degrees.
bars[i, :, :] = rotate(bars[i], angle, reshape=False)
return bars
test += create_bars(m // 5) # Thick bars.
test += create_bars(m // 25) # Thin bars.
for i in range(3):
plt.figure()
plt.imshow(test[i])
plt.show()
从下面的示例图像中,您可以看到重叠区域的强度高于其余条形。如果不希望这样,则需要一起创建刻度线和细条,并且可以处理重叠区域。
我们可以通过3D数组的相应索引生成平面和圆柱体。我们可以旋转这些索引以获取旋转形状的新索引(我们需要在旋转之前将索引居中,然后再次移回)。这是一些示例代码:
"""Coordinate system is z, y, x for indexing the 3D array (i.e. test[z, y, x])."""
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def rotate_z(angle):
return np.array([
[1, 0, 0],
[0, np.cos(angle), -np.sin(angle)],
[0, np.sin(angle), np.cos(angle)],
])
def rotate_y(angle):
return np.array([
[np.cos(angle), 0, np.sin(angle)],
[0, 1, 0],
[-np.sin(angle), 0, np.cos(angle)],
])
def rotate_x(angle):
return np.array([
[np.cos(angle), -np.sin(angle), 0],
[np.sin(angle), np.cos(angle), 0],
[0, 0, 1],
])
l = m = n = 40 # Use only small number of points due to plotting.
test = np.random.uniform(0, 0.95, (l, m, n))
d = l // 10 # Thickness of plane.
i_thick = np.array([*np.ndindex(d, m, n)]).T # Indices for plane.
i_thick[0, :] -= d // 2
i_thick[1, :] -= m // 2
i_thick[2, :] -= n // 2
angle_y = angle_x = 0 # Angles about which the plane is rotated.
i_thick = rotate_y(angle_y) @ i_thick
i_thick = rotate_x(angle_x) @ i_thick
i_thick[0, :] += d // 2 + l // 2
i_thick[1, :] += m // 2
i_thick[2, :] += n // 2
i_thick = np.clip(np.round(i_thick).astype(int), 0, np.array(test.shape)[:, None] - 1) # Correct rounding errors.
test[i_thick.tolist()] = np.random.uniform(0.95, 1.0, i_thick.shape[1]) # Add the plane.
r = m // 8 # Radius of cylinder.
i_cylinder = np.array([*np.ndindex(l, m, n)])
i_cylinder = i_cylinder[
(i_cylinder[:, 0] < l // 2)
& (np.sqrt((i_cylinder[:, 1] - m // 2)**2 + (i_cylinder[:, 2] - n // 2)**2) < r)
].T
i_cylinder[0, :] -= l // 2
i_cylinder[1, :] -= m // 2
i_cylinder[2, :] -= n // 2
# Align cylinder with plane.
i_cylinder = rotate_y(angle_y) @ i_cylinder
i_cylinder = rotate_x(angle_x) @ i_cylinder
angle2_z = angle2_y = angle2_x = 0 # Angles about which the cylinder is rotated.
i_cylinder = rotate_z(angle2_z) @ i_cylinder
i_cylinder = rotate_y(angle2_y) @ i_cylinder
i_cylinder = rotate_x(angle2_x) @ i_cylinder
i_cylinder[0, :] += l // 2
i_cylinder[1, :] += m // 2
i_cylinder[2, :] += n // 2
i_cylinder = np.clip(np.round(i_cylinder).astype(int), 0, np.array(test.shape)[:, None] - 1)
test[i_cylinder.tolist()] = np.random.uniform(0.95, 1.0, i_cylinder.shape[1])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
test_plot = test.copy()
test_plot = np.moveaxis(test_plot, [0, 1, 2], [-1, 0, 1]) # Reorder axes from `z, y, x` to `y, x, z` in order to be aligned with plt.scatter.
test_plot = np.flip(test_plot, axis=2) # Flip along `z` in order to plot top-to-bottom rather than bottom-to-top.
ax.scatter(*np.array([*np.ndindex(m, n, l)]).T[:, test_plot.ravel() >= 0.95].tolist(), s=1)
ax.set_xlim([0, test.shape[1] - 1])
ax.set_ylim([0, test.shape[0] - 1])
ax.set_zlim([0, test.shape[2] - 1])
plt.show()
例如,两个形状均未旋转:
平面绕x
旋转-pi/2
和圆柱体另外绕z
和x
旋转pi/8
的另一个示例: