How to execute skeleton code on different binary images

132 Views Asked by At

I want to draw the skeleton of the following image, enter image description here I've tried with the following Python code:

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

# # 2D AOF Skeleton
#This is a jupyter notebook for 2D AOF Skeletonization code

# In[ ]:





# In[58]:


import matplotlib.pyplot as plt
from scipy.misc import imresize


# In[59]:


import matplotlib.image as mpimg
import math
import numpy as np

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])


# In[60]:


fileName = "horse.png"


# In[61]:


I=mpimg.imread(fileName)


# In[62]:


I = rgb2gray(I)
I = I[100:500,100:500]
I = imresize(I,0.3)
print(I.shape)


# In[63]:


imgplot = plt.imshow(I)


# In[64]:


plt.show()


# In[65]:


number_of_samples = 60
epsilon = 1 
flux_threshold = 18


# In[66]:


import scipy.ndimage.morphology as morphOps


# In[67]:


distImage,IDX = morphOps.distance_transform_edt(I,return_indices=True);


# In[68]:


plt.imshow(distImage)


# In[69]:


def sample_sphere_2D(number_of_samples):
    sphere_points = np.zeros((number_of_samples,2))
    alpha = (2*math.pi)/(number_of_samples)
    for i in range(number_of_samples):
        sphere_points[i][0] = math.cos(alpha*(i-1))
        sphere_points[i][1] = math.sin(alpha*(i-1))
    return sphere_points


# In[70]:


print(number_of_samples)


# In[71]:


sphere_points = sample_sphere_2D(number_of_samples)


# In[72]:


def sub2ind(array_shape, rows, cols):
    ind = rows*array_shape[1] + cols
    ind[ind < 0] = -1
    ind[ind >= array_shape[0]*array_shape[1]] = -1
    return ind

def ind2sub(array_shape, ind):
    ind[ind < 0] = -1
    ind[ind >= array_shape[0]*array_shape[1]] = -1
    rows = (ind.astype('int') / array_shape[1])
    cols = ind % array_shape[1]
    return (rows, cols)

def compute_aof(distImage ,IDX,sphere_points,epsilon):

    m = distImage.shape[0]
    n = distImage.shape[1]
    normals = np.zeros(sphere_points.shape)
    fluxImage = np.zeros((m,n))
    for t in range(0,number_of_samples):
        normals[t] = sphere_points[t]
    sphere_points = sphere_points * epsilon
    
    XInds = IDX[0]
    YInds = IDX[1]
    
    for i in range(0,m):
        print(i)
        for j in range(0,n):       
            flux_value = 0
            if (distImage[i][j] > -1.5):
                if( i > epsilon and j > epsilon and i < m - epsilon and j < n - epsilon ):
#                   sum over dot product of normal and the gradient vector field (q-dot)
                    for ind in range (0,number_of_samples):
                                                
#                       a point on the sphere
                        px = i+sphere_points[ind][0]+0.5;
                        py = j+sphere_points[ind][1]+0.5;
                        
                        
                        
                        
#                       the indices of the grid cell that sphere points fall into 
                        cI = math.floor(i+sphere_points[ind][0]+0.5)
                        cJ = math.floor(j+sphere_points[ind][1]+0.5)
                                               

#                       closest point on the boundary to that sphere point

                        bx = XInds[cI][cJ]
                        by = YInds[cI][cJ]
#                       the vector connect them
                        qq = [bx-px,by-py]
                    
                        d = np.linalg.norm(qq)
                        if(d!=0):
                            qq = qq / d
                        else:
                            qq = [0,0]                        
                        flux_value = flux_value + np.dot(qq,normals[ind])
            fluxImage[i][j] = flux_value  
    return fluxImage


# In[73]:


fluxImage = compute_aof(distImage,IDX,sphere_points,epsilon)


# In[74]:


print(fluxImage.shape)


# In[75]:


plt.imshow(fluxImage)

How can I try this code for other inputs? Also, this piece of code gives an error in the imresize section because it is obsolete, what alternative do you suggest to make the code run correctly?

I tried with cv2 and resize code, but it had a problem in recognizing the length and width of the shape and it recreated the skeleton of the shape incorrectly. The code snippet is available at the address below: https://github.com/mrezanejad/2DAOFSkeleton_Python

1

There are 1 best solutions below

0
fmw42 On

Here is one simple way to do that using Python/OpenCV/Skimage.

Input:

enter image description here

import cv2
import numpy as np
import skimage.morphology

img = cv2.imread("horse.png")
ht, wd = img.shape[:2]

# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# create a binary thresholded image and invert so horse is white on black background
thresh = cv2.threshold(gray, 0, 1, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]

# apply skeletonization
skeleton = skimage.morphology.skeletonize(thresh)
skeleton = (255*skeleton).clip(0,255).astype(np.uint8)

# save result
cv2.imwrite("horse_skeleton.png", skeleton)

# show results
cv2.imshow("skeleton", skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here