Okay, hier ist eine andere mögliche Lösung. Ich weiß, dass Sie mit Python arbeiten - ich arbeite mit C ++. Ich gebe Ihnen einige Ideen und hoffe, dass Sie diese Antwort umsetzen können, wenn Sie dies wünschen.
Die Hauptidee ist, überhaupt keine Vorverarbeitung zu verwenden (zumindest nicht in der Anfangsphase) und sich stattdessen auf jedes Zielzeichen zu konzentrieren, einige Eigenschaften zu erhalten und jeden Blob nach diesen Eigenschaften zu filtern .
Ich versuche, die Vorverarbeitung nicht zu verwenden, weil: 1) Filter und morphologische Stadien die Qualität der Blobs beeinträchtigen können und 2) Ihre Ziel-Blobs einige Eigenschaften aufweisen, die wir ausnutzen könnten, hauptsächlich: Seitenverhältnis und Fläche .
Probieren Sie es aus, die Zahlen und Buchstaben scheinen alle größer als breiter zu sein. Außerdem scheinen sie innerhalb eines bestimmten Bereichswerts zu variieren. Sie möchten beispielsweise Objekte "zu breit" oder "zu groß" verwerfen .
Die Idee ist, dass ich alles filtern werde, was nicht in vorberechnete Werte fällt. Ich habe die Zeichen (Zahlen und Buchstaben) untersucht und dabei minimale, maximale Flächenwerte und ein minimales Seitenverhältnis (hier das Verhältnis zwischen Höhe und Breite) angegeben.
Lassen Sie uns am Algorithmus arbeiten. Lesen Sie zunächst das Bild und ändern Sie die Größe auf die Hälfte der Abmessungen. Ihr Bild ist viel zu groß. In Graustufen konvertieren und über otsu ein Binärbild erhalten, hier im Pseudocode:
//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" );
Cool. Wir werden mit diesem Bild arbeiten. Sie müssen jeden weißen Fleck untersuchen und einen "Eigenschaftenfilter" anwenden . Ich verwende verbundene Komponenten mit Statistiken, um durch jeden Blob zu schleifen und dessen Fläche und Seitenverhältnis zu ermitteln. In C ++ geschieht dies wie folgt:
//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…
};
Jetzt wenden wir den Eigenschaftenfilter an. Dies ist nur ein Vergleich mit den vorberechneten Schwellenwerten. Ich habe folgende Werte verwendet:
Minimum Area: 40 Maximum Area:400
MinimumAspectRatio: 1
for
Vergleichen Sie in Ihrer Schleife die aktuellen Blob-Eigenschaften mit diesen Werten. Wenn die Tests positiv sind, "malen" Sie den Klecks schwarz. Fortsetzung innerhalb der for
Schleife:
//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 );
}
Erstellen Sie nach der Schleife das gefilterte Bild:
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];
}
}
Und ... das war's auch schon. Sie haben alle Elemente gefiltert, die nicht dem entsprechen, wonach Sie suchen. Wenn Sie den Algorithmus ausführen, erhalten Sie folgendes Ergebnis:
Ich habe zusätzlich die Begrenzungsrahmen der Blobs gefunden, um die Ergebnisse besser zu visualisieren:
Wie Sie sehen, werden einige Elemente falsch erkannt. Sie können den "Eigenschaftenfilter" verfeinern, um die gesuchten Zeichen besser zu identifizieren. Eine tiefere Lösung, die ein wenig maschinelles Lernen erfordert, erfordert die Konstruktion eines "idealen Merkmalsvektors", das Extrahieren von Merkmalen aus den Blobs und das Vergleichen beider Vektoren über ein Ähnlichkeitsmaß. Sie können auch eine Nachbearbeitung anwenden , um die Ergebnisse zu verbessern ...
Was auch immer, Mann, Ihr Problem ist weder trivial noch einfach skalierbar, und ich gebe Ihnen nur Ideen. Hoffentlich können Sie Ihre Lösung implementieren.