首页 > 编程问答 >如何在不模糊脊线的情况下增强指纹图像?我正在使用 Django

如何在不模糊脊线的情况下增强指纹图像?我正在使用 Django

时间:2024-09-24 21:25:59浏览次数:1  
标签:python django opencv django-models fingerprint

如何在不模糊脊线的情况下增强指纹图像?我正在使用 Django。 我目前正在使用 OpenCV 开发一个指纹增强项目,当我的代码产生结果时,指纹图像中的脊线变得模糊。 这是我的代码

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"

我目前正在开发一个项目,专注于使用 OpenCV 增强指纹图像。我一直在实施各种技术,包括将图像转换为灰度、应用直方图均衡、执行伽玛校正、使用自适应阈值处理以及执行形态学操作。

最初,这些步骤似乎提高了图像的对比度和清晰度。然而,我遇到了一个问题:指纹中的脊线图案显得模糊而不是清晰。我希望看到清晰、轮廓分明的脊线,但最终结果缺乏清晰度。

我很想听到任何建议或调整,以提高指纹图像中的脊线清晰度。任何建议将不胜感激!


在指纹增强过程中遇到脊线模糊问题,这很正常。已经实施了一些常用的预处理技术,但有些其他技术可以帮助获得更清晰的脊线:

1. 方向图:

  • 指纹图像的主要问题是脊线的方向不同。使用方向图可以增强局部脊线方向,同时最小化来自其他方向的噪声。
  • 可以使用 OpenCV 中可用的 Sobel 算子或其他梯度计算方法来计算方向图。
  • 下面是一个使用 Sobel 算子的简单示例:

    ```python def compute_orientation_map(image): # 计算 x 和 y 方向的梯度 sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=5) sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=5)

     # 计算方向角(弧度)
     orientation = np.arctan2(sobely, sobelx)
    
     return orientation
    

    ```

2. 频率估计:

  • 指纹脊线具有特定的频率。估计此频率并使用它来构建 Gabor 滤波器可以帮助增强脊线。
  • 可以使用傅立叶变换或其他频域分析方法来估计频率。
  • 一旦获得了频率,就可以创建针对该特定频率的 Gabor 滤波器,并将其应用于图像。

3. Gabor 滤波:

  • Gabor 滤波器非常适合增强具有特定方向和频率的特征,例如指纹脊线。
  • 使用计算出的方向图和频率,可以创建一组 Gabor 滤波器,以增强图像的不同部分。
  • 这是一个使用 OpenCV 应用 Gabor 滤波的示例:

    ```python def apply_gabor_filter(image, orientation, frequency): # 定义 Gabor 内核大小 kernel_size = 31

     # 创建 Gabor 内核
     kernel = cv2.getGaborKernel((kernel_size, kernel_size), 5, orientation, frequency, 1, 0, ktype=cv2.CV_32F)
    
     # 将 Gabor 滤波器应用于图像
     filtered_image = cv2.filter2D(image, cv2.CV_8UC3, kernel)
    
     return filtered_image
    

    ```

4. 图像二值化:

  • 处理后的图像可以使用自适应阈值处理方法(如已经使用的)进行二值化。
  • 调整阈值方法的参数以获得最佳结果。

5. 细化脊线:

  • 为了获得更清晰的脊线,可以使用细化算法来细化二值化图像中的脊线。
  • OpenCV 提供了“骨架化”算法,该算法可以有效地执行此操作。

将这些技术纳入的代码:

# ...(现有的代码)...

# 计算方向图
orientation_map = compute_orientation_map(gray)

# 估计脊线频率(需要实现此功能)
frequency = estimate_ridge_frequency(gray)

# 应用 Gabor 滤波
enhanced_image = apply_gabor_filter(gray, orientation_map, frequency)

# ...(现有的二值化和形态学操作)...

# 细化脊线(可选)
skeleton = cv2.ximgproc.thinning(thresh2, thinningType = cv2.ximgproc.THINNING_ZHANG_SUEN)

# ...(现有的代码的其余部分)...

其他提示:

  • 尝试不同的预处理技术组合及其顺序,看看哪些对的图像最有效。
  • 调整每个步骤的参数,以找到最佳设置。
  • 如果可能,请使用高质量的指纹图像,因为图像质量会显着影响最终结果。

通过实施这些额外的技术并微调的代码,应该能够提高指纹图像中脊线的清晰度。

标签:python,django,opencv,django-models,fingerprint
From: 79018835

相关文章

  • 头歌实践教学平台 Python程序设计 实训答案(三)
    第七阶段文件实验一文本文件的读取第1关:学习-Python文件之文本文件的读取任务描述本关任务:使用open函数以只写的方式打开文件,打印文件的打开方式。相关知识为了完成本关任务,你需要掌握:文本文件;open函数及其参数;文件打开模式;文件对象常用属性;关闭文件close......
  • python如何实现日期加减
    首先通过importdatetime,导入日期处理库。然后把日期转化成datetime标准格式,使用datetime.datetime.strptime()方法将字符串格式的时间转化为标准格式。其中"%Y/%m/%d%H:%M:%S"为time字符串的时间格式:Y为年,m为月,d为天,H为小时,M为分钟,S为秒。如果我们要加的时间是天......
  • 如何在django项目中启动websocket服务
    首先下载redis,windows上要下5.0以上的版本,链接为:Releases·tporadowski/redis(github.com)紧接着python要安装redis,channls以及daphne,asgi_redis然后在settings中配置 必须放在第一行,以及channlesWSGI_APPLICATION="start_up_file_km.wsgi.application"ASGI_APPLICATI......
  • Django+Echarts+Ajax动态加载横、纵坐标数据
    前端html页面(不是重点,可以直接不看):<!--第三部分可视化展示模块start--><divid="diff_analysis3_graphic"style="width:1200px;margin:0auto;margin-top:40px;"><divclass="StatHomemainHeaderStyle">&......
  • Python实现图形学光照和着色的Gouraud着色算法
    目录使用Python实现图形学光照和着色的Gouraud着色算法引言1.Gouraud着色算法概述1.1算法原理2.Python实现Gouraud着色算法2.1向量类2.2光源类2.3材质类2.4Gouraud着色器类2.5使用示例3.实例分析4.Gouraud着色算法的优缺点4.1优点4.2缺点5.改进方向6.应......
  • Python实现Phong着色模型算法
    目录使用Python实现Phong着色模型算法引言Phong着色模型的基本原理1.模型组成2.公式Phong着色模型的Python实现1.向量类的实现2.光源类的实现3.材质类的实现4.Phong着色器类的实现整体实现总结使用Python实现Phong着色模型算法引言在计算机图形学中,光照和......
  • 【开题报告】基于django+vue医院电子病历管理(论文+程序)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着医疗技术的飞速发展和医疗信息化建设的不断深入,医院电子病历管理系统已成为现代医疗体系中不可或缺的一部分。传统的纸质病历不仅存储......
  • 头歌实践教学平台 Python程序设计实训答案(二)
    第四阶段组合数据类型实验一列表的基本操作第1关:列表增删改:客人名单的变化任务描述列表是由按一定顺序排列的元素组成,其中的元素根据需要可能会发生变化。其中,列表元素的添加、删除或修改等是最常见的操作。下面以一则请客的故事来说明列表元素操作的应用场景。有个人邀......
  • 1、A+B(python语法格式,模块,主模块等)
    总结:python有许多模块,通过import引入模块,或者使用from从模块导入函数#导入math模块importmath#使用模块中的定义的变量或者函数的语法格式为:模块.变量/函数print(math.sqrt(25))#使用math模块中的sqrt函数,表示开平方根#从math模块中导入sqrtfrommathimpor......
  • 【Python学习笔记】字符串
    目录1.定义字符串2.基本操作2.1索引:2.2访问单个字符:2.3访问范围内字符:2.4单个字符编码3.转义符4.运算符5.格式化6.常用字符串函数6.1查找类函数6.2分割类函数6.3字符串连接方法6.4大小写字符转换方法6.5替换方法6.6删除字符串两端、右端或左端连续空白字符......