Tutorial i exercisis
Els descriptors són mesures numèriques que resumeixen propietats d’un objecte o d’una regió de la imatge. En lloc de comparar directament tots els píxels, es calculen valors com l’àrea, el perímetre, el nombre de forats o la forma general. Això facilita comparar objectes, classificar-los o utilitzar-los com a entrada en sistemes d’aprenentatge automàtic.
Un descriptor és útil si conserva la informació important per a la tasca i ignora variacions que no haurien de canviar la decisió. Per exemple, si volem reconèixer una forma, pot interessar que el descriptor no canviï gaire quan l’objecte es desplaça, gira o canvia lleugerament de mida. Aquesta propietat s’anomena robustesa o invariància, segons el cas.
Carreguem les imatges que utilitzarem en aquesta sessió pràctica
monedes = imread("Imagenes\monedas_color.jpg");
monedes = imresize(monedes,[400,400]);
monedes = rgb2gray(monedes);
montage(monedes)

Segmentem la imatge. Volem fons negre, així que prenem la imatge negativa.
monedes = 255-monedes;
I binaritzem utilitzant el mètode d’OTSU
En aquest punt, Otsu serveix per obtenir automàticament una màscara inicial de l’objecte. Aquesta màscara no és només un resultat final: és la base sobre la qual es calcularan descriptors. Per això, si la binarització és dolenta, els descriptors també poden ser poc fiables.
T_otsu = graythresh(monedes);
monedes_bin = imbinarize(monedes,T_otsu);
montage(monedes_bin)

Millorem la segmentació mitjançant mètodes morfològics per a imatges binàries
La qualitat dels descriptors depèn molt de la segmentació prèvia. Si la màscara binària conté soroll, forats no desitjats o parts d’objecte perdudes, les mesures obtingudes poden ser incorrectes. Per això és habitual aplicar operacions morfològiques abans de calcular descriptors: es busca una representació més neta i coherent de l’objecte.
monedes_bin = imfill(monedes_bin,"holes");
SE = strel("disk",5);
monedes_bin = imclose(monedes_bin,SE);
montage(monedes_bin)

Descriptors topològics
Els descriptors topològics descriuen propietats relacionades amb la connectivitat. No mesuren exactament la mida o la forma, sinó quantes components hi ha, quants forats apareixen o com s’organitza l’estructura de l’objecte. Aquest tipus de descriptor és bastant estable davant deformacions suaus, sempre que no canviï la connexió entre parts de l’objecte.
Nombre de components connexes.
Comptar components connexes vol dir comptar quants objectes separats hi ha a la màscara binària. El resultat depèn de la connectivitat escollida i de la qualitat de la segmentació. Soroll petit pot aparèixer com a components addicionals si no s’ha eliminat abans.
nombre_components_connexes = bwconncomp(monedes_bin).NumObjects
nombre_components_connexes = 8
comp_connexes = bwlabel(monedes_bin);
Una altra manera de comptar components connexes
nombre_components_connexes_2 = max(comp_connexes(:))
nombre_components_connexes_2 = 8
montage({label2rgb(comp_connexes,"jet","k","shuffle")})

Nombre de forats. Matlab extreu les vores de cada component connexa; si hi ha dues vores, és perquè una de les vores és interior i envolta un forat.
El nombre de forats és un descriptor topològic perquè descriu l’estructura interna de l’objecte. No depèn directament de la mida, sinó de si hi ha regions de fons completament envoltades per l’objecte. Pot ser molt útil per diferenciar formes amb aparença semblant però topologia diferent.
Definim un vector buit que portarà el compte dels forats de cada component connexa.
forats = [];
Iterem a través de cada objecte etiquetat o component connexa per veure si té forats
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
vora = bwboundaries(comp_i);
if length(vora) > 1
forats = [forats,length(vora)-1];
end
end
forats
forats =
[]
Característica d’Euler. Recordeu que la característica d’Euler és el nombre de components connexes que no són negres, és a dir, fons, menys el nombre de forats.
La característica d’Euler combina en un sol valor el nombre de components connexes i el nombre de forats. És una mesura simple, però pot ser molt informativa quan els objectes tenen topologies diferents. Per exemple, pot ajudar a diferenciar objectes sense forats d’objectes amb una o més cavitats. Tot i això, no descriu la mida ni la forma exacta de l’objecte.
Definim un vector buit que portarà el compte de la característica d’Euler de cada component connexa.
caracteristica_euler = [];
Iterem a través de cada objecte etiquetat o component connexa per veure quina és la seva característica d’Euler
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
vora = bwboundaries(comp_i);
caracteristica_euler = [caracteristica_euler,1-(length(vora)-1)];
end
caracteristica_euler
caracteristica_euler = 1x8
1 1 1 1 1 1 1 1
Un altre exemple
figures_forats = imread("Imagenes\figuras_agujeros.png");
figures_forats = rgb2gray(figures_forats);
T_otsu_figures = graythresh(figures_forats);
figures_forats_bin = imbinarize(figures_forats,T_otsu_figures);
montage(figures_forats_bin)

nombre_comps_connexes = bwconncomp(figures_forats_bin).NumObjects
nombre_comps_connexes = 6
comp_connexes_figures = bwlabel(figures_forats_bin);
montage({label2rgb(comp_connexes_figures,"jet","k","shuffle")})

forats_2 = [];
caracteristica_euler_2 = [];
for i = 1:nombre_comps_connexes
comp_i = (comp_connexes_figures == i);
vora = bwboundaries(comp_i);
if length(vora) > 1
forats_2 = [forats_2,length(vora)-1];
caracteristica_euler_2 = [caracteristica_euler_2,1-(length(vora)-1)];
end
end
forats_2
forats_2 = 1x6
1 2 2 1 2 2
caracteristica_euler_2
caracteristica_euler_2 = 1x6
0 -1 -1 0 -1 -1
Càlcul de l’esquelet. Càlcul basat en la transformada de la distància
L’esquelet és una representació simplificada de la forma d’un objecte. La idea és reduir l’objecte a una estructura central, fina i connectada, que mantingui la seva organització general. Aquesta representació pot ser útil per estudiar objectes allargats o ramificats. No obstant això, petites irregularitats del contorn poden generar branques addicionals que no sempre tenen significat real.
monedes_skel = bwskel(monedes_bin);
Càlcul basat en aprimament amb operadors morfològics
monedes_skel_2 = bwmorph(monedes_bin,"skeleton",Inf);
montage({monedes_bin,monedes_skel,monedes_skel_2})

Càlcul de la transformada de la distància
D = bwdist(~monedes_bin);
imshow(D,[])

Descriptors geomètrics
Els descriptors geomètrics mesuren propietats relacionades amb la mida, la posició i la forma de l’objecte. Alguns, com l’àrea i el perímetre, depenen directament de l’escala de la imatge. Altres, com la compacitat o l’excentricitat, descriuen proporcions i poden ser més útils per comparar objectes de mides diferents.
montage(monedes_bin)

Càlcul de l’àrea.
L’àrea es calcula comptant els píxels que pertanyen a l’objecte. És una mesura senzilla de mida, però depèn de l’escala de la imatge i de la resolució. Si dues imatges tenen escales diferents, cal normalitzar o interpretar l’àrea amb cura.
Definim un vector buit que calcularà l’àrea de cada component connexa.
area = [];
Iterem a través de cada objecte etiquetat o component connexa per veure quina és la seva àrea
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
area = [area,sum(comp_i(:))];
end
area
area = 1x8
5453 5074 3563 2436 7174 3047 8253 8731
Càlcul del perímetre.
El perímetre mesura la longitud del contorn de l’objecte. A diferència de l’àrea, és molt sensible a irregularitats de la vora: un contorn amb soroll pot tenir un perímetre artificialment gran. Per això sovint convé netejar la màscara abans de calcular-lo.
perimetre = [];
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
perimetre = [perimetre,regionprops(comp_i, 'Perimeter').Perimeter];
end
perimetre
perimetre = 1x8
258.9320 250.6950 209.2860 175.7500 301.8050 196.0870 320.1980 332.9510
Igual que el perímetre, l’àrea també es pot calcular amb la comanda regionprops(comp_i, 'Area').Area]
Càlcul del centroide o centre de masses
El centroide és el punt mitjà de l’objecte si tots els seus píxels tinguessin el mateix pes. Serveix per resumir la posició de l’objecte amb un sol punt. És útil per seguiment, comparació de formes i càlcul de relacions espacials entre objectes.
centroide = [];
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
centroide = [centroide;regionprops(comp_i, 'Centroid').Centroid];
end
centroide
centroide = 8x2
86.5034 185.0011
85.0530 305.2221
94.6444 91.2088
171.4179 240.7373
192.8400 143.6901
211.6853 320.4207
302.5620 252.9773
305.9201 101.5368
Càlcul de la compacitat
La compacitat relaciona l’àrea d’un objecte amb el seu perímetre. Un objecte arrodonit i amb contorn suau acostuma a ser més compacte que un objecte molt allargat o amb moltes irregularitats. Per això, aquesta mesura pot donar informació sobre la complexitat de la forma, encara que no descrigui tots els detalls del contorn.
compacitat = perimetre.*perimetre./area
compacitat = 1x8
12.2952 12.3863 12.2932 12.6798 12.6967 12.6190 12.4230 12.6969
Càlcul del diàmetre
diametre = [];
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
diametre = [diametre,regionprops(comp_i, 'MajorAxisLength').MajorAxisLength];
end
diametre
diametre = 1x8
83.5045 80.6870 67.6135 56.6321 96.2877 63.1585 104.0661 106.1058
Càlcul de l’excentricitat, és a dir, de la relació eix major-eix menor
L’excentricitat descriu fins a quin punt una forma és allargada. Un objecte proper a un cercle té excentricitat baixa, mentre que un objecte allargat té excentricitat alta. Aquesta mesura és útil perquè descriu proporció de forma i no només mida absoluta.
diametre_menor = [];
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
diametre_menor = [diametre_menor,regionprops(comp_i, 'MinorAxisLength').MinorAxisLength];
end
excentricitat = diametre./diametre_menor
excentricitat = 1x8
1.0041 1.0074 1.0074 1.0328 1.0146 1.0274 1.0304 1.0124
Càlcul de la bounding box
La bounding box és el rectangle més simple que permet localitzar aproximadament un objecte dins de la imatge. No descriu el contorn exacte, però resumeix posició, amplada i alçada d’una manera molt pràctica. Aquesta idea també és fonamental en detecció d’objectes amb aprenentatge profund, on les caixes delimitadores es comparen amb anotacions mitjançant mesures com la IoU.
imshow(monedes_bin);
hold on;
for i = 1:nombre_components_connexes
comp_i = (comp_connexes == i);
bounding_box = regionprops(comp_i, 'boundingbox').BoundingBox;
rectangle = rectangle('Position', bounding_box, 'EdgeColor', 'r', 'LineWidth', 2);
end
hold off
