No account yet ?
Tested in Anaconda and Python 3.7
import matplotlib.pyplot as plt import cv2 def showimage(myimage, figsize=[10,10]): if (myimage.ndim>2): #This only applies to RGB or RGBA images (e.g. not to Black and White images) myimage = myimage[:,:,::-1] #OpenCV follows BGR order, while matplotlib likely follows RGB order fig, ax = plt.subplots(figsize=figsize) ax.imshow(myimage, cmap = 'gray', interpolation = 'bicubic') plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis plt.show() "load image data" Img_Original = cv2.imread( 'Emprunte-digitale-01.jpg', 0) # Gray image, rgb images need pre-conversion showimage(Img_Original) from skimage.filters import threshold_otsu Otsu_Threshold = threshold_otsu(Img_Original) BW_Original = Img_Original > Otsu_Threshold # must set object region as 1, background region as 0 ! from skimage.morphology import skeletonize BW_Skeleton = skeletonize(BW_Original) showimage(BW_Skeleton)
Original image
Skeleton image
Tested in Anaconda and Python 3.7
import cv2 as cv from matplotlib import pyplot as plt def showimage(myimage, figsize=[10,10]): if (myimage.ndim>2): #This only applies to RGB or RGBA images (e.g. not to Black and White images) myimage = myimage[:,:,::-1] #OpenCV follows BGR order, while matplotlib likely follows RGB order fig, ax = plt.subplots(figsize=figsize) ax.imshow(myimage, cmap = 'gray', interpolation = 'bicubic') plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis plt.show() from skimage.filters import threshold_otsu from skimage.filters import threshold_yen from skimage.filters import threshold_li img = cv.imread( 'Emprunte-digitale-01.jpg', 0) showimage(img) Otsu_Threshold = threshold_otsu(img) th1 = img > Otsu_Threshold showimage(th1) Yen_Threshold = threshold_yen(img) th2 = img > Yen_Threshold showimage(th2) Li_Threshold = threshold_li(img) th3 = img > Li_Threshold showimage(th3) ret,th4 = cv.threshold(img,127,255,cv.THRESH_BINARY) showimage(th4) th5 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY,11,2) showimage(th5)
Original image
Otsu thresholding
Yen thresholding
Li thresholding
Global thresholding
Adaptative thresholding
Tested in Anaconda and Python 3.7
import numpy as np import cv2 import matplotlib.pyplot as plt import skimage.io as io import skimage.morphology from PIL import Image, ImageDraw from skimage.filters import threshold_otsu, threshold_yen, threshold_li from skimage.morphology import convex_hull_image, erosion, square, skeletonize def getTerminationBifurcation(img, mask): img = img == 255; (rows, cols) = img.shape; minutiaeTerm = np.zeros(img.shape); minutiaeBif = np.zeros(img.shape); for i in range(1,rows-1): for j in range(1,cols-1): if(img[i][j] == 1): block = img[i-1:i+2,j-1:j+2]; block_val = np.sum(block); if(block_val == 2): minutiaeTerm[i,j] = 1; elif(block_val == 4): minutiaeBif[i,j] = 1; mask = convex_hull_image(mask>0) mask = erosion(mask, square(5)) # Structuing element for mask erosion = square(5) minutiaeTerm = np.uint8(mask)*minutiaeTerm return(minutiaeTerm, minutiaeBif) def removeSpuriousMinutiae(minutiaeList, img, thresh): img = img * 0; SpuriousMin = []; numPoints = len(minutiaeList); D = np.zeros((numPoints, numPoints)) for i in range(1,numPoints): for j in range(0, i): (X1,Y1) = minutiaeList[i]['centroid'] (X2,Y2) = minutiaeList[j]['centroid'] dist = np.sqrt((X2-X1)**2 + (Y2-Y1)**2); D[i][j] = dist if(dist < thresh): SpuriousMin.append(i) SpuriousMin.append(j) SpuriousMin = np.unique(SpuriousMin) for i in range(0,numPoints): if(not i in SpuriousMin): (X,Y) = np.int16(minutiaeList[i]['centroid']); img[X,Y] = 1; img = np.uint8(img); return(img) "load image data" Img_Original = io.imread('Original.bmp') imgplot = plt.imshow(Img_Original, 'gray') plt.axis('off') plt.show() Otsu_Threshold = threshold_otsu(Img_Original) BW_Original = Img_Original > Otsu_Threshold imgplot = plt.imshow(BW_Original, 'gray') plt.axis('off') plt.imsave('BW-Original.jpg', BW_Original, cmap='gray') plt.show() BW_Skeleton = skeletonize(BW_Original) imgplot = plt.imshow(BW_Skeleton, 'gray') plt.axis('off') plt.imsave('skeleton.jpg', BW_Skeleton, cmap='gray') plt.show() Otsu_Threshold = threshold_otsu(Img_Original) th1 = Img_Original > Otsu_Threshold Yen_Threshold = threshold_yen(Img_Original) th2 = Img_Original > Yen_Threshold Li_Threshold = threshold_li(Img_Original) th3 = Img_Original > Li_Threshold ret,th4 = cv2.threshold(Img_Original,127,255,cv2.THRESH_BINARY) th5 = cv2.adaptiveThreshold(Img_Original,255,cv2.ADAPTIVE_THRESH_MEAN_C,\ cv2.THRESH_BINARY,11,2) # plot all the images and their histograms images = [th1, th2, th3, th4, th5] titles = ['Ots-Threshold', "Yen-Threshold", "Li-Threshold", "Global-Threshold", "Adaptive-Threshold"] for i in range(5): imgplot = plt.imshow(images[i], 'gray') plt.axis('off') plt.title(titles[i]) plt.imsave('%s.jpg' % (titles[i]), images[i], cmap='gray') plt.show() img = Image.open('skeleton.jpg').convert('L') Img_Original = img # To reach different pixels from given pixel .... cells = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)] # Function to determine type of minutiae at pixel P(i,j) .... def minutiae_at(pixels, i, j): values = [pixels[i + k][j + l] for k, l in cells] crossings = 0 for k in range(0, 8): crossings += abs(values[k] - values[k + 1]) crossings /= 2 if pixels[i][j] == 1: if crossings == 1: return "ending" if crossings == 3: return "bifurcation" return "none" # Function to convert the image into pixels .... def load_image(im): (x,y) = im.size im_load = im.load() result = [] for i in range(0, x): result.append([]) for j in range(0, y): result[i].append(im_load[i, j]) return result # Function to apply particular property to each pixel .... def apply_to_each_pixel(pixels, f): for i in range(0, len(pixels)): for j in range(0, len(pixels[i])): pixels[i][j] = f(pixels[i][j]) # Function to show minutiae on the image .... def show_minutiaes(im): pixels = load_image(im) apply_to_each_pixel(pixels, lambda x: 0.0 if x > 10 else 1.0) (x, y) = im.size result = im.convert("RGB") draw = ImageDraw.Draw(result) colors = {"ending" : (150, 0, 0), "bifurcation" : (0, 150, 0)} ellipse_size = 8 for i in range(1, x - 1): for j in range(1, y - 1): minutiae = minutiae_at(pixels, i, j) if minutiae != "none": draw.ellipse([(i - ellipse_size, j - ellipse_size), (i + ellipse_size, j + ellipse_size)], outline = colors[minutiae]) del draw return result # Applying Minutiae Detection Algorithm to image .... Minutiae_Image = show_minutiaes(img) # Displaying the results .... imgplot = plt.imshow(Img_Original, 'gray') plt.axis('off') plt.title('Original image') plt.show() imgplot = plt.imshow(Minutiae_Image) plt.axis('off') plt.title('Minutiae in the image') plt.show() Minutiae_Image.save('Minutiae.jpg') img = cv2.imread('Original.bmp', 0) img = np.uint8(img > 128) skel = skimage.morphology.skeletonize(img) skel = np.uint8(skel)*255; mask = skel*255; (minutiaeTerm, minutiaeBif) = getTerminationBifurcation(skel, mask); minutiaeTerm = skimage.measure.label(minutiaeTerm, 8); RP = skimage.measure.regionprops(minutiaeTerm) minutiaeTerm = removeSpuriousMinutiae(RP, np.uint8(img), 10); BifLabel = skimage.measure.label(minutiaeBif, 8); TermLabel = skimage.measure.label(minutiaeTerm, 8); minutiaeBif = minutiaeBif * 0; minutiaeTerm = minutiaeTerm * 0; (rows, cols) = skel.shape DispImg = np.zeros((rows,cols,3), np.uint8) DispImg[:,:,0] = skel; DispImg[:,:,1] = skel; DispImg[:,:,2] = skel; RP = skimage.measure.regionprops(BifLabel) for i in RP: (row, col) = np.int16(np.round(i['Centroid'])) minutiaeBif[row, col] = 1; (rr, cc) = skimage.draw.circle_perimeter(row, col, 3); skimage.draw.set_color(DispImg, (rr,cc), (255,0,0)); RP = skimage.measure.regionprops(TermLabel) for i in RP: (row, col) = np.int16(np.round(i['Centroid'])) minutiaeTerm[row, col] = 1; (rr, cc) = skimage.draw.circle_perimeter(row, col, 3); skimage.draw.set_color(DispImg, (rr,cc), (0, 0, 255)); plt.imshow(DispImg) plt.axis('off') plt.title('Minutiae image') plt.imsave('Minutiae-image.jpg', DispImg) plt.show()
Original image
Grayscale
Skeletonization
Ots thresholding
Yen thresholding
Li thresholding
Global thresholding
Adaptative thresholding
Minutiae
Minutiae in the image
Minutiae-Extraction - GitHub
Welcome, my name is Eric Soupet and I am the administrator of the site elodees.com. elodees.com is a state of the art of Artificial Intelligence and aims to be collaborative, you can now offer content such as articles, events, tutorials, ... so don't hesitate !
Platform images credit : Pixabay - Pixabay License | Pexels - Pexels License