Ottieni la posizione di tutto il testo presente nell'immagine usando opencv


11

Ho questa immagine che contiene testo (numeri e alfabeti) al suo interno. Voglio ottenere la posizione di tutto il testo e i numeri presenti in questa immagine. Voglio anche estrarre tutto il testo.

inserisci qui la descrizione dell'immagine

Come ottengo le coordinate così come tutto il testo (numeri e alfabeti) nella mia immagine. Ad esempio 10B, 44, 16, 38, 22B ecc


qual è la tua versione di tensorflow? Se la tua versione è 2.1, prova a installare 2.0
gellezzz il

1
Lanciare taglie a cattive domande non è una buona pratica. Non hai mostrato alcuna conoscenza su come farlo, quindi sembra che tu stia semplicemente cercando di attirare gli sviluppatori a codificare una soluzione completa in cambio di alcuni punti rep. Non mi aspetto di vedere risposte perfette per questo motivo, ma credo che tu possa ottenere soluzioni migliori sui siti web freelance se paghi le persone per il loro tempo.
karlphillip,

@karlphillip così dispiaciuto, ma io sono un principiante ho bisogno di qualcosa per iniziare, giusto? Potete aiutarmi con questo
Pulkit Bhatnagar,

Risposte:


13

Ecco un potenziale approccio che utilizza operazioni morfologiche per filtrare contorni non testuali. L'idea è:

  1. Ottieni immagine binaria. Carica immagine, scala di grigi, quindi soglia di Otsu

  2. Rimuovere le linee orizzontali e verticali. Crea kernel orizzontali e verticali usando cv2.getStructuringElementquindi rimuovi le linee concv2.drawContours

  3. Rimuovi linee diagonali, oggetti circolari e contorni curvi. Filtra utilizzando l'area del contorno cv2.contourArea e l'approssimazione del contorno cv2.approxPolyDP per isolare i contorni non testuali

  4. Estrai ROI e OCR di testo. Trova contorni e filtro per ROI e OCR utilizzando Pytesseract .


Linee orizzontali rimosse evidenziate in verde

inserisci qui la descrizione dell'immagine

Linee verticali rimosse

inserisci qui la descrizione dell'immagine

Rimossi i contorni non testuali assortiti (linee diagonali, oggetti circolari e curve)

inserisci qui la descrizione dell'immagine

Regioni di testo rilevate

inserisci qui la descrizione dell'immagine

import cv2
import numpy as np
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
clean = thresh.copy()

# Remove horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

# Remove vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,30))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

cnts = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    # Remove diagonal lines
    area = cv2.contourArea(c)
    if area < 100:
        cv2.drawContours(clean, [c], -1, 0, 3)
    # Remove circle objects
    elif area > 1000:
        cv2.drawContours(clean, [c], -1, 0, -1)
    # Remove curve stuff
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    x,y,w,h = cv2.boundingRect(c)
    if len(approx) == 4:
        cv2.rectangle(clean, (x, y), (x + w, y + h), 0, -1)

open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
opening = cv2.morphologyEx(clean, cv2.MORPH_OPEN, open_kernel, iterations=2)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,2))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=4)
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    area = cv2.contourArea(c)
    if area > 500:
        ROI = image[y:y+h, x:x+w]
        ROI = cv2.GaussianBlur(ROI, (3,3), 0)
        data = pytesseract.image_to_string(ROI, lang='eng',config='--psm 6')
        if data.isalnum():
            cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
            print(data)

cv2.imwrite('image.png', image)
cv2.imwrite('clean.png', clean)
cv2.imwrite('close.png', close)
cv2.imwrite('opening.png', opening)
cv2.waitKey()

È una buona idea rimuovere prima quelle righe.
karlphillip,

cattiva idea di rimuovere anche parti di lettere ...
Walter Tross,

8

Bene, ecco un'altra possibile soluzione. So che lavori con Python, io lavoro con C ++. Ti darò alcune idee e, si spera, se lo desideri, sarai in grado di attuare questa risposta.

L'idea principale è di non usare affatto la pre-elaborazione (almeno non nella fase iniziale) e concentrarsi invece su ciascun personaggio target, ottenere alcune proprietà e filtrare ogni BLOB in base a queste proprietà.

Sto cercando di non utilizzare la pre-elaborazione perché: 1) I filtri e le fasi morfologiche potrebbero degradare la qualità dei BLOB e 2) i BLOB target sembrano mostrare alcune caratteristiche che potremmo sfruttare, principalmente: proporzioni e area .

Dai un'occhiata, i numeri e le lettere sembrano tutti più alti che più larghi ... inoltre, sembrano variare entro un certo valore di area. Ad esempio, si desidera eliminare gli oggetti "troppo larghi" o "troppo grandi" .

L'idea è che filtrerò tutto ciò che non rientra nei valori precalcolati. Ho esaminato i caratteri (numeri e lettere) e sono arrivato con valori minimi, massimi dell'area e un rapporto d'aspetto minimo (qui, il rapporto tra altezza e larghezza).

Lavoriamo sull'algoritmo. Inizia leggendo l'immagine e ridimensionandola a metà delle dimensioni. La tua immagine è troppo grande. Converti in scala di grigi e ottieni un'immagine binaria tramite otsu, ecco lo pseudo-codice:

//Read input:
inputImage = imread( "diagram.png" );

//Resize Image;
resizeScale = 0.5;

inputResized = imresize( inputImage, resizeScale );

//Convert to grayscale;
inputGray = rgb2gray( inputResized );

//Get binary image via otsu:
binaryImage = imbinarize( inputGray, "Otsu" );

Freddo. Lavoreremo con questa immagine. È necessario esaminare tutti i BLOB bianchi e applicare un "filtro proprietà" . Sto usando componenti collegati con statistiche per eseguire il loop attraverso ogni BLOB e ottenere la sua area e proporzioni, in C ++ questo viene fatto come segue:

//Prepare the output matrices:
cv::Mat outputLabels, stats, centroids;
int connectivity = 8;

//Run the binary image through connected components:
int numberofComponents = cv::connectedComponentsWithStats( binaryImage, outputLabels, stats, centroids, connectivity );

//Prepare a vector of colors  color the filtered blobs in black
std::vector<cv::Vec3b> colors(numberofComponents+1);
colors[0] = cv::Vec3b( 0, 0, 0 ); // Element 0 is the background, which remains black.

//loop through the detected blobs:
for( int i = 1; i <= numberofComponents; i++ ) {

    //get area:
    auto blobArea = stats.at<int>(i, cv::CC_STAT_AREA);

    //get height, width and compute aspect ratio:
    auto blobWidth = stats.at<int>(i, cv::CC_STAT_WIDTH);
    auto blobHeight = stats.at<int>(i, cv::CC_STAT_HEIGHT);
    float blobAspectRatio = (float)blobHeight/(float)blobWidth;

    //Filter your blobs

};

Ora applicheremo il filtro delle proprietà. Questo è solo un confronto con le soglie pre-calcolate. Ho usato i seguenti valori:

Minimum Area: 40  Maximum Area:400
MinimumAspectRatio:  1

All'interno del tuo forciclo, confronta le proprietà BLOB correnti con questi valori. Se i test sono positivi, "dipingi" il blob di nero. Continuando all'interno del forciclo:

    //Filter your blobs

    //Test the current properties against the thresholds:
    bool areaTest =  (blobArea > maxArea)||(blobArea < minArea);
    bool aspectRatioTest = !(blobAspectRatio > minAspectRatio); //notice we are looking for TALL elements!

    //Paint the blob black:
    if( areaTest || aspectRatioTest ){
        //filtered blobs are colored in black:
        colors[i] = cv::Vec3b( 0, 0, 0 );
    }else{
        //unfiltered blobs are colored in white:
        colors[i] = cv::Vec3b( 255, 255, 255 );
    }

Dopo il ciclo, costruisci l'immagine filtrata:

cv::Mat filteredMat = cv::Mat::zeros( binaryImage.size(), CV_8UC3 );
for( int y = 0; y < filteredMat.rows; y++ ){
    for( int x = 0; x < filteredMat.cols; x++ )
    {
        int label = outputLabels.at<int>(y, x);
        filteredMat.at<cv::Vec3b>(y, x) = colors[label];
    }
}

E ... è praticamente tutto. Hai filtrato tutti gli elementi che non sono simili a quello che stai cercando. Eseguendo l'algoritmo si ottiene questo risultato:

inserisci qui la descrizione dell'immagine

Ho inoltre trovato le Bounding Boxes dei BLOB per visualizzare meglio i risultati:

inserisci qui la descrizione dell'immagine

Come vedi, alcuni elementi vengono rilevati in modo errato. Puoi perfezionare il "filtro proprietà" per identificare meglio i caratteri che stai cercando. Una soluzione più profonda, che implica un po 'di apprendimento automatico, richiede la costruzione di un "vettore di caratteristiche ideali", l'estrazione di caratteristiche dai BLOB e il confronto di entrambi i vettori tramite una misura di somiglianza. Puoi anche applicare alcuni post- elaborazione per migliorare i risultati ...

Qualunque cosa, amico, il tuo problema non è banale né facilmente scalabile, e ti sto solo dando idee. Spero che sarai in grado di implementare la tua soluzione.


Ogni possibilità è possibile convertire lo stesso programma in python
Pulkit Bhatnagar il

@PulkitBhatnagar Sì, certo. Tieniti forte, avrò una porta perfetta pronta in pochi minuti.
eldesgraciado,

?? l'hai fatto, in modo che io possa assegnarti la grazia
Pulkit Bhatnagar,

Ah sì. Mi dispiace terribilmente, signore, ho avuto qualche problema, ma la conversione sta procedendo bene. Aspetta. Grazie.
eldesgraciado,

non mi sarei mai chiesto che potesse essere un sarcasmo.
Pulkit Bhatnagar,

4

Un metodo consiste nell'utilizzare la finestra scorrevole (è costosa).

Determina la dimensione dei caratteri nell'immagine (tutti i caratteri hanno le stesse dimensioni che vedi nell'immagine) e imposta la dimensione della finestra. Prova a tesseract per il rilevamento (l'immagine di input richiede una pre-elaborazione). Se una finestra rileva i caratteri consecutivamente, quindi memorizza le coordinate della finestra. Unisci le coordinate e ottieni la regione sui personaggi.


Penso che 100bounty sia per la risposta
Himanshu Poddar il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.