wake-up-neo.com

OpenCV - Entfernen von Rauschen im Bild

Ich habe hier ein Bild mit einer Tabelle. In der rechten Spalte ist der Hintergrund mit Rauschen gefüllt

Wie erkennt man die Bereiche mit Lärm? Ich möchte nur eine Art Filter auf die Teile mit Rauschen anwenden, da ich OCR machen muss und jede Art von Filter die Gesamterkennung reduzieren wird

Und welcher Filter ist der beste, um das Hintergrundrauschen im Bild zu entfernen?

Wie gesagt muss ich OCR auf dem Bild machen

 enter image description here

18
clarkk

Ich habe einige Filter/Operationen in OpenCV ausprobiert und es scheint ziemlich gut zu funktionieren.

Schritt 1: Dilate das Bild - 

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

 Dilated Image

Wie Sie sehen, ist das Rauschen verschwunden, aber die Zeichen sind sehr hell, also habe ich das Bild erodiert. 

Schritt 2: Erode das Bild - 

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

 Eroded dilated image

Wie Sie sehen, ist das Rauschen verschwunden, jedoch sind einige Zeichen in den anderen Spalten gebrochen. Ich würde empfehlen, diese Operationen nur in der lauten Spalte auszuführen. Vielleicht möchten Sie HoughLines verwenden, um die letzte Spalte zu finden. Dann können Sie nur diese Spalte extrahieren, die Dilatation + Abtragung ausführen und diese durch die entsprechende Spalte im Originalbild ersetzen. Außerdem ist Dilatation + Erosion eine Operation namens close. Dies können Sie direkt anrufen mit - 

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

Wie @Ermlg vorschlug, funktioniert medianBlur mit einem Kernel von 3 auch wunderbar.

cv2.medianBlur(img, 3)

 Median Blur

Alternativer Schritt

Wie Sie sehen, funktionieren alle diese Filter, aber es ist besser, wenn Sie diese Filter nur in dem Teil implementieren, in dem das Rauschen auftritt. Verwenden Sie dazu Folgendes:

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

Dann können Sie diesen Teil nur wie folgt extrahieren:

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

 Extracted image

Implementieren Sie dann den Filter (Median oder Schließen) in diesem Bild. Nach dem Entfernen des Rauschens müssen Sie dieses gefilterte Bild anstelle des unscharfen Teils im Originalbild einfügen. image [y1: h, x1: w] = Median

Dies ist in C++ einfach: 

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

Endergebnis mit alternativer Methode

 Final Result Ich hoffe es hilft!

9
Rick M.

Meine Lösung basiert auf Schwellenwerten, um das Ergebnis in 4 Schritten zu erhalten.

  1. Bild von OpenCV 3.2.0 lesen. 
  2. Wenden Sie GaussianBlur() an, um ein Bild zu glätten, insbesondere die Region in grauer Farbe. 
  3. Maskieren Sie das Bild, um den Text in Weiß und den Rest in Schwarz zu ändern. 
  4. Invertieren Sie das maskierte Bild in schwarzen Text in Weiß.

Der Code ist in Python 2.7. Es kann leicht in C++ geändert werden.

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

Das Folgende ist die geplotteten Bilder durch den Code als Referenz.

 enter image description here

Hier ist das Ergebnisbild bei 2197 x 3218 Pixel.

 enter image description here

7
thewaywewere

Wie ich weiß, ist der Medianfilter die beste Lösung, um das Rauschen zu reduzieren. Ich würde empfehlen, Medianfilter mit 3x3-Fenster zu verwenden. Siehe Funktion cv :: medianBlur ()

Seien Sie jedoch vorsichtig, wenn Sie gleichzeitig mit OCR eine Geräuschfilterung verwenden. Dies kann zu einer Verringerung der Erkennungsgenauigkeit führen.

Ich würde auch empfehlen, ein Paar von Funktionen (cv :: erode () und cv :: dilate ()) zu verwenden. Aber ich bin nicht sicher, dass es die beste Lösung ist, dann cv :: medianBlur () mit Fenster 3x3.

3
ErmIg

Ich würde mit mittlerer Unschärfe gehen (wahrscheinlich 5 * 5-Kernel). 

wenn Sie planen, das Bild mit OCR anzuwenden. Ich würde dir folgendes empfehlen:

  1. Filtern Sie das Bild mit dem Medianfilter.
  2. Suchen Sie im gefilterten Bild nach Konturen, Sie erhalten nur Textkonturen (Rufen Sie sie anF).
  3. Finden Sie Konturen im Originalbild (Rufen Sie sie anODER).
  4. isolieren Sie alle Konturen inO, die sich mit einer beliebigen Kontur inFschneiden.

Schnellere Lösung:

  1. Finden Sie Konturen im Originalbild.
  2. Filtern Sie sie nach Größe.
2
Humam Helfawi

Ergebnis:

 enter image description here

2
Antonio

Wenn die Verarbeitungszeit kein Problem darstellt, wäre es in diesem Fall eine sehr effektive Methode, alle schwarzen verbundenen Komponenten zu berechnen und diese zu entfernen, die kleiner als einige Pixel sind. Dadurch werden alle störenden Punkte (abgesehen von denjenigen, die eine gültige Komponente berühren) entfernt, alle Zeichen und die Dokumentstruktur (Linien usw.) bleiben jedoch erhalten.

Die zu verwendende Funktion wäre connectedComponentWithStats (bevor Sie wahrscheinlich ein negatives Bild erzeugen müssen, würde in diesem Fall die Schwellen Funktion mit THRESH_BINARY_INV funktionieren), wobei weiße Rechtecke mit kleinen verbundenen Komponenten gezeichnet wurden.

Tatsächlich könnte dieses Verfahren verwendet werden, um Zeichen zu finden, die als verbundene Komponenten einer gegebenen minimalen und maximalen Größe und mit einem Seitenverhältnis in einem gegebenen Bereich definiert sind.

1
Antonio

Ich war schon vor demselben Problem gestanden und hatte die beste Lösung. Konvertieren Sie das Quellbild in Graustufenbild und wenden Sie die fastNlMeanDenoising -Funktion an und wenden Sie dann Schwellenwert an.

So - fastNlMeansDenoising (grau, dst, 3.0,21,7); Schwelle (dst, finaldst, 150,255, THRESH_BINARY);

Mit ALSO können Sie die Schwellenwerte an Ihr Hintergrundgeräuschbild anpassen. eg- Schwelle (dst, finaldst, 200,255, THRESH_BINARY);

HINWEIS - Wenn Ihre Spaltenzeilen entfernt wurden ... Sie können eine Maske aus Spaltenzeilen aus dem Quellbild nehmen und sie mit BITWISE-Vorgängen wie AND, OR, XOR auf das Denois-Ergebnis anwenden.

1
Amul Mittal

Wenn Sie sehr besorgt sind, Pixel zu entfernen, die Ihre OCR-Erkennung beeinträchtigen könnten. Ohne das Hinzufügen von Artefakten muss das Original so rein wie möglich sein. Dann sollten Sie einen Blob-Filter erstellen. Und löschen Sie alle Blobs, die kleiner als n Pixel sind. 

Ich werde zwar keinen Code schreiben, aber ich weiß, dass dies großartig ist, da ich dies selbst benutze, obwohl ich nicht OpenCV benutze (ich habe meinen eigenen Multithread-Blobfilter aus Geschwindigkeitsgründen geschrieben). Und leider kann ich meinen Code hier nicht teilen. Beschreibe einfach, wie es geht.

1
user3800527