Suivi d'objets à l'aide d'OpenCV3 et de Python3 (suivi des points caractéristiques spécifiés par la souris à l'aide de la méthode Lucas-Kanade)

introduction

Cette fois, je vais spécifier la cible de suivi de la vidéo avec un clic de souris et essayer de suivre l'objet dans l'espace 3D en temps réel. Comparé à la correspondance de modèles, il utilise un algorithme basé sur des fonctionnalités qui nécessite moins de calculs et peut être suivi même lorsqu'il est pivoté.

OpenCV OpenCV (Open Source Computer Vision Library) est une collection de bibliothèques de traitement vidéo / image sous licence BSD. Il existe de nombreux algorithmes tels que le filtrage d'images, la mise en correspondance de modèles, la reconnaissance d'objets, l'analyse vidéo et l'apprentissage automatique.

■ Exemple de suivi de mouvement avec OpenCV (OpenCV Google Summer of Code 2015) https://www.youtube.com/watch?v=OUbUFn71S4s

■ Cliquez ici pour une installation et une utilisation facile Installer OpenCV 3 (core + contrib) dans l'environnement Python 3 & Différence entre OpenCV 2 et OpenCV 3 & Easy operation check

■ Cliquez ici pour filtrer les images fixes Essayez la détection des bords avec OpenCV Effectuer divers filtres avec OpenCV (Gradient, Highpass, Laprasian, Gaussian) Extraire des points caractéristiques avec OpenCV (AgastFeature, FAST, GFTT, MSER, AKAZE, BRISK, KAZE, ORB, SimpleBlob)

■ Cliquez ici pour le traitement des fichiers vidéo Essayez de convertir des vidéos en temps réel avec OpenCV Essayez de convertir des vidéos de caméra Web / caméra vidéo en temps réel avec OpenCV Dessinez un flux optique en temps réel avec OpenCV (méthode Shi-Tomasi, méthode Lucas-Kanade)

Aperçu fonctionnel

Cette fois, créez un programme avec les fonctions suivantes.

La fonction de pause est très importante lors de la spécification des points caractéristiques d'une vidéo avec un clic de souris. Mettez la vidéo en pause avec la touche "s" et spécifiez lentement les points caractéristiques.

programme

motion.py


import cv2
import numpy as np

#Touche Echap
ESC_KEY = 0x1b
#clé s
S_KEY = 0x73
#touche r
R_KEY = 0x72
#Nombre maximum de points caractéristiques
MAX_FEATURE_NUM = 500
#Condition de terminaison de l'algorithme itératif
CRITERIA = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)
#Intervalle (1000/fréquence d'images)
INTERVAL = 30
#Données vidéo
VIDEO_DATA = '768x576.avi'

class Motion:
    #constructeur
    def __init__(self):
        #Fenêtre d'affichage
        cv2.namedWindow("motion")
        #Enregistrement de rappel pour les événements de souris
        cv2.setMouseCallback("motion", self.onMouse)
        #Vidéo
        self.video = cv2.VideoCapture(VIDEO_DATA)
        #intervalle
        self.interval = INTERVAL
        #Cadre actuel (couleur)
        self.frame = None
        #Cadre actuel (gris)
        self.gray_next = None
        #Dernier cadre (gris)
        self.gray_prev = None
        #Point caractéristique
        self.features = None
        #État des points caractéristiques
        self.status = None

    #Boucle principale
    def run(self):
        
        #Traitement de la première image
        end_flag, self.frame = self.video.read()
        self.gray_prev = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

        while end_flag:
            #Convertir en échelle de gris
            self.gray_next = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

            #Calculer le flux optique lorsque les points caractéristiques sont enregistrés
            if self.features is not None:
                #Calcul du flux optique
                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)

                #Ne laissez que les points caractéristiques valides
                self.refreshFeatures()
                
                #Dessinez des points caractéristiques valides sur le cadre
                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)
            
            #afficher
            cv2.imshow("motion", self.frame)
            
            #Préparation de la prochaine boucle
            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)

            #intervalle
            key = cv2.waitKey(self.interval)
            # "Esc"Appuyez sur la touche pour terminer
            if key == ESC_KEY:
                break
            # "s"Pause en appuyant sur une touche
            elif key == S_KEY:
                self.interval = 0
            elif key == R_KEY:
                self.interval = INTERVAL
                
            
        #Terminer le traitement
        cv2.destroyAllWindows()
        self.video.release()


    #Spécifiez des points caractéristiques en un clic de souris
    #S'il y a un point caractéristique existant dans le voisinage cliqué, supprimez le point caractéristique existant
    #S'il n'y a pas de point caractéristique existant dans le voisinage cliqué, ajoutez un nouveau point caractéristique
    def onMouse(self, event, x, y, flags, param):
        #Autre que le clic gauche
        if event != cv2.EVENT_LBUTTONDOWN:
            return

        #Premier point caractéristique ajouté
        if self.features is None:
            self.addFeature(x, y)
            return

        #Rayon de recherche (pixel)
        radius = 5
        #Rechercher des points caractéristiques existants à proximité
        index = self.getFeatureIndex(x, y, radius)

        #Puisqu'il existe un point caractéristique existant à proximité du clic, supprimez le point caractéristique existant
        if index >= 0:
            self.features = np.delete(self.features, index, 0)
            self.status = np.delete(self.status, index, 0)

        #Puisqu'il n'y a aucun point caractéristique existant près de la zone cliquée, un nouveau point caractéristique est ajouté.
        else:
            self.addFeature(x, y)

        return


    #Obtenez un index des points caractéristiques existants dans le rayon spécifié
    #S'il n'y a pas de points caractéristiques dans l'index de rayon spécifié= -Répondre 1
    def getFeatureIndex(self, x, y, radius):
        index = -1
        
        #Aucun point caractéristique n'est enregistré
        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:
                #Ce point caractéristique se trouve dans le rayon spécifié
                return index
            else:
                #Ce point caractéristique est en dehors du rayon spécifié
                index += 1
                
        #Tous les points caractéristiques sont en dehors du rayon spécifié
        return -1


    #Ajouter de nouveaux points caractéristiques
    def addFeature(self, x, y):
        
        #Les points caractéristiques ne sont pas enregistrés
        if self.features is None:
            #Créer un ndarray et enregistrer les coordonnées des points caractéristiques
            self.features = np.array([[[x, y]]], np.float32)
            self.status = np.array([1])
            #Points caractéristiques très précis
            cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA)

        #Dépasse le nombre maximum de points caractéristiques enregistrés
        elif len(self.features) >= MAX_FEATURE_NUM:
            print("max feature num over: " + str(MAX_FEATURE_NUM))

        #Points caractéristiques supplémentaires enregistrés
        else:
            #Ajouter des coordonnées de point d'entité à la fin d'un ndarray existant
            self.features = np.append(self.features, [[[x, y]]], axis = 0).astype(np.float32)
            self.status = np.append(self.status, 1)
            #Points caractéristiques très précis
            cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA)
            

    #Ne laissez que les points caractéristiques valides
    def refreshFeatures(self):
        #Les points caractéristiques ne sont pas enregistrés
        if self.features is None:
            return
        
        #Vérifier tous les statuts
        i = 0
        while i < len(self.features):
            
            #Ne peut pas être reconnu comme un point caractéristique
            if self.status[i] == 0:
                #Supprimer du ndarray existant
                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()

Résultat d'exécution

Le programme a utilisé l'exemple de vidéo OpenCV (768x576.avi), mais il n'a pas toujours la même apparence sur le même écran. Toute vidéo est OK. Changez la partie VIDEO_DATA du programme en votre vidéo préférée. Par exemple, à titre d'exemple du résultat de l'exécution, utilisons Uchimura, qui joue la barre de fer lors de la finale individuelle de gymnastique olympique de Rio de Janeiro 2016. Dans cette vidéo, Uchimura, qui joue la barre de fer, bouge également, mais le cadre d'arrière-plan se déplace également de haut en bas selon Uchimura. Utilisez la touche "s" pour mettre la vidéo en pause et définir le point pour suivre les chaussettes d'Uchimura. Les points jaunes représentent les points caractéristiques. Lorsque vous lisez la vidéo, vous pouvez voir que les points jaunes suivent les chaussettes d'Uchimura. (Parce que les orteils d'Uchimura sont parfaitement alignés, on peut dire qu'il peut continuer à le reconnaître comme le même point caractéristique.)

u1.png

u2.png

u3.png

u4.png

u5.png

Défis du programme

Lorsque vous exécutez réellement le programme, vous pouvez voir que ce programme (en utilisant simplement cv2.calcOpticalFlowPyrLK ()) a trois problèmes.

  1. Si les points d'entité d'arrière-plan et les points d'entité suivis se chevauchent, une erreur d'identification se produira et les points d'entité d'arrière-plan seront capturés.
  2. Si le point caractéristique en cours de suivi est masqué, le suivi s'arrête et même si le point caractéristique apparaît, il ne sera plus suivi.
  3. Si le point caractéristique spécifié n'a pas d'entité, le suivi s'arrête immédiatement.

Dans les deux cas, le montant du calcul augmentera, mais il existe des moyens de le gérer. Je vais essayer de faire une version compatible bientôt.

Recommended Posts

Suivi d'objets à l'aide d'OpenCV3 et de Python3 (suivi des points caractéristiques spécifiés par la souris à l'aide de la méthode Lucas-Kanade)
J'ai essayé la détection d'objets en utilisant Python et OpenCV
Je viens d'effacer l'objet en utilisant la réparation d'image (inpaint) (OpenCV: Python)
Extraction d'objets dans l'image par correspondance de modèles en utilisant OpenCV avec Python
Obtenez et estimez la forme de la tête en utilisant Dlib et OpenCV avec python
Divise la chaîne de caractères par le nombre de caractères spécifié. En Ruby et Python.
Estimation de l'orientation de la tête avec Python et OpenCV + dlib
J'ai essayé d'utiliser le module Datetime de Python
Correspondance des fonctionnalités avec OpenCV 3 et Python 3 (A-KAZE, KNN)
Approximer une courbe de Bézier à travers un point spécifié en utilisant la méthode des moindres carrés en Python
[Python] Vous pouvez enregistrer un objet dans un fichier en utilisant le module pickle.
[Python] Spécifiez la plage de l'image en faisant glisser la souris
Déterminer le seuil à l'aide de la méthode P-tile en python
Envoyez et recevez Gmail via l'API Gmail en utilisant Python
Le VIF calculé par Python et le VIF calculé par Excel sont différents .. ??
J'ai regroupé le yen dollar en utilisant la méthode k-medoids en python et j'ai trouvé le taux de réponse correct.
[Apprentissage automatique] Ecrivez vous-même la méthode k-plus proche voisin en python et reconnaissez les nombres manuscrits.