I want to find medial axis distance transform at middle, fifth pixel at each end point. my input image and desired point are:

Input Image Input Image Desired point on skeleton enter image description here

My code as follows:

skeleton, distance = medial_axis(cimg, return_distance=True)
                med_dist = distance * skeleton
                width = med_dist*2
                skeld=width[skeleton]
                dwidth=skeld[skeld.shape[0]//2]

But it doesn't give correct result

1

There are 1 best solutions below

5
Prefect On BEST ANSWER

EDIT 0: If you are saying, the skeleton can be any oriented, let's get complicated :). Let me start with a similar problem from my past. There, I needed an approach to track down the pixels between given two points at a skeleton. Please check the accepted answer at the question, and, keep this approach in your mind, because I will use it for your problem too.

Here are the steps that I followed for your problem.

  1. Get the skeleton image
  2. Get the tips (i.e. start, end points) of the skeleton by using the number of adjacent pixels around the tips
  3. Draw the path between the start and end points by BFS
  4. Get the desired indices (fifth pixel of end points) from the drawn path
import numpy as np
import cv2
import os
import matplotlib.pyplot as plt
import sys
from collections import deque
from skimage.morphology import medial_axis
from itertools import combinations


img = cv2.imread('curvy_1.png',0)/255
skel = medial_axis(img, return_distance=False) # skeleton


img_conv = cv2.filter2D(skel.astype(np.uint8),-1,np.ones((3,3))) #
img_conv = img_conv*skel
img_tips = img_conv == 2
tips = np.array(np.nonzero(img_tips)).T
tip_combs = combinations(tips, 2) # get all the combinations of the tips in case the skeleton are branched

Here are the found tips. tips of the skeleton

# BFS
def findPathBwTwoPoints(img_binary,points):
    '''
    img_binary: skeleton image
    points: (y_start_point,x_start_point),(y_end_point,x_end_point)
    '''
    height, width = img_binary.shape

    # The start and end point you're looking at
    # start, end = (31, 14), (34, 51)

    start,end = points

    # print(start,end)

    # All 8 directions
    delta = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)]

    # Store the results of the BFS as the shortest distance to start
    grid = [[sys.maxsize for _ in range(width)] for _ in range(height)]
    grid[start[0]][start[1]] = 0

    # The actual BFS algorithm
    bfs = deque([start])
    found = False
    while len(bfs) > 0:
        y, x = bfs.popleft()
        # print(y,x)
        # We've reached the end!
        if (y, x) == end:
            found = True
            break

        # Look all 8 directions for a good path
        for dy, dx in delta:
            yy, xx = y + dy, x + dx
            # If the next position hasn't already been looked at and it's white
            if 0 <= yy < height and 0 <= xx < width and grid[y][x] + 1 < grid[yy][xx] and img_binary[yy][xx] != 0:
                grid[yy][xx] = grid[y][x] + 1
                bfs.append((yy, xx))

    if found:
        # Now rebuild the path from the end to beginning
        path = []
        y, x = end
        while grid[y][x] != 0:
            for dy, dx in delta:
                yy, xx = y + dy, x + dx
                if 0 <= yy < height and 0 <= xx < width and grid[yy][xx] == grid[y][x] - 1:
                    path.append([yy, xx])
                    y, x = yy, xx

        return np.array(path)
    else:
        # print(f'No path found between {start} and {end}')
        return 0

Let's get the path between the found tips by using BFS.

for tip_comb in list(tip_combs):

    start, end = tuple(tip_comb[0]), tuple(tip_comb[1])

    paths = findPathBwTwoPoints(skel,points=[start,end]) # this will return the path between the start and end points

    # ready to get the indices you are asking for
    first_fifth = paths[4]
    last_fifth = paths[-5]
    middle = paths[int(len(paths)/2)]


    fig,ax = plt.subplots(1)
    ax.imshow(skel,'gray')
    ax.scatter( [first_fifth[1],last_fifth[1],middle[1]],
                [first_fifth[0],last_fifth[0],middle[0]],s=10,c='r')

plt.show()

indices on the skeleton

Here are a few more example output from my approach.

curvy_2

In case your skeleton is branched, this approach will give you the indices for all the combinations between the tips.

curvy_3_0 curvy_3_1 curvy_3_2