How to Enhance Fingerprint Images Without Blurring Ridges? i am using django [closed]

How to Enhance Fingerprint Images Without Blurring Ridges? i am using django. I'm currently working on a fingerprint enhancement project using OpenCV, and while my code is producing results, the ridges in the fingerprint images are coming out blurred. here is my code

import cv2
import numpy as np
import math
import fingerprint_enhancer  # Ensure this module is available
from django.shortcuts import render
from django.core.files.base import ContentFile
from .forms import HandFingerForm
from .models import ThumbImage
import base64

MAX_IMAGES = 10

def remove_green(img):
    empty_img = np.zeros_like(img)
    RED, GREEN, BLUE = (2, 1, 0)
    reds = img[:, :, RED]
    greens = img[:, :, GREEN]
    blues = img[:, :, BLUE]
    
    # Create a mask for the areas to keep
    tmpMask = (greens < 35) | (reds > greens) | (blues > greens)
    img[tmpMask == 0] = (0, 0, 0)  # Remove background from original picture
    empty_img[tmpMask] = (255, 255, 255)  # Mask with finger in white
    return img, empty_img

def detect_nail(gray_mask_finger):
    # Find contours in the mask image
    contours, _ = cv2.findContours(gray_mask_finger, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
        # Only consider large enough contours as nails
        if cv2.contourArea(contour) > 100:  # Adjust this threshold as needed
            x, y, w, h = cv2.boundingRect(contour)
            # Draw a rectangle around the detected nail
            cv2.rectangle(gray_mask_finger, (x, y), (x + w, y + h), (255, 0, 0), 2)  # Blue rectangle

def process_fingerprint(image):
    clip_hist_percent = 25

    # Convert to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Calculate grayscale histogram
    hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
    hist_size = len(hist)

    # Calculate cumulative distribution from the histogram
    accumulator = []
    accumulator.append(float(hist[0]))
    for index in range(1, hist_size):
        accumulator.append(accumulator[index - 1] + float(hist[index]))

    # Locate points to clip
    maximum = accumulator[-1]
    clip_hist_percent *= (maximum / 100.0)
    clip_hist_percent /= 2.0

    # Locate left cut
    minimum_gray = 0
    while accumulator[minimum_gray] < clip_hist_percent:
        minimum_gray += 1

    # Locate right cut
    maximum_gray = hist_size - 1
    while accumulator[maximum_gray] >= (maximum - clip_hist_percent):
        maximum_gray -= 1

    # Calculate alpha and beta values
    alpha = 255 / (maximum_gray - minimum_gray)
    beta = -minimum_gray * alpha

    auto_result = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)

    gray = cv2.cvtColor(auto_result, cv2.COLOR_BGR2GRAY)

    # Compute gamma
    mid = 0.5
    mean = np.mean(gray)
    gamma = math.log(mid * 255) / math.log(mean)
    
    # Apply gamma correction
    img_gamma = np.power(auto_result, gamma).clip(0, 255).astype(np.uint8)
    g1 = cv2.cvtColor(img_gamma, cv2.COLOR_BGR2GRAY)

    # Adaptive thresholding
    thresh2 = cv2.adaptiveThreshold(g1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                    cv2.THRESH_BINARY, 199, 3)

    # Morphological operations
    blur = ((3, 3), 1)
    erode_ = (5, 5)
    dilate_ = (3, 3)
    dilate = cv2.dilate(cv2.erode(cv2.GaussianBlur(thresh2 / 255, blur[0], blur[1]),
                                    np.ones(erode_)), np.ones(dilate_)) * 255

    # Enhance fingerprint
    out = fingerprint_enhancer.enhance_Fingerprint(dilate)
    
    return out

def upload_image(request):
    if 'upload_count' not in request.session:
        request.session['upload_count'] = 0

    upload_count = request.session['upload_count']

    if request.method == 'POST':
        if 'skip' in request.POST:
            request.session['upload_count'] = 0
            return render(request, 'captureimage.html', {
                'message': 'Skipped the remaining uploads.',
                'next_finger': None,
                'max_images': MAX_IMAGES
            })

        finger_number = request.POST.get('finger')
        image_data = request.POST.get('image')

        if not image_data or ';base64,' not in image_data:
            return render(request, 'captureimage.html', {
                'error': 'Invalid image data',
                'next_finger': upload_count + 1,
                'max_images': MAX_IMAGES
            })

        try:
            format, imgstr = image_data.split(';base64,')
        except ValueError:
            return render(request, 'captureimage.html', {
                'error': 'Failed to parse image data',
                'next_finger': upload_count + 1,
                'max_images': MAX_IMAGES
            })

        ext = format.split('/')[-1]
        image_file = ContentFile(base64.b64decode(imgstr), name=f'finger_{finger_number}.{ext}')

        form_data = {'finger': finger_number}
        form_files = {'image': image_file}

        form = HandFingerForm(form_data, form_files)

        if form.is_valid():
            form.save()

            # Load and process the saved image
            saved_image_path = form.instance.image.path
            image = cv2.imread(saved_image_path, 1)  # Load the image
            image = cv2.resize(image, None, fx=0.3, fy=0.3)  # Resize
            image = cv2.GaussianBlur(image, (3, 3), 0)  # Apply Gaussian blur

            # Process fingerprint
            enhanced_image = process_fingerprint(image)

            # Remove green background
            no_green_image, mask_finger = remove_green(enhanced_image)

            # Convert to grayscale
            gray_mask_finger = cv2.cvtColor(mask_finger, cv2.COLOR_BGR2GRAY)

            # Call the function to detect nail
            detect_nail(gray_mask_finger)

            request.session['upload_count'] += 1

            if request.session['upload_count'] < MAX_IMAGES:
                return render(request, 'captureimage.html', {
                    'message': 'Finger image uploaded successfully.',
                    'next_finger': request.session['upload_count'] + 1,
                    'max_images': MAX_IMAGES
                })
            else:
                request.session['upload_count'] = 0
                return render(request, 'captureimage.html', {
                    'message': 'All 10 images uploaded successfully!',
                    'next_finger': None,
                    'max_images': MAX_IMAGES
                })
        else:
            return render(request, 'captureimage.html', {
                'error': 'Invalid form data',
                'details': form.errors,
                'next_finger': upload_count + 1,
                'max_images': MAX_IMAGES
            })

    return render(request, 'captureimage.html', {
        'next_finger': request.session['upload_count'] + 1,
        'max_images': MAX_IMAGES
    })

#frontend

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Capture Finger Image</title>
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
  <style>
    body {
      font-family: 'Roboto', sans-serif;
      background-color: #f4f4f9;
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }

    .container {
      background: #ffffff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
      max-width: 500px;
      width: 100%;
      text-align: center;
    }

    h2 {
      margin-bottom: 20px;
      color: #333;
    }

    #instructions {
      font-size: 1.1em;
      margin-bottom: 20px;
      color: #555;
    }

    #video {
      width: 100%;
      border-radius: 8px;
      margin-bottom: 10px;
      border: 2px solid #007bff;
    }

    #preview {
      margin: 10px 0;
    }

    #capturedImage {
      max-width: 100%;
      border-radius: 8px;
      border: 2px solid #28a745;
    }

    select {
      width: 100%;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 4px;
      margin-bottom: 20px;
      font-size: 1em;
    }

    .button-group {
      display: flex;
      justify-content: space-between;
      flex-wrap: wrap;
      margin-top: 20px;
    }

    button {
      background-color: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      padding: 10px 15px;
      font-size: 1em;
      cursor: pointer;
      transition: background-color 0.3s;
      flex: 1;
      margin: 5px;
    }

    button:hover {
      background-color: #0056b3;
    }

    .skip-btn {
      background-color: #dc3545;
    }

    .skip-btn:hover {
      background-color: #c82333;
    }

    /* Responsive styles */
    @media (max-width: 600px) {
      .button-group {
        flex-direction: column;
      }

      button {
        margin: 5px 0;
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>Capture Finger Image</h2>
    
    <div id="instructions">
      Please select a finger and place it in front of the camera with good lighting for a clear image.
    </div>
    
    <!-- Display Success or Error Message -->
    {% if message %}
      <p style="color:green;">{{ message }}</p>
    {% elif error %}
      <p style="color:red;">{{ error }}</p>
    {% endif %}
    
    <div class="video-container">
      <!-- Video stream -->
      <video id="video" autoplay></video>
      
      <!-- Preview for captured image -->
      <div id="preview">
        <p>Captured Image:</p>
        <img id="capturedImage" src="" alt="No image captured yet">
      </div>
    </div>
    
    <!-- Dropdown for selecting finger -->
    <form id="fingerForm">
      <select id="fingerSelect" name="finger">
        <option value="">Select Finger</option>
        <option value="Right Thumb">Right Thumb</option>
        <option value="Left Thumb">Left Thumb</option>
        <option value="Right Index">Right Index</option>
        <option value="Left Index">Left Index</option>
        <option value="Right Middle">Right Middle</option>
        <option value="Left Middle">Left Middle</option>
        <option value="Right Ring">Right Ring</option>
        <option value="Left Ring">Left Ring</option>
        <option value="Right Pinky">Right Pinky</option>
        <option value="Left Pinky">Left Pinky</option>
      </select>
    </form>

    <div class="button-group">
      <button id="snap">Capture Finger Image</button>

      <!-- Image Upload Form -->
      <form id="imageForm" action="{% url 'upload_image' %}" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        <input type="hidden" name="image" id="imageInput">
        <button type="submit" id="uploadButton" disabled>Upload Finger Image</button>
      </form>
      
      <!-- Skip Button -->
      <form action="{% url 'upload_image' %}" method="POST">
        {% csrf_token %}
        <button type="submit" class="skip-btn" name="skip" value="true">Skip Remaining</button>
      </form>
    </div>
  </div>

  <script>
    const video = document.getElementById('video');
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    const snap = document.getElementById('snap');
    const imageInput = document.getElementById('imageInput');
    const capturedImage = document.getElementById('capturedImage');
    const uploadButton = document.getElementById('uploadButton');
    const fingerSelect = document.getElementById('fingerSelect');

    // Access the camera with higher resolution for better detail
    navigator.mediaDevices.getUserMedia({ video: { width: 1280, height: 720 } })
      .then((stream) => {
        video.srcObject = stream;
      })
      .catch((error) => {
        console.error("Error accessing camera: ", error);
      });

    // Capture image on button click
    snap.addEventListener('click', () => {
      // Check if a finger is selected
      if (fingerSelect.value === "") {
        alert("Please select a finger before capturing the image.");
        return;
      }

      // Set canvas size to match the video feed
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;

      // Apply a sharpness filter to enhance the fingerprint details
      context.filter = 'contrast(1.5) brightness(1.2)'; // Adjust contrast and brightness for clarity
      context.drawImage(video, 0, 0, canvas.width, canvas.height);

      // Convert the canvas image to base64
      const dataURL = canvas.toDataURL('image/png');
      imageInput.value = dataURL; // Set base64 image in hidden input

      // Display the captured image in the img tag
      capturedImage.src = dataURL;

      // Set the selected finger in the form data
      const fingerInput = document.createElement('input');
      fingerInput.type = 'hidden';
      fingerInput.name = 'finger';
      fingerInput.value = fingerSelect.value;
      document.getElementById('imageForm').appendChild(fingerInput);

      // Enable the upload button
      uploadButton.disabled = false;
    });

    // Enable form submission when a finger is selected
    fingerSelect.addEventListener('change', () => {
      if (fingerSelect.value !== "") {
        uploadButton.disabled = true; // Reset button state
      }
    });
  </script>
</body>
</html>

#models.py

from django.db import models

class ThumbImage(models.Model):
    FINGER_CHOICES = [
        ('Right Thumb', 'Right Thumb'),
        ('Left Thumb', 'Left Thumb'),
        ('Right Index', 'Right Index'),
        ('Left Index', 'Left Index'),
        ('Right Middle', 'Right Middle'),
        ('Left Middle', 'Left Middle'),
        ('Right Ring', 'Right Ring'),
        ('Left Ring', 'Left Ring'),
        ('Right Pinky', 'Right Pinky'),
        ('Left Pinky', 'Left Pinky'),
    ]
    finger = models.CharField(max_length=50, choices=FINGER_CHOICES)
    image = models.ImageField(upload_to='finger_images/')

    def __str__(self):
        return f"{self.finger} image"

I’m currently working on a project that focuses on enhancing fingerprint images using OpenCV. I've been implementing various techniques, including converting the images to grayscale, applying histogram equalization, performing gamma correction, using adaptive thresholding, and carrying out morphological operations.

Initially, these steps seemed to improve the contrast and clarity of the images. However, I've encountered a problem: the ridge patterns in the fingerprints appear blurred instead of sharp. I expected to see clear, well-defined ridges, but the final results are lacking in clarity.

I would love to hear any suggestions or adjustments I can make to improve the ridge clarity in my fingerprint images. Any advice would be greatly appreciated!

Back to Top