c++ - OpenCV-Eliminación de ruido en imagen.




image-processing noise-reduction (6)

Como sé, el filtro mediano es la mejor solución para reducir el ruido. Yo recomendaría usar filtro de mediana con ventana de 3x3. Ver función cv::medianBlur() .

Pero tenga cuidado cuando utilice cualquier filtración de ruido simultáneamente con OCR. Su puede conducir a la disminución de la precisión de reconocimiento.

También recomendaría probar el par de funciones (cv :: erode () y cv :: dilate ()). Pero no estoy seguro de que sea la mejor solución que cv :: medianBlur () con la ventana 3x3.

Tengo una imagen aquí con una tabla. En la columna de la derecha, el fondo está lleno de ruido.

¿Cómo detectar las zonas con ruido? Solo quiero aplicar algún tipo de filtro en las partes con ruido porque necesito hacer OCR en él y cualquier tipo de filtro reducirá el reconocimiento general

¿Y qué tipo de filtro es el mejor para eliminar el ruido de fondo en la imagen?

Como he dicho, necesito hacer OCR en la imagen.


Intenta poner un umbral a la imagen como esta. Asegúrate de que tu src esté en escala de grises. Este método solo retendrá los píxeles que están entre 150 y 255 de intensidad.

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

Es posible que desee invertir la imagen mientras intenta negar los píxeles grises. Después de la operación, inviértalo nuevamente para obtener el resultado deseado.


Mi solución se basa en los umbrales para obtener la imagen resultante en 4 pasos.

  1. Leer imagen por OpenCV 3.2.0 .
  2. Aplique GaussianBlur() para suavizar la imagen, especialmente la región en color gris.
  3. Enmascara la imagen para cambiar el texto a blanco y el resto a negro.
  4. Invertir la imagen enmascarada en texto negro en blanco.

El código está en Python 2.7 . Se puede cambiar a C++ fácilmente.

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

# read Danish doc image 
img = cv2.imread('./images/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()

Lo siguiente son las imágenes trazadas por el código de referencia.

Aquí está la imagen del resultado en 2197 x 3218 píxeles.


Probé algunos filtros / operaciones en OpenCV y parece funcionar bastante bien.

Paso 1: Dilatar la imagen -

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

Como se ve, el ruido se ha ido pero los caracteres son muy ligeros, así que erosioné la imagen.

Paso 2: erosionar la imagen -

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

Como puede ver, el ruido desaparece, sin embargo, algunos caracteres de las otras columnas están rotos. Recomendaría ejecutar estas operaciones solo en la columna ruidosa. Es posible que desee utilizar HoughLines para encontrar la última columna. Luego puede extraer esa columna solamente, ejecutar dilatación + erosión y reemplazarla con la columna correspondiente en la imagen original. Además, la dilatación + erosión es en realidad una operación llamada cierre . Esto se puede llamar directamente usando -

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

Como sugirió @Ermlg, medianBlur con un núcleo de 3 también funciona maravillosamente.

cv2.medianBlur(img, 3)

Paso alternativo

Como puede ver, todos estos filtros funcionan, pero es mejor si implementa estos filtros solo en la parte donde está el ruido. Para hacer eso, usa lo siguiente:

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)**

Entonces, puedes extraer esta parte solo como:

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

Luego, implementa el filtro (mediana o cierre) en esta imagen. Después de eliminar el ruido, debe colocar esta imagen filtrada en lugar de la parte borrosa en la imagen original. imagen [y1: h, x1: w] = mediana

Esto es sencillo en C ++:

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

Resultado final con método alternativo

¡Espero eso ayude!


Si está muy preocupado de eliminar píxeles que podrían dañar su detección de OCR. Sin agregar artefactos, sé tan puro como el original. Entonces deberías crear un filtro de burbujas. Y elimine cualquier blobs que sea más pequeño que n píxeles aproximadamente.

No voy a escribir código, pero sé que esto funciona muy bien ya que lo uso yo mismo, aunque no uso openCV (escribí mi propio blobfilter multihilo por razones de velocidad). Y lo siento pero no puedo compartir mi código aquí. Sólo describiendo cómo hacerlo.


Ya había enfrentado el mismo problema y obtuve la mejor solución. Convierta la imagen de origen a una imagen en escala de grises y aplique la función fastNlMeanDenoising y luego aplique el umbral .

Así: fastNlMeansDenoising (grey, dst, 3.0,21,7); umbral (dst, finaldst, 150,255, THRESH_BINARY);

El uso TAMBIÉN puede ajustar el umbral según la imagen de ruido de fondo por ejemplo, umbral (dst, finaldst, 200,255, THRESH_BINARY);

NOTA: si se eliminaron las líneas de columna ... Puede tomar una máscara de líneas de columna de la imagen de origen y puede aplicarlas a la imagen resultante sin ruido utilizando las operaciones BITWISE como AND, OR, XOR.





noise-reduction