Tutorial i exercisis
Aquesta pràctica se centra en característiques locals que permeten trobar correspondències entre imatges. Una correspondència indica que un punt d’una imatge i un punt d’una altra probablement representen la mateixa part de l’escena o del mateix objecte. Perquè això funcioni, el detector ha de trobar punts repetibles i el descriptor ha de representar-los de manera prou estable davant canvis d’escala, rotació, punt de vista o il·luminació.
Carreguem les imatges que utilitzarem en la sessió pràctica
cocacola_lata_1 = imread("Imagenes\coca_cola_1.jpg");
cocacola_lata_2 = imread("Imagenes\coca_cola_2.jpg");
frame1 = imread("Imagenes\Frame 1.tif");
Passem les imatges a escala de grisos, per a una millor detecció de les característiques
Molts detectors locals treballen sobre intensitat perquè les cantonades, vores i gradients es poden definir clarament en una sola imatge de grisos. Això redueix la complexitat i evita que diferències de color poc rellevants interfereixin en la detecció.
cocacola_lata_1 = rgb2gray(cocacola_lata_1);
cocacola_lata_2 = rgb2gray(cocacola_lata_2);
montage({cocacola_lata_1,cocacola_lata_2})

Característiques tipus SIFT
SIFT és un mètode dissenyat per detectar punts d’interès estables. Una de les seves idees principals és analitzar la imatge a diferents escales, perquè un mateix objecte pot aparèixer més gran o més petit segons la distància a la càmera. A més, assigna una orientació als punts detectats i calcula descriptors basats en gradients, cosa que ajuda a comparar punts encara que la imatge estigui girada o tingui canvis moderats d’il·luminació.
Utilitzem la comanda detectSIFTFeatures per obtenir tots els punts d’interès de tipus SIFT juntament amb els seus descriptors. Després els mostrem sobre la imatge original per veure quin tipus de característiques detecta aquest algorisme.
SIFT_features_lata_2 = detectSIFTFeatures(cocacola_lata_2);
puntos_SIFT_lata_2 = SIFT_features_lata_2.Location;
imshow(cocacola_lata_2)
hold on
plot(puntos_SIFT_lata_2(:,1),puntos_SIFT_lata_2(:,2),'+',Color='r');
hold off

Anàlisi dels paràmetres d’entrada: llindar per als màxims i els mínims, és a dir, per a la supressió de no-màxims; llindar per eliminar els punts d’interès pertanyents a rectes; definició del nombre de capes en les octaves i del valor inicial de la variància.
Els paràmetres del detector influeixen directament en el nombre i la qualitat dels punts detectats. Si els llindars són massa permissius, apareixen molts punts, però alguns poden ser poc estables o correspondre a soroll. Si els llindars són massa estrictes, es redueix el nombre de punts i es poden perdre zones útils. Per això cal entendre aquests paràmetres com un equilibri entre sensibilitat i fiabilitat.
Un altre exemple
SIFT_features_frame_1 = detectSIFTFeatures(frame1);
puntos_SIFT_frame_1 = SIFT_features_frame_1.selectStrongest(550);
puntos_SIFT_frame_1 = puntos_SIFT_frame_1.Location;
imshow(frame1);
hold on
plot(puntos_SIFT_frame_1(:,1),puntos_SIFT_frame_1(:,2),'o',Color='r')
hold off

Característiques tipus FAST
FAST és un detector de cantonades pensat per ser molt ràpid. Analitza els píxels d’una circumferència al voltant del punt candidat i comprova si hi ha un canvi d’intensitat prou clar. Aquesta simplicitat el fa molt eficient en aplicacions on el temps de càlcul és important. Tot i això, FAST detecta punts, però no proporciona per si sol un descriptor complet per comparar-los entre imatges.
Utilitzem la comanda detectFASTFeatures per obtenir tots els punts d’interès de tipus FAST. Després els mostrem sobre la imatge original per veure quin tipus de característiques detecta aquest algorisme.
FAST_features_lata_2 = detectFASTFeatures(cocacola_lata_2);
puntos_FAST_lata_2 = FAST_features_lata_2.Location;
imshow(cocacola_lata_2)
hold on
plot(puntos_FAST_lata_2(:,1),puntos_FAST_lata_2(:,2),'o',Color='r');
hold off

Un altre exemple
FAST_features_frame_1 = detectFASTFeatures(frame1);
puntos_FAST_frame_1 = FAST_features_frame_1.Location;
imshow(frame1)
hold on
plot(puntos_FAST_frame_1(:,1),puntos_FAST_frame_1(:,2),'+',Color='r')
hold off

Característiques tipus ORB
ORB combina idees de detecció ràpida amb descriptors binaris. Parteix d’un detector eficient, relacionat amb FAST, i afegeix orientació i una descripció compacta del voltant del punt. Com que el descriptor és binari, la comparació entre punts es pot fer amb distància de Hamming, que és computacionalment senzilla. Per això ORB és molt utilitzat quan es vol un bon equilibri entre velocitat i qualitat.
Utilitzem la comanda detectORBFeatures per obtenir tots els punts d’interès de tipus ORB juntament amb els seus descriptors. Després els mostrem sobre la imatge original per veure quin tipus de característiques detecta aquest algorisme.
ORB_features_lata_2 = detectORBFeatures(cocacola_lata_2);
puntos_ORB_lata_2 = ORB_features_lata_2.selectStrongest(1000);
puntos_coordenadas_ORB_lata_2 = puntos_ORB_lata_2.Location;
imshow(cocacola_lata_2)
hold on
plot(puntos_coordenadas_ORB_lata_2(:,1),puntos_coordenadas_ORB_lata_2(:,2),'o',Color='r');
hold off

Anàlisi dels paràmetres d’entrada: factor d’escala per a la millora de la part FAST de l’algorisme, nombre d’octaves i una regió d’interès per si es volen detectar les característiques en una subregió de la imatge original.
Un altre exemple
ORB_features_frame_1 = detectORBFeatures(frame1);
puntos_ORB_frame_1 = ORB_features_frame_1.selectStrongest(1000);
puntos_coordenadas_ORB_frame_1 = puntos_ORB_frame_1.Location;
imshow(frame1)
hold on
plot(puntos_coordenadas_ORB_frame_1(:,1),puntos_coordenadas_ORB_frame_1(:,2),'+',Color='r')
hold off

Extreure les característiques d’un cert tipus i comparar-les
Quan s’extreuen descriptors de dues imatges, el matching busca quins punts tenen descriptors més semblants. Aquest pas dona correspondències candidates, però no totes han de ser correctes. Dos punts diferents poden tenir aparença local semblant, especialment si hi ha textures repetides o zones poc distintives. Per això és habitual afegir una verificació geomètrica posterior.
La comanda extractFeatures permet extreure el vector descriptor de les característiques introduïdes com a argument.
Un descriptor és un vector que resumeix l’aparença local al voltant d’un punt d’interès. El detector diu on hi ha punts rellevants; el descriptor diu com és el voltant d’aquests punts. Aquesta separació és important perquè detectar i descriure no són exactament la mateixa tasca.
[descriptor_lata_2, SIFT_features_lata_2] = extractFeatures(cocacola_lata_2,SIFT_features_lata_2);
Per comparar objectes entre si, repetim el procés amb l’altra imatge que conté una llauna.
SIFT_features_lata_1 = detectSIFTFeatures(cocacola_lata_1);
[descriptor_lata_1, SIFT_features_lata_1] = extractFeatures(cocacola_lata_1,SIFT_features_lata_1);
Comparem els dos vectors descriptors amb la comanda matchFeatures. Si és binari, s’utilitza la distància de Hamming i, si no, s’utilitza la distància euclidiana normalitzada. La funció retorna els índexs de les característiques emparellades per a les dues imatges, i la comanda length d’aquest vector ens informa de quantes característiques s’han emparellat.
El matching busca, per a cada descriptor, el descriptor més semblant a l’altra imatge. En descriptors binaris, la distància de Hamming compta quants bits són diferents; en descriptors reals, s’utilitzen distàncies numèriques com l’euclidiana. Un bon matching hauria de donar moltes correspondències correctes, però sempre pot incloure errors.
[indices_pares_features,metrica] = matchFeatures(descriptor_lata_2,descriptor_lata_1,"MatchThreshold",10);
length(indices_pares_features)
ans = 71
Ens quedem només amb les característiques emparellades
matched_SIFT_features_lata_2 = SIFT_features_lata_2(indices_pares_features(:,1),:);
matched_SIFT_features_lata_1 = SIFT_features_lata_1(indices_pares_features(:,2),:);
Mostrem l’emparellament entre aquestes característiques
Visualitzar els emparellaments és una comprovació qualitativa important. Si moltes línies uneixen parts coherents de l’objecte, els descriptors estan funcionant bé. Si moltes línies es creuen sense sentit o uneixen zones diferents, cal esperar que la verificació geomètrica elimini aquests errors.
figure
showMatchedFeatures(cocacola_lata_2,cocacola_lata_1, matched_SIFT_features_lata_2,matched_SIFT_features_lata_1,"montage");

Calculem la transformació geomètrica, via RANSAC, que permet fer l’ajust geomètric entre les dues imatges en funció de les característiques emparellades. Utilitzem aquesta transf. per transformar una de les imatges i comparem el resultat.
RANSAC és un mètode robust per estimar una transformació geomètrica quan hi ha correspondències errònies. Prova diferents subconjunts de punts i comprova quines correspondències són coherents amb el mateix model de transformació. Les correspondències coherents s’anomenen inliers, i les incoherents, outliers. D’aquesta manera, l’alineament final depèn sobretot dels emparellaments fiables.
T = estimateGeometricTransform(matched_SIFT_features_lata_2,matched_SIFT_features_lata_1,"affine");
T.T
ans = 3x3 single matrix
-0.6308 -0.2532 0
0.2542 -0.6325 0
329.8466 431.7157 1.0000
cocacola_lata_2_T = imwarp(cocacola_lata_2,T);
montage({cocacola_lata_2_T,cocacola_lata_1})
