如何将 3d 数组 (nxnxn) 绕 x、y 和 z 轴旋转 x 度?
How can I rotate a 3d array (nxnxn) by x degrees around x, y, and z axes?
我有一个用 numpy 创建的 3d 数组,我想知道如何将它旋转自定义角度,而不仅仅是 numpy 具有的 rot90
函数。有人可以帮忙吗?
3d 矩阵表示图像(例如立方体或其他形状)即
0:
1 1 1
1 1
1 1 1
1:
1 1
1 1
2:
1 1 1
1 1
1 1 1
编辑:
将解决方案移至答案
看看 scipy.ndimage.interpolation.rotate 函数。
这是在 scipy 而不是在 numpy 中的原因是将图像旋转 90 度只需更改数组的索引即可。但是,如果您想将图像旋转任意度数,则必须处理插值,这给问题增加了一个全新的复杂层。这是因为当您将图像旋转 90 度时,原始图像中的所有像素 "perfectly lines up with" 旋转图像中的像素。旋转图像时通常不会出现这种情况。
您必须创建一个旋转矩阵并将此矩阵乘以您的数组。这里的信息
Wikipedea旋转矩阵信息
我认为您应该考虑对数据使用 "vector" 表示,而不是当前的 "raster" 表示。
矢量表示意味着,不是每个 "voxel" 由其在网格中的位置定义,而是具有某种体素列表,具有实际的 3D 坐标。
因此,与其使用 MxNxD 矩阵,其中每个体素都是一个 "black/white" 点,不如使用 Mx3 矩阵,其中每一行是一个点,列是 X、Y 和 Z。
这样,您可以将该列表乘以 3x3 旋转矩阵,并得到另一个变换坐标列表。
您仍然会遇到 "rendering" 这些矢量点(或线,更好)到光栅矩阵(像素或体素,但您的样本图像看起来像 3D 信息已投影到 2D)的问题space)。有很多技巧可以做到这一点。
经过反复试验,我想出了一些代码用于我的目的(0 表示数组中为空,另一个数字表示填充的体素。
def rotate(self, deg_angle, axis):
d = len(self.matrix)
h = len(self.matrix[0])
w = len(self.matrix[0][0])
min_new_x = 0
max_new_x = 0
min_new_y = 0
max_new_y = 0
min_new_z = 0
max_new_z = 0
new_coords = []
angle = radians(deg_angle)
for z in range(d):
for y in range(h):
for x in range(w):
new_x = None
new_y = None
new_z = None
if axis == "x":
new_x = int(round(x))
new_y = int(round(y*cos(angle) - z*sin(angle)))
new_z = int(round(y*sin(angle) + z*cos(angle)))
elif axis == "y":
new_x = int(round(z*sin(angle) + x*cos(angle)))
new_y = int(round(y))
new_z = int(round(z*cos(angle) - x*sin(angle)))
elif axis == "z":
new_x = int(round(x*cos(angle) - y*sin(angle)))
new_y = int(round(x*sin(angle) + y*cos(angle)))
new_z = int(round(z))
val = self.matrix.item((z, y, x))
new_coords.append((val, new_x, new_y, new_z))
if new_x < min_new_x: min_new_x = new_x
if new_x > max_new_x: max_new_x = new_x
if new_y < min_new_y: min_new_y = new_y
if new_y > max_new_y: max_new_y = new_y
if new_z < min_new_z: min_new_z = new_z
if new_z > max_new_z: max_new_z = new_z
new_x_offset = abs(min_new_x)
new_y_offset = abs(min_new_y)
new_z_offset = abs(min_new_z)
new_width = abs(min_new_x - max_new_x)
new_height = abs(min_new_y - max_new_y)
new_depth = abs(min_new_z - max_new_z)
rotated = np.empty((new_depth + 1, new_height + 1, new_width + 1))
rotated.fill(0)
for coord in new_coords:
val = coord[0]
x = coord[1]
y = coord[2]
z = coord[3]
if rotated[new_z_offset + z][new_y_offset + y][new_x_offset + x] == 0:
rotated[new_z_offset + z][new_y_offset + y][new_x_offset + x] = val
self.matrix = rotated
我上面代码的使用方式是:
cube = Rect_Prism(20, 20, 20) # creates a 3d array similar to above example, just bigger
cube.rotate(20, "x")
cube.rotate(60, "y")
Rect_Prism 创建一个 MxNxD 矩阵,但在本例中为 NxNxN。
打印结果:
# # # # # # # # # # # #
# # # # # # #
# # # # # # #
# # # # #
# # # # # # # #
# # # # # # #
# # # # # # # # # # # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # # # #
# # # #
# # # # # # # # # # # #
# # # # #
# # # # # # # #
# # # # # # #
# # # # # # #
# # # # # # #
# # # # # #
# # # # # # # # # # # #
我有一个用 numpy 创建的 3d 数组,我想知道如何将它旋转自定义角度,而不仅仅是 numpy 具有的 rot90
函数。有人可以帮忙吗?
3d 矩阵表示图像(例如立方体或其他形状)即
0:
1 1 1
1 1
1 1 1
1:
1 1
1 1
2:
1 1 1
1 1
1 1 1
编辑: 将解决方案移至答案
看看 scipy.ndimage.interpolation.rotate 函数。
这是在 scipy 而不是在 numpy 中的原因是将图像旋转 90 度只需更改数组的索引即可。但是,如果您想将图像旋转任意度数,则必须处理插值,这给问题增加了一个全新的复杂层。这是因为当您将图像旋转 90 度时,原始图像中的所有像素 "perfectly lines up with" 旋转图像中的像素。旋转图像时通常不会出现这种情况。
您必须创建一个旋转矩阵并将此矩阵乘以您的数组。这里的信息
Wikipedea旋转矩阵信息
我认为您应该考虑对数据使用 "vector" 表示,而不是当前的 "raster" 表示。
矢量表示意味着,不是每个 "voxel" 由其在网格中的位置定义,而是具有某种体素列表,具有实际的 3D 坐标。
因此,与其使用 MxNxD 矩阵,其中每个体素都是一个 "black/white" 点,不如使用 Mx3 矩阵,其中每一行是一个点,列是 X、Y 和 Z。
这样,您可以将该列表乘以 3x3 旋转矩阵,并得到另一个变换坐标列表。
您仍然会遇到 "rendering" 这些矢量点(或线,更好)到光栅矩阵(像素或体素,但您的样本图像看起来像 3D 信息已投影到 2D)的问题space)。有很多技巧可以做到这一点。
经过反复试验,我想出了一些代码用于我的目的(0 表示数组中为空,另一个数字表示填充的体素。
def rotate(self, deg_angle, axis):
d = len(self.matrix)
h = len(self.matrix[0])
w = len(self.matrix[0][0])
min_new_x = 0
max_new_x = 0
min_new_y = 0
max_new_y = 0
min_new_z = 0
max_new_z = 0
new_coords = []
angle = radians(deg_angle)
for z in range(d):
for y in range(h):
for x in range(w):
new_x = None
new_y = None
new_z = None
if axis == "x":
new_x = int(round(x))
new_y = int(round(y*cos(angle) - z*sin(angle)))
new_z = int(round(y*sin(angle) + z*cos(angle)))
elif axis == "y":
new_x = int(round(z*sin(angle) + x*cos(angle)))
new_y = int(round(y))
new_z = int(round(z*cos(angle) - x*sin(angle)))
elif axis == "z":
new_x = int(round(x*cos(angle) - y*sin(angle)))
new_y = int(round(x*sin(angle) + y*cos(angle)))
new_z = int(round(z))
val = self.matrix.item((z, y, x))
new_coords.append((val, new_x, new_y, new_z))
if new_x < min_new_x: min_new_x = new_x
if new_x > max_new_x: max_new_x = new_x
if new_y < min_new_y: min_new_y = new_y
if new_y > max_new_y: max_new_y = new_y
if new_z < min_new_z: min_new_z = new_z
if new_z > max_new_z: max_new_z = new_z
new_x_offset = abs(min_new_x)
new_y_offset = abs(min_new_y)
new_z_offset = abs(min_new_z)
new_width = abs(min_new_x - max_new_x)
new_height = abs(min_new_y - max_new_y)
new_depth = abs(min_new_z - max_new_z)
rotated = np.empty((new_depth + 1, new_height + 1, new_width + 1))
rotated.fill(0)
for coord in new_coords:
val = coord[0]
x = coord[1]
y = coord[2]
z = coord[3]
if rotated[new_z_offset + z][new_y_offset + y][new_x_offset + x] == 0:
rotated[new_z_offset + z][new_y_offset + y][new_x_offset + x] = val
self.matrix = rotated
我上面代码的使用方式是:
cube = Rect_Prism(20, 20, 20) # creates a 3d array similar to above example, just bigger
cube.rotate(20, "x")
cube.rotate(60, "y")
Rect_Prism 创建一个 MxNxD 矩阵,但在本例中为 NxNxN。
打印结果:
# # # # # # # # # # # #
# # # # # # #
# # # # # # #
# # # # #
# # # # # # # #
# # # # # # #
# # # # # # # # # # # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # # # #
# # # #
# # # # # # # # # # # #
# # # # #
# # # # # # # #
# # # # # # #
# # # # # # #
# # # # # # #
# # # # # #
# # # # # # # # # # # #