【问题标题】:How to get the checkbox position or region on the image using OpenCV [duplicate]如何使用 OpenCV 获取图像上的复选框位置或区域
【发布时间】:2021-09-03 15:36:47
【问题描述】:

我的目标是使用 openCV 检测所有复选框的位置,并使用该位置来检测是否选中了哪个复选框。

你能给我一些帮助吗?

谢谢。

有一个我想使用的图像示例

【问题讨论】:

    标签: python python-3.x opencv opencv4


    【解决方案1】:

    这是一个可能的解决方案。它涉及使用 morphology 创建复选框的掩码。我们首先创建一个垂直蒙版,这样所有高于一定高度的元素都将在形态学操作中幸存下来。我们重复此步骤以获得水平蒙版,现在寻找超过一定宽度的元素。连接两个掩码将产生一个最终掩码,其中应包含复选框和一些小噪声。最后,我们可以通过检测最终图像上的轮廓并根据区域过滤斑点来过滤噪声。该算法非常简单,步骤如下:

    1. 通过 Otsu 的阈值化创建输入的二进制图像
    2. 使用形态生成垂直蒙版
    3. 使用形态生成水平蒙版
    4. 通过按位或连接两个掩码
    5. 检测最终蒙版上的轮廓
    6. 过滤低于某个阈值区域的轮廓

    让我们看看代码:

    # 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 中。这是最终的图像,目标边界矩形用红色绘制:

    【讨论】:

    • 感谢您的回答,
    • 所以要检测我可以使用boundingRect的位置?并检查检查框是否被选中,我可以比较以下所有图像:rectX = boundRect[0] rectY = boundRect[1] rectWidth = boundRect[2] rectHeight = boundRect[3] 位置?
    • @TsifiStifen 当然。您还可以获得每个矩形的面积。选中的框可能比空框有更多的像素(因此,面积)。
    猜你喜欢
    • 2012-02-04
    • 2012-07-08
    • 2018-06-15
    • 1970-01-01
    • 2012-02-23
    • 2016-06-23
    • 2014-01-10
    • 2021-04-11
    • 2012-10-29
    相关资源
    最近更新 更多