Как удалить перекрывающиеся контуры и выделить каждый символ как отдельный контур для извлечения символов?

Я пытаюсь реализовать извлечение символов из изображений в Python, используя MSER в opencv. Это мой код до сих пор:

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)

Но этот метод дает несколько контуров для одной и той же буквы, а в некоторых местах несколько слов помещаются в один контур. Вот, например: исходное изображение:

введите здесь описание изображения

После добавления контуров:

введите здесь описание изображения

Здесь первая Т имеет несколько контуров вокруг, а два rs объединены в один контур. Как мне предотвратить это?


person Shantanu Shinde    schedule 26.12.2019    source источник
comment
Почему вы используете MSER вместо какого-то порога?   -  person Ziri    schedule 26.12.2019
comment
тогда как извлечь буквы? Я попробовал функцию cv2.findContours(), но она возвращает только самый внешний контур.   -  person Shantanu Shinde    schedule 26.12.2019
comment
Можете ли вы опубликовать исходное изображение?   -  person Ziri    schedule 26.12.2019
comment
@Ziri добавил оригинальное изображение   -  person Shantanu Shinde    schedule 26.12.2019
comment
findContours дает вам все буквы. Вам нужно только правильно установить иерархии. Этот источник поможет вам в этом: docs.opencv.org/trunk/d9/d8b /   -  person MH304    schedule 26.12.2019


Ответы (1)


Вместо использования MSER здесь предлагается простой подход, использующий пороговое значение + контурную фильтрацию. Сначала мы удаляем границу, затем порог Оцу, чтобы получить бинарное изображение. Идея в том, что каждая буква должна быть отдельным контуром. Находим контуры и рисуем каждый прямоугольник.

Убрана рамка -> бинарное изображение -> результат

Примечание. В некоторых случаях буквы соединены, поэтому для удаления объединенных символов мы можем сначала увеличить изображение с помощью imutils.resize(), а затем выполнить erusion или морфологическое открытие для разделения каждого символа. Однако мне не удалось добиться отличных результатов, поскольку текст исчезал даже с ядром самого маленького размера.

Код

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()
person nathancy    schedule 31.12.2019