Objektverfolgung mit OpenCV3 und Python3 (Verfolgung von Funktionspunkten, die mit der Maus mithilfe der Lucas-Kanade-Methode festgelegt wurden)

Einführung

Dieses Mal werde ich das Verfolgungsziel für das Video mit einem Mausklick angeben und versuchen, das Objekt im 3D-Raum in Echtzeit zu verfolgen. Im Vergleich zum Vorlagenabgleich wird ein funktionsbasierter Algorithmus verwendet, der weniger Rechenaufwand erfordert und auch bei Drehung verfolgt werden kann.

OpenCV OpenCV (Open Source Computer Vision Library) ist eine Sammlung von BSD-lizenzierten Video- / Bildverarbeitungsbibliotheken. Es gibt viele Algorithmen wie Bildfilterung, Vorlagenabgleich, Objekterkennung, Videoanalyse und maschinelles Lernen.

■ Beispiel für Bewegungsverfolgung mit OpenCV (OpenCV Google Summer of Code 2015) https://www.youtube.com/watch?v=OUbUFn71S4s

■ Klicken Sie hier für die Installation und einfache Verwendung Installieren Sie OpenCV 3 (Core + Contrib) in der Python 3-Umgebung und unterscheiden Sie zwischen OpenCV 2 und OpenCV 3 und überprüfen Sie die einfache Bedienung

■ Klicken Sie hier, um Standbilder zu filtern Versuchen Sie die Kantenerkennung mit OpenCV Führen Sie verschiedene Filter mit OpenCV durch (Gradient, Highpass, Laplacian, Gaussian) Extrahieren Sie Feature-Punkte mit OpenCV (AgastFeature, FAST, GFTT, MSER, AKAZE, BRISK, KAZE, ORB, SimpleBlob)

■ Klicken Sie hier, um Videodateien zu verarbeiten Versuchen Sie, Videos in Echtzeit mit OpenCV zu konvertieren Versuchen Sie, Webkamera- / Videokamera-Videos in Echtzeit mit OpenCV zu konvertieren Zeichnen Sie den optischen Fluss in Echtzeit mit OpenCV (Shi-Tomasi-Methode, Lucas-Kanade-Methode)

Funktionsübersicht

Erstellen Sie dieses Mal ein Programm mit den folgenden Funktionen.

Die Pausenfunktion ist sehr wichtig, wenn Sie mit einem Mausklick Funktionspunkte für ein Video festlegen. Halten Sie das Video mit der Taste "s" an und geben Sie die Funktionspunkte langsam an.

Programm

motion.py


import cv2
import numpy as np

#Esc-Taste
ESC_KEY = 0x1b
#s Schlüssel
S_KEY = 0x73
#r Taste
R_KEY = 0x72
#Maximale Anzahl von Feature-Punkten
MAX_FEATURE_NUM = 500
#Beendigungsbedingung des iterativen Algorithmus
CRITERIA = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)
#Intervall (1000/Bildrate)
INTERVAL = 30
#Videodaten
VIDEO_DATA = '768x576.avi'

class Motion:
    #Konstrukteur
    def __init__(self):
        #Anzeigefenster
        cv2.namedWindow("motion")
        #Rückrufregistrierung für Mausereignisse
        cv2.setMouseCallback("motion", self.onMouse)
        #Video
        self.video = cv2.VideoCapture(VIDEO_DATA)
        #Intervall
        self.interval = INTERVAL
        #Aktueller Rahmen (Farbe)
        self.frame = None
        #Aktueller Frame (grau)
        self.gray_next = None
        #Letzter Frame (grau)
        self.gray_prev = None
        #Funktionspunkt
        self.features = None
        #Funktionspunktstatus
        self.status = None

    #Hauptschleife
    def run(self):
        
        #Verarbeitung des ersten Frames
        end_flag, self.frame = self.video.read()
        self.gray_prev = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

        while end_flag:
            #In Graustufen konvertieren
            self.gray_next = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

            #Berechnen Sie den optischen Fluss, wenn Feature-Punkte registriert werden
            if self.features is not None:
                #Berechnung des optischen Flusses
                features_prev = self.features
                self.features, self.status, err = cv2.calcOpticalFlowPyrLK( \
                                                    self.gray_prev, \
                                                    self.gray_next, \
                                                    features_prev, \
                                                    None, \
                                                    winSize = (10, 10), \
                                                    maxLevel = 3, \
                                                    criteria = CRITERIA, \
                                                    flags = 0)

                #Lassen Sie nur gültige Feature-Punkte
                self.refreshFeatures()
                
                #Zeichnen Sie gültige Feature-Punkte auf den Rahmen
                if self.features is not None:
                    for feature in self.features:
                        cv2.circle(self.frame, (feature[0][0], feature[0][1]), 4, (15, 241, 255), -1, 8, 0)
            
            #Anzeige
            cv2.imshow("motion", self.frame)
            
            #Vorbereitung für die nächste Schleife
            self.gray_prev = self.gray_next
            end_flag, self.frame = self.video.read()
            if end_flag:
                self.gray_next = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

            #Intervall
            key = cv2.waitKey(self.interval)
            # "Esc"Drücken Sie die Taste, um den Vorgang abzuschließen
            if key == ESC_KEY:
                break
            # "s"Pause durch Drücken einer Taste
            elif key == S_KEY:
                self.interval = 0
            elif key == R_KEY:
                self.interval = INTERVAL
                
            
        #Verarbeitung beenden
        cv2.destroyAllWindows()
        self.video.release()


    #Geben Sie Feature-Punkte mit einem Mausklick an
    #Wenn in der angeklickten Nachbarschaft ein Feature-Point vorhanden ist, löschen Sie den vorhandenen Feature-Point
    #Wenn in der angeklickten Umgebung kein Feature-Punkt vorhanden ist, fügen Sie einen neuen Feature-Punkt hinzu
    def onMouse(self, event, x, y, flags, param):
        #Anders als Linksklick
        if event != cv2.EVENT_LBUTTONDOWN:
            return

        #Erster Feature-Punkt hinzugefügt
        if self.features is None:
            self.addFeature(x, y)
            return

        #Suchradius (Pixel)
        radius = 5
        #Suchen Sie nach vorhandenen Feature-Punkten in der Nähe
        index = self.getFeatureIndex(x, y, radius)

        #Da sich in der Nähe des Klicks ein vorhandener Feature-Punkt befindet, löschen Sie den vorhandenen Feature-Punkt
        if index >= 0:
            self.features = np.delete(self.features, index, 0)
            self.status = np.delete(self.status, index, 0)

        #Da in der Nähe des angeklickten Bereichs kein Feature-Punkt vorhanden ist, wird ein neuer Feature-Punkt hinzugefügt.
        else:
            self.addFeature(x, y)

        return


    #Ruft einen Index der vorhandenen Feature-Punkte innerhalb des angegebenen Radius ab
    #Wenn innerhalb des angegebenen Radiusindex keine Feature-Punkte vorhanden sind= -Antwort 1
    def getFeatureIndex(self, x, y, radius):
        index = -1
        
        #Es sind keine Feature-Punkte registriert
        if self.features is None:
            return index
        
        max_r2 = radius ** 2
        index = 0
        for point in self.features:
            dx = x - point[0][0]
            dy = y - point[0][1]
            r2 = dx ** 2 + dy ** 2
            if r2 <= max_r2:
                #Dieser Feature-Punkt liegt innerhalb des angegebenen Radius
                return index
            else:
                #Dieser Feature-Punkt liegt außerhalb des angegebenen Radius
                index += 1
                
        #Alle Feature-Punkte liegen außerhalb des angegebenen Radius
        return -1


    #Fügen Sie neue Feature-Punkte hinzu
    def addFeature(self, x, y):
        
        #Feature Points werden nicht registriert
        if self.features is None:
            #Erstellen Sie ndarray und registrieren Sie die Koordinaten der Feature-Punkte
            self.features = np.array([[[x, y]]], np.float32)
            self.status = np.array([1])
            #Hochgenaue Merkmalspunkte
            cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA)

        #Überschreitet die maximale Anzahl registrierter Feature-Punkte
        elif len(self.features) >= MAX_FEATURE_NUM:
            print("max feature num over: " + str(MAX_FEATURE_NUM))

        #Zusätzliche Feature-Punkte registriert
        else:
            #Fügen Sie am Ende eines vorhandenen ndarray Feature-Punkt-Koordinaten hinzu
            self.features = np.append(self.features, [[[x, y]]], axis = 0).astype(np.float32)
            self.status = np.append(self.status, 1)
            #Hochgenaue Merkmalspunkte
            cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA)
            

    #Lassen Sie nur gültige Feature-Punkte
    def refreshFeatures(self):
        #Feature Points werden nicht registriert
        if self.features is None:
            return
        
        #Überprüfen Sie alle Status
        i = 0
        while i < len(self.features):
            
            #Kann nicht als Feature-Punkt erkannt werden
            if self.status[i] == 0:
                #Aus vorhandenem ndarray entfernen
                self.features = np.delete(self.features, i, 0)
                self.status = np.delete(self.status, i, 0)
                i -= 1
            
            i += 1


if __name__ == '__main__':
    Motion().run()

Ausführungsergebnis

Das Programm verwendete das OpenCV-Beispielvideo (768x576.avi), es sieht jedoch nicht immer auf demselben Bildschirm gleich aus. Jedes Video ist in Ordnung. Ändern Sie den Teil "VIDEO_DATA" des Programms in Ihr Lieblingsvideo. Als Beispiel für das Ausführungsergebnis verwenden wir beispielsweise Uchimura, der die Eisenstange im individuellen Gesamtfinale der Olympischen Gymnastik 2016 in Rio de Janeiro spielt. In diesem Video bewegt sich auch Uchimura, der die Eisenstange spielt, aber laut Uchimura bewegt sich auch der Hintergrundrahmen auf und ab. Verwenden Sie die Taste "s", um das Video anzuhalten und den Punkt festzulegen, an dem Sie Uchimuras Socken folgen möchten. Die gelben Punkte repräsentieren die Merkmalspunkte. Wenn Sie das Video abspielen, können Sie sehen, dass die gelben Punkte Uchimuras Socken verfolgen. (Da Uchimuras Zehen ordentlich ausgerichtet sind, kann man sagen, dass er sie weiterhin als denselben Merkmalspunkt erkennen kann.)

u1.png

u2.png

u3.png

u4.png

u5.png

Programmherausforderungen

Wenn Sie das Programm tatsächlich ausführen, können Sie feststellen, dass dieses Programm (einfach mit cv2.calcOpticalFlowPyrLK ()) drei Probleme hat.

  1. Wenn sich die Hintergrund-Feature-Punkte und die zu verfolgenden Feature-Punkte überlappen, tritt eine falsche Identifizierung auf und die Hintergrund-Feature-Punkte werden abgefangen.
  2. Wenn der zu verfolgende Feature-Punkt ausgeblendet ist, endet die Verfolgung, und selbst wenn der Feature-Punkt angezeigt wird, wird er nicht erneut verfolgt.
  3. Wenn der angegebene Feature-Punkt kein Feature hat, wird die Verfolgung sofort beendet.

In beiden Fällen erhöht sich der Rechenaufwand, es gibt jedoch Möglichkeiten, damit umzugehen. Ich werde versuchen, bald eine kompatible Version zu erstellen.

Recommended Posts

Objektverfolgung mit OpenCV3 und Python3 (Verfolgung von Funktionspunkten, die mit der Maus mithilfe der Lucas-Kanade-Methode festgelegt wurden)
Ich habe versucht, Objekte mit Python und OpenCV zu erkennen
Ich habe das Objekt gerade mit Image Repair (Inpaint) (OpenCV: Python) gelöscht.
Objektextraktion im Bild durch Mustervergleich mit OpenCV mit Python
Erhalten und schätzen Sie die Form des Kopfes mit Dlib und OpenCV mit Python
Teilt die Zeichenfolge durch die angegebene Anzahl von Zeichen. In Ruby und Python.
Schätzung der Kopforientierung mit Python und OpenCV + dlib
Ich habe versucht, das Datetime-Modul von Python zu verwenden
Feature Matching mit OpenCV 3 und Python 3 (A-KAZE, KNN)
Approximieren Sie eine Bezier-Kurve durch einen bestimmten Punkt mit der Methode der kleinsten Quadrate in Python
[Python] Sie können ein Objekt mithilfe des Pickle-Moduls in einer Datei speichern.
[Python] Geben Sie den Bereich des Bildes durch Ziehen der Maus an
Bestimmen Sie den Schwellenwert mithilfe der P-Tile-Methode in Python
Senden und empfangen Sie Google Mail über die Google Mail-API mit Python
Das von Python berechnete VIF und das von Excel berechnete VIF sind unterschiedlich.
Ich habe den Dollar-Yen mit der k-medoids-Methode in Python geclustert und die richtige Antwortrate gefunden.
[Maschinelles Lernen] Schreiben Sie die Methode des nächsten Nachbarn in Python selbst und erkennen Sie handgeschriebene Zahlen.