从指纹图像中去除边框轮廓

3
如何在不影响脊线和谷线轮廓的情况下去除指纹图像边缘的外部轮廓线
处理前

original photo

分割和感兴趣区域(ROI)之后

segmentation and roi

应用CLAHE和增强后的结果

[fingerprint] (https://istack.dev59.com/TIMu6.webp)

import cv2

image = cv2.imread('fingerprint.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (9,9), 0)
thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
dilate = cv2.dilate(opening, dilate_kernel, iterations=5)

cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
    ROI = original[y:y+h, x:x+w]
    break

cv2.imshow('ROI', ROI)

但是我没有得到期望的结果。


1
你有原始的非二元图像吗?还是直接从扫描仪捕捉这个图像?假设外部轮廓是最大的,你可以通过长度进行过滤,甚至可以使用边界框面积... - stateMachine
是的,我做了。这个指纹是从相机中捕捉到的,并且经过了ROI裁剪。在应用CLAHE和其他预处理操作之后,我得到了上述结果。 - dmetrosoft
@dmetrosoft请在处理之前提供原始的未经处理的图像。 - Bilal
@Bilal 我已经包含了原始图片。 - dmetrosoft
没有边界,那只是闪电的阴影。 - toyota Supra
1个回答

3
这是一个可能的解决方案。我正在处理二进制图像。你没有展示如何获得这个图像,你提到了“分割”和“CLAHE”,但在你的代码片段中没有展示这些操作。在实际获取指纹脊线的二进制图像之前,也许更容易处理那里的“边界”。
无论如何,我的解决方案假设边界是在从左到右扫描图像时首先遇到的第一个和最后一个斑点。它还假设边界是连续的。这个想法是定位它们,然后用任何颜色(在这种情况下是黑色)填充它们,以“擦除”它们。
首先,找到最外部的轮廓。可以通过将图像缩小为一行来实现。使用“MAX”模式进行缩小后,缩小的行将给出第一个和最后一个白色像素的精确水平位置 - 这应该对应于外部边界。由于边界似乎位于图像的上部,您可以只选择您确定边界位置的部分。
import cv2
# Set image path
imagePath = "D://opencvImages//TIMu6.jpg"

# Load image:
image = cv2.imread(imagePath)

# Get binary image:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binaryImage = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]
showImage("Binary", binaryImage)

# BGR of binary image:
bgrImage = cv2.cvtColor(binaryImage, cv2.COLOR_GRAY2BGR)
bgrCopy = bgrImage.copy()

# Get image dimensions:
imageHeight, imageWidth = binaryImage.shape[0:2]

# Vertically divide in 4 parts:
heightDivision = 4
heightPortion = imageHeight // heightDivision

# Store divisions here:
imageDivisions = []

# Check out divisions:
for i in range(heightDivision):
    # Compute y coordinate:
    y = i * heightPortion

    # Set crop dimensions:
    x = 0
    w = imageWidth
    h = heightPortion

    # Crop portion:
    portionCrop = binaryImage[y:y + h, x:x + w]

    # Store portion:
    imageDivisions.append(portionCrop)

    # Draw rectangle:
    cv2.rectangle(bgrImage, (0, y), (w, y + h), (0, 255, 0), 1)
    cv2.imshow("Portions", bgrImage)
    cv2.waitKey(0)

这个初始部分只是将图像垂直分割成四个部分。仅供视觉目的,让我们看到这四个区域:

我将每个部分存储在imageDivisions列表中,但您只需要第一个部分。接下来,使用MAX模式将其减少为一行:
# Reduce first portion to a row:
reducedImage = cv2.reduce(imageDivisions[0], 0, cv2.REDUCE_MAX)

这将垂直地“压缩”矩阵成为一行(即垂直投影),其中每个像素值都是每列的最大值(在本例中为255 - 白色)。结果是一个有点难以看清的小行:

让我们搜索第一个和最后一个白色像素。您只需在此数组中寻找从黑到白和从白到黑的转换即可:

# Get first and last white pixel positions:
pastPixel = 0
pixelCoordinates = []
for i in range(imageWidth):
    # Get current pixel:
    currentPixel = reducedImage[0][i]

    # Search for first transition black to white:
    if currentPixel == 255 and pastPixel == 0:
        pixelCoordinates.append(i)
    else:
        # Search for last transition white to black:
        if currentPixel == 0 and pastPixel == 255:
            pixelCoordinates.append(i - 1)

    # Set last pixel:
    pastPixel = currentPixel

白色像素的水平坐标存储在pixelCoordinates列表中。最后,让我们将其作为定位最外部边界并进行填充的位置使用:
# Flood fill original image:
color = (0, 0, 255)  # Red

for i in range(len(pixelCoordinates)):
    # Get x coordinate:
    x = pixelCoordinates[i]
    # Set y coordinate:
    y = heightPortion

    # Set seed point:
    seedPoint = (x, y)
    # Flood-fill:
    cv2.floodFill(bgrCopy, None, seedPoint, color)
    cv2.imshow("Flood-filled", bgrCopy)
    cv2.waitKey(0)

这里我实际上正在对原始的BGR图像进行深度复制,并使用红色进行泛洪填充。 如果你想用黑色填充边框,只需将color更改为(0,0,0)。如果你想要对原始二进制图像进行泛洪填充,只需更改floodFill函数的第一个参数。这是结果:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接