Pour installer OpenCV avec SIFT sur une machine personnelle : conda install -c menpo opencv
Pour utiliser ce notebook sur le serveur Jupyter de l'UFR : sélectionner le noyau "Python 2" (menu "Kernel", puis "Change kernel")
# Chargement des packages numpy et OpenCV
import numpy as np
from matplotlib import pyplot as plt
import cv2
# Lecture et affichage des images
img1 = cv2.imread("box.png", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("box_in_scene.png", cv2.IMREAD_GRAYSCALE)
plt.figure(figsize=(16,6))
plt.subplot(1,2,1)
plt.imshow(img1, cmap='gray')
plt.subplot(1,2,2)
plt.imshow(img2, cmap='gray');
# Création d'un objet de la classe SIFT
sift = cv2.xfeatures2d.SIFT_create()
# Détection des points SIFT sur les deux images
kp1 = sift.detect(img1,None)
kp2 = sift.detect(img2,None)
# Affichage des images avec leurs points
res1 = cv2.drawKeypoints(img1,kp1,img1,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
res2 = cv2.drawKeypoints(img2,kp2,img2,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
plt.figure(figsize=(16,6))
plt.subplot(1,2,1)
plt.imshow(res1)
plt.subplot(1,2,2)
plt.imshow(res2);
# Calcul des descripteurs SIFT pour les deux images
kp1,dsc1 = sift.compute(img1,kp1)
kp2,dsc2 = sift.compute(img2,kp2)
# Création d'un objet pour la mise en correspondance des keypoints
bf = cv2.BFMatcher(cv2.NORM_L2);
# Calcul des correspondances
matches = bf.match(dsc1, dsc2)
# Affichage des correspondances
image_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches, None)
plt.figure(figsize=(16,6))
plt.imshow(image_matches);
# Préparation : on contruit explicitement les matrices x et y des points x_i et y_i
# de telle sorte que les correspondances soient les (x_i,y_i).
# On donne les points x_i en coordonnées homogènes (avec un 1 en 3e position) et les points y_i en coordonnées
# usuelles (donc x sera de taille (3,n) et y de taille (2,n))
n = len(matches)
x = np.zeros((3,n))
y = np.zeros((2,n))
for i in range(0,n):
indx = matches[i].queryIdx
indy = matches[i].trainIdx
x[0,i], x[1,i] = kp1[indx].pt
x[2,i] = 1
y[0,i], y[1,i] = kp2[indy].pt
# RANSAC pour les transformations affines
def RANSAC_affine(x, y, pi, d):
# arguments:
# x: matrice de taille (3,n) des x_i en coordonnées homogènes
# y: matrice de taille (2,n) des y_i
# pi: scalaire entre 0 et 1, proportion estimée des correspondances à retenir
# d: distance seuil en pixels pour considérer qu'il y a concordance au modèle
# retourne:
# M: matrice de taille (2,3) donnant la transformation affine,
# index : liste d'indices des correspondances retenues.
# ... to do ...
return M, index
# test de l'algorithme.
pi = ...
d = ...
M, index = RANSAC_affine(x,y,pi,d)
# Extraction des correspondances correspondant aux indices retenus
matches_selec = [matches[i] for i in index]
image_matches_selec = cv2.drawMatches(img1, kp1, img2, kp2, matches_selec, None)
plt.figure(figsize=(16,6))
plt.imshow(image_matches_selec);
# Application de la transformation affine sur la première image, et affichage
res = cv2.warpAffine(img1, M, (img2.shape[1], img2.shape[0]) )
plt.figure(figsize=(16,6))
plt.imshow(res, cmap='gray');
# Affichage d'une image en couleurs montrant la superposition
tmp2 = np.zeros(img2.shape)
mix = np.stack((img2,res,tmp2),2).astype(float)/255
plt.figure(figsize=(16,6))
plt.imshow(mix);