如何从二元骨架化图像中找到分支点

时间:2017-03-27 03:54:15

标签: python python-2.7 opencv image-processing computer-vision

我使用Python OpenCV对这样的图像进行骨架化:

This is the skeletonized image

我希望找到骨架的分支点

This is the point that I wanted

我不知道该怎么做。有什么想法吗?

4 个答案:

答案 0 :(得分:2)

这个问题已经很老了,但如果其他人偶然发现了这个问题并希望得到一个不依赖于其他包并使用简单的形态学操作的答案,您可能会发现以下内容很有帮助。

这个想法只是简单地应用命中或未命中变换来搜索满足分支点条件的像素。骨架中的分支点是连接到三个或四个其他像素的像素。给定适当的结构元素列表 selems,您可以在一个输出图像中优雅地组合多个命中或未命中变换,如下所示。

import numpy as np
import scipy.ndimage as ndi


branches = np.zeros_like(skeleton, dtype=bool)
for selem in selems:
    branches |= ndi.binary_hit_or_miss(skeleton, selem)

这非常节省空间,因为您直接将每个变换的结果添加到同一个结果数组中。现在的问题是如何创建结构元素列表。一种解决方案如下。

selems = list()
selems.append(np.array([[0, 1, 0], [1, 1, 1], [0, 0, 0]]))
selems.append(np.array([[1, 0, 1], [0, 1, 0], [1, 0, 0]]))
selems.append(np.array([[1, 0, 1], [0, 1, 0], [0, 1, 0]]))
selems.append(np.array([[0, 1, 0], [1, 1, 0], [0, 0, 1]]))
selems.append(np.array([[0, 0, 1], [1, 1, 1], [0, 1, 0]]))
selems = [np.rot90(selems[i], k=j) for i in range(5) for j in range(4)]

selems.append(np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]))
selems.append(np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]]))

最后两行只有在您还想检测具有四个分支的分支点时才需要。如果您只对三个分支感兴趣,则可以省略最后两行。

那么完整的解决方案是

import numpy as np
import scipy.ndimage as ndi


selems = list()
selems.append(np.array([[0, 1, 0], [1, 1, 1], [0, 0, 0]]))
selems.append(np.array([[1, 0, 1], [0, 1, 0], [1, 0, 0]]))
selems.append(np.array([[1, 0, 1], [0, 1, 0], [0, 1, 0]]))
selems.append(np.array([[0, 1, 0], [1, 1, 0], [0, 0, 1]]))
selems.append(np.array([[0, 0, 1], [1, 1, 1], [0, 1, 0]]))
selems = [np.rot90(selems[i], k=j) for i in range(5) for j in range(4)]

selems.append(np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]))
selems.append(np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]]))

branches = np.zeros_like(skeleton, dtype=bool)
for selem in selems:
    branches |= ndi.binary_hit_or_miss(skeleton, selem)

同样,您可以使用以下结构元素列表来搜索端点。

selems = list()
selems.append(np.array([[0, 1, 0], [0, 1, 0], [0, 0, 0]]))
selems.append(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 0]]))
selems = [np.rot90(selems[i], k=j) for i in range(2) for j in range(4)]

答案 1 :(得分:1)

这里的主要思想是看附近。您可以为每个像素([1 1 1; 1 1 1; 1 1 1],中心是要探索的邻域的像素!)使用8个连接的邻域。

在每个分支点,像素的度数将大于2,而常规像素的度数将为2(即,在其附近连接到2个像素)。

在您的情况下,您的目标是找到一个“交叉点”,其度数> 3。

答案 2 :(得分:0)

您可以使用库Skan查找分支点。

from skan import skeleton_to_csgraph
from skimage import io, morphology

# loading image
image = io.imread('https://i.stack.imgur.com/FpSt9.jpg')

# make image binary
image_binary = image >= 200

# skeletonize
sk = morphology.skeletonize(image_binary).astype(bool)

# receive a degree matrix
_, _, degrees = skeleton_to_csgraph(sk)

# consider all values larger than two as intersection
intersection_matrix = degrees > 2

这里的结果不是单个像素,因为多个分支在一个点相遇。可以使用regionprops确定此中心区域,然后在需要一个像素的情况下找到质心。

答案 3 :(得分:-1)

输出(覆盖在输入图像上):

enter image description here

代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Find branch point in example image.
"""

import numpy as np
import matplotlib.pyplot as plt
from mahotas.morph import hitmiss as hit_or_miss
from skimage.morphology import medial_axis as skeletonize
# from scipy.ndimage import binary_hit_or_miss as hit_or_miss

def find_branch_points(skel):
    X=[]
    #cross X
    X0 = np.array([[0, 1, 0],
                   [1, 1, 1],
                   [0, 1, 0]])
    X1 = np.array([[1, 0, 1],
                   [0, 1, 0],
                   [1, 0, 1]])
    X.append(X0)
    X.append(X1)
    #T like
    T=[]
    #T0 contains X0
    T0=np.array([[2, 1, 2],
                 [1, 1, 1],
                 [2, 2, 2]])

    T1=np.array([[1, 2, 1],
                 [2, 1, 2],
                 [1, 2, 2]])  # contains X1

    T2=np.array([[2, 1, 2],
                 [1, 1, 2],
                 [2, 1, 2]])

    T3=np.array([[1, 2, 2],
                 [2, 1, 2],
                 [1, 2, 1]])

    T4=np.array([[2, 2, 2],
                 [1, 1, 1],
                 [2, 1, 2]])

    T5=np.array([[2, 2, 1],
                 [2, 1, 2],
                 [1, 2, 1]])

    T6=np.array([[2, 1, 2],
                 [2, 1, 1],
                 [2, 1, 2]])

    T7=np.array([[1, 2, 1],
                 [2, 1, 2],
                 [2, 2, 1]])
    T.append(T0)
    T.append(T1)
    T.append(T2)
    T.append(T3)
    T.append(T4)
    T.append(T5)
    T.append(T6)
    T.append(T7)
    #Y like
    Y=[]
    Y0=np.array([[1, 0, 1],
                 [0, 1, 0],
                 [2, 1, 2]])

    Y1=np.array([[0, 1, 0],
                 [1, 1, 2],
                 [0, 2, 1]])

    Y2=np.array([[1, 0, 2],
                 [0, 1, 1],
                 [1, 0, 2]])

    Y2=np.array([[1, 0, 2],
                 [0, 1, 1],
                 [1, 0, 2]])

    Y3=np.array([[0, 2, 1],
                 [1, 1, 2],
                 [0, 1, 0]])

    Y4=np.array([[2, 1, 2],
                 [0, 1, 0],
                 [1, 0, 1]])
    Y5=np.rot90(Y3)
    Y6 = np.rot90(Y4)
    Y7 = np.rot90(Y5)
    Y.append(Y0)
    Y.append(Y1)
    Y.append(Y2)
    Y.append(Y3)
    Y.append(Y4)
    Y.append(Y5)
    Y.append(Y6)
    Y.append(Y7)

    bp = np.zeros(skel.shape, dtype=int)
    for x in X:
        bp = bp + hit_or_miss(skel,x)
    for y in Y:
        bp = bp + hit_or_miss(skel,y)
    for t in T:
        bp = bp + hit_or_miss(skel,t)

    return bp

def find_end_points(skel):
    endpoint1=np.array([[0, 0, 0],
                        [0, 1, 0],
                        [2, 1, 2]])

    endpoint2=np.array([[0, 0, 0],
                        [0, 1, 2],
                        [0, 2, 1]])

    endpoint3=np.array([[0, 0, 2],
                        [0, 1, 1],
                        [0, 0, 2]])

    endpoint4=np.array([[0, 2, 1],
                        [0, 1, 2],
                        [0, 0, 0]])

    endpoint5=np.array([[2, 1, 2],
                        [0, 1, 0],
                        [0, 0, 0]])

    endpoint6=np.array([[1, 2, 0],
                        [2, 1, 0],
                        [0, 0, 0]])

    endpoint7=np.array([[2, 0, 0],
                        [1, 1, 0],
                        [2, 0, 0]])

    endpoint8=np.array([[0, 0, 0],
                        [2, 1, 0],
                        [1, 2, 0]])

    ep1=hit_or_miss(skel,endpoint1)
    ep2=hit_or_miss(skel,endpoint2)
    ep3=hit_or_miss(skel,endpoint3)
    ep4=hit_or_miss(skel,endpoint4)
    ep5=hit_or_miss(skel,endpoint5)
    ep6=hit_or_miss(skel,endpoint6)
    ep7=hit_or_miss(skel,endpoint7)
    ep8=hit_or_miss(skel,endpoint8)
    ep = ep1+ep2+ep3+ep4+ep5+ep6+ep7+ep8
    return ep

# --------------------------------------------------------------------------------
# script
# --------------------------------------------------------------------------------

img = plt.imread("test.jpg")

# for some reason (screenshot?), example image is not binary
binary = img >= 250

skeleton = skeletonize(binary)

branch_pts = find_branch_points(skeleton)

plt.imshow(binary + branch_pts, cmap='gray', interpolation='nearest'); plt.show()