OpenCV - удаление шума в изображении

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

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

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

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

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

Ответы

Ответ 1

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

Шаг 1: Развернуть изображение -

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

Dilated Image

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

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

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

Разъеденное расширенное изображение

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

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

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

cv2.medianBlur(img, 3)

Среднее размытие

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

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

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

Извлеченное изображение

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

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

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

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

Конечный результат Надеюсь, это поможет!

Ответ 2

Мое решение основано на пороговом значении для получения полученного изображения за 4 шага.

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

Код находится в 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()

Ниже приведены построенные изображения с помощью кода для справки.

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

Вот изображение результата с разрешением 2197 x 3218 пикселей.

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Быстрое решение:

  • Найти контуры в исходном изображении.
  • Отфильтруйте их по размеру.

Ответ 5

Результат:

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

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

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

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