2017-02-16 4 views
18

У меня есть изображение здесь со столом .. В колонке справа на фоне наполнен шумомOpenCV - Удаление шума в изображении

Как обнаружить участки с шумом? Я только хочу применить какой-то фильтр на деталях с шумом, потому что мне нужно сделать OCR на нем, и любой вид фильтра уменьшит общее распознавание.

И какой фильтр лучше всего удалять фоновый шум в изображение?

Как сказал, что нужно сделать OCR на изображении

enter image description here

+1

Возможно, вы захотите удалить «личную» информацию с вашего образца изображения. – cwap

+1

Не могли бы вы указать язык в документе? – thewaywewere

+1

его датский ..... – clarkk

ответ

7

Я пробовал некоторые фильтры/операции в OpenCV и, похоже, работает очень хорошо.

Шаг 1: Dilate изображение -

kernel = np.ones((5, 5), np.uint8) 
cv2.dilate(img, kernel, iterations = 1) 

Dilated Image

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

Шаг 2: Ирода изображение -

kernel = np.ones((5, 5), np.uint8) 
cv2.erode(img, kernel, iterations = 1) 

Eroded dilated image

Как вы можете видеть, шум исчезает, однако некоторые символы на другие столбцы разбиты. Я бы рекомендовал использовать эти операции только для столбца с помехами. Вы можете использовать HoughLines, чтобы найти последний столбец. Затем вы можете извлечь только этот столбец, запустить dilation + erosion и заменить его соответствующим столбцом исходного изображения. Кроме того, дилатация + эрозия на самом деле является операцией под названием закрытие. Это можно назвать непосредственно с помощью -

cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) 

Как предложил @Ermlg, medianBlur с ядром 3 также прекрасно работает.

cv2.medianBlur(img, 3) 

Median Blur

Альтернативный шаг

Как вы можете видеть все эти фильтры работают, но это лучше, если вы реализуете эти фильтры только в той части, где шум. Чтобы сделать это, используйте следующую команду:

edges = cv2.Canny(img, 50, 150, apertureSize = 3) // img is gray here 
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, 1000, 50) // last two arguments are minimum line length and max gap between two lines respectively. 
for line in lines: 
    for x1, y1, x2, y2 in line: 
     print x1, y1 
// This gives the start coordinates for all the lines. You should take the x value which is between (0.75 * w, w) where w is the width of the entire image. This will give you essentially **(x1, y1) = (1896, 766)** 

Затем, вы можете извлечь эту часть только как:

extract = img[y1:h, x1:w] // w, h are width and height of the image 

Extracted image

Затем, реализующий фильтр (средний или закрытия) в этом изображении , После удаления шума вам нужно поместить это отфильтрованное изображение вместо размытой части исходного изображения. изображение [y1: ч, x1: ш] = средний

Это просто в C++:

extract.copyTo(img, new Rect(x1, y1, w - x1, h - y1)) 

Окончательный результат с альтернативным методом

Final Result Надеюсь, что это помогает!

+0

Есть ли у вас пример кода, который может обнаружить последний столбец с шумом .. Как вы сами говорите .. Независимо от того, какой фильтр вы применяете - текст всегда будет сложнее распознать. Поэтому я хочу только применить фильтр со стороны изображения с шумом. – clarkk

+1

Да, дайте мне когда-нибудь и Я добавлю это к ответу. –

+2

Добавлен метод обнаружения последнего столбца. Дайте мне знать, если он ответит на ваш вопрос. –

3

Как я знаю, что медианный фильтр является лучшим решением для снижения уровня шума. Я бы рекомендовал использовать медианный фильтр с окном 3х3. См. Функцию cv::medianBlur().

Но будьте осторожны при использовании любой фильтрации шума одновременно с OCR. Это может привести к снижению точности распознавания.

Также я бы рекомендовал попробовать использовать пару функций (cv :: erode() и cv :: dilate()). Но я не уверен, что это лучшее решение, а cv :: medianBlur() с окном 3x3.

+0

Если фильтрация шума может привести к плохой OCR, могли бы вы затем определить области, где расположен шум (если есть шум), и применять фильтр только там? – clarkk

+0

@clarkk Нелегко отделить шум и тонкую структуру символов. Но в вашем случае я думаю, что это не проблема, потому что шрифт достаточно большой по сравнению с шумом. – ErmIg

2

Я бы пошел со средним размытием (возможно, 5 * 5 ядром).

Если вы планируете применять OCR изображение. Я бы посоветовал вам следующее:

  1. Отфильтровать изображение с помощью медианного фильтра.
  2. Найти контуры в отфильтрованном изображении, вы получите только текстовые контуры (назовите их F).
  3. Найти контуры в исходном изображении (назовите их O).
  4. изолировать все контуры в O, которые имеют пересечение с любым контуром в F.

Faster решение:

  1. Найти контуры в исходном изображении.
  2. Фильтровать их по размеру.
-2

Попробуйте установить изображение таким образом. Убедитесь, что ваш src находится в оттенках серого. Этот метод будет сохранять только пиксели, которые составляют от 150 до 255.

threshold(src, output, 150, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 

Возможно, вы захотите инвертировать изображение, поскольку вы пытаетесь свести на нет серые пиксели. После операции инвертируйте его снова, чтобы получить желаемый результат.

+0

Если вы внимательно посмотрите на пиксели входного изображения, вы увидите, что вход здесь уже является двоичным изображением с пикселями или 0 или 255 – Antonio

4

Мое решение основано на пороговых значениях, чтобы получить приведенное изображение за 4 шага.

  1. Прочитать изображение от OpenCV 3.2.0.
  2. Применить GaussianBlur(), чтобы сгладить изображение, особенно в сером цвете.
  3. Маска изображения для изменения текста на белый, а остальное на черный.
  4. Инвертировать замаскированное изображение в черный текст в белом.

Код в Python 2.7. Его можно легко заменить на C++.

import numpy as np 
import cv2 
import matplotlib.pyplot as plt 
%matplotlib inline 

# read Danish doc image 
img = cv2.imread('./imagesStackoverflow/danish_invoice.png') 

# apply GaussianBlur to smooth image 
blur = cv2.GaussianBlur(img,(5,3), 1) 

# threshhold gray region to white (255,255, 255) and sets the rest to black(0,0,0) 
mask=cv2.inRange(blur,(0,0,0),(150,150,150)) 

# invert the image to have text black-in-white 
res = 255 - mask 

plt.figure(1) 
plt.subplot(121), plt.imshow(img[:,:,::-1]), plt.title('original') 
plt.subplot(122), plt.imshow(blur, cmap='gray'), plt.title('blurred') 
plt.figure(2) 
plt.subplot(121), plt.imshow(mask, cmap='gray'), plt.title('masked') 
plt.subplot(122), plt.imshow(res, cmap='gray'), plt.title('result') 
plt.show() 

Ниже приведены нанесенные изображения по коду для справки.

enter image description here

Здесь результат изображения при 2197 х 3218 пикселей.

enter image description here

+0

это все еще применит фильтр на целом изображении. Мне нужно решение, которое ТОЛЬКО применяет фильтр со стороны с шумом – clarkk

+0

@clarkk OK. Является ли область шума фиксированной и известной? Как образ образца, который вы приложили? Если нет, то еще образцы документов для показа? – thewaywewere

1

Если вы очень беспокоитесь удаления пикселей, которые могут повредить ваше обнаружение OCR. Без добавления артефактов ea быть как можно более чистым к оригиналу. Затем вы должны создать фильтр blob. И удалите любые капли, которые меньше, чем n пикселей или около того.

Не собираюсь писать код, но я знаю, что это отлично работает, поскольку я использую это сам, хотя я не использую openCV (я написал свой собственный многопоточный blobfilter из соображений скорости). И извините, но я не могу поделиться своим кодом здесь. Просто описывая, как это сделать.

1

Если время обработки не является проблемой, очень эффективный метод в этом случае будет чтобы вычислить все черные подключенные компоненты и удалить те, которые меньше нескольких пикселей. Он удалит все шумные точки (кроме тех, которые касаются действительного компонента), но сохранит все символы и структуру документа (строки и т. Д.).

Функция использовать будет connectedComponentWithStats (прежде, чем Вы, вероятно, нужно произвести негативный образ, то threshold функция THRESH_BINARY_INV будет работать в этом случае), используя белые прямоугольники, где небольшие связные компоненты, где найдены.

Фактически этот метод можно использовать для поиска символов, определенных как связанные компоненты заданного минимального и максимального размера, и с отношением сторон в заданном диапазоне.

+0

A i sugested ранее – user3800527

+0

@ user3800527 Правда, я пропустил это. Мой ответ добавляет некоторые подсказки для реализации opencv. – Antonio

0

Я уже столкнулся с той же проблемой и получил лучшее решение. Преобразуйте исходное изображение в изображение в оттенках серого и примените fastNlMeanDenoising, а затем применить порог.

Нравится: fastNlMeansDenoising (gray, dst, 3.0,21,7); порог (dst, finaldst, 150,255, THRESH_BINARY);

ТАКЖЕ может использовать пороговое значение, соответствующее вашему фоновому шумовому изображению. eg- порог (dst, finaldst, 200,255, THRESH_BINARY);

ПРИМЕЧАНИЕ. - Если ваши строки столбцов удалены ... Вы можете взять маску строк столбцов из исходного изображения и применить к полученному изображением, используя данные BITWISE, такие как AND, OR, XOR.

Смежные вопросы