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
Desired point on skeleton
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
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.
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
# 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()
Here are a few more example output from my approach.
In case your skeleton is branched, this approach will give you the indices for all the combinations between the tips.