需要帮助找到 2 个单独的轮廓而不是 MICR 代码中的组合轮廓

Need Help in finding 2 seperate contours instead of a combined contour in MICR code

我使用 pyimagesearch tutorial 对银行支票进行 运行 OCR 检测 micr 代码。本教程中使用的代码从包含符号的参考图像中检测组轮廓和字符轮廓。

在本教程中,当找到下面符号的 轮廓

代码使用内置的 python 迭代器迭代轮廓(这里是 3 个单独的轮廓)并组合以给出一个用于识别目的的字符。


但是在我使用的检查数据集中,我有低分辨率的符号

支票的实际底部是:

这会导致迭代器将 contour-2 和 contour-3 视为单个轮廓。因此,迭代器迭代上述符号(此处为“0”)之后的字符,并准备一个不正确的模板来匹配参考符号。您可以查看下面的代码以便更好地理解。

我知道图像中的噪点是一个因素,但是否可以降低噪点并找到准确的轮廓来检测符号?

我尝试在 cv2.findContours 步骤之前使用 cv2.fastNlMeansDenoisingcv2.GaussianBlur 等降噪技术,轮廓 2 和 3 被检测为单个轮廓而不是 2 个单独的轮廓。 我还尝试更改“cv2.findContours”参数

为了更好地理解 python 内置迭代器,下面是迭代字符的工作代码:

def extract_digits_and_symbols(image, charCnts, minW=5, minH=10):
    # grab the internal Python iterator for the list of character
    # contours, then  initialize the character ROI and location
    # lists, respectively
    charIter = charCnts.__iter__()
    rois = []
    locs = []

    # keep looping over the character contours until we reach the end
    # of the list
    while True:
        try:
            # grab the next character contour from the list, compute
            # its bounding box, and initialize the ROI
            c = next(charIter)
            (cX, cY, cW, cH) = cv2.boundingRect(c)
            roi = None

            # check to see if the width and height are sufficiently
            # large, indicating that we have found a digit
            if cW >= minW and cH >= minH:
                # extract the ROI
                roi = image[cY:cY + cH, cX:cX + cW]
                rois.append(roi)
                cv2.imshow('roi',roi)
                cv2.waitKey(0)
                locs.append((cX, cY, cX + cW, cY + cH))

            # otherwise, we are examining one of the special symbols
            else:
                # MICR symbols include three separate parts, so we
                # need to grab the next two parts from our iterator,
                # followed by initializing the bounding box
                # coordinates for the symbol
                parts = [c, next(charIter), next(charIter)]
                (sXA, sYA, sXB, sYB) = (np.inf, np.inf, -np.inf,
                                        -np.inf)

                # loop over the parts
                for p in parts:
                    # compute the bounding box for the part, then
                    # update our bookkeeping variables
                    # c = next(charIter)
                    # (cX, cY, cW, cH) = cv2.boundingRect(c)
                    # roi = image[cY:cY+cH, cX:cX+cW]
                    # cv2.imshow('symbol', roi)
                    # cv2.waitKey(0)
                    # roi = None
                    (pX, pY, pW, pH) = cv2.boundingRect(p)
                    sXA = min(sXA, pX)
                    sYA = min(sYA, pY)
                    sXB = max(sXB, pX + pW)
                    sYB = max(sYB, pY + pH)

                # extract the ROI
                roi = image[sYA:sYB, sXA:sXB]
                cv2.imshow('symbol', roi)
                cv2.waitKey(0)
                rois.append(roi)
                locs.append((sXA, sYA, sXB, sYB))

        # we have reached the end of the iterator; gracefully break
        # from the loop
        except StopIteration:
            break

    # return a tuple of the ROIs and locations
    return (rois, locs)

编辑:等高线 2 和 3 而不是等高线 1 和 2

尝试找到正确的阈值,而不是使用 cv2.THRESH_OTSU。似乎应该可以从提供的示例中找到合适的阈值。如果找不到适用于所有图像的阈值,可以尝试使用 1 像素宽度的结构元素对阈值结果进行形态学收敛。

编辑(步骤):

对于阈值,您需要手动找到合适的值,在您的图像中阈值 100 似乎有效:

i = cv.imread('image.png')
g = cv.cvtColor(i, cv.COLOR_BGR2GRAY)
_, tt = cv.threshold(g, 100, 255, cv.THRESH_BINARY_INV)

至于关闭变体:

_, t = cv.threshold(g, 0,255,cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
kernel = np.ones((12,1), np.uint8)
c = cv.morphologyEx(t, cv.MORPH_OPEN, kernel)

请注意,我使用了 import cv2 as cv。我还使用了打开而不是关闭,因为在示例中它们在阈值处理期间反转了颜色