Reputation: 906
I have some font character images of fixed size as shown under the Input image sample. I want to extract the character skeleton (single-pixel wide). I have tried various ways as shown below but the outputs are all different and not smooth. I thought that the one-pixel-wide skeleton will be smooth (pixels not breaking and no noise pixels). Is there a better way to do this? If no which one is the best among these three?
Input image sample
1) Example
from skimage import img_as_bool, io, color, morphology
import matplotlib.pyplot as plt
image = img_as_bool(color.rgb2gray(io.imread('image.jpeg')))
out = morphology.medial_axis(image)
f, (ax0, ax1) = plt.subplots(1, 2)
ax0.imshow(image, cmap='gray', interpolation='nearest')
ax1.imshow(out, cmap='gray', interpolation='nearest')
plt.show()
Output1
2) Example
from PIL import Image, ImageDraw, ImageFont
import mahotas as mh
import numpy as np
image = Image.new("RGBA", (600,150), (255,255,255))
draw = ImageDraw.Draw(image)
fontsize = 150
font = ImageFont.truetype("font.TTF", fontsize)
txt = '가'
draw.text((30, 5), txt, (0,0,0), font=font)
img = image.resize((188,45), Image.ANTIALIAS)
print(type(img))
plt.imshow(img)
img = np.array(img)
im = img[:,0:50,0]
im = im < 128
skel = mh.thin(im)
noholes = mh.morph.close_holes(skel)
plt.subplot(311)
plt.imshow(im)
plt.subplot(312)
plt.imshow(skel)
Output2
3) Example
from skimage.morphology import skeletonize
from skimage import draw
from skimage.io import imread, imshow
from skimage.color import rgb2gray
import os
# load image from file
img_fname='D:\Ammar Data\Debbie_laptop_data\Ammar\sslab-deeplearning\GAN models\sslab_GAN\skeleton\hangul_1.jpeg'
image=imread(img_fname)
# Change RGB color to gray
image=rgb2gray(image)
# Change gray image to binary
image=np.where(image>np.mean(image),1.0,0.0)
# perform skeletonization
skeleton = skeletonize(image)
plt.imshow(skeleton)
output3
Upvotes: 2
Views: 5024
Reputation: 2197
Your code is fine but you may need to change the way you are converting the image to binary. Also, to avoid the noisy looking output, you can apply binary_closing
to your skeleton image. Take a look at the below code -
import matplotlib.pyplot as plt
from skimage import img_as_bool
from skimage.io import imread
from skimage.color import rgb2gray
from skimage.morphology import skeletonize, binary_closing
im = img_as_bool(rgb2gray(imread('0jQjL.jpg')))
out = binary_closing(skeletonize(im))
f, (ax0, ax1) = plt.subplots(1, 2)
ax0.imshow(im, cmap='gray', interpolation='nearest')
ax1.imshow(out, cmap='gray', interpolation='nearest')
plt.show()
Your two sample images gave me the below output -
EDIT: To avoid the precision loss when converting the image to bool, you can also binarize the image using one of the available thresholding algorithms. I prefer otsu's.
import matplotlib.pyplot as plt
from skimage.io import imread
from skimage.filters import threshold_otsu
from skimage.color import rgb2gray
from skimage.morphology import skeletonize, binary_closing
def get_binary(img):
thresh = threshold_otsu(img)
binary = img > thresh
return binary
im = get_binary(rgb2gray(imread('Snip20190410_9.png')))
out = binary_closing(skeletonize(im))
f, (ax0, ax1) = plt.subplots(1, 2)
ax0.imshow(im, cmap='gray', interpolation='nearest')
ax1.imshow(out, cmap='gray', interpolation='nearest')
plt.show()
Upvotes: 2