【发布时间】:2021-09-03 15:36:47
【问题描述】:
【问题讨论】:
标签: python python-3.x opencv opencv4
【问题讨论】:
标签: python python-3.x opencv opencv4
这是一个可能的解决方案。它涉及使用 morphology 创建复选框的掩码。我们首先创建一个垂直蒙版,这样所有高于一定高度的元素都将在形态学操作中幸存下来。我们重复此步骤以获得水平蒙版,现在寻找超过一定宽度的元素。连接两个掩码将产生一个最终掩码,其中应包含复选框和一些小噪声。最后,我们可以通过检测最终图像上的轮廓并根据区域过滤斑点来过滤噪声。该算法非常简单,步骤如下:
让我们看看代码:
# Imports:
import numpy as np
import cv2
# Set image path and image name:
path = "D://opencvImages//"
fileName = "74k9I.png"
# Read the image in default mode:
inputImage = cv2.imread(path + fileName)
# Prepare a deep copy for results:
inputImageCopy = inputImage.copy()
# Convert BGR to Grayscale
grayImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Threshold via Otsu:
_, binaryImage = cv2.threshold(grayImage, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
第一位产生初始二进制掩码:
让我们应用形态学。我正在应用erosion,然后是dilation。结构元素 (SE) 只是大小为8 x 1 的(矩形)列。尺寸将“擦除”图像上低于 SE 设置的高度的斑点。这将创建垂直蒙版:
# Create Vertical Mask:
opIterations = 1
# Structuring Element dimensions:
kernelCols = 1
kernelRows = 8
# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelCols, kernelRows))
# Perform Erode and Dilate:
verticalMask = cv2.morphologyEx(binaryImage, cv2.MORPH_ERODE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)
verticalMask = cv2.morphologyEx(verticalMask, cv2.MORPH_DILATE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)
这是垂直掩码:
好的,现在让我们重复这个过程,但这次我们将切换 SE 的尺寸以创建一行 1 x 8。这将隔离更广泛的元素,请务必对初始二进制掩码进行操作:
# Create Horizontal Mask:
# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelRows, kernelCols))
# Perform Erode and Dilate:
horizontalMask = cv2.morphologyEx(binaryImage, cv2.MORPH_ERODE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)
horizontalMask = cv2.morphologyEx(horizontalMask, cv2.MORPH_DILATE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)
这是水平掩码:
我们可能可以通过调整 SE 的尺寸来调整过滤器,但现在,让我们看看这个结果。让我们通过ORing 这两个图像来生成最终的蒙版:
# OR the masks to create the final checkbox mask:
finalMask = cv2.bitwise_or(verticalMask, horizontalMask)
生成此图像的最终复选框掩码:
请注意,复选框大部分不受过滤管道的干扰,尽管仍然存在一些噪音。然而,复选框是图像中较大的元素——它们也比剩余的噪声大得多。让我们检测轮廓并使用最小面积(和最大)阈值对其进行过滤。我们还可以将复选框的轮廓近似为漂亮的边界矩形:
# Get contours of the final mask:
contours, hierarchy = cv2.findContours(finalMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Store the checkbox bounding rectangle here:
rectanglesList = []
# Look for the outer bounding boxes (no children):
for _, c in enumerate(contours):
# Get current blob area:
currentArea = cv2.contourArea(c)
# Set a min area threshold:
minArea = 150
maxArea = 200
# Look for target contours:
if minArea < currentArea < maxArea:
# Approximate the contour to a polygon:
contoursPoly = cv2.approxPolyDP(c, 3, True)
# Get the polygon's bounding rectangle:
boundRect = cv2.boundingRect(contoursPoly)
# Store rectangles in list:
rectanglesList.append(boundRect)
# Get the dimensions of the bounding rect:
rectX = boundRect[0]
rectY = boundRect[1]
rectWidth = boundRect[2]
rectHeight = boundRect[3]
# Set bounding rect:
color = (0, 0, 255)
cv2.rectangle( inputImageCopy, (int(rectX), int(rectY)),
(int(rectX + rectWidth), int(rectY + rectHeight)), color, 2 )
cv2.imshow("Checkboxes", inputImageCopy)
cv2.waitKey(0)
另外请注意,我将边界矩形存储在rectanglesList 中。这是最终的图像,目标边界矩形用红色绘制:
【讨论】: