opencv 从指纹图像中去除边界轮廓

lztngnrs  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(124)

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

处理前

分割和ROI后

应用CLAHE和增强后的结果

[

](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)

但我没有得到想要的结果。

jtw3ybtb

jtw3ybtb1#

这里有一个可能的解决方案。我正在处理二进制图像。您没有显示如何获得此图像,您提到了 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函数的first参数。结果如下:

相关问题