Как получить ограничивающий прямоугольник текста, который перекрывается фоновыми линиями? - PullRequest
3 голосов
/ 22 февраля 2020

Например, на следующем снимке экрана приложения я хочу получить ограничивающую рамку, плотно округленную по CA-85S (текст на горизонтальной синей линии) и Almaden Expy (текст, который перекрывается с синей линией). Я извлекаю эти ограничивающие рамки для OCR.

Я пробовал несколько подходов в openCV, что ни один из этих подходов не работает для меня. enter image description here

1 Ответ

3 голосов
/ 22 февраля 2020

Используя замечание о том, что нужный текст выделяется черным цветом и имеет контраст, отличный от фоновых линий голубой реки, потенциальный подход заключается в использовании цветового порога с cv2.inRange. Вот основная идея и реализация с использованием Python:

  1. Получение маски с пороговым значением цвета. Загрузка изображения, преобразование в формат HSV, определение нижнего и верхнего цветовых диапазонов, затем порог цвета, чтобы получить маску.

  2. Объединить текст в один контур. Мы создадим прямоугольный angular структурирующий элемент, используя cv2.getStructuringElement, затем используйте морфологические операции , чтобы объединить отдельные текстовые буквы в один контур.

  3. Фильтр для текстовых контуров. Мы находим контуры с помощью cv2.findContours, итерация по контурам, затем фильтрация с использованием cv2.contourArea и форматное соотношение . Если контур проходит этот фильтр, мы находим повернутую ограничивающую рамку.

  4. Изолировать текст. Мы можем выполнить этот необязательный шаг, чтобы извлечь только текст, используя cv2.bitwise_and.


Вот визуализация процесса:

Цветная пороговая маска

image

Превращается в текст, чтобы соединить текст в один контур

image

Результат

image

Извлеченный отдельный текст

image

Код

import cv2
import numpy as np

# Load image, convert to HSV, color threshold to get mask
image = cv2.imread('1.png')
original = image.copy()
blank = np.zeros(image.shape[:2], dtype=np.uint8)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 0])
upper = np.array([179, 255, 165])
mask = cv2.inRange(hsv, lower, upper)

# Merge text into a single contour
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=3)

# Find contours
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    # Filter using contour area and aspect ratio
    x,y,w,h = cv2.boundingRect(c)
    area = cv2.contourArea(c)
    ar = w / float(h)
    if (ar > 1.4 and ar < 4) or ar < .85 and area > 100:
        # Find rotated bounding box
        rect = cv2.minAreaRect(c)
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        cv2.drawContours(image,[box],0,(36,255,12),2)
        cv2.drawContours(blank,[box],0,(255,255,255),-1)

# Bitwise operations to isolate text
extract = cv2.bitwise_and(mask, blank)
extract = cv2.bitwise_and(original, original, mask=extract)
extract[extract==0] = 255

cv2.imshow('mask', mask)
cv2.imshow('image', image)
cv2.imshow('close', close)
cv2.imshow('extract', extract)
cv2.waitKey()

Примечание: Нижний и верхний диапазоны цветовых порогов HSV были определены с использованием этого сценария

import cv2
import numpy as np

def nothing(x):
    pass

# Load image
image = cv2.imread('1.png')

# Create a window
cv2.namedWindow('image')

# Create trackbars for color change
# Hue is from 0-179 for Opencv
cv2.createTrackbar('HMin', 'image', 0, 179, nothing)
cv2.createTrackbar('SMin', 'image', 0, 255, nothing)
cv2.createTrackbar('VMin', 'image', 0, 255, nothing)
cv2.createTrackbar('HMax', 'image', 0, 179, nothing)
cv2.createTrackbar('SMax', 'image', 0, 255, nothing)
cv2.createTrackbar('VMax', 'image', 0, 255, nothing)

# Set default value for Max HSV trackbars
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)

# Initialize HSV min/max values
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

while(1):
    # Get current positions of all trackbars
    hMin = cv2.getTrackbarPos('HMin', 'image')
    sMin = cv2.getTrackbarPos('SMin', 'image')
    vMin = cv2.getTrackbarPos('VMin', 'image')
    hMax = cv2.getTrackbarPos('HMax', 'image')
    sMax = cv2.getTrackbarPos('SMax', 'image')
    vMax = cv2.getTrackbarPos('VMax', 'image')

    # Set minimum and maximum HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Convert to HSV format and color threshold
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    result = cv2.bitwise_and(image, image, mask=mask)

    # Print if there is a change in HSV value
    if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
        print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
        phMin = hMin
        psMin = sMin
        pvMin = vMin
        phMax = hMax
        psMax = sMax
        pvMax = vMax

    # Display result image
    cv2.imshow('image', result)
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
...