Как извлечь белую область на изображении
У меня есть образец изображения, как это
Я ищу способ затемнить шум от изображения так, чтобы я получил изображение с черным текстом на белом фоне, чтобы я мог отправить его в 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)