如何获得1像素宽的骨架?

时间:2019-05-13 11:46:31

标签: matlab image-processing

我想从二进制血管树中得到一个1像素宽的骨架。应用代码后得到的骨架具有一些小的假分支,并且不是1像素宽。如何获得完美的骨骼?

使用Frangi过滤器增强船只,并在执行阈值设置后提取二叉树。这是当时的图像: binary vessel map

然后,执行细化处理以获取骨架:

% getting the skeleton
Iskel = bwmorph(Out,'thin',8);
figure,imshow(Iskel);

% because of the discontinuity in my skeleton, I've applied imdilate to create continuity 
se = strel('square',2);
Skel = imdilate(Iskel, se);
figure,imshow(Skel); title('Skel 8');

我希望输出为一个像素宽的骨架,但实际上不确定我的宽度是否为一个像素宽,并且还存在小的假分支。

1 个答案:

答案 0 :(得分:0)

我使用 Zhang-Suen 算法从原始图像创建骨架。但结果可能不是单像素骨架。所以,我决定创建一个算法来去除多余的像素。最后,我想得到了一个单像素骨架。您可以将我的代码视为解决方案。

这是我的 Python 实现(我还在下面添加了我的代码的结果):

import cv2
import numpy as np
import math

def check_condition(img, r, c):
    top = max(0, r - 1)
    right = min(img.shape[1] - 1, c + 1)
    bottom = min(img.shape[0] - 1, r + 1)
    left = max(0, c - 1)

    sub_img = img[top: bottom + 1, left: right + 1]
    if np.sum(sub_img) >= 255*5:
        return True
    return False

def check_near(coord1, coord2):
    r1, c1 = coord1
    r2, c2 = coord2
    distance = math.sqrt((r1-r2)**2 + (c1-c2)**2)
    if distance == 1:
        return True


def remove_redudant(img, r, c):
    coords = []
    if img[r-1][c-1] == 255:
        coords.append((r-1, c-1))
    if img[r-1][c] == 255:
        coords.append((r-1, c))
    if img[r-1][c+1] == 255:
        coords.append((r-1, c+1))

    if img[r][c-1] == 255:
        coords.append((r, c-1))
    if img[r][c+1] == 255:
        coords.append((r, c+1))

    if img[r+1][c-1] == 255:
        coords.append((r+1, c-1))
    if img[r+1][c] == 255:
        coords.append((r+1, c))
    if img[r+1][c+1] == 255:
        coords.append((r+1, c+1))
    
    coords.append((r, c))
    coord_count = []
    for coord in coords[:-1]:
        count = 0
        for coord_ in coords:
            if check_near(coord, coord_):
                count += 1
        coord_count.append((coord, count))
    
    coord_count.sort(key=lambda x: (x[1], int(x[0] in coords)))
    remove_r, remove_c = coord_count[-1][0]

    # remove
    img[remove_r][remove_c] = 0

def single_pixel(img):
    while True:
        # Find positions of non-zero pixels
        (rows, cols) = np.nonzero(img)

        # Initialize empty list of co-ordinates
        coords = []

        # For each non-zero pixel...
        for (r, c) in zip(rows, cols):
            if check_condition(img, r, c):
                coords.append((r,c))

        # saved a image with end-point to check
        if len(coords) == 0:
            break

        for i, j in coords:
            # check whether (i, j) point is removed or not
            if img[i][j] == 255:

                # check again:
                if check_condition(img, i, j):
                    remove_redudant(img, i, j)

def single_pixel_skeleton(path):
    image = cv2.imread(path, 0)

    # using zhang suen algorithm
    thinned = cv2.ximgproc.thinning(image)

    # create single pixel skeleton
    single_pixel(thinned)

    return thinned

if __name__ == '__main__':
    path = 'sample.png'
    saved_path = 'skeleton.png'

    out_img = single_pixel_skeleton(path)
    cv2.imwrite(saved_path, out_img)

enter image description here