Matplotlib 渲染所有内部体素(带 alpha) [英] Matplotlib render all internal voxels (with alpha)

查看:86
本文介绍了Matplotlib 渲染所有内部体素(带 alpha)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 matplotlib 中渲染一个体积.体积是一个简单的 7x7x7 立方体,我希望能够看到所有内部体素(即使我知道它看起来会一团糟).

我已经能够渲染具有透明度的体素,但是任何不在表面上的体素似乎永远不会被绘制.

体积的每个 7x7 切片应如下所示:

我拼凑了一个 MWE

以下代码创建一个 5x5x5 的体积,其中包含红色、绿色、蓝色、黄色和青色 5x5 层.每层的 alpha 设置为 0.5,所以整个东西应该是透明的.

然后我将所有非表面体素的颜色更改为带有 alpha 1 的黑色,因此如果它们显示出来,我们应该能够在中心看到一个黑框.

单独渲染它会产生左侧的图形,但是如果我们从青色层中删除填充,我们可以看到黑框确实存在,因为它被100%遮挡了,所以即使它被遮挡,它也不会被显示那些遮挡体素的alpha小于1.

 将matplotlib.pyplot导入为plt从mpl_toolkits.mplot3d导入Axes3D#NOQA空间轴 = [5, 5, 5]填充 = np.ones(spatial_axes, dtype=np.bool)颜色 = np.empty(spatial_axes + [4], dtype=np.float32)阿尔法 = .5colors [0] = [1、0、0,alpha]colors [1] = [0,1,0,alpha]颜色[2] = [0, 0, 1, alpha]colors [3] = [1,1,0,alpha]colors [4] = [0,1,1,alpha]#将所有内部颜色设置为带有alpha = 1的黑色colors [1:-1,1:-1,1:-1,0:3] = 0颜色 [1:-1, 1:-1, 1:-1, 3] = 1无花果= plt.figure()ax = fig.add_subplot('111',projection ='3d')ax.voxels(填充,facecolors=colors,edgecolors='k')无花果= plt.figure()ax = fig.add_subplot('111',projection ='3d')Filled [-1] = Falseax.voxels(填充,facecolors=colors,edgecolors='k')

有什么方法可以渲染所有被遮挡的体素?

解决方案

要将上面的评论变成答案:

  • 你可能总是像这样绘制所有体素
    • I want to render a volume in matplotlib. The volume is a simple 7x7x7 cube, and I want to be able to see all internal voxels (even though I know it will look like a mess).

      I've been able to render voxels with transparency, but any voxel not on the surface seems to never be drawn.

      Each 7x7 slice of the volume should look like this:

      I've thrown together a MWE

      The following code creates a 5x5x5 volume with a red,green,blue,yellow, and cyan 5x5 layers. The alpha of each layer is set to .5, so the whole thing should be see-through.

      Then I chang the colors of all non-surface voxels to black with alpha 1, so if they were showing we should be able to see a black box in the center.

      Rendering it by itself produces the figure on the left, but if we remove the fill from the cyan layer, we can see that the black box does indeed exist, it is just not being shown because it is 100% occluded even though those occluding voxels have alpha less than 1.

      import matplotlib.pyplot as plt
      from mpl_toolkits.mplot3d import Axes3D  # NOQA
      
      spatial_axes = [5, 5, 5]
      filled = np.ones(spatial_axes, dtype=np.bool)
      
      colors = np.empty(spatial_axes + [4], dtype=np.float32)
      alpha = .5
      colors[0] = [1, 0, 0, alpha]
      colors[1] = [0, 1, 0, alpha]
      colors[2] = [0, 0, 1, alpha]
      colors[3] = [1, 1, 0, alpha]
      colors[4] = [0, 1, 1, alpha]
      
      # set all internal colors to black with alpha=1
      colors[1:-1, 1:-1, 1:-1, 0:3] = 0
      colors[1:-1, 1:-1, 1:-1, 3] = 1
      
      fig = plt.figure()
      
      ax = fig.add_subplot('111', projection='3d')
      ax.voxels(filled, facecolors=colors, edgecolors='k')
      
      fig = plt.figure()
      ax = fig.add_subplot('111', projection='3d')
      filled[-1] = False
      ax.voxels(filled, facecolors=colors, edgecolors='k')
      

      Is there any way to render all occluded voxels?

      解决方案

      To turn my comments above into an answer:

      Despite the small issues, you may monkey patch the current status of the pull request into your code:

      import numpy as np
      import matplotlib.pyplot as plt
      from mpl_toolkits.mplot3d import Axes3D, art3d  # NOQA
      from matplotlib.cbook import _backports
      from collections import defaultdict
      import types
      
      def voxels(self, *args, **kwargs):
      
          if len(args) >= 3:
              # underscores indicate position only
              def voxels(__x, __y, __z, filled, **kwargs):
                  return (__x, __y, __z), filled, kwargs
          else:
              def voxels(filled, **kwargs):
                  return None, filled, kwargs
      
          xyz, filled, kwargs = voxels(*args, **kwargs)
      
          # check dimensions
          if filled.ndim != 3:
              raise ValueError("Argument filled must be 3-dimensional")
          size = np.array(filled.shape, dtype=np.intp)
      
          # check xyz coordinates, which are one larger than the filled shape
          coord_shape = tuple(size + 1)
          if xyz is None:
              x, y, z = np.indices(coord_shape)
          else:
              x, y, z = (_backports.broadcast_to(c, coord_shape) for c in xyz)
      
          def _broadcast_color_arg(color, name):
              if np.ndim(color) in (0, 1):
                  # single color, like "red" or [1, 0, 0]
                  return _backports.broadcast_to(
                      color, filled.shape + np.shape(color))
              elif np.ndim(color) in (3, 4):
                  # 3D array of strings, or 4D array with last axis rgb
                  if np.shape(color)[:3] != filled.shape:
                      raise ValueError(
                          "When multidimensional, {} must match the shape of "
                          "filled".format(name))
                  return color
              else:
                  raise ValueError("Invalid {} argument".format(name))
      
          # intercept the facecolors, handling defaults and broacasting
          facecolors = kwargs.pop('facecolors', None)
          if facecolors is None:
              facecolors = self._get_patches_for_fill.get_next_color()
          facecolors = _broadcast_color_arg(facecolors, 'facecolors')
      
          # broadcast but no default on edgecolors
          edgecolors = kwargs.pop('edgecolors', None)
          edgecolors = _broadcast_color_arg(edgecolors, 'edgecolors')
      
          # include possibly occluded internal faces or not
          internal_faces = kwargs.pop('internal_faces', False)
      
          # always scale to the full array, even if the data is only in the center
          self.auto_scale_xyz(x, y, z)
      
          # points lying on corners of a square
          square = np.array([
              [0, 0, 0],
              [0, 1, 0],
              [1, 1, 0],
              [1, 0, 0]
          ], dtype=np.intp)
      
          voxel_faces = defaultdict(list)
      
          def permutation_matrices(n):
              """ Generator of cyclic permutation matices """
              mat = np.eye(n, dtype=np.intp)
              for i in range(n):
                  yield mat
                  mat = np.roll(mat, 1, axis=0)
      
          for permute in permutation_matrices(3):
              pc, qc, rc = permute.T.dot(size)
              pinds = np.arange(pc)
              qinds = np.arange(qc)
              rinds = np.arange(rc)
      
              square_rot = square.dot(permute.T)
      
              for p in pinds:
                  for q in qinds:
                      p0 = permute.dot([p, q, 0])
                      i0 = tuple(p0)
                      if filled[i0]:
                          voxel_faces[i0].append(p0 + square_rot)
      
                      # draw middle faces
                      for r1, r2 in zip(rinds[:-1], rinds[1:]):
                          p1 = permute.dot([p, q, r1])
                          p2 = permute.dot([p, q, r2])
                          i1 = tuple(p1)
                          i2 = tuple(p2)
                          if filled[i1] and (internal_faces or not filled[i2]):
                              voxel_faces[i1].append(p2 + square_rot)
                          elif (internal_faces or not filled[i1]) and filled[i2]:
                              voxel_faces[i2].append(p2 + square_rot)
      
                      # draw upper faces
                      pk = permute.dot([p, q, rc-1])
                      pk2 = permute.dot([p, q, rc])
                      ik = tuple(pk)
                      if filled[ik]:
                          voxel_faces[ik].append(pk2 + square_rot)
      
          # iterate over the faces, and generate a Poly3DCollection for each voxel
          polygons = {}
          for coord, faces_inds in voxel_faces.items():
              # convert indices into 3D positions
              if xyz is None:
                  faces = faces_inds
              else:
                  faces = []
                  for face_inds in faces_inds:
                      ind = face_inds[:, 0], face_inds[:, 1], face_inds[:, 2]
                      face = np.empty(face_inds.shape)
                      face[:, 0] = x[ind]
                      face[:, 1] = y[ind]
                      face[:, 2] = z[ind]
                      faces.append(face)
      
              poly = art3d.Poly3DCollection(faces,
                  facecolors=facecolors[coord],
                  edgecolors=edgecolors[coord],
                  **kwargs
              )
              self.add_collection3d(poly)
              polygons[coord] = poly
      
          return polygons
      
      
      
      spatial_axes = [5, 5, 5]
      filled = np.ones(spatial_axes, dtype=np.bool)
      
      colors = np.empty(spatial_axes + [4], dtype=np.float32)
      alpha = .5
      colors[0] = [1, 0, 0, alpha]
      colors[1] = [0, 1, 0, alpha]
      colors[2] = [0, 0, 1, alpha]
      colors[3] = [1, 1, 0, alpha]
      colors[4] = [0, 1, 1, alpha]
      
      # set all internal colors to black with alpha=1
      colors[1:-1, 1:-1, 1:-1, 0:3] = 0
      colors[1:-1, 1:-1, 1:-1, 3] = 1
      
      fig = plt.figure()
      
      ax = fig.add_subplot('111', projection='3d')
      ax.voxels = types.MethodType(voxels, ax)
      ax.voxels(filled, facecolors=colors, edgecolors='k',internal_faces=True)
      
      fig = plt.figure()
      ax = fig.add_subplot('111', projection='3d')
      ax.voxels = types.MethodType(voxels, ax)
      filled[-1] = False
      ax.voxels(filled, facecolors=colors, edgecolors='k',internal_faces=True)
      
      plt.show()
      

      这篇关于Matplotlib 渲染所有内部体素(带 alpha)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆