python - 来自分割的 3d 骨架

标签 python opencv image-processing scikit-image

我想根据现有的分段创建骨架,类似于此处所做的(来自 sk-image):

my goal

但是我想对 3D 数据执行此操作。那里有代码吗?最好使用 Python,但任何语言都有帮助。

我知道 this很棒的网站,但我认为他们不提供任何代码。

我计划在大约 500x500x500 像素的体积上使用它,因此它应该可以很好地缩放...

最佳答案

我正在下面的这个链接中开发这个工具。名为 convOptimize.py 的程序中的函数 getSkeletonize3D 可让您细化 3D 数据。给出我拥有的 512 立方体的结果大约需要 30 分钟。如果您有任何问题,请告诉我。 https://github.com/3Scan/3scan-skeleton .我用来实现的论文在下面代码的注释里

这个 3D 骨架化算法的工作原理基本上是,在每次传递中它有 12 次子迭代,在这些子迭代中它迭代地移除特定方向的边界,直到你在中心得到一个骨架。

骨架化数据所需的主要 Python 代码如下所示。因为它需要从不同的其他 porgrams rotationalOperators 导入,它从另一个名为 Thin3dtemplates 的文件导入。我建议您下载 rotationalOperators、Thin3dtemplates、convoptimize python 脚本文件,并下载 lookuparray.npy,这是一个用作查找表的文件,采用预先计算的 numpy 数组格式,用于验证标记为删除或不删除的体素。您需要安装 python > 3 版本、scipy、numpy 和 pyeda 模块才能运行这些代码。

import numpy as np
import time
from scipy import ndimage
from scipy.ndimage.filters import convolve

"""
   the following subiteration functions are how each image is rotated to the next direction for removing
   boundary voxels in the order described in the reference paper
   us, ne, wd,..
"""
from rotationalOperators import firstSubiteration, secondSubiteration, thirdSubiteration, fourthSubiteration, fifthSubiteration, sixthSubiteration, seventhSubiteration, eighthSubiteration, ninthSubiteration, tenthSubiteration, eleventhSubiteration, twelvethSubiteration

"""
   reference paper
   http://web.inf.u-szeged.hu/ipcg/publications/papers/PalagyiKuba_GMIP1999.pdf
   input should be a binary image/ already segmented
"""


"""
   array that has calculated the validity of the 14 templates beforehand and stored each index which is
   decimal number of the binary string of 26 values (sqrt(3) connectivity) that are around a single voxel 
"""

lookUpTablearray = np.load('lookupTablearray.npy')


def _convolveImage(arr, flippedKernel):
    arr = np.ascontiguousarray(arr, dtype=np.uint64)
    result = convolve(arr, flippedKernel, mode='constant', cval=0)
    result[arr == 0] = 0
    return result


"""
each of the 12 iterations corresponds to each of the following
directions - us, ne, wd, es, uw, nd, sw, un, ed, nw, ue, sd
imported from template expressions
evaluated in advance using pyeda
https://pyeda.readthedocs.org/en/latest/expr.html
"""

sElement = ndimage.generate_binary_structure(3, 1)


def _getBouondariesOfimage(image):
    """
       function to find boundaries/border/edges of the array/image
    """

    erode_im = ndimage.morphology.binary_erosion(image, sElement)
    boundaryIm = image - erode_im
    return boundaryIm

"""
each of the 12 iterations corresponds to each of the following
directions - us, ne, wd, es, uw, nd, sw, un, ed, nw, ue, sd
imported from template expressions
evaluated in advance using pyeda
https://pyeda.readthedocs.org/en/latest/expr.html
"""

directionList = [firstSubiteration, secondSubiteration, thirdSubiteration, fourthSubiteration,
                 fifthSubiteration, sixthSubiteration, seventhSubiteration, eighthSubiteration,
                 ninthSubiteration, tenthSubiteration, eleventhSubiteration, twelvethSubiteration]


def _skeletonPass(image):
    """
        each pass consists of 12 serial subiterations and finding the
        boundaries of the padded image/array
    """
    boundaryIm = _getBouondariesOfimage(image)
    numPixelsremovedList = [] * 12
    boundaryIndices = list(set(map(tuple, list(np.transpose(np.nonzero(boundaryIm))))))
    for i in range(0, 12):
        convImage = _convolveImage(image, directionList[i])
        totalPixels, image = _applySubiter(image, boundaryIndices, convImage)
        print("number of pixels removed in the {} direction is {}". format(i, totalPixels))
        numPixelsremovedList.append(totalPixels)
    numPixelsremoved = sum(numPixelsremovedList)
    return numPixelsremoved, image


def _applySubiter(image, boundaryIndices, convImage):
    """
       each subiteration paralleley reduces the border voxels in 12 directions
       going through each voxel and marking if it can be deleted or not in a
       different image named temp_del and finally multiply it with the original
       image to delete the voxels so marked
    """
    temp_del = np.zeros_like(image)
    # boundaryIndicesCopy = copy.deepcopy(boundaryIndices)
    lenB = len(boundaryIndices)
    for k in range(0, lenB):
        temp_del[boundaryIndices[k]] = lookUpTablearray[convImage[boundaryIndices[k]]]
    numpixel_removed = np.einsum('ijk->', image * temp_del, dtype=int)
    image[temp_del == 1] = 0
    return numpixel_removed, image


def getSkeletonize3D(image):
    """
    function to skeletonize a 3D binary image with object in brighter contrast than background.
    In other words, 1 = object, 0 = background
    """
    assert np.max(image) in [0, 1]
    zOrig, yOrig, xOrig = np.shape(image)
    padImage = np.lib.pad(image, 1, 'constant', constant_values=0)
    start_skeleton = time.time()
    pass_no = 0
    numpixel_removed = 0
    while pass_no == 0 or numpixel_removed > 0:
        numpixel_removed, padImage = _skeletonPass(padImage)
        print("number of pixels removed in pass {} is {}".format(pass_no, numpixel_removed))
        pass_no += 1
    print("done %i number of pixels in %f seconds" % (np.sum(image), time.time() - start_skeleton))
    return padImage[1: zOrig + 1, 1: yOrig + 1, 1: xOrig + 1]

if __name__ == '__main__':
    sample = np.ones((5, 5, 5), dtype=np.uint8)
    resultSkel = getSkeletonize3D(sample)
    # gives a single voxel at the center
    print("resultSkel", resultSkel)

关于python - 来自分割的 3d 骨架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31878214/

相关文章:

python - 删除数据框中每个 ID 的前 n 行

c++ - 仅突出显示掌纹图像中的折痕(主要线条和皱纹)

php - 如何使用 ImageMagick 对图像的一部分进行像素化?

python - 使用 Scrapy 检测表单(并填写)

python - 使用 Django、celery 和 Redis 安排任务

python - TensorFlow 中的高效图像膨胀

android - 如何在后台使用 Android 相机?

python - 如何判断图像是否暗?

java - 如何从android中的位图中获取图像的原始字符串?

python - 如何检查我是否在Python的shell(有终端)中运行?