Как извлечь белую область на изображении

У меня есть образец изображения, как это

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

Я ищу способ затемнить шум от изображения так, чтобы я получил изображение с черным текстом на белом фоне, чтобы я мог отправить его в tesseract.

Я пытался с

kernel = np.ones((4,4),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow("opening", opening)

но это не похоже на работу.

Я также пытался найти контуры

img = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
(cnts, _) = cv2.findContours(img, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    roi=rotated[y:y+h,x:x+w].copy()
    cv2.imwrite("roi.png", roi)

С помощью приведенного выше кода я получаю следующие контуры:

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

что приводит к этому изображению, когда обрезается:

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

что все еще недостаточно хорошо. Мне нужен черный текст на белом фоне, чтобы я мог отправить его на OSS для тессеракта и иметь хороший показатель успеха.

Есть ли что-нибудь еще, что я могу попробовать?

Обновить

Вот дополнительное похожее изображение. Это немного проще, потому что в нем есть гладкий прямоугольник

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

3 ответа

Решение

Следующее работает для вашего данного примера, хотя может потребоваться настройка для более широкого диапазона изображений.

import numpy as np
import cv2

image_src = cv2.imread("input.png")
gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(gray, 250,255,0)

image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
largest_area = sorted(contours, key=cv2.contourArea)[-1]
mask = np.zeros(image_src.shape, np.uint8)
cv2.drawContours(mask, [largest_area], 0, (255,255,255,255), -1)
dst = cv2.bitwise_and(image_src, mask)
mask = 255 - mask
roi = cv2.add(dst, mask)

roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(roi_gray, 250,255,0)
image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

max_x = 0
max_y = 0
min_x = image_src.shape[1]
min_y = image_src.shape[0]

for c in contours:
    if 150 < cv2.contourArea(c) < 100000:
        x, y, w, h = cv2.boundingRect(c)
        min_x = min(x, min_x)
        min_y = min(y, min_y)
        max_x = max(x+w, max_x)
        max_y = max(y+h, max_y)

roi = roi[min_y:max_y, min_x:max_x]
cv2.imwrite("roi.png", roi)

Дает вам следующий тип выходных изображений:

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

А также...

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

Код работает, сначала находя самую большую область контура. Из этого создается маска, которая используется, чтобы сначала выбрать только область внутри, то есть текст. Затем к изображению добавляется инверсия маски, чтобы преобразовать область вне маски в белый цвет.

Наконец, контуры снова найдены для этого нового изображения. Любые области контура за пределами подходящего диапазона размеров отбрасываются (это используется для игнорирования любых небольших шумовых областей), и для каждой найден ограничивающий прямоугольник. С каждым из этих прямоугольников outer ограничивающий прямоугольник рассчитывается для всех оставшихся контуров, и обрезка выполняется с использованием этих значений для получения окончательного изображения.

Обновление - чтобы получить оставшуюся часть изображения, т.е. с удалением вышеуказанной области, можно использовать следующее:

image_src = cv2.imread("input.png")
gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(gray, 10, 255,0)
image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
largest_area = sorted(contours, key=cv2.contourArea)[-1]
mask = np.zeros(image_src.shape, np.uint8)
cv2.drawContours(mask, [largest_area], 0, (255,255,255,255), -1)
image_remainder = cv2.bitwise_and(image_src, 255 - mask)

cv2.imwrite("remainder.png", image_remainder)

Я получаю это: Результат

Исходный код:

if __name__ == '__main__':
  SrcImg = cv2.imread('./Yahi9.png', cv2.CV_LOAD_IMAGE_GRAYSCALE)
  _, BinImg = cv2.threshold(SrcImg, 80, 255, cv2.THRESH_OTSU)

  Contours, Hierarchy = cv2.findContours(image=copy.deepcopy(SrcImg),
                                         mode=cv2.cv.CV_RETR_EXTERNAL,
                                         method=cv2.cv.CV_CHAIN_APPROX_NONE)
  MaxContour, _ = getMaxContour(Contours)
  Canvas = np.ones(SrcImg.shape, np.uint8)
  cv2.drawContours(image=Canvas, contours=[MaxContour], contourIdx=0, color=(255), thickness=-1)
  mask = (Canvas != 255)
  RoiImg = copy.deepcopy(BinImg)
  RoiImg[mask] = 255
  RoiImg = cv2.morphologyEx(src=RoiImg, op=cv2.MORPH_CLOSE, kernel=np.ones((3,3)), iterations=4)
  cv2.imshow('RoiImg', RoiImg)
  cv2.waitKey(0)

Функция:

def getMaxContour(contours):
  MaxArea = 0
  Location = 0
  for idx in range(0, len(contours)):
      Area = cv2.contourArea(contours[idx])
      if Area > MaxArea:
          MaxArea = Area
          Location = idx
  MaxContour = np.array(contours[Location])
  return MaxContour, MaxArea

Эхх, это код Python. Это работает только тогда, когда белая область является максимальным контуром.

Основная идея этого ответа заключается в использовании рамки вокруг текста.

1) Размыть горизонтально с очень большим ядром, скажем, размером 100 пикселей или в 8 раз больше, чем ожидаемый символ, что-то вроде этого. Это должно быть сделано по строкам. Крайняя ордината даст y-расположение границ вокруг текста.

2) Обрабатывать по вертикали таким же образом, чтобы получить x-расположение границ вокруг текста. Затем используйте эти места, чтобы обрезать изображение, которое вы хотите.

- Одним из преимуществ этого метода является то, что каждое предложение / слово сегментируется отдельно, что, я полагаю, хорошо для распознавания текста.

Удачного кодирования:)

Под редакцией Марка Сетчелла

Вот демо 1)

Вот демо 2)

Другие вопросы по тегам