├── Dockerfile ├── README.md ├── app.py ├── database ├── 101_1.tif ├── 101_2.tif ├── 102_1.tif └── 102_2.tif ├── enhance ├── __init__.py ├── __init__.pyc ├── frequest.py ├── frequest.pyc ├── image_enhance.py ├── image_enhance.pyc ├── ridge_filter.py ├── ridge_filter.pyc ├── ridge_freq.py ├── ridge_freq.pyc ├── ridge_freq_2.py ├── ridge_orient.py ├── ridge_orient.pyc ├── ridge_segment.py └── ridge_segment.pyc ├── requirements.txt ├── run.sh └── Препознавање на отпечатоци.docx /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-slim 2 | 3 | # Set the working directory to /app 4 | WORKDIR /app 5 | 6 | # Copy the current directory contents into the container at /app 7 | COPY . /app 8 | 9 | # Install the basic packages to run opencv 10 | RUN apt-get update && apt-get install -y \ 11 | libglib2.0-0 \ 12 | libsm6 \ 13 | libxext6 \ 14 | libxrender-dev 15 | 16 | # Install any needed packages specified in requirements.txt 17 | RUN pip install --trusted-host pypi.python.org -r requirements.txt 18 | 19 | # Run app.py when the container launches 20 | # ENTRYPOINT python /app/app.py 101_1.tif 102_1.tif 21 | ENTRYPOINT ["/app/run.sh"] 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Fingerprint Recognition 2 | 3 | Fingerprint recognition with SKimage and OpenCV 4 | 5 | Requirements: 6 | - NumPy 7 | - SKimage 8 | - OpenCV2 9 | 10 | 11 | Works by extracting minutiae points using harris corner detection. 12 | 13 | Uses SIFT (ORB) go get formal descriptors around the keypoints with brute-force hamming distance and then analyzes the returned matches using thresholds. 14 | 15 | Usage: 16 | 17 | 1. Place 2 fingerprint images that you want to compare inside the database folder 18 | 2. Pass the names of the images as arguments in the console 19 | 20 | ## Dockerfile 21 | 22 | If you don't want to install the libraries, or want a easier way to test the application you can follow the commands: 23 | 24 | ```shell 25 | docker build -t . 26 | 27 | docker run -it 28 | ``` 29 | 30 | If you don't have Docker Engine installed, you can get the instructions to install it here: [Install Docker](https://docs.docker.com/v17.09/engine/installation/) 31 | 32 | NOTE: the fingerprints must be in the `/database` folder 33 | 34 | ## Credits 35 | 36 | Special thanks to https://github.com/Utkarsh-Deshmukh/Fingerprint-Enhancement-Python for providing a library used to enhance the fingerprint picture. 37 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import os 3 | import sys 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from enhance import image_enhance 7 | from skimage.morphology import skeletonize, thin 8 | 9 | os.chdir("/app/") 10 | 11 | def removedot(invertThin): 12 | temp0 = numpy.array(invertThin[:]) 13 | temp0 = numpy.array(temp0) 14 | temp1 = temp0/255 15 | temp2 = numpy.array(temp1) 16 | temp3 = numpy.array(temp2) 17 | 18 | enhanced_img = numpy.array(temp0) 19 | filter0 = numpy.zeros((10,10)) 20 | W,H = temp0.shape[:2] 21 | filtersize = 6 22 | 23 | for i in range(W - filtersize): 24 | for j in range(H - filtersize): 25 | filter0 = temp1[i:i + filtersize,j:j + filtersize] 26 | 27 | flag = 0 28 | if sum(filter0[:,0]) == 0: 29 | flag +=1 30 | if sum(filter0[:,filtersize - 1]) == 0: 31 | flag +=1 32 | if sum(filter0[0,:]) == 0: 33 | flag +=1 34 | if sum(filter0[filtersize - 1,:]) == 0: 35 | flag +=1 36 | if flag > 3: 37 | temp2[i:i + filtersize, j:j + filtersize] = numpy.zeros((filtersize, filtersize)) 38 | 39 | return temp2 40 | 41 | 42 | def get_descriptors(img): 43 | clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) 44 | img = clahe.apply(img) 45 | img = image_enhance.image_enhance(img) 46 | img = numpy.array(img, dtype=numpy.uint8) 47 | # Threshold 48 | ret, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) 49 | # Normalize to 0 and 1 range 50 | img[img == 255] = 1 51 | 52 | #Thinning 53 | skeleton = skeletonize(img) 54 | skeleton = numpy.array(skeleton, dtype=numpy.uint8) 55 | skeleton = removedot(skeleton) 56 | # Harris corners 57 | harris_corners = cv2.cornerHarris(img, 3, 3, 0.04) 58 | harris_normalized = cv2.normalize(harris_corners, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32FC1) 59 | threshold_harris = 125 60 | # Extract keypoints 61 | keypoints = [] 62 | for x in range(0, harris_normalized.shape[0]): 63 | for y in range(0, harris_normalized.shape[1]): 64 | if harris_normalized[x][y] > threshold_harris: 65 | keypoints.append(cv2.KeyPoint(y, x, 1)) 66 | # Define descriptor 67 | orb = cv2.ORB_create() 68 | # Compute descriptors 69 | _, des = orb.compute(img, keypoints) 70 | return (keypoints, des); 71 | 72 | 73 | def main(): 74 | image_name = sys.argv[1] 75 | img1 = cv2.imread("database/" + image_name, cv2.IMREAD_GRAYSCALE) 76 | kp1, des1 = get_descriptors(img1) 77 | 78 | image_name = sys.argv[2] 79 | img2 = cv2.imread("database/" + image_name, cv2.IMREAD_GRAYSCALE) 80 | kp2, des2 = get_descriptors(img2) 81 | 82 | # Matching between descriptors 83 | bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) 84 | matches = sorted(bf.match(des1, des2), key= lambda match:match.distance) 85 | # Plot keypoints 86 | img4 = cv2.drawKeypoints(img1, kp1, outImage=None) 87 | img5 = cv2.drawKeypoints(img2, kp2, outImage=None) 88 | f, axarr = plt.subplots(1,2) 89 | axarr[0].imshow(img4) 90 | axarr[1].imshow(img5) 91 | plt.show() 92 | # Plot matches 93 | img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, flags=2, outImg=None) 94 | plt.imshow(img3) 95 | plt.show() 96 | 97 | # Calculate score 98 | score = 0; 99 | for match in matches: 100 | score += match.distance 101 | score_threshold = 33 102 | if score/len(matches) < score_threshold: 103 | print("Fingerprint matches.") 104 | else: 105 | print("Fingerprint does not match.") 106 | 107 | 108 | 109 | if __name__ == "__main__": 110 | try: 111 | main() 112 | except: 113 | raise 114 | -------------------------------------------------------------------------------- /database/101_1.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/database/101_1.tif -------------------------------------------------------------------------------- /database/101_2.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/database/101_2.tif -------------------------------------------------------------------------------- /database/102_1.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/database/102_1.tif -------------------------------------------------------------------------------- /database/102_2.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/database/102_2.tif -------------------------------------------------------------------------------- /enhance/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/__init__.py -------------------------------------------------------------------------------- /enhance/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/__init__.pyc -------------------------------------------------------------------------------- /enhance/frequest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Apr 22 02:51:53 2016 4 | 5 | @author: utkarsh 6 | """ 7 | 8 | 9 | 10 | # FREQEST - Estimate fingerprint ridge frequency within image block 11 | # 12 | # Function to estimate the fingerprint ridge frequency within a small block 13 | # of a fingerprint image. This function is used by RIDGEFREQ 14 | # 15 | # Usage: 16 | # freqim = freqest(im, orientim, windsze, minWaveLength, maxWaveLength) 17 | # 18 | # Arguments: 19 | # im - Image block to be processed. 20 | # orientim - Ridge orientation image of image block. 21 | # windsze - Window length used to identify peaks. This should be 22 | # an odd integer, say 3 or 5. 23 | # minWaveLength, maxWaveLength - Minimum and maximum ridge 24 | # wavelengths, in pixels, considered acceptable. 25 | # 26 | # Returns: 27 | # freqim - An image block the same size as im with all values 28 | # set to the estimated ridge spatial frequency. If a 29 | # ridge frequency cannot be found, or cannot be found 30 | # within the limits set by min and max Wavlength 31 | # freqim is set to zeros. 32 | # 33 | # Suggested parameters for a 500dpi fingerprint image 34 | # freqim = freqest(im,orientim, 5, 5, 15); 35 | # 36 | # See also: RIDGEFREQ, RIDGEORIENT, RIDGESEGMENT 37 | 38 | ### REFERENCES 39 | 40 | # Peter Kovesi 41 | # School of Computer Science & Software Engineering 42 | # The University of Western Australia 43 | # pk at csse uwa edu au 44 | # http://www.csse.uwa.edu.au/~pk 45 | 46 | 47 | import numpy as np 48 | import math 49 | import scipy.ndimage 50 | #import cv2 51 | def frequest(im,orientim,windsze,minWaveLength,maxWaveLength): 52 | rows,cols = np.shape(im); 53 | 54 | # Find mean orientation within the block. This is done by averaging the 55 | # sines and cosines of the doubled angles before reconstructing the 56 | # angle again. This avoids wraparound problems at the origin. 57 | 58 | 59 | cosorient = np.mean(np.cos(2*orientim)); 60 | sinorient = np.mean(np.sin(2*orientim)); 61 | orient = math.atan2(sinorient,cosorient)/2; 62 | 63 | # Rotate the image block so that the ridges are vertical 64 | 65 | #ROT_mat = cv2.getRotationMatrix2D((cols/2,rows/2),orient/np.pi*180 + 90,1) 66 | #rotim = cv2.warpAffine(im,ROT_mat,(cols,rows)) 67 | rotim = scipy.ndimage.rotate(im,orient/np.pi*180 + 90,axes=(1,0),reshape = False,order = 3,mode = 'nearest'); 68 | 69 | # Now crop the image so that the rotated image does not contain any 70 | # invalid regions. This prevents the projection down the columns 71 | # from being mucked up. 72 | 73 | cropsze = int(np.fix(rows/np.sqrt(2))); 74 | offset = int(np.fix((rows-cropsze)/2)); 75 | rotim = rotim[offset:offset+cropsze][:,offset:offset+cropsze]; 76 | 77 | # Sum down the columns to get a projection of the grey values down 78 | # the ridges. 79 | 80 | proj = np.sum(rotim,axis = 0); 81 | dilation = scipy.ndimage.grey_dilation(proj, windsze,structure=np.ones(windsze)); 82 | 83 | temp = np.abs(dilation - proj); 84 | 85 | peak_thresh = 2; 86 | 87 | maxpts = (temp np.mean(proj)); 88 | maxind = np.where(maxpts); 89 | 90 | rows_maxind,cols_maxind = np.shape(maxind); 91 | 92 | # Determine the spatial frequency of the ridges by divinding the 93 | # distance between the 1st and last peaks by the (No of peaks-1). If no 94 | # peaks are detected, or the wavelength is outside the allowed bounds, 95 | # the frequency image is set to 0 96 | 97 | if(cols_maxind<2): 98 | freqim = np.zeros(im.shape); 99 | else: 100 | NoOfPeaks = cols_maxind; 101 | waveLength = (maxind[0][cols_maxind-1] - maxind[0][0])/(NoOfPeaks - 1); 102 | if waveLength>=minWaveLength and waveLength<=maxWaveLength: 103 | freqim = 1/np.double(waveLength) * np.ones(im.shape); 104 | else: 105 | freqim = np.zeros(im.shape); 106 | 107 | return(freqim); 108 | -------------------------------------------------------------------------------- /enhance/frequest.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/frequest.pyc -------------------------------------------------------------------------------- /enhance/image_enhance.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Apr 18 22:50:30 2016 4 | 5 | @author: utkarsh 6 | """ 7 | from .ridge_segment import ridge_segment 8 | from .ridge_orient import ridge_orient 9 | from .ridge_freq import ridge_freq 10 | from .ridge_filter import ridge_filter 11 | 12 | def image_enhance(img): 13 | blksze = 16; 14 | thresh = 0.1; 15 | normim,mask = ridge_segment(img,blksze,thresh); # normalise the image and find a ROI 16 | 17 | 18 | gradientsigma = 1; 19 | blocksigma = 7; 20 | orientsmoothsigma = 7; 21 | orientim = ridge_orient(normim, gradientsigma, blocksigma, orientsmoothsigma); # find orientation of every pixel 22 | 23 | 24 | blksze = 38; 25 | windsze = 5; 26 | minWaveLength = 5; 27 | maxWaveLength = 15; 28 | freq,medfreq = ridge_freq(normim, mask, orientim, blksze, windsze, minWaveLength,maxWaveLength); #find the overall frequency of ridges 29 | 30 | 31 | freq = medfreq*mask; 32 | kx = 0.65;ky = 0.65; 33 | newim = ridge_filter(normim, orientim, freq, kx, ky); # create gabor filter and do the actual filtering 34 | 35 | 36 | #th, bin_im = cv2.threshold(np.uint8(newim),0,255,cv2.THRESH_BINARY); 37 | return(newim < -3) -------------------------------------------------------------------------------- /enhance/image_enhance.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/image_enhance.pyc -------------------------------------------------------------------------------- /enhance/ridge_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Apr 22 03:15:03 2016 4 | 5 | @author: utkarsh 6 | """ 7 | 8 | 9 | # RIDGEFILTER - enhances fingerprint image via oriented filters 10 | # 11 | # Function to enhance fingerprint image via oriented filters 12 | # 13 | # Usage: 14 | # newim = ridgefilter(im, orientim, freqim, kx, ky, showfilter) 15 | # 16 | # Arguments: 17 | # im - Image to be processed. 18 | # orientim - Ridge orientation image, obtained from RIDGEORIENT. 19 | # freqim - Ridge frequency image, obtained from RIDGEFREQ. 20 | # kx, ky - Scale factors specifying the filter sigma relative 21 | # to the wavelength of the filter. This is done so 22 | # that the shapes of the filters are invariant to the 23 | # scale. kx controls the sigma in the x direction 24 | # which is along the filter, and hence controls the 25 | # bandwidth of the filter. ky controls the sigma 26 | # across the filter and hence controls the 27 | # orientational selectivity of the filter. A value of 28 | # 0.5 for both kx and ky is a good starting point. 29 | # showfilter - An optional flag 0/1. When set an image of the 30 | # largest scale filter is displayed for inspection. 31 | # 32 | # Returns: 33 | # newim - The enhanced image 34 | # 35 | # See also: RIDGEORIENT, RIDGEFREQ, RIDGESEGMENT 36 | 37 | # Reference: 38 | # Hong, L., Wan, Y., and Jain, A. K. Fingerprint image enhancement: 39 | # Algorithm and performance evaluation. IEEE Transactions on Pattern 40 | # Analysis and Machine Intelligence 20, 8 (1998), 777 789. 41 | 42 | ### REFERENCES 43 | 44 | # Peter Kovesi 45 | # School of Computer Science & Software Engineering 46 | # The University of Western Australia 47 | # pk at csse uwa edu au 48 | # http://www.csse.uwa.edu.au/~pk 49 | 50 | 51 | 52 | import numpy as np 53 | import scipy; 54 | def ridge_filter(im, orient, freq, kx, ky): 55 | angleInc = 3; 56 | im = np.double(im); 57 | rows,cols = im.shape; 58 | newim = np.zeros((rows,cols)); 59 | 60 | freq_1d = np.reshape(freq,(1,rows*cols)); 61 | ind = np.where(freq_1d>0); 62 | 63 | ind = np.array(ind); 64 | ind = ind[1,:]; 65 | 66 | # Round the array of frequencies to the nearest 0.01 to reduce the 67 | # number of distinct frequencies we have to deal with. 68 | 69 | non_zero_elems_in_freq = freq_1d[0][ind]; 70 | non_zero_elems_in_freq = np.double(np.round((non_zero_elems_in_freq*100)))/100; 71 | 72 | unfreq = np.unique(non_zero_elems_in_freq); 73 | 74 | # Generate filters corresponding to these distinct frequencies and 75 | # orientations in 'angleInc' increments. 76 | 77 | sigmax = 1/unfreq[0]*kx; 78 | sigmay = 1/unfreq[0]*ky; 79 | 80 | sze = np.round(3*np.max([sigmax,sigmay])); 81 | 82 | x,y = np.meshgrid(np.linspace(-sze,sze,(2*sze + 1)),np.linspace(-sze,sze,(2*sze + 1))); 83 | 84 | reffilter = np.exp(-(( (np.power(x,2))/(sigmax*sigmax) + (np.power(y,2))/(sigmay*sigmay)))) * np.cos(2*np.pi*unfreq[0]*x); # this is the original gabor filter 85 | 86 | filt_rows, filt_cols = reffilter.shape; 87 | 88 | gabor_filter = np.array(np.zeros((int(180/angleInc),int(filt_rows),int(filt_cols)))); 89 | 90 | for o in range(0,int(180/angleInc)): 91 | 92 | # Generate rotated versions of the filter. Note orientation 93 | # image provides orientation *along* the ridges, hence +90 94 | # degrees, and imrotate requires angles +ve anticlockwise, hence 95 | # the minus sign. 96 | 97 | rot_filt = scipy.ndimage.rotate(reffilter,-(o*angleInc + 90),reshape = False); 98 | gabor_filter[o] = rot_filt; 99 | 100 | # Find indices of matrix points greater than maxsze from the image 101 | # boundary 102 | 103 | maxsze = int(sze); 104 | 105 | temp = freq>0; 106 | validr,validc = np.where(temp) 107 | 108 | temp1 = validr>maxsze; 109 | temp2 = validrmaxsze; 111 | temp4 = validc maxorientindex): 130 | orientindex[i][j] = orientindex[i][j] - maxorientindex; 131 | finalind_rows,finalind_cols = np.shape(finalind); 132 | sze = int(sze); 133 | for k in range(0,finalind_cols): 134 | r = validr[finalind[0][k]]; 135 | c = validc[finalind[0][k]]; 136 | 137 | img_block = im[r-sze:r+sze + 1][:,c-sze:c+sze + 1]; 138 | 139 | newim[r][c] = np.sum(img_block * gabor_filter[int(orientindex[r][c]) - 1]); 140 | 141 | return(newim); -------------------------------------------------------------------------------- /enhance/ridge_filter.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/ridge_filter.pyc -------------------------------------------------------------------------------- /enhance/ridge_freq.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Apr 19 12:14:49 2016 4 | 5 | @author: utkarsh 6 | """ 7 | 8 | 9 | # RIDGEFREQ - Calculates a ridge frequency image 10 | # 11 | # Function to estimate the fingerprint ridge frequency across a 12 | # fingerprint image. This is done by considering blocks of the image and 13 | # determining a ridgecount within each block by a call to FREQEST. 14 | # 15 | # Usage: 16 | # [freqim, medianfreq] = ridgefreq(im, mask, orientim, blksze, windsze, ... 17 | # minWaveLength, maxWaveLength) 18 | # 19 | # Arguments: 20 | # im - Image to be processed. 21 | # mask - Mask defining ridge regions (obtained from RIDGESEGMENT) 22 | # orientim - Ridge orientation image (obtained from RIDGORIENT) 23 | # blksze - Size of image block to use (say 32) 24 | # windsze - Window length used to identify peaks. This should be 25 | # an odd integer, say 3 or 5. 26 | # minWaveLength, maxWaveLength - Minimum and maximum ridge 27 | # wavelengths, in pixels, considered acceptable. 28 | # 29 | # Returns: 30 | # freqim - An image the same size as im with values set to 31 | # the estimated ridge spatial frequency within each 32 | # image block. If a ridge frequency cannot be 33 | # found within a block, or cannot be found within the 34 | # limits set by min and max Wavlength freqim is set 35 | # to zeros within that block. 36 | # medianfreq - Median frequency value evaluated over all the 37 | # valid regions of the image. 38 | # 39 | # Suggested parameters for a 500dpi fingerprint image 40 | # [freqim, medianfreq] = ridgefreq(im,orientim, 32, 5, 5, 15); 41 | # 42 | 43 | # See also: RIDGEORIENT, FREQEST, RIDGESEGMENT 44 | 45 | # Reference: 46 | # Hong, L., Wan, Y., and Jain, A. K. Fingerprint image enhancement: 47 | # Algorithm and performance evaluation. IEEE Transactions on Pattern 48 | # Analysis and Machine Intelligence 20, 8 (1998), 777 789. 49 | 50 | ### REFERENCES 51 | 52 | # Peter Kovesi 53 | # School of Computer Science & Software Engineering 54 | # The University of Western Australia 55 | # pk at csse uwa edu au 56 | # http://www.csse.uwa.edu.au/~pk 57 | 58 | 59 | 60 | import numpy as np 61 | #import math 62 | #import scipy.ndimage 63 | from .frequest import frequest 64 | 65 | def ridge_freq(im, mask, orient, blksze, windsze,minWaveLength, maxWaveLength): 66 | rows,cols = im.shape; 67 | freq = np.zeros((rows,cols)); 68 | 69 | for r in range(0,rows-blksze,blksze): 70 | for c in range(0,cols-blksze,blksze): 71 | blkim = im[r:r+blksze][:,c:c+blksze]; 72 | blkor = orient[r:r+blksze][:,c:c+blksze]; 73 | 74 | 75 | freq[r:r+blksze][:,c:c+blksze] = frequest(blkim,blkor,windsze,minWaveLength,maxWaveLength); 76 | 77 | freq = freq*mask; 78 | freq_1d = np.reshape(freq,(1,rows*cols)); 79 | ind = np.where(freq_1d>0); 80 | 81 | ind = np.array(ind); 82 | ind = ind[1,:]; 83 | 84 | non_zero_elems_in_freq = freq_1d[0][ind]; 85 | 86 | meanfreq = np.mean(non_zero_elems_in_freq); 87 | medianfreq = np.median(non_zero_elems_in_freq); # does not work properly 88 | return(freq,meanfreq) -------------------------------------------------------------------------------- /enhance/ridge_freq.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/ridge_freq.pyc -------------------------------------------------------------------------------- /enhance/ridge_freq_2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Apr 22 03:02:23 2016 4 | 5 | @author: utkarsh 6 | """ 7 | 8 | import numpy as np 9 | #import math 10 | #import scipy.ndimage 11 | from frequest import frequest 12 | 13 | def rifdge_freq(im, mask, orient, blksze, windsze,minWaveLength, maxWaveLength): 14 | rows,cols = im.shape; 15 | freq = np.zeros((rows,cols)); 16 | 17 | for r in range(0,rows-blksze,blksze): 18 | for c in range(0,cols-blksze,blksze): 19 | blkim = im[r:r+blksze][:,c:c+blksze]; 20 | blkor = orient[r:r+blksze][:,c:c+blksze]; 21 | 22 | 23 | freq[r:r+blksze][:,c:c+blksze] = frequest(blkim,blkor,windsze,minWaveLength,maxWaveLength); 24 | 25 | freq = freq*mask; 26 | freq_1d = np.reshape(freq,(1,rows*cols)); 27 | ind = np.where(freq_1d>0); 28 | 29 | ind = np.array(ind); 30 | ind = ind[1,:]; 31 | 32 | non_zero_elems_in_freq = freq_1d[0][ind]; 33 | 34 | medianfreq = np.median(non_zero_elems_in_freq); 35 | 36 | return(medianfreq) -------------------------------------------------------------------------------- /enhance/ridge_orient.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Apr 19 11:31:54 2016 4 | 5 | @author: utkarsh 6 | """ 7 | 8 | 9 | 10 | # RIDGEORIENT - Estimates the local orientation of ridges in a fingerprint 11 | # 12 | # Usage: [orientim, reliability, coherence] = ridgeorientation(im, gradientsigma,... 13 | # blocksigma, ... 14 | # orientsmoothsigma) 15 | # 16 | # Arguments: im - A normalised input image. 17 | # gradientsigma - Sigma of the derivative of Gaussian 18 | # used to compute image gradients. 19 | # blocksigma - Sigma of the Gaussian weighting used to 20 | # sum the gradient moments. 21 | # orientsmoothsigma - Sigma of the Gaussian used to smooth 22 | # the final orientation vector field. 23 | # Optional: if ommitted it defaults to 0 24 | # 25 | # Returns: orientim - The orientation image in radians. 26 | # Orientation values are +ve clockwise 27 | # and give the direction *along* the 28 | # ridges. 29 | # reliability - Measure of the reliability of the 30 | # orientation measure. This is a value 31 | # between 0 and 1. I think a value above 32 | # about 0.5 can be considered 'reliable'. 33 | # reliability = 1 - Imin./(Imax+.001); 34 | # coherence - A measure of the degree to which the local 35 | # area is oriented. 36 | # coherence = ((Imax-Imin)./(Imax+Imin)).^2; 37 | # 38 | # With a fingerprint image at a 'standard' resolution of 500dpi suggested 39 | # parameter values might be: 40 | # 41 | # [orientim, reliability] = ridgeorient(im, 1, 3, 3); 42 | # 43 | # See also: RIDGESEGMENT, RIDGEFREQ, RIDGEFILTER 44 | 45 | ### REFERENCES 46 | 47 | # May 2003 Original version by Raymond Thai, 48 | # January 2005 Reworked by Peter Kovesi 49 | # October 2011 Added coherence computation and orientsmoothsigma made optional 50 | # 51 | # School of Computer Science & Software Engineering 52 | # The University of Western Australia 53 | # pk at csse uwa edu au 54 | # http://www.csse.uwa.edu.au/~pk 55 | 56 | 57 | import numpy as np; 58 | import cv2; 59 | from scipy import ndimage; 60 | from scipy import signal 61 | 62 | def ridge_orient(im, gradientsigma, blocksigma, orientsmoothsigma): 63 | rows,cols = im.shape; 64 | #Calculate image gradients. 65 | sze = np.fix(6*gradientsigma); 66 | if np.remainder(sze,2) == 0: 67 | sze = sze+1; 68 | 69 | gauss = cv2.getGaussianKernel(np.int(sze),gradientsigma); 70 | f = gauss * gauss.T; 71 | 72 | fy,fx = np.gradient(f); #Gradient of Gaussian 73 | 74 | #Gx = ndimage.convolve(np.double(im),fx); 75 | #Gy = ndimage.convolve(np.double(im),fy); 76 | 77 | Gx = signal.convolve2d(im,fx,mode='same'); 78 | Gy = signal.convolve2d(im,fy,mode='same'); 79 | 80 | Gxx = np.power(Gx,2); 81 | Gyy = np.power(Gy,2); 82 | Gxy = Gx*Gy; 83 | 84 | #Now smooth the covariance data to perform a weighted summation of the data. 85 | 86 | sze = np.fix(6*blocksigma); 87 | 88 | gauss = cv2.getGaussianKernel(np.int(sze),blocksigma); 89 | f = gauss * gauss.T; 90 | 91 | Gxx = ndimage.convolve(Gxx,f); 92 | Gyy = ndimage.convolve(Gyy,f); 93 | Gxy = 2*ndimage.convolve(Gxy,f); 94 | 95 | # Analytic solution of principal direction 96 | denom = np.sqrt(np.power(Gxy,2) + np.power((Gxx - Gyy),2)) + np.finfo(float).eps; 97 | 98 | sin2theta = Gxy/denom; # Sine and cosine of doubled angles 99 | cos2theta = (Gxx-Gyy)/denom; 100 | 101 | 102 | if orientsmoothsigma: 103 | sze = np.fix(6*orientsmoothsigma); 104 | if np.remainder(sze,2) == 0: 105 | sze = sze+1; 106 | gauss = cv2.getGaussianKernel(np.int(sze),orientsmoothsigma); 107 | f = gauss * gauss.T; 108 | cos2theta = ndimage.convolve(cos2theta,f); # Smoothed sine and cosine of 109 | sin2theta = ndimage.convolve(sin2theta,f); # doubled angles 110 | 111 | orientim = np.pi/2 + np.arctan2(sin2theta,cos2theta)/2; 112 | return(orientim); -------------------------------------------------------------------------------- /enhance/ridge_orient.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/ridge_orient.pyc -------------------------------------------------------------------------------- /enhance/ridge_segment.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Apr 18 23:04:30 2016 4 | 5 | @author: utkarsh 6 | """ 7 | 8 | 9 | 10 | # RIDGESEGMENT - Normalises fingerprint image and segments ridge region 11 | # 12 | # Function identifies ridge regions of a fingerprint image and returns a 13 | # mask identifying this region. It also normalises the intesity values of 14 | # the image so that the ridge regions have zero mean, unit standard 15 | # deviation. 16 | # 17 | # This function breaks the image up into blocks of size blksze x blksze and 18 | # evaluates the standard deviation in each region. If the standard 19 | # deviation is above the threshold it is deemed part of the fingerprint. 20 | # Note that the image is normalised to have zero mean, unit standard 21 | # deviation prior to performing this process so that the threshold you 22 | # specify is relative to a unit standard deviation. 23 | # 24 | # Usage: [normim, mask, maskind] = ridgesegment(im, blksze, thresh) 25 | # 26 | # Arguments: im - Fingerprint image to be segmented. 27 | # blksze - Block size over which the the standard 28 | # deviation is determined (try a value of 16). 29 | # thresh - Threshold of standard deviation to decide if a 30 | # block is a ridge region (Try a value 0.1 - 0.2) 31 | # 32 | # Returns: normim - Image where the ridge regions are renormalised to 33 | # have zero mean, unit standard deviation. 34 | # mask - Mask indicating ridge-like regions of the image, 35 | # 0 for non ridge regions, 1 for ridge regions. 36 | # maskind - Vector of indices of locations within the mask. 37 | # 38 | # Suggested values for a 500dpi fingerprint image: 39 | # 40 | # [normim, mask, maskind] = ridgesegment(im, 16, 0.1) 41 | # 42 | # See also: RIDGEORIENT, RIDGEFREQ, RIDGEFILTER 43 | 44 | ### REFERENCES 45 | 46 | # Peter Kovesi 47 | # School of Computer Science & Software Engineering 48 | # The University of Western Australia 49 | # pk at csse uwa edu au 50 | # http://www.csse.uwa.edu.au/~pk 51 | 52 | 53 | import numpy as np 54 | 55 | def normalise(img,mean,std): 56 | normed = (img - np.mean(img))/(np.std(img)); 57 | return(normed) 58 | 59 | def ridge_segment(im,blksze,thresh): 60 | 61 | rows,cols = im.shape; 62 | 63 | im = normalise(im,0,1); # normalise to get zero mean and unit standard deviation 64 | 65 | 66 | new_rows = np.int(blksze * np.ceil((np.float(rows))/(np.float(blksze)))) 67 | new_cols = np.int(blksze * np.ceil((np.float(cols))/(np.float(blksze)))) 68 | 69 | padded_img = np.zeros((new_rows,new_cols)); 70 | stddevim = np.zeros((new_rows,new_cols)); 71 | 72 | padded_img[0:rows][:,0:cols] = im; 73 | 74 | for i in range(0,new_rows,blksze): 75 | for j in range(0,new_cols,blksze): 76 | block = padded_img[i:i+blksze][:,j:j+blksze]; 77 | 78 | stddevim[i:i+blksze][:,j:j+blksze] = np.std(block)*np.ones(block.shape) 79 | 80 | stddevim = stddevim[0:rows][:,0:cols] 81 | 82 | mask = stddevim > thresh; 83 | 84 | mean_val = np.mean(im[mask]); 85 | 86 | std_val = np.std(im[mask]); 87 | 88 | normim = (im - mean_val)/(std_val); 89 | 90 | return(normim,mask) -------------------------------------------------------------------------------- /enhance/ridge_segment.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/enhance/ridge_segment.pyc -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scikit-image 3 | opencv-python 4 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python /app/app.py "$1" "$2" 3 | -------------------------------------------------------------------------------- /Препознавање на отпечатоци.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjanko/python-fingerprint-recognition/65a6ceba509469f3f838fb91e59eb0c5ee1d0a0a/Препознавање на отпечатоци.docx --------------------------------------------------------------------------------