[PYTHON] Lassen Sie uns etwas näher auf den Feature-Point-Matching mit OpenCV eingehen

Was ist Feature Point Matching?

So ein Typ. Feature-Punkte werden erkannt und zwischen einem 400 x 400 Pixel großen Bild und einem 200 x 200 Pixel großen und gedrehten Bild angepasst.

download.jpg


Code

Dies ist der Code, der das obige Bild ausgibt. nur das.

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


#Bild wird geladen
img1 = cv2.imread('/path/to/dir/megane400x400.png')
img2 = cv2.imread('/path/to/dir/megane200x200_rotate.png')

#Funktionspunkterkennung
akaze = cv2.AKAZE_create()
kp1, des1 = akaze.detectAndCompute(img1, None)
kp2, des2 = akaze.detectAndCompute(img2, None)

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

#Sortieren Sie nach dem Brummabstand zwischen den Feature-Punkten
matches = sorted(matches, key=lambda x: x.distance)

#Erstellen Sie ein passendes Ergebnisbild zwischen 2 Bildern
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))

Teilen wir den Code auf

Bild wird geladen

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)

Der BGR-Wert pro Pixel wird zurückgegeben. Bei der Methode cv2.imread () wird BGR (die Reihenfolge der Werte ist unterschiedlich) anstelle von RGB verwendet. Beachten Sie, dass es bei Verwendung mit Pillow in RGB konvertiert werden muss. Siehe auch: https://note.nkmk.me/python-opencv-bgr-rgb-cvtcolor/

Dies ist ein 400x400px-Bild, daher ist die Form (400, 400, 3). [255 255 255] <- Dies ist der BGR-Wert pro Pixel. Im weißen Teil des Bildes sind [255 255 255] aufgereiht.


Funktionspunkterkennung

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

#Der erkannte Feature-Punkt ist cv2.Wird als Array in der KeyPoint-Klasse zurückgegeben.


print('#####Anzahl der Feature-Punkte#####')
print(len(kp1))
# 143

#Anzahl der Merkmalspunkte Variiert je nach Art und Größe des Bildes
#Sie können die Anzahl der Feature-Punkte erhöhen, indem Sie das Bild vergrößern. Wenn es jedoch einen bestimmten Wert überschreitet, wird nur der Rechenaufwand erhöht. Erhöhen Sie ihn daher, während Sie die Ausgabe überprüfen.


print('#####Feature-Deskriptor#####')
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 kehrt als 61-dimensionaler Vektor zurück


print('#####Merkmalsvektor#####')
print(des1.shape)
# (143, 61) <- (58 ist die Anzahl der Merkmalspunkte,Anzahl der Elemente im Feature-Deskriptor)

AKAZE ist einer der Algorithmen zur Erkennung von Merkmalspunkten und hat dieselbe Standposition wie ORB, SIFT, SURF usw. Es scheint Vorteile wie schnelle Berechnungsgeschwindigkeit und Benutzerfreundlichkeit zu haben, da es Open Source ist.

Demnach scheint AKAZE eine höhere Erkennungsgenauigkeit als ORB zu haben. https://docs.opencv.org/3.0-rc1/dc/d16/tutorial_akaze_tracking.html


Wie erkennt man Feature-Punkte?

feature_building.jpg

Zitat: 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 ist ein Teil, der aus diesem Bild ausgeschnitten ist. Wissen Sie, wo sich das zugeschnittene Bild befindet? Ich denke, viele Menschen haben einen solchen Eindruck.

A, B-> Ich verstehe, dass es der Himmel und die Wand sind, aber es ist schwierig, den Ort zu bestimmen. (eben) C, D-> Sie können sehen, dass es sich irgendwo im oberen Teil des Gebäudes befindet. Es ist jedoch schwierig, den genauen Ort zu bestimmen. (Kante) E, F-> Sie können die Ecke des Gebäudes leicht sehen. (Ecke)

Daraus ergibt sich, dass Teile wie E und F gute Eigenschaften sind. Um Ecken wie E und F zu finden, erkennen Algorithmen wie AKAZE Bereiche mit großen Helligkeitsänderungen.

Referenz: http://www.lab.kochi-tech.ac.jp/yoshilab/thesis/1150295.pdf


Feature Point Matching

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)
print(matches)
#Übereinstimmende Feature-Punkte sind cv2.Wird als Array als DMatch-Klasse zurückgegeben
# [<DMatch 0x1260f5150>, <DMatch 0x1260f5490>, ... <DMatch 0x1260f65f0>, <DMatch 0x1260f69d0>]

print(len(matches))
# 58

print('###Abstand zwischen Feature-Deskriptoren###')
for i in matches:
    print(i.distance)
# 6.0
# 6.0
# .
# .
# .
# 142.0
# 150.0

BFMatcher berechnet den Abstand des Merkmalsmengen-Deskriptors, der aus zwei Bildern (hier der Brummabstand) durch Runden erhalten wird, und stimmt mit dem nächstgelegenen überein. Das erste Argument von BFMatcher (), cv2.NORM_HAMMING, gibt die Berechnung der Brummentfernung nach Entfernung an. Der Standard-CrossCheck für das erste Ladeargument ist False, wodurch eine Asymmetrie entsteht, bei der ein Schlüsselpunkt am nächsten liegt, der andere jedoch näher. Wenn True festgelegt ist, wird nur das Ergebnis mit beiden kürzesten zurückgegeben.

Sortieren nach Rückgabewert durch Übergeben einer Funktion an den Argumentschlüssel von sorted ().

--matches-> Liste der Objekte vom Typ DMatch --DMatch.distance-> Je geringer der Abstand zwischen Feature-Deskriptoren ist, desto höher ist der Übereinstimmungsgrad. --DMatch.trainIdx-> Index des Deskriptors im Trainingsdeskriptor (Referenzdaten) --DMatch.queryIdx-> Index des Deskriptors im Abfragedeskriptor (Suchdaten) --DMatch.imgIdx-> Index des Trainingsbildes

Was ist die summende Distanz?

Die Anzahl der verschiedenen Zeichen an den entsprechenden Positionen in zwei Zeichenfolgen mit der gleichen Anzahl von Zeichen.

• Der Brummabstand zwischen 1011101 und 1001001 beträgt 2. • Der Brummabstand zwischen 2173896 und 2233796 beträgt 3. -Der Brummabstand zwischen "getönt" und "Rosen" beträgt 3.

def1 und def2, die an bf.match () übergeben werden, sind Arrays, die mehrere 61-dimensionale Feature-Deskriptoren enthalten.

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

Es scheint, dass die folgende Verarbeitung in bf.match () erfolgt.

  1. Berechnen Sie die Brummstrecke, indem Sie die Dezimalzahl-> Binärzahl konvertieren
  2. Nehmen Sie die Summe der Abstände für 61 Elemente
  3. Ermitteln Sie den Abstand zwischen allen Merkmalsgrößen per Round-Robin
  4. Gibt das Ergebnis zurück, das einen bestimmten Schwellenwert überschreitet. <- Dies ist nicht bestätigt

Versuch 1

Sie können sehen, dass es in Dezimal-> Binär konvertiert wurde.

#0 ist eine Binärzahl 00000000
des1 = np.array([0]).astype('uint8')
#255 ist eine Binärzahl 11111111
des2 = np.array([255]).astype('uint8')
# ※ astype('uint8')Wenn nicht, bf.match()Ich kann es dir nicht geben.

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 <-Summende Distanz
#244 ist eine Binärzahl 11111110
des1 = np.array([244]).astype('uint8')
#255 ist eine Binärzahl 11111111
des2 = np.array([255]).astype('uint8')
# ※ astype('uint8')Wenn nicht, bf.match()Ich kann es dir nicht geben.

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

for i in matches:
    print(i.distance)
# 1.0 <-Summende Distanz

Experiment 2

Sie können sehen, dass wir die Abstände zwischen den Elementen im Feature-Deskriptor summieren.

#Eine binäre Darstellung ist durch Hinzufügen eines 0b-Präfixes möglich.
des1 = np.array([[0b0001, 0b0001, 0b0001], [0b0011, 0b0011, 0b0011], [0b0111, 0b0111, 0b0111]]).astype('uint8')
des2 = np.array([[0b0000, 0b0000, 0b0000]]).astype('uint8')
# ※ astype('uint8')Wenn nicht, bf.match()Ich kann es dir nicht geben.

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

# [0b0001, 0b0001, 0b0001]Wann[0b0000, 0b0000, 0b0000]Nur das Ergebnis von
for i in matches:
    print(i.distance)
# 3.0 <-Summende Distanz

Übereinstimmendes Ergebnisbild erstellen (erstes Bild)

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)

Durch Setzen von Übereinstimmungen [: 10] im Argument von drawMatches () werden 10 nahe beieinander liegende Feature-Punkte von oben gezeichnet.

Das Ende

Recommended Posts

Lassen Sie uns etwas näher auf den Feature-Point-Matching mit OpenCV eingehen
Finden Sie Kartenillustrationen aus Bildern mithilfe der Feature-Point-Anpassung
Lassen Sie uns etwas näher auf den Feature-Point-Matching mit OpenCV eingehen
Es ist ein Mac. Was ist der Linux-Befehl Linux?
[Teil 2] Erstellen wir einen Webserver mit EC2 Linux
Lassen Sie uns das Abhängigkeitsmanagement mit pip etwas einfacher machen
[Teil 1] Lassen Sie uns einen Micra-Server unter Linux einrichten
Lassen Sie uns eine Mac-App mit Tkinter und py2app erstellen
Keine Dual-Boots oder VMs mehr! Erstellen wir eine Linux-Umgebung mit WSL2 und Windows Terminal [WSL2]