[PYTHON] Examinons un peu plus la correspondance des points caractéristiques à l'aide d'OpenCV

Qu'est-ce que la correspondance des points caractéristiques?

Un tel gars. Les points caractéristiques sont détectés et mis en correspondance entre une image 400x400px et une image redimensionnée et pivotée de 200x200px.

download.jpg


code

C'est le code qui produit l'image ci-dessus. seulement ça.

import cv2
from IPython.display import Image
from IPython.display import display


#Chargement d'image
img1 = cv2.imread('/path/to/dir/megane400x400.png')
img2 = cv2.imread('/path/to/dir/megane200x200_rotate.png')

#Détection des points caractéristiques
akaze = cv2.AKAZE_create()
kp1, des1 = akaze.detectAndCompute(img1, None)
kp2, des2 = akaze.detectAndCompute(img2, None)

#correspondant à
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)

#Trier par distance de bourdonnement entre les points caractéristiques
matches = sorted(matches, key=lambda x: x.distance)

#Créer une image de résultat correspondante entre 2 images
img1_2 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
decoded_bytes = cv2.imencode('.jpg', img1_2)[1].tobytes()
display(Image(data=decoded_bytes))

Divisons le code

Chargement d'image

img1 = cv2.imread('/path/to/dir/megane400x400.png')
img2 = cv2.imread('/path/to/dir/megane200x200_rotate.png')
print(img1)

# [[[255 255 255]
#   [255 255 255]
#   [255 255 255]
#   ...
#   [255 255 255]
#   [255 255 255]
#   [255 255 255]]
#
#  [[255 255 255]
#   [255 255 255]
#   [255 255 255]
#   ...
#   [255 255 255]
#   [255 255 255]
#   [255 255 255]]
#
#  ...
#
#  [[255 255 255]
#   [255 255 255]
#   [255 255 255]
#   ...
#   [255 255 255]
#   [255 255 255]
#   [255 255 255]]
#
#  [[255 255 255]
#   [255 255 255]
#   [255 255 255]
#   ...
#   [255 255 255]
#   [255 255 255]
#   [255 255 255]]]

print(img1.shape)
# (400, 400, 3)

La valeur BGR pour chaque pixel est renvoyée. Dans la méthode cv2.imread (), BGR (l'ordre des valeurs est différent) au lieu de RVB. Notez qu'il doit être converti en RVB lorsqu'il est utilisé avec Pillow. Voir aussi: https://note.nkmk.me/python-opencv-bgr-rgb-cvtcolor/

Il s'agit d'une image 400x400px, donc la forme est (400, 400, 3). [255 255 255] <-C'est la valeur BGR par pixel. La partie blanche de l'image est l'endroit où [255 255 255] sont alignés.


Détection des points caractéristiques

akaze = cv2.AKAZE_create()
kp1, des1 = akaze.detectAndCompute(img1, None)
kp2, des2 = akaze.detectAndCompute(img2, None)
print('#####Point caractéristique#####')
print(kp1)
# [<KeyPoint0x11af41db0>, <KeyPoint0x11af649c0>, <KeyPoint0x11af64ba0>,
# ...
# <KeyPoint 0x126265030>, <KeyPoint 0x126265120>, <KeyPoint 0x126265150>]

#Le point caractéristique détecté est cv2.Renvoyé sous forme de tableau dans la classe KeyPoint.


print('#####Nombre de points caractéristiques#####')
print(len(kp1))
# 143

#Nombre de points caractéristiques Varie selon le type et la taille de l'image
#Vous pouvez augmenter le nombre de points caractéristiques en agrandissant l'image, mais si elle dépasse une certaine valeur, cela ne fera qu'augmenter la quantité de calcul, donc augmentez-la tout en vérifiant la sortie.


print('#####Descripteur de fonctionnalité#####')
print(des1)
# [[ 32 118   2 ... 253 255   0]
#  [ 33  50  12 ... 253 255  48]
#  [  0 134   0 ... 253 255  32]
#  ...
#  [ 74  24 240 ... 128 239  31]
#  [245  25 122 ... 255 239  31]
#  [165 242  15 ... 127 238  55]]

#AKAZE revient en tant que vecteur à 61 dimensions


print('#####Vecteur caractéristique#####')
print(des1.shape)
# (143, 61) <- (58 est le nombre de points caractéristiques,Nombre d'éléments dans le descripteur de fonction)

AKAZE est l'un des algorithmes de détection des points caractéristiques et a la même position debout que ORB, SIFT, SURF, etc. Il semble avoir des avantages tels que la vitesse de calcul rapide et la facilité d'utilisation car il est open source.

En outre, selon cela, AKAZE semble avoir une précision de détection plus élevée que ORB. https://docs.opencv.org/3.0-rc1/dc/d16/tutorial_akaze_tracking.html


Comment détectez-vous les points caractéristiques?

feature_building.jpg

Citation: http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.html#features-meaning

A ~ F est une partie découpée de cette image. Savez-vous où se trouve l'image recadrée? Je pense que beaucoup de gens ont ce genre d'impression.

A, B-> Je comprends que c'est le ciel et le mur, mais il est difficile de préciser l'emplacement. (plat) C, D-> Vous pouvez voir que c'est quelque part dans la partie supérieure du bâtiment. Cependant, il est difficile d'identifier l'emplacement exact. (Bord) E, F-> Vous pouvez facilement voir le coin du bâtiment. (coin)

De là, il semble que des pièces telles que E et F sont de bonnes fonctionnalités. Afin de trouver des coins tels que E et F, des algorithmes tels que AKAZE détectent les zones avec de grands changements de luminosité.

Référence: http://www.lab.kochi-tech.ac.jp/yoshilab/thesis/1150295.pdf


Correspondance des points caractéristiques

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)
print(matches)
#Les points caractéristiques correspondants sont cv2.Renvoyé sous forme de tableau en tant que classe DMatch
# [<DMatch 0x1260f5150>, <DMatch 0x1260f5490>, ... <DMatch 0x1260f65f0>, <DMatch 0x1260f69d0>]

print(len(matches))
# 58

print('###Distance entre les descripteurs d'entités###')
for i in matches:
    print(i.distance)
# 6.0
# 6.0
# .
# .
# .
# 142.0
# 150.0

BFMatcher calcule la distance du descripteur de quantité de caractéristiques obtenu à partir de deux images (ici, la distance de bourdonnement) en arrondissant, et correspond à la plus proche. Le premier argument de BFMatcher (), cv2.NORM_HAMMING, spécifie le calcul de la distance de bourdonnement par distance. Le crossCheck par défaut pour le premier argument de chargement est False, ce qui crée une asymétrie dans laquelle un point-clé est le plus proche, mais l'autre point-clé est plus proche. Si défini sur True, seul le résultat avec le plus court des deux côtés sera renvoyé.

Trier par valeur de retour en passant une fonction à la clé d'argument de sorted ().

--matches-> Liste des objets de type DMatch --DMatch.distance-> Plus la distance entre les descripteurs d'entités est faible, plus le degré de correspondance est élevé. --DMatch.trainIdx-> Index du descripteur dans le descripteur d'apprentissage (données de référence) --DMatch.queryIdx-> Index du descripteur dans le descripteur de requête (données de recherche) --DMatch.imgIdx-> Index de l'image d'entraînement

Quelle est la distance de bourdonnement?

Le nombre de caractères différents aux positions correspondantes dans deux chaînes avec le même nombre de caractères.

• La distance de bourdonnement entre 1011101 et 1001001 est de 2. • La distance de bourdonnement entre 2173896 et 2233796 est de 3. -La distance de bourdonnement entre "tonique" et "roses" est de 3.

def1 et def2 passés à bf.match () sont des tableaux contenant plusieurs descripteurs de caractéristiques à 61 dimensions.

print(des1)
# [[ 32 118   2 ... 253 255   0] <-61 pièces
#  [ 33  50  12 ... 253 255  48] <-61 pièces
#  [  0 134   0 ... 253 255  32] 
#  ...
#  [ 74  24 240 ... 128 239  31] 
#  [245  25 122 ... 255 239  31] 
#  [165 242  15 ... 127 238  55]

Il semble que le traitement suivant soit effectué dans bf.match ().

  1. Calculez la distance de bourdonnement en convertissant le nombre décimal-> nombre binaire
  2. Prenez la somme des distances pour 61 éléments
  3. Trouvez la distance entre toutes les quantités d'entités par round robin
  4. Renvoie le résultat qui dépasse un certain seuil <-Ceci n'est pas confirmé

Expérience 1

Vous pouvez voir qu'il a été converti en décimal-> binaire.

#0 est un nombre binaire 00000000
des1 = np.array([0]).astype('uint8')
#255 est un nombre binaire 11111111
des2 = np.array([255]).astype('uint8')
# ※ astype('uint8')Si vous ne le faites pas, bf.match()Je ne peux pas te le donner.

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)

for i in matches:
    print(i.distance)
# 8.0 <-Distance de fredonnement
#244 est un nombre binaire 11111110
des1 = np.array([244]).astype('uint8')
#255 est un nombre binaire 11111111
des2 = np.array([255]).astype('uint8')
# ※ astype('uint8')Si vous ne le faites pas, bf.match()Je ne peux pas te le donner.

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)

for i in matches:
    print(i.distance)
# 1.0 <-Distance de fredonnement

Expérience 2

Vous pouvez voir que nous additionnons les distances entre les éléments dans le descripteur d'entités.

#La représentation binaire est possible en ajoutant un préfixe 0b.
des1 = np.array([[0b0001, 0b0001, 0b0001], [0b0011, 0b0011, 0b0011], [0b0111, 0b0111, 0b0111]]).astype('uint8')
des2 = np.array([[0b0000, 0b0000, 0b0000]]).astype('uint8')
# ※ astype('uint8')Si vous ne le faites pas, bf.match()Je ne peux pas te le donner.

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)

# [0b0001, 0b0001, 0b0001]Quand[0b0000, 0b0000, 0b0000]Seul le résultat de
for i in matches:
    print(i.distance)
# 3.0 <-Distance de fredonnement

Créer une image de résultat correspondante (première image)

img1_2 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
decoded_bytes = cv2.imencode('.jpg', img1_2)[1].tobytes()
display(Image(data=decoded_bytes)

En définissant matches [: 10] dans l'argument de drawMatches (), 10 points caractéristiques proches les uns des autres sont dessinés à partir du haut.

La fin

Recommended Posts

Examinons un peu plus la correspondance des points caractéristiques à l'aide d'OpenCV
Rechercher des illustrations de cartes à partir d'images à l'aide de la correspondance des points caractéristiques
Examinons un peu plus la correspondance des points caractéristiques à l'aide d'OpenCV
C'est un Mac. Qu'est-ce que la commande Linux Linux?
[Partie 2] Construisons un serveur Web avec EC2 Linux
Facilitons un peu la gestion des dépendances avec pip
[Partie 1] Configurons un serveur Micra sur Linux
Créons une application Mac avec Tkinter et py2app
Plus de double démarrage ou de VM! Construisons un environnement Linux avec WSL2 et Windows Terminal [WSL2]