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.
- Get the skeleton image
- Get the tips (i.e. start, end points) of the skeleton by using the number of adjacent pixels around the tips
- Draw the path between the start and end points by BFS
- 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.

# 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.
