TP4: Assemblage de photos

Par Pierre-Marc Levasseur

Description

à partir d'un ensemble d'image, je devais développer un algorithme capable de les assembler en un panorama automatiquement. L'algorithme est assez complex et a été développé en plusieurs étapes. Dans les sections suivantes, vous trouverez une brève description des différentes parties de l'algorithme ainsi que les résultats que j'ai obtenu tout au long du développement.

Vous pouvez cliquer sur les images pour les voir en plein écran.

Réchauffement

Brièvement, voici comment ma fonction appliqueTransformation(img, H) fonctionne. Elle calcule tout d'abord la taille de l'image transformée en appliquant l'homographie au quatre coins de l'image passée en paramètre. Elle calcule en même temps les décalages en x et en y (positif ou négatif) pour recadrer la photo transformée plus tard. Elle applique ensuite la transformation inverse à chacun des pixels de l'image et utilise interp2 pour retrouver leur couleur.

Voici le résultat avec la matrice et l'image fournie :

Appariement manuel

Description de l'algorithme

Pour réussir à faire les panoramas, j'ai divisé mon algorithme en plusieurs étapes distinctes. J'ai commencé par extraire des points d'intérets avec l'outil fourni au dernier tp (Morphage de visage). Pour chaque paire d'image, j'ai seulement extrait 8 points pour obtenir les résultats présentés plus bas.

Avec ces points, j'ai fait une fonction qui permet de calculer une homographie à partir d'une série de points de correspondance. Cette fonction résoud un système de la forme Ah = 0 en utilisant la décomposition SVD de la matrice A. Donc, pour chaque paire d'images adjacentes, j'ai calculé une matrice de transformation H à l'aide de cette fonction.

J'ai ensuite utilisé la fonction développée à la section Réchauffement pour transformé chacune des images avec leur matrice de transformation H correspondante. Donc, puisque les images fournies étaient tous regroupées trois par trois, j'ai utilisé l'image du centre commen référence (sans transformation) et j'ai transformé les deux images du bout.

Finalement, avec les images transformées, j'ai simplement fusionné les images en utilisant un seul point de correspondance pour chaque paire. Par exemple, pour fusionner l'image de gauche transformée avec l'image centrale de référence, j'ai transformé un des points de l'image de gauche avec sa matrice de transformation et, en utilisant le point correspondant dans l'image de référence, j'ai simplement calculé ou serait le coin supérieur gauche de l'image de référence. Ayant ce point en main, j'ai composé les images ensemble en faisant une moyenne pondérée aux endroits où elles se chevauchaient.

Voici les résultat sur les trois séries fournies:

Série 1

Voici les points d'intérêts pour l'image précédente :

Série 2

L'alignement ici n'est pas parfait sur le bas de l'image, mais la ligne d'horizon est bien alignée. Je crois qu'avec un plus grand nombre de point, l'homographie calculé aurait été un peu plus précise et le résultat aurait été un peu plus convaincant.

Voici les points d'intérêts fournis pour l'image précédente :

Série 3

Voici les points d'intérêts pour l'image précédente :

Appariement automatique

Encore une fois l'algorithme que j'ai programmé est divisé en plusieurs grandes étapes. J'utilise tout d'abord la fonction harris sur chacune des images pour extraire des points d'intérêt. Pour limiter la quantité de point utiliser pour faire l'appariement, j'ai fait la fonction filtrerPoints(pts, nbPoint) qui prend les points résultant de la fonction harris et qui renvoie un certain nombre de point déterminer par le deuxième paramètre. La fonction garde donc les points d'intérêts les plus important en utilisant répression maximale non adaptative.

Pour chaque série de points filtrés, j'utilise ensuite la fonction obtenirDescripteur(pts,im) qui extrait des descripteurs pour chaque point. Les descripteurs sont des petites images de 8 par 8 pixels créé à partir d'un bloc de 40 par 40 pixels autour de chacun des points d'intérêts. Le descripteur est normalisé (à l'aide des méthodes mean2(A) et std2(A)) avec la formule : I = (I - μ)/σ.

Avec les descripteurs en main, l'algorithme détermine les correspondances entre ceux-ci grâce à la fonction apparierDescripteurs(desc1, desc2) qui prend deux séries de descripteurs et renvoie un vecteur contenant les correspondance (l'élément à la ligne 1 correspond à l'index du descripteur dans desc2 qui correspond au descripteur 1 dans desc1). La correspondance est calculée en comparant les distances entre chaque descripteur avec la fonction dist2(X,C). Pour chaque descripteur, la fonction garde les deux plus proches voisins et fait un ratio entre ceux-ci. Si le ratio est plus petit que le seuil 0.4, la correspondance est gardée et ajoutée au vecteur. Sinon, le descripteur est considéré comme n'ayant aucune de correspondance et -1 est ajouté à son index dans le vecteur de correspondance et sera donc ignoré dans les calculs plus tard.

Avec ces vecteurs de correspondances, l'algorithme utilise la fonction calculerHomographieRANSAC(pts1, pts2, correspondances) qui utilise l'algorithme RANSAC pour calculer les homographies entre chaque paire d'images adjacentes. La fonction choisi donc 10000 fois quatres points au hasard dans pts1 et calcul une homographie avec les quatres points correspondant dans pts2. Elle applique ensuite l'homographie aux points pts1 et compte le nombre de points qui sont à une distance de moins de 5 pixels de leur point de correspondance dans pts2. L'homographie ayant le plus grand nombre de point est sélectionnée et renvoyée.

Finalement, avec les homographies est les correspondances l'algorithme assemble les images pour construire le panorama final en utilisant une technique similaire à la section précédente.

Voici les résultats de mon algorithme sur les images fournies:

On peut voir ici un exemple de points restant après le filtrage pour les deux premières images. Pour cette série, j'ai seulement gardé 64 points par image.

Problèmes et difficultés

Comme vous pouvez le constater, les résultats ne sont pas toujours convaincant lorsqu'il y a beaucoup d'images. Si je prend seulement une paire d'images avec beaucoup d'information, mon algorithme fonctionne très bien. L'exemple ci-dessous le montre très bien avec des photos que j'ai prises. Par contre, lorsque que le nombre d'image augmente, l'assemblage est plus difficile et la projection tend à fortement s'agrandir vers la gauche (dépend de la référence choisie). Malheureusement, j'ai manqué de temps pour rafiner mon algorithme d'assemblage. C'est pourquoi j'ai seulement mis les résultats pour les images du centre et du bas sans les assembler pour la dernière série.

Ensuite, si les images contiennent moins d'informations, comme les images du ciel de la dernière série des panoramas automatique, mon algorithme à de la difficulté à trouver des correspondances entre les descripteurs et calcule une homographie incorrecte. Il aurait peut-être fallu augmenter le nombre de point et rafiner la génération des descripteur.

Finalement, une partie de mon code n'est pas modulaire. J'ai isolé beaucoup de fonctions (le filtrage des points avec la répression maximale non adaptative, l'extraction des descripteurs, appariement des descripteurs, l'algorithme RANSAC), mais pour faire l'assemblage des différentes séries d'images, j'ai dû faire un script par série.

Appariement sur mes images

Voici le résultat de l'algorithme de la section précédente sur mes propres photos:

Mon poste de travail:

Voici un panorama de mon point de vue pendant que je travaillais sur ce devoir. (J'avais besoin d'un panorama pour contenir tous ces écrans!)

Cégep Garneau

Voici un panorama du cégep Garneau vu de mon balcon. Le résultat est vraiment bon pour cette série de photos.

Crédits supplémentaires

Graffiti

Pour faire cette image, j'ai pris une photo de mon école primaire. J'ai ensuite manuellement sélectionné quelques points à l'endroit où je voulais insérer le graffiti. J'ai ensuite calculé une homographie en faisant correspondre les points dans l'image de l'école avec les quatres coins de l'image de graffiti. Finalement, j'ai déformé l'image de graffiti avec l'homographie et je l'ai inséré dans l'image. J'ai pris soin de seulement prendre la partie coloré de l'image et de la mélangé à 60% avec l'image de l'école.

Panneau routier

Pour faire cette image, j'ai utilisé une technique similaire à celle utilisé pour insérer le graffiti. J'ai sélectionné les points correspondant aux quatres coins du panneau dans l'image. J'ai calculé une homographie pour déformer l'image que je voulais coller et j'ai insérer l'image déformé à la bonne place.

Mélange à différent moment

J'ai fait plusieurs panorama du cégep Garneau à différent moment dans la journée. Le premier à été présenté à la section précédente et il a été fait en plein jour. Le second à été fait en début de soirée et le dernier a été fait au couché du soleil. J'ai fait un panorama mélangé en prenant la première photo (à gauche) prisent le jour, la seconde prise au couché du soleil et les deux dernières prises en début de soirée. Le résultat n'est pas tout à fait parfait (j'ai quand même pris les photos avec mon téléphone), mais il est toute fois intéressant.

Voici tous les panoramas que j'ai fait à l'aide de mon algorithme automatique. Le dernier est le résultat du mélange.

Sources