如何去除重叠轮廓并将每个字符分离为单独的轮廓以进行字符提取?

How to remove overlapping contours and separate each character as an individual contour for character extraction?

我正在尝试使用 opencv 中的 MSER 从 Python 中的图像中提取字符。到目前为止,这是我的代码:

import cv2
import numpy as np

# create MSER object
mser = cv2.MSER_create()
# convert image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# detect the regions
regions,_ = mser.detectRegions(gray)
# find convex hulls of the regions
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
# initialize threshold area of the contours
ThresholdContourArea = 10000
# initialize empty list for the characters and their locations
char = []
loc =[]
# get the character part of the image and it's location if the area of contour less than threshold
for contour in hulls:
    if cv2.contourArea(contour) > ThresholdContourArea:
        continue
    # get the bounding rectangle around the contour
    bound_rect = cv2.boundingRect(contour)
    loc.append(bound_rect)
    det_char = gray[bound_rect[1]:bound_rect[1]+bound_rect[3],bound_rect[0]:bound_rect[0]+bound_rect[2]]
    char.append(det_char)

但是这种方法为同一个字母给出了多个轮廓,并且在某些地方将多个单词放在一个轮廓中。这是一个例子: 原图:

添加轮廓后:

这里第一个T周围有多个轮廓,两个rs组合成一个轮廓。我该如何预防?

这里没有使用 MSER,而是使用阈值 + 轮廓过滤的简单方法。我们首先去除边界,然后去除 Otsu 的阈值以获得二值图像。这个想法是每个字母都应该是一个单独的轮廓。我们找到轮廓并绘制每个矩形。

删除边框->二值图像->结果

注意:在某些情况下,字母是连在一起的,所以要去除合并的字符,我们可以先使用imutils.resize()放大图像,然后执行erosion or morphological opening 来分隔每个字符。但是,我无法获得很好的结果,因为即使使用最小尺寸的内核,文本也会消失。

代码

import cv2
import imutils

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
image = imutils.resize(image, width=500)

# Remove border
kernel_vertical = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
temp1 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_vertical)
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
temp2 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, horizontal_kernel)
temp3 = cv2.add(temp1, temp2)
result = cv2.add(temp3, image)

# Convert to grayscale and Otsu's threshold
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find contours and filter using contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(result, (x, y), (x + w, y + h), (36,255,12), 2)

cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey()