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

问题描述 投票:0回答:1

如何去除该指纹图像边缘的外部轮廓线而不影响脊和谷轮廓

加工前

分割和投资回报率之后

应用CLAHE和增强后的结果

[fingerprint] (https://i.stack.imgur.com/TIMu6.jpg)

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)

但没有得到想要的结果。

python opencv image-processing computer-vision fingerprint
1个回答
0
投票

这是一个可能的解决方案。我正在处理二进制图像。您没有显示如何获取此图像,您提到了segmentationCLAHE,但这些操作都没有显示在您的代码片段中。在实际获得指脊的二值图像之前,处理那里的“边界”可能会更容易。

无论如何,我的解决方案假设边界是从左到右扫描图像时遇到的第一个和最后一个斑点。它还假设边界是连续的。我们的想法是找到它们,然后用任何颜色(在本例中为黑色)“洪水填充”它们,以“擦除”它们。 首先,找到最外部的轮廓。可以通过

将图像缩小为一行

来完成。如果使用 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函数的参数即可。这是结果:

    

© www.soinside.com 2019 - 2024. All rights reserved.