如何在不模糊脊线的情况下增强指纹图像?我正在使用 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