美文网首页
PolyDataToImageData的Python实现注意事项

PolyDataToImageData的Python实现注意事项

作者: 药柴 | 来源:发表于2018-09-10 17:48 被阅读0次

    为将STL模型转化为具有空间局部性的图像(体素)格式,模仿官方例子用Python实现了算法。

    def stl_to_voxel(stl, padding=0.0, spacing=None, scale=None):
        """ Transform STL file to voxelbased volumes
        Args:
            stl (vtkPolyData): vtk 3D poly data in the form of points and lines
            padding (float): adds padding space in calculating the bounds of stl 
                file, in order to preserve the surface attached to orignal bounds.
            spacing (float or tuple): spacing in three directions.
            scale (int or tuple): the resolution of output 3D data. Not used
                if spacing is specified.
        Return:
            voxel (vtkImageData): vtk 3D image data which contain voxel representation
            of input stl.
        """
        assert isinstance(stl, vtk.vtkPolyData)
        assert isinstance(padding, float)
        assert isinstance(spacing, (int, tuple)) or isinstance(scale, (int, tuple))
    
        bounds = np.array(stl.GetBounds())
    
        # Add small padding to bounds
        if padding != 0:
            padding = (bounds[1::2] - bounds[::2]) * padding
            bounds[::2] = bounds[::2] - padding
            bounds[1::2] = bounds[1::2] + padding
    
        if spacing:
            if isinstance(spacing, float):
                spacing = [spacing for i in range(3)]
        else:
            if isinstance(scale, int):
                scale = [scale for i in range(3)]
            spacing = [(bounds[i * 2 + 1] - bounds[i * 2]) / scale[i]
                       for i in range(3)]
    
        whiteImage = vtk.vtkImageData()
        whiteImage.SetSpacing(spacing)
    
        # Set dim
        dim = [
            math.ceil((bounds[i * 2 + 1] - bounds[i * 2]) / spacing[i])
            for i in range(3)
        ]
    
        whiteImage.SetDimensions(dim)
        whiteImage.SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1)
    
        # Set origin
        origin = [bounds[i * 2] + spacing[i] / 2 for i in range(3)]
        whiteImage.SetOrigin(origin)
    
        whiteImage.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1)
    
        # Fill the image with foreground voxels
        inval = 1
        outval = 0
        for i in range(whiteImage.GetNumberOfPoints()):
            whiteImage.GetPointData().GetScalars().SetTuple1(i, inval)
    
        # Polygonal data --> image stencil
        pol2stenc = vtk.vtkPolyDataToImageStencil()
        pol2stenc.SetInputData(stl)
        pol2stenc.SetOutputOrigin(origin)
        pol2stenc.SetOutputSpacing(spacing)
        pol2stenc.SetOutputWholeExtent(whiteImage.GetExtent())
        pol2stenc.Update()
    
        # Cut the corresponding white image and set the background
        imgstenc = vtk.vtkImageStencil()
        imgstenc.SetInputData(whiteImage)
        imgstenc.SetStencilConnection(pol2stenc.GetOutputPort())
        imgstenc.ReverseStencilOff()
        imgstenc.SetBackgroundValue(outval)
        imgstenc.Update()
    
        return imgstenc.GetOutput()
    

    但是在使用过程中,发现这个转换特别的慢,经过运行时间分析发现,上述代码对于输入的STL模型的点数与面数不敏感,但对模型输出大小特别敏感。这说明,代码在建立输出时产生了特别耗时的操作,尤其有可能是初始化操作。经过研究发现,符合了“Python请不要使用for循环定律”,问题出现在下述代码中。

    for i in range(whiteImage.GetNumberOfPoints()):
        whiteImage.GetPointData().GetScalars().SetTuple1(i, inval)
    

    采用如下代码替换后,效率明显改善。

    whiteImage.GetPointData().GetScalars().Fill(inval)
    

    这次事件的启示是:python用for循环请三思。转换C代码时千万不要无脑照抄for循环。

    相关文章

      网友评论

          本文标题:PolyDataToImageData的Python实现注意事项

          本文链接:https://www.haomeiwen.com/subject/qntegftx.html