Domain Name For Sale

Unlock the Potential of DeeperPython.com: Your Premium Domain for Python in Deep Learning and Machine Learning!

Are you passionate about Python and its incredible applications in the world of deep learning and machine learning? Do you own a domain that...

Monday, June 12, 2023

Contactless Fingerprint Recognition & Verification in Python: Secure and Efficient With Complete Source Code

Contactless Fingerprints Recognition in Python

Background 

This research method proposes a contactless fingerprint recognition system that eliminates the need for physical contact and utilizes pure image processing techniques.The system is designed to run on a normal CPU core i3. The system captures finger photos from a distance using an image sensor or mobile camera and enhances them using image processing methods like Gabor filters and CLAHE. It extracts global features using a Siamese Convolutional Neural Network (CNN) and incorporates minutiae-based features for fingerprint matching. The matching scores obtained from both approaches are fused to generate the final matching score. The system achieves promising results in terms of accuracy, making it a viable option for contactless fingerprint recognition on a standard CPU core i3.

The process begins by capturing finger photos using an image sensor. These photos are then subjected to various image processing techniques, including Gabor filters and Contrast Limited Adaptive Histogram Equalization (CLAHE), among others. These techniques enhance the quality of the fingerprint images and improve the visibility of important features. To extract fingerprint features, a Siamese Convolutional Neural Network (CNN) is specifically designed.

This CNN is responsible for extracting global features from the given finger photos. Global features represent the overall fingerprint patterns and can aid in matching fingerprints accurately. Additionally, the system also incorporates minutiae-based features for fingerprint matching. Minutiae are small, distinctive ridge characteristics such as ridge endings and bifurcations. By analyzing these minutiae, the system can establish more detailed and localized patterns within the fingerprints. The matching process involves computing matching scores based on the CNN-based features and the minutiae-based features. The scores derived from both approaches are then fused to obtain the final matching score between the probe (input fingerprint) and reference fingerprint templates. This fusion process combines the strengths of global and local features, resulting in a more accurate and robust matching mechanism.

Very First, This code is implementing a function called remove_background that removes the background from images in a specified input folder and saves the resulting images in an output folder.

Contactless Fingerprints Preprocessing
Fingerprints Enhancement using Gabor Filter and different techniques

Background Removal Script:


import cv2
import numpy as np
import os

def remove_background(input_folder_path, output_folder_path):

    # Create the output folder if it doesn't exist

    os.makedirs(output_folder_path, exist_ok=True)

    # Loop through all image files in the input folder

    for file_name in os.listdir(input_folder_path):

        # Check if the file is an image

        if file_name.endswith('.jpg') or file_name.endswith('.png'):

            # Construct the full input and output file paths

            input_file_path = os.path.join(input_folder_path, file_name)

            output_file_path = os.path.join(output_folder_path, file_name)


            # Read the image

            imgo = cv2.imread(input_file_path)


            # Removing the background

            height, width = imgo.shape[:2]


            # Create a mask holder

            mask = np.zeros(imgo.shape[:2], np.uint8)


            # Grab Cut the object

            bgdModel = np.zeros((1, 65), np.float64)

            fgdModel = np.zeros((1, 65), np.float64)


            # Hard Coding the Rect… The object must lie within this rect.

            rect = (10, 10, width - 30, height - 30)

            cv2.grabCut(imgo, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)

            mask = np.where((mask == 2) | (mask == 0), 0, 1).astype("uint8")

            img1 = imgo * mask[:, :, np.newaxis]

            # Get the background

            background = cv2.absdiff(imgo, img1)

            # Change all pixels in the background that are not dark enough to white

            background[np.where((background > [30, 30, 30]).all(axis=2))] = [255, 255, 255]

            # Add the background and the image

            final = background + img1

            # To be done – Smoothening the edges….

            cv2.imwrite(output_file_path, final)

            # Delete the input file

            os.remove(input_file_path)

# Replace the folder paths

input_folder_path = r"C:\Users\FingerPrintRecognition\ReducedImages"

output_folder_path = r"C:\\FingerPrintRecognition\BackgroundRemoves"

remove_background(input_folder_path, output_folder_path)


Image Processing Code for Fingerprints Pattern Enhancement

import os
import cv2
import numpy as np
from skimage import io
from skimage.filters import frangi


def gabor_filter(img, sigma, theta, lambd, gamma, psi):
    ksize = 31
    kernel = cv2.getGaborKernel((ksize, ksize), sigma, theta, lambd, gamma, psi, ktype=cv2.CV_64F)
    enhanced_img = cv2.filter2D(img, cv2.CV_64F, kernel)

    enhanced_img = np.abs(enhanced_img)
    enhanced_img = ((enhanced_img - np.min(enhanced_img)) / (np.max(enhanced_img) - np.min(enhanced_img))) * 255

    return enhanced_img.astype(np.uint8)


def enhance_image(img):
    # create a CLAHE object
    clahe = cv2.createCLAHE(clipLimit=5, tileGridSize=(12, 12))
    img = clahe.apply(img)

    enhanced_img = enhance_ridges(img)
    return enhanced_img


def normalize(img):
    img_min, img_max = np.min(img), np.max(img)
    normalized_img = (img - img_min) * (255 / (img_max - img_min))
    return normalized_img.astype(np.uint8)


def enhance_ridges(img):
    img = normalize(img)

    sigmas = [1, 2, 3]
    thetas = [np.pi * t / 6 for t in range(12)]
    lambd = 3
    gamma = 0.5
    psi = 0

    filtered_imgs = []
    for sigma in sigmas:
        for theta in thetas:
            filtered_img = gabor_filter(img, sigma, theta, lambd, gamma, psi)
            filtered_imgs.append(filtered_img)

    enhanced_img = np.max(filtered_imgs, axis=0)
    return enhanced_img


def binarize(img):
    blockSize = 15
    C = 3
    binary_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize, C)
    return binary_img


def denoise(img):
    kernel = np.ones((1, 1), np.uint8)
    opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
    return closing


def process_fingerprint(img):
    enhanced_img = enhance_image(img)
    binary_img = binarize(enhanced_img)
    denoised_img = denoise(binary_img)
    return denoised_img


def main():
    input_dir = r"C:\Users\PycharmProjects\FingerPrintRecognition\BackgroundRemoves"  # Input folder path
    output_dir = r"C:\Users\PycharmProjects\FingerPrintRecognition\frangi"  # Output folder path

    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    for filename in os.listdir(input_dir):
        if filename.endswith(".jpg") or filename.endswith(".png"):
            img_path = os.path.join(input_dir, filename)
            img = io.imread(img_path, as_gray=True)
            img = (img * 255).astype(np.uint8)

            processed_fingerprint = process_fingerprint(img)

            output_filename = f"{os.path.splitext(filename)[0]}.png"
            output_img_path = os.path.join(output_dir, output_filename)
            cv2.imwrite(output_img_path, processed_fingerprint)

            print(f"Processed and saved {output_filename} to the output directory.")
            os.remove(img_path)
            print(f"Deleted {filename} from the input directory.")

    print("All images processed successfully.")


if __name__ == "__main__":
    main()

Fingerprints Matching and Verification

import numpy as np
import cv2 as cv
import glob, os


def match_fingerprints(single_image_folder, multiple_images_folder):
    # Assume the single image is the first one in the directory
    single_image_file = os.listdir(single_image_folder)[0]
    single_image_path = os.path.join(single_image_folder, single_image_file)

    input_img = cv.imread(single_image_path)
    input_img = input_img.astype('uint8')
    gray = cv.cvtColor(input_img, cv.COLOR_BGR2GRAY)
    sift = cv.SIFT_create()
    kp1, des1 = sift.detectAndCompute(input_img, None)

    flag = 0
    highest_match_percentage = 0
    highest_match_file = None

    for file in os.listdir(multiple_images_folder):
        frame_path = os.path.join(multiple_images_folder, file)
        frame = cv.imread(frame_path)
        frame = frame.astype('uint8')
        gray1 = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

        sift = cv.SIFT_create()
        kp2, des2 = sift.detectAndCompute(frame, None)

        FLANN_INDEX_KDTREE = 0
        index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
        search_params = dict(checks=50)
        flann = cv.FlannBasedMatcher(index_params, search_params)
        matches = flann.knnMatch(des1, des2, k=2)
        good = []
        for m, n in matches:
            if m.distance < 0.7 * n.distance:
                good.append(m)

        total_keypoints = min(len(kp1), len(kp2))

        if total_keypoints > 0:
            match_percentage = len(good) / total_keypoints * 100
            print(f"Matched {file} with match percentage: {match_percentage}%")

            if match_percentage > highest_match_percentage:
                highest_match_percentage = match_percentage
                highest_match_file = file

        if len(good) > 10:
            src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
            dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
            M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)
            matchesMask = mask.ravel().tolist()
            flag = 1
        else:
            matchesMask = None

        draw_params = dict(matchColor=(0, 255, 0),  # draw matches in green color
                           singlePointColor=None,
                           matchesMask=matchesMask,  # draw only inliers
                           flags=2)

        img1_kp = cv.drawKeypoints(input_img, kp1, None)
        img2_kp = cv.drawKeypoints(frame, kp2, None)

        img3 = cv.drawMatches(img1_kp, kp1, img2_kp, kp2, good, None, **draw_params)

    if flag == 0:
        print("No Matches among the given set!!")
    else:
        print(f"Highest match file: {highest_match_file} with match percentage: {highest_match_percentage}%")

    # Delete the single_image_path file after all processing is complete
    if os.path.isfile(single_image_path):
        os.remove(single_image_path)

    return os.path.splitext(highest_match_file)[0] if highest_match_file else None

Code Summary and Conclusion

The code provided implements several functions related to fingerprint image processing and matching. It utilizes various image processing techniques and algorithms to enhance fingerprint images, remove background, and match a single fingerprint image with a set of multiple fingerprint images. The following is a summary of each component:

Remove Background

The "remove_background" function takes an input folder path and an output folder path as parameters. It iterates through the files in the input folder and processes each image to remove the background using the GrabCut algorithm. The resulting foreground image is saved in the output folder.

Fingerprint Image Enhancement

The code includes functions for enhancing fingerprint images. It applies Contrast Limited Adaptive Histogram Equalization (CLAHE) to improve image contrast and uses Gabor filters to enhance the ridges in the fingerprint. The enhanced images are then converted to binary form through adaptive thresholding and noise removal techniques.

SIFT-Based Fingerprint Matching

The "match_fingerprints" function implements a fingerprint matching algorithm using the Scale-Invariant Feature Transform (SIFT) technique. It takes a single fingerprint image and a folder of multiple fingerprint images as input. The SIFT algorithm is used to detect and compute the keypoints and descriptors for the images. The FLANN matcher is applied to find matches between the descriptors, and the match percentage is calculated. The function returns the filename of the image with the highest match percentage.

Overall, the code provides functionalities to remove background from fingerprint images, enhance the quality of fingerprint images, and match a single fingerprint image with a set of multiple images using the SIFT algorithm. These components contribute to the broader goal of fingerprint image processing and analysis.

No comments:

Post a Comment