D'accord, voici une autre solution possible. Je sais que vous travaillez avec Python - je travaille avec C ++. Je vais vous donner quelques idées et j'espère que si vous le souhaitez, vous pourrez mettre en œuvre cette réponse.
L'idée principale est de ne pas utiliser du tout le prétraitement (du moins pas au stade initial) et de se concentrer à la place sur chaque personnage cible, d'obtenir certaines propriétés et de filtrer chaque blob en fonction de ces propriétés.
J'essaie de ne pas utiliser le prétraitement car: 1) les filtres et les étapes morphologiques pourraient dégrader la qualité des blobs et 2) vos blobs cibles semblent présenter certaines caractéristiques que nous pourrions exploiter, principalement: le rapport d'aspect et la zone .
Vérifiez-le, les chiffres et les lettres semblent tous être plus grands que plus larges… en outre, ils semblent varier dans une certaine valeur de zone. Par exemple, vous souhaitez supprimer les objets "trop larges" ou "trop gros" .
L'idée est que je filtre tout ce qui ne correspond pas aux valeurs pré-calculées. J'ai examiné les caractères (chiffres et lettres) et suis venu avec des valeurs minimales et maximales de surface et un rapport d'aspect minimum (ici, le rapport entre la hauteur et la largeur).
Travaillons sur l'algorithme. Commencez par lire l'image et redimensionnez-la à la moitié des dimensions. Votre image est bien trop grande. Convertissez en niveaux de gris et obtenez une image binaire via otsu, voici en pseudo-code:
//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. Nous allons travailler avec cette image. Vous devez examiner chaque goutte blanche et appliquer un "filtre de propriétés" . J'utilise des composants connectés avec des statistiques pour parcourir chaque blob et obtenir sa zone et son rapport d'aspect, en C ++, cela se fait comme suit:
//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…
};
Maintenant, nous allons appliquer le filtre des propriétés. Ce n'est qu'une comparaison avec les seuils pré-calculés. J'ai utilisé les valeurs suivantes:
Minimum Area: 40 Maximum Area:400
MinimumAspectRatio: 1
Dans votre for
boucle, comparez les propriétés de blob actuelles avec ces valeurs. Si les tests sont positifs, vous "peignez" le blob en noir. Continuer à l'intérieur de la for
boucle:
//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 );
}
Après la boucle, construisez l'image filtrée:
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];
}
}
Et c'est à peu près tout. Vous avez filtré tous les éléments qui ne sont pas similaires à ce que vous recherchez. En exécutant l'algorithme, vous obtenez ce résultat:
J'ai également trouvé les boîtes englobantes des blobs pour mieux visualiser les résultats:
Comme vous le voyez, certains éléments sont mal détectés. Vous pouvez affiner le "filtre des propriétés" pour mieux identifier les caractères que vous recherchez. Une solution plus approfondie, impliquant un peu d'apprentissage automatique, nécessite la construction d'un "vecteur de caractéristiques idéal", extrayant les caractéristiques des blobs et comparant les deux vecteurs via une mesure de similarité. Vous pouvez également appliquer un post- traitement pour améliorer les résultats ...
Quoi qu'il en soit, mec, votre problème n'est pas trivial ni facile à évoluer, et je vous donne juste des idées. Espérons que vous pourrez mettre en œuvre votre solution.