2016-05-18 19 views
11

Sto cercando di sviluppare una semplice applicazione per PC per il riconoscimento delle targhe (Java + OpenCV + Tess4j). Le immagini non sono molto buone (in più andranno bene). Voglio preelaborare l'immagine per tesseract e sono bloccato al rilevamento della targa (rilevamento rettangolo).Preelaborazione delle immagini con OpenCV prima di eseguire il riconoscimento dei caratteri (tesseract)

miei passi:

1) Fonte immagine

True Image

Mat img = new Mat(); 
img = Imgcodecs.imread("sample_photo.jpg"); 
Imgcodecs.imwrite("preprocess/True_Image.png", img); 

2) Scala di grigi

Mat imgGray = new Mat(); 
Imgproc.cvtColor(img, imgGray, Imgproc.COLOR_BGR2GRAY); 
Imgcodecs.imwrite("preprocess/Gray.png", imgGray); 

3) Controllo sfocatura

Mat imgGaussianBlur = new Mat(); 
Imgproc.GaussianBlur(imgGray,imgGaussianBlur,new Size(3, 3),0); 
Imgcodecs.imwrite("preprocess/gaussian_blur.png", imgGaussianBlur); 

4) Soglia Adaptive

Mat imgAdaptiveThreshold = new Mat(); 
Imgproc.adaptiveThreshold(imgGaussianBlur, imgAdaptiveThreshold, 255, CV_ADAPTIVE_THRESH_MEAN_C ,CV_THRESH_BINARY, 99, 4); 
Imgcodecs.imwrite("preprocess/adaptive_threshold.png", imgAdaptiveThreshold); 

Qui dovrebbe essere 5 ° passo, che è il rilevamento della regione di piastra (probabilmente anche senza raddrizzamento per ora).

ho croped zona necessaria da immagine (dopo il 4 ° passo) con Paint, ed ha ottenuto:

plate region

Poi ho fatto OCR (via Tesseract, tess4j):

File imageFile = new File("preprocess/adaptive_threshold_AFTER_PAINT.png"); 
ITesseract instance = new Tesseract(); 
instance.setLanguage("eng"); 
instance.setTessVariable("tessedit_char_whitelist", "acekopxyABCEHKMOPTXY"); 
String result = instance.doOCR(imageFile); 
System.out.println(result); 

e ottenuto (abbastanza buono?) risultato - "Y841ox EH" (quasi vero)

Come è possibile rilevare e ritagliare la regione della piastra dopo il 4 ° passaggio? Devo apportare alcune modifiche (miglioramenti) in 1-4 passaggi? Vorrei vedere qualche esempio implementato tramite Java + OpenCV (non JavaCV).
Grazie in anticipo.

EDIT (grazie alla risposta di @Abdul Fatir) Beh, fornisco di lavoro (per me atleast) esempio di codice (Netbeans + Java + OpenCV + Tess4j) per chi interessato a questa domanda. Il codice non è il massimo, ma l'ho fatto solo per studiare.
http://pastebin.com/H46wuXWn (non dimenticate di mettere tessdata cartella nella cartella del progetto)

+1

Si potrebbe provare ad analizzare i contorni. Tuttavia potrebbe essere più affidabile utilizzare un [classificatore a cascata] (http://docs.opencv.org/2.4/modules/objdetect/doc/cascade_classification.html) per individuare la targa (testare il proprio algoritmo con una macchina bianca e vedere come funziona). Allineare il piatto in modo che sia orizzonatale. Dovresti anche aggiungere una fase addizionale prima di tesseract - segmentare la targa in caratteri individuali (la proiezione verticale probabilmente funzionerà bene data la qualità della tua immagine) e darle solo a tesseract. –

+0

Puoi postare l'immagine dopo il passo 4 come bene? Penso che dovresti essere in grado di rilevare il bordo della placca estraendo i contorni e filtrandoli sulle dimensioni e sul rapporto h/w. Se hai il contorno (dal momento che sai che è un rettangolo, puoi annullare la trasformazione di proiezione) – RobAu

+0

@RobAu, Sì sicuro: http://i.imgur.com/chrNMYX.png – DocC

risposta

6

Ecco come suggerisco di eseguire questa operazione.

  1. Converti in scala di grigi.
  2. Gaussian Blur con filtro 3x3 o 5x5.
  3. Applica il filtro Sobel per trovare i bordi verticali.

    Sobel(gray, dst, -1, 1, 0)

  4. Threshold l'immagine risultante per ottenere un'immagine binaria.
  5. Applicare un'operazione di chiusura morfologica utilizzando un elemento di strutturazione adatto.
  6. Trova i contorni dell'immagine risultante.
  7. Trova minAreaRect di ogni contorno. Seleziona i rettangoli in base al formato e all'area minima e massima.
  8. Per ciascun contorno selezionato, trovare la densità del bordo. Impostare una soglia per la densità degli spigoli e scegliere i rettangoli che superano quella soglia come possibili regioni della piastra.
  9. Pochi rettangoli rimarranno dopo questo. Puoi filtrarli in base all'orientamento o ai criteri che ritieni adatti.
  10. Ritaglia queste parti rettangolari rilevate dall'immagine dopo adaptiveThreshold e applica OCR.

a) Risultato dopo il punto 5

Result after Step 5

b) Risultato dopo la fase 7. quelli verdi sono tutti i minAreaRect s e quelli rossi sono quelli che soddisfano i seguenti criteri: gamma Aspect ratio (2,12) & gamma Area (300,10000)

c) Risultato dopo passaggio 9. Rettangolo selezionato. Criteri: Densità Bordo> 0,5

enter image description here

EDIT

Per bordo densità, quello che ho fatto negli esempi di cui sopra è il seguente.

  1. Applicare il rilevatore Canny Edge direttamente all'immagine di input. Lasciare che l'immagine dell'utensile sia Ic.
  2. Moltiplicare i risultati del filtro Sobel e Ic. Fondamentalmente, prendi un E di immagini Sobel e Canny.
  3. Gaussian Sfocare l'immagine risultante con un filtro di grandi dimensioni. Ho usato 21x21.
  4. Soglia l'immagine risultante utilizzando il metodo OTSU. Otterrai un'immagine binaria
  5. Per ciascun rettangolo rosso, ruota la porzione all'interno di questo rettangolo (nell'immagine binaria) per renderla verticale. Passa attraverso i pixel del rettangolo e contati i pixel bianchi. (How to rotate?)

Densità bordo = numero di pixel bianchi nel rettangolo/numero totale.di Pixel nel rettangolo

  1. Scegliere una soglia per la densità del bordo.

NOTA: Invece di passare attraverso i passaggi da 1 a 3, è anche possibile utilizzare l'immagine binaria dal passaggio 5 per calcolare la densità bordo.

+0

Rispondere per una risposta così dettagliata! Ho fatto tutto ciò che hai descritto tranne il passo "c", che è "Densità del bordo". Fino a questo passo l'algoritmo ha funzionato bene - ho giocato un po 'con soglie e rapporti (grazie a "Mastering OpenCV Capitolo 5" https://github.com/MasteringOpenCV/code/blob/master/Chapter5_NumberPlateRecognition/DetectRegions.cpp in particolare "verifySizes" funzione) e per alcune foto ha funzionato abbastanza bene senza i criteri di densità del bordo. Puoi spiegare come posso verificare RotatedRec (che è dato da _minAreaRect_) per i criteri di Densità bordo? – DocC

+0

Ciao! Si prega di verificare la risposta modificata. Si prega di votare e contrassegnare come risposta se funziona per voi. :) –

+0

Sì, ho saltato 1-4 passaggi (da ** Modifica ** paragrafo) e forzato al passaggio 5. Ho ritagliato ogni rettangolo ottenuto (di solito ci sono 1-3 "possibili" lastre) dall'immagine (_adaptiveThreshold_ Mat object) . Quindi conto un totale di pixel bianchi (_countNonZero_) e la quantità totale di pixel; ha densità (> = ~ 0.6 ++ la densità è buona) e il rettangolo necessario. Anche Tesseract ha funzionato bene (penso che segmenterò ogni singolo personaggio su un piatto per un migliore riconoscimento in seguito, come consigliato da @Dan). – DocC

1
  • a trovare tutti i componenti collegati (le aree bianche) e determinare il loro contorno.
  • Se li si filtra in base alla dimensione (come parte dell'immagine), rapporto (larghezza-altezza) e rapporto bianco/nero per recuperare le targhe candidate.
  • annullare la trasformazione del rettangolo
  • Rimuovere i bulloni
  • Pass immagine al motore OCR.
2

modello realtà OpenCV ha pre-addestrato appositamente per targhe russi: haarcascade_russian_plate_number

Inoltre v'è il progetto open source per ANPR targhe russi: plate_recognition. Non si usa tesseract, ma ha una buona rete neurale pre-addestrata.

+0

Bene, grazie per la risposta. Ho già visto questo progetto: è buono, ma molto C++ e QT (non sono bravo in questo). Immagino che ritagliare ogni simbolo dalla piastra (che viene rilevato da cascata) e passarlo a tesseract-engine possa funzionare anche ed è facile farlo con Java. Vorrei interpretare il progetto C++ (o associare JNI) per Java, ma non ho molto tempo ora. – DocC

Problemi correlati