Questo è un bel problema da affrontare. Ecco un approccio che potresti usare, ma ammetto che non è affatto perfetto e potrebbe non essere così robusto. Speriamo che possa darti idee ...
Quello che ho fatto è fondamentalmente filtrare l'immagine con un filtro mediano (come hai fatto tu) e rimuovere piccoli elementi usando bwareaopen
. Quindi ho chiamato regionprops
per ottenere un gruppo di proprietà, tra le quali le più importanti sono le area
e eccentricity
. L'idea era che tutte le lettere "a" dovessero avere un'eccentricità alquanto simile, quindi una volta che conosciamo l'eccentricità di una lettera possiamo trovare le altre lettere che hanno lo stesso. Probabilmente potresti rendere il codice più robusto usando proprietà aggiuntive che fanno risaltare le lettere dal resto; forse il rapporto MajorAxisLength/MinorAxisLength
per esempio. Lascerò questa parte a te :)
Quindi il modo più semplice per scegliere una lettera in questo caso era selezionare l'oggetto con l'area più grande, ovvero il grande a al centro dell'immagine. Una volta che abbiamo la sua eccentricità, possiamo applicare qualche soglia e selezionare solo gli oggetti trovati usando regionprops
che hanno un'eccentricità simile. Il filtro mediano e la chiamata a bwareaopen
applicati in precedenza sono importanti qui perché il tipo di rumore nei 4 riquadri sulla destra può complicare le cose se non vengono rimossi, poiché alcuni dei punti casuali possono avere un'eccentricità simile alla nostra cara lettera a".
Detto questo, ecco il codice commentato. Si noti che ho cambiato il nome della variabile text
in textIm
poiché text
è una funzione Matlab.
clc
clear
close all
textIm = imread('http://i.stack.imgur.com/N4nCm.png');
%// find threshold and change to binary image
border = graythresh(textIm);
%// =========== NEW \\ ===========
%// NOTICE the use of ~im2bw(...)
textbw = ~im2bw(textIm, border);
%// remove noise with median filter
%// =========== NEW \\ ===========
textfilt = medfilt2(textbw,[7 7]);
textfilt = bwareaopen(textfilt,8);
%// =========== NEW \\ ===========
%// Use an absurdely large line structuring element oriented at 25 degrees
%// to make the a's stand out
se = strel('line', 20 ,25);
textfilt = imclose(textfilt, se);
%// Get a couple properties. Note the "Eccentricity"
S = regionprops(textfilt, 'Area','Eccentricity','Centroid','BoundingBox');
All_areas = vertcat(S.Area);
%// Find the largest element (i.e. the big a). We will use it to get its
%// eccentricity and fetch other a's.
[MaxArea, MaxAreaIdx] = (max(All_areas(:)));
%// Get eccentricity of largest letter.
RefEcc = S(MaxAreaIdx).Eccentricity
Qui l'eccentricità del grande "a" è 0,6654. Un'eccentricità di 0 significa un cerchio e un'eccentricità di 1 significa una linea.
%// Just concatenate everything. Easier to work with.
All_Ecc = vertcat(S.Eccentricity);
All_Centroids = vertcat(S.Centroid);
All_BB = vertcat(S.BoundingBox)
%// Find elements that have the approximate eccentricity of the large a
%// found earlier. You can be more/less stringent and add more conditions here.
PotA = find(All_Ecc > RefEcc*.8 & All_Ecc < RefEcc*1.2)
%// Display output with centroids and bounding boxes.
imshow(textIm)
hold on
scatter(All_Centroids(PotA,1),All_Centroids(PotA,2),60,'r','filled');
for k = 1:numel(PotA)
rectangle('Position',All_BB(PotA(k),:),'EdgeColor','y','LineWidth',2)
end
e output, con centroidi come puntini rossi e le caselle di delimitazione come rettangoli gialli:

E 'stato divertente! Spero di poter aiutare in qualche modo. Potrebbe essere necessario adattare il codice per altre lettere o se ci sono altri oggetti circolari nell'immagine, ma immagino che sia un inizio.
Hai provato tecniche di correlazione/corrispondenza del modello con un'immagine modello della lettera "a" ridimensionata a diverse scale? – eigenchris