Vous amener à développer un modèle de reconnaissance gestuelle dynamique vidéo

Cet article est partagé par la communauté Huawei Cloud « Reconnaissance dynamique des gestes vidéo CNN-VIT [Jouer avec Huawei Cloud] », auteur : HouYanSong.

Reconnaissance gestuelle dynamique vidéo CNN-VIT

RC.gif

Le développement de l’intelligence artificielle évolue chaque jour et a également profondément affecté le développement du domaine de l’interaction homme-machine. Les gestes, en tant que moyen d'interaction naturel et rapide, sont largement utilisés dans des domaines tels que la conduite intelligente et la réalité virtuelle. La tâche de la reconnaissance gestuelle est que lorsque l'opérateur effectue un certain geste, l'ordinateur peut déterminer rapidement et avec précision le type de geste. Cet article utilisera ModelArts pour développer et entraîner un modèle d'algorithme de reconnaissance de gestes dynamiques vidéo afin de détecter les catégories de gestes dynamiques telles que le balayage vers le haut, le balayage vers le bas, le balayage vers la gauche, le balayage vers la droite, l'ouverture, la fermeture, etc., pour obtenir une fonction similaire à l'air. gestes sur les téléphones mobiles Huawei.

Introduction à l'algorithme

L'algorithme de reconnaissance dynamique des gestes vidéo CNN-VIT utilise d'abord le réseau pré-entraîné InceptionResNetV2 pour extraire les caractéristiques des clips d'action vidéo image par image, puis entre dans l'encodeur du transformateur pour la classification. Nous utilisons l'échantillon de données de reconnaissance dynamique des gestes pour tester l'algorithme, qui contient un total de 108 vidéos. L'ensemble de données contient des vidéos de 7 gestes, y compris des gestes invalides, glisser vers le haut, glisser vers le bas, glisser vers la gauche, glisser vers la droite, ouvrir, fermer, etc. Le processus de fonctionnement spécifique comme suit :

Présentation 1_edit_569379046802172.png

Tout d'abord, nous décodons le fichier vidéo capturé pour extraire les images clés, les enregistrons toutes les 4 images, puis effectuons un recadrage central et un prétraitement de l'image. Le code est le suivant :

def load_video(nom_fichier) :
    cap = cv2.VideoCapture (nom_fichier)
    # Extraire toutes les quelques images
    frame_interval = 4
    cadres = []
    compte = 0
    tandis que Vrai :
        à droite, frame = cap.read()
        sinon ret :
            casser
        
        # Enregistrez chaque image frame_interval
        si compte % frame_interval == 0 :
            #Recadrage central    
            cadre = crop_center_square(cadre)
            # Zoom
            cadre = cv2.resize(cadre, (IMG_SIZE, IMG_SIZE))
            # BGR -> RVB [0,1,2] -> [2,1,0]
            cadre = cadre[:, :, [2, 1, 0]]
            frames.append (cadre)
        compter += 1
        
    retourner np.array (images)

Ensuite, nous créons un extracteur de caractéristiques d'image et utilisons le modèle pré-entraîné InceptionResNetV2 pour extraire les caractéristiques de l'image. Le code est le suivant :

def get_feature_extractor() :
    feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2(
        poids = 'imagenet',
        include_top = Faux,
        mise en commun = 'moyenne',
        input_shape = (IMG_SIZE, IMG_SIZE, 3)
    )
    
    preprocess_input = keras.applications.inception_resnet_v2.preprocess_input
    
    entrées = keras.Input((IMG_SIZE, IMG_SIZE, 3))
    prétraité = preprocess_input (entrées)
    sorties = feature_extractor (prétraité)
    
    model = keras.Model (entrées, sorties, nom = 'feature_extractor')
    
    modèle de retour

Extrayez ensuite le vecteur de caractéristiques vidéo. Si la vidéo contient moins de 40 images, créez un tableau composé uniquement de 0 pour le remplissage :

def load_data (vidéos, étiquettes) :
    
    vidéo_features = []

    pour la vidéo dans tqdm(vidéos) :
        frames = load_video(vidéo)
        comptes = len (images)
        # Si le nombre d'images est inférieur à MAX_SEQUENCE_LENGTH
        si compte < MAX_SEQUENCE_LENGTH :
            # remplisseur
            diff = MAX_SEQUENCE_LENGTH - compte
            #Créer un tableau numpy de tous les 0
            remplissage = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))
            # Concaténation de tableaux
            frames = np.concatenate((frames, padding))
        # Récupère la trame MAX_SEQUENCE_LENGTH précédente
        frames = frames[:MAX_SEQUENCE_LENGTH, :]
        # Extraire les fonctionnalités par lots
        video_feature = feature_extractor.predict (images)
        video_features.append(video_feature)
        
    retourner np.array (video_features), np.array (étiquettes)

Enfin, créez le modèle VIT avec le code suivant :

#Position encodage
classe PositionalEmbedding (layers.Layer):
    def __init__(self, seq_length, output_dim) :
        super().__init__()
        #Construire une liste de 0~MAX_SEQUENCE_LENGTH
        self.positions = tf.range(0, limite=MAX_SEQUENCE_LENGTH)
        self.positional_embedding = layer.Embedding(input_dim=seq_length, output_dim=output_dim)
    
    appel def (soi, x):
        #Position encodage
        positions_embedding = self.positional_embedding(self.positions)
        # Ajouter des entrées
        retourner x + positions_embedding

# Encodeur
classe TransformerEncoder (layers.Layer) :
    
    def __init__(self, num_heads, embed_dim) :
        super().__init__()
        self.p_embedding = PositionalEmbedding (MAX_SEQUENCE_LENGTH, NUM_FEATURES)
        self.attention = layer.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, dropout=0.1)
        self.layernorm = layer.LayerNormalization()
    
    appel def (soi, x):
        # intégration positionnelle
        positional_embedding = self.p_embedding(x)
        # attention personnelle
        attention_out = soi.attention(
            requête = positional_embedding,
            valeur = positional_embedding,
            clé = positional_embedding,
            attention_mask = Aucun
        )
        # norme de couche avec connexion résiduelle        
        sortie = self.layernorm (positional_embedding + attention_out)
        sortie de retour

def video_cls_model(class_vocab) :
    #Nombre de catégories
    classes_num = len(class_vocab)
    # Définir le modèle
    modèle =keras.Sequential([
        layer.InputLayer(input_shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)),
        TransformateurEncoder(2, NUM_FEATURES),
        couches.GlobalMaxPooling1D(),
        couches.Dropout(0.1),
        layer.Dense(classes_num, activation="softmax")
    ])
    # Compiler le modèle
    model.compile (optimiseur = keras.optimizers.Adam (1e-5),
                  perte = keras.losses.SparseCategoricalCrossentropy(from_logits=False),
                  métriques = ['précision']
    )
    modèle de retour

Formation sur modèle

Pour une expérience complète, vous pouvez cliquer sur Exécuter dans ModelArts pour exécuter le Notebook que j'ai publié en un clic :

Capture d'écran 2024-04-28 133611_edit_572368136181552.pngLa précision finale du modèle sur l'ensemble des données a atteint 87 %, ce qui signifie que la formation sur un petit ensemble de données a donné des résultats relativement bons.

raisonnement vidéo

Chargez d’abord le modèle VIT et obtenez la balise d’index de catégorie vidéo :

importer au hasard
#Charger le modèle
modèle = tf.keras.models.load_model('saved_model')
# Balises de catégorie
label_to_name = {0 : « Geste invalide », 1 : « Faites glisser vers le haut », 2 :                                          7 : 'zoom avant', 8 : 'zoom arrière'}

Utilisez ensuite l'extracteur de fonctionnalités d'image InceptionResNetV2 pour extraire les fonctionnalités vidéo :

# Obtenez des fonctionnalités vidéo
def getVideoFeat (images) :
    
    frames_count = len (images)
    
    # Si le nombre d'images est inférieur à MAX_SEQUENCE_LENGTH
    si frames_count < MAX_SEQUENCE_LENGTH :
        # remplisseur
        diff = MAX_SEQUENCE_LENGTH - frames_count
        #Créer un tableau numpy de tous les 0
        remplissage = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))
        # Concaténation de tableaux
        frames = np.concatenate((frames, padding))

    # Récupère la trame MAX_SEQ_LENGTH précédente
    frames = frames[:MAX_SEQUENCE_LENGTH,:]
    # Calculer les fonctionnalités vidéo N, 1536
    video_feat = feature_extractor.predict (images)

    retourner video_feat

Enfin, le vecteur caractéristique de la séquence vidéo est entré dans le Transformer Encoder pour la prédiction :

#Prédiction vidéo
def testVideo() :
    test_file = random.sample(vidéos, 1)[0]
    étiquette = test_file.split('_')[-2]

    print('Nom du fichier : {}'.format(fichier_test) )
    print('Catégorie réelle :{}'.format(label_to_name.get(int(label))) )

    # Lisez chaque image de la vidéo
    frames = load_video(test_file)
    #Sélectionnez l'image précédente MAX_SEQUENCE_LENGTH à afficher
    frames = frames[:MAX_SEQUENCE_LENGTH].astype(np.uint8)
    # Enregistrer au format GIF
    imageio.mimsave('animation.gif', frames, durée=10)
    # Obtenez des fonctionnalités
    feat = getVideoFeat (images)
    # Inférence de modèle
    prob = model.predict(tf.expand_dims(feat, axis=0))(0]
    
    print('Catégorie prévue : ')
    pour moi dans np.argsort(prob)[::-1][:5] :
        print('{} : {}%'.format(label_to_name[i], round(prob[i]*100, 2)))
    
    return display(Image(open('animation.gif', 'rb').read()))

Résultats de prédiction du modèle :

Nom du fichier : hand_gesture/woman_014_0_7.mp4
Classe réelle : geste invalide
Catégorie de prévision :
Gestes invalides : 99,82%
Baisse : 0,12 %
Clôture : 0,04 %
Balayez vers la gauche : 0,01 %
Ouvert : 0,01%

 

Cliquez pour suivre et découvrir les nouvelles technologies de Huawei Cloud dès que possible~

 

J'ai décidé d'abandonner les logiciels industriels open source. OGG 1.0 est sorti, Huawei a contribué à tout le code source. Ubuntu 24.04 LTS a été officiellement publié. L'équipe de Google Python Foundation a été tuée par la "montagne de merde de code" . ". Fedora Linux 40 a été officiellement lancé. Une société de jeux bien connue a publié de nouvelles réglementations : les cadeaux de mariage des employés ne doivent pas dépasser 100 000 yuans. China Unicom lance la première version chinoise Llama3 8B au monde du modèle open source. Pinduoduo est condamné à compenser 5 millions de yuans pour concurrence déloyale Méthode de saisie dans le cloud domestique - seul Huawei n'a aucun problème de sécurité de téléchargement de données dans le cloud.
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/u/4526289/blog/11062248
conseillé
Classement