【问题标题】:How can I rotate a 3d array (nxnxn) by x degrees around x, y, and z axes?如何将 3d 数组 (nxnxn) 围绕 x、y 和 z 轴旋转 x 度?
【发布时间】:2018-03-04 16:35:10
【问题描述】:

我有一个用 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

编辑: 移动解决方案来回答

【问题讨论】:

  • 数组代表什么?图片?飞机?线?您的问题的答案取决于数组应该是什么。
  • @tehhowch 应该是 3d 图像(错误编辑帖子)

标签: python numpy multidimensional-array rotatetransform


【解决方案1】:

看看scipy.ndimage.interpolation.rotate函数。

这是在 scipy 中而不是在 numpy 中的原因是,只需更改数组的索引即可将图像旋转 90 度。但是,如果您想将图像旋转任意角度,则必须处理插值,这为问题增加了一个全新的复杂层。这是因为当您将原始图像旋转 90 度时,原始图像中的所有像素都与旋转图像中的像素“完美对齐”。旋转图像时通常不会出现这种情况。

【讨论】:

  • 这个函数使用样条插值,我得到的结果与使用默认使用双线性插值的torchvision.transforms.functional.rotate完全不同(没有样条插值选项)。
  • 还尝试了 skimage.transform.rotate。得到的结果与 torchvision 和 scipy 不同。无语……
【解决方案2】:

经过反复试验,我想出了一些用于我的目的的代码(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。

以及打印时的结果:

                            # # # # # # # # # # # #          
                      # # #     #         # #       #        
                  # #           #   # # #           #        
              # #               # #                 #        
        # # #               # # # #                   #      
    # #               # # #       #                   #      
# # # # # # # # # # #             #                   #      
#                   #               #                   #    
  #                 #               #                   #    
  #                 #               #                   #    
  #                 #                 #                   #  
    #                 #               #                   #  
    #                 #               #                   #  
    #                 #                 #                 #  
      #                 #               #                 #  
      #                 #               # #               # #
      #                   #               #                 #
      #                   #               # # # # # # # # # #
      #                   #           # #                 #  
        #                   #   # # #               # # #    
        #                   # # #             # # #          
        #             # # # #             # #                
          #       # #         #     # # #                    
          #   # #             # # #                          
          # # # # # # # # # # # #                            

【讨论】:

  • 漂亮的功能!你是如何定义“矩阵”类的
  • 有兴趣者:self.matrix可以换成numpy.ndarray
  • 尝试实现此 A.rotate(40,"x") "AttributeError: 'numpy.ndarray' object has no attribute 'rotate'" 有人可以对此发表评论?
【解决方案3】:

你必须创建一个旋转矩阵并将你的这个矩阵乘以你的数组。这里有资料

Wikipedea旋转矩阵信息

An example for 2d rotating

【讨论】:

  • 恐怕这不适用于像素/体素图像(或更具体地说是光栅图像)。旋转矩阵用于 3D 和矢量图形,但不能将 1000x1000x3 矩阵(1Mpix RGB 图像)乘以 2x2 旋转矩阵。
【解决方案4】:

我认为您应该考虑为您的数据使用“矢量”表示,而不是当前的“光栅”表示。

矢量表示意味着,每个“体素”不是由其在网格中的位置定义,而是具有某种体素列表,具有实际的 3D 坐标。

因此,您可以使用 Mx3 矩阵,其中每一行是一个点,列是 X、Y 和 Z,而不是使用 MxNxD 矩阵,其中每个体素是一个“黑/白”点。

这样,您可以将列表乘以 3x3 旋转矩阵,并获得另一个变换坐标列表。

您仍然会遇到将这些矢量点(或线,更好)“渲染”到光栅矩阵(像素或体素,但您的示例图像看起来像 3D 信息已投影到 2D 空间)的问题。有很多技术可以做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 2019-09-18
    • 1970-01-01
    相关资源
    最近更新 更多