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 for
ciclo, confronta le proprietà BLOB correnti con questi valori. Se i test sono positivi, "dipingi" il blob di nero. Continuando all'interno del for
ciclo:
//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:
Ho inoltre trovato le Bounding Boxes dei BLOB per visualizzare meglio i risultati:
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.