Извлечение отпечатков пальцев из фотографии – утончение линийPython

Программы на Python
Ответить
Anonymous
 Извлечение отпечатков пальцев из фотографии – утончение линий

Сообщение Anonymous »

Я работаю над школьным проектом для своего класса биометрии. Я должен извлечь тип отпечатка пальца из поля направления (арка, направленная дуга, петля, завиток, двойная петля) и минуты из гребней.
Мне как-то удалось это сделать. извлеките линии из образца фотографии, но, несмотря на все виды фильтров, результат все равно очень-очень шумный и непригоден для извлечения минут. Мне нужны несколько советов относительно используемой фильтрации. Я понял, что одна из проблем заключается в том, что линии не связаны, а наличие шума делает невозможным поиск реальных минут. Я пробовал фильтры Гаусса, двусторонние фильтры, фильтры Габора и все такое. Это лучший результат, который мне удалось получить.
Это мой код (полностью рабочий, автономный пример). В этот пост также включен пример вывода, демонстрирующий проблемы, с которыми я столкнулся. Кроме того, я добавил фотографию отпечатка пальца в конце этого поста (это стандартная фотография, я обычно использую свои собственные отпечатки пальцев, которые не очень хочу публиковать здесь):

Код: Выделить всё

import cv2
import numpy as np
import math
import matplotlib.pyplot as plt

# Hardcoded path to input image
IMAGE_PATH = '20241108_171310.jpg'  # Replace with the path to your image

# Extracts the finger
def crop_image(image):
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# I use skin tone to get the boundaries.  There may be better options.
lower_skin = np.array([0, 0, 80], dtype=np.uint8)
upper_skin = np.array([7, 255, 255], dtype=np.uint8)
lower_skin2 = np.array([170, 0, 80], dtype=np.uint8)
upper_skin2 = np.array([179, 255, 255], dtype=np.uint8)

skin_mask = cv2.bitwise_or(cv2.inRange(hsv_image, lower_skin, upper_skin),
cv2.inRange(hsv_image, lower_skin2, upper_skin2))
skin_mask = cv2.GaussianBlur(skin_mask, (51, 51), 20)
skin_mask = cv2.inRange(skin_mask, 200, 255)
contours, _ = cv2.findContours(skin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

if not contours:
return image

largest_contour = max(contours, key=cv2.contourArea)
blacked = cv2.bitwise_and(image, image, mask=skin_mask)

x, y, w, h = cv2.boundingRect(largest_contour)
h = min(int(1.5 * w), h)
cropped_image = blacked[y:y + h, x:x + w]

return cropped_image

# Scales to target resolution
def scale_image(image, final_width):
coefficient = final_width / image.shape[1]
return cv2.resize(image, (int(image.shape[1] * coefficient), int(image.shape[0] * coefficient)))

# Calculates and draws the direction field out of sobel gradients
def draw_directions(directions, image, tile_size):
for y in range(directions.shape[0]):
for x in range(directions.shape[1]):
cx = x * tile_size + tile_size // 2
cy = y * tile_size + tile_size // 2
dir_x, dir_y = np.cos(directions[y, x]), np.sin(directions[y, x])
magnitude = math.sqrt(dir_x ** 2 + dir_y ** 2)
dir_x /= magnitude
dir_y /= magnitude
line_length = 15
x_end = cx + int(dir_x * line_length / 2)
y_end = cy + int(dir_y * line_length / 2)
x_start = cx - int(dir_x * line_length / 2)
y_start = cy - int(dir_y * line_length / 2)
cv2.line(image, (x_start, y_start), (x_end, y_end), color=(0, 0, 255), thickness=2)

def get_directions(grad_x, grad_y, image_shape, tile_size):
directions = np.zeros((image_shape[0] // tile_size, image_shape[1] // tile_size), dtype=np.float32)
for y in range(image_shape[0] // tile_size):
for x in range(image_shape[1] // tile_size):
tile_grad_x = grad_x[y * tile_size:(y + 1) * tile_size, x * tile_size:(x + 1) * tile_size]
tile_grad_y = grad_y[y * tile_size:(y + 1) * tile_size, x * tile_size:(x + 1) * tile_size]

a = 2 * np.sum(tile_grad_x * tile_grad_y)
b = np.sum(tile_grad_x ** 2 - tile_grad_y ** 2)
directions[y, x] = 0.5 * np.arctan2(a, b) + np.pi / 2

return directions

def extract_lines(grayscale_image):
# Enhance contrast
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
enhanced = clahe.apply(grayscale_image)

# Apply stronger Gaussian blur
enhanced = cv2.GaussianBlur(enhanced, (5, 5), 3)

# Adaptive thresholding with adjusted parameters
thresholded = cv2.adaptiveThreshold(enhanced, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
31, -2)

# Morphological operations
kernel = np.ones((2, 2), np.uint8)
thresholded = 255 - cv2.erode(255 - thresholded, kernel, iterations=1)

# Enhance continuity
thresholded = enhance_continuity(thresholded)

return thresholded

def enhance_continuity(binary_image):
kernel = np.ones((3, 3), np.uint8)
# Close small gaps
closed = cv2.morphologyEx(binary_image, cv2.MORPH_CLOSE, kernel)
# Remove small noise
opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)
return opened

def thin_lines(binary_image):
# Ensure ridges are white, valleys are black for thinning operation
thinned = cv2.ximgproc.thinning(binary_image)
return thinned

def connect_ridges(thinned_image, max_gap=5):
result = thinned_image.copy()

# Find endpoints
kernel = np.array([[1, 1, 1],
[1, 10, 1],
[1, 1, 1]], dtype=np.uint8)
conv = cv2.filter2D(result.astype(np.float32), -1, kernel)
endpoints = np.where((conv == 11) &  (result == 255))

# Connect nearby endpoints
for i in range(len(endpoints[0])):
y1, x1 = endpoints[0][i], endpoints[1][i]
for j in range(i + 1, len(endpoints[0])):
y2, x2 = endpoints[0][j], endpoints[1][j]
dist = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
if 0 < dist  1 else None)
plt.title(titles[i])
plt.axis('off')
plt.tight_layout()
plt.show()
Изображение
Изображение


Подробнее здесь: https://stackoverflow.com/questions/791 ... e-thinning
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»