Llevarlo a desarrollar un modelo de reconocimiento de gestos dinámicos en video.

Este artículo es compartido por la comunidad de Huawei Cloud " Reconocimiento dinámico de gestos por video CNN-VIT [jugando con Huawei Cloud] ", autor: HouYanSong.

Reconocimiento dinámico de gestos por vídeo CNN-VIT

RC.gif

El desarrollo de la inteligencia artificial está cambiando cada día que pasa y también ha afectado profundamente el desarrollo del campo de la interacción persona-computadora. Los gestos, como forma natural y rápida de interacción, son muy utilizados en campos como la conducción inteligente y la realidad virtual. La tarea del reconocimiento de gestos es que cuando el operador realiza un determinado gesto, la computadora pueda determinar de forma rápida y precisa el tipo de gesto. Este artículo utilizará ModelArts para desarrollar y entrenar un modelo de algoritmo de reconocimiento de gestos dinámicos de video para detectar categorías de gestos dinámicos como deslizar hacia arriba, deslizar hacia abajo, deslizar hacia la izquierda, deslizar hacia la derecha, abrir, cerrar, etc., para lograr una función similar al aire. Gestos en teléfonos móviles Huawei.

Introducción al algoritmo

El algoritmo de reconocimiento de gestos dinámicos de video CNN-VIT primero utiliza la red previamente entrenada InceptionResNetV2 para extraer características de clips de acción de video cuadro por cuadro y luego ingresa el codificador Transformer para su clasificación. Usamos el conjunto de datos de muestra de reconocimiento dinámico de gestos para probar el algoritmo, que contiene un total de 108 videos. El conjunto de datos contiene videos de 7 gestos, incluidos gestos no válidos, deslizar hacia arriba, deslizar hacia abajo, deslizar hacia la izquierda, deslizar hacia la derecha, abrir, cerrar,. etc. El proceso de operación específico es el siguiente:

Presentación 1_edit_569379046802172.png

Primero, decodificamos el archivo de video capturado para extraer fotogramas clave, los guardamos cada 4 fotogramas y luego realizamos el recorte central y el preprocesamiento de la imagen.

def cargar_video(nombre_archivo):
    tapa = cv2.VideoCapture(nombre_archivo)
    # Extraer cada pocos fotogramas
    intervalo_cuadro = 4
    marcos = []
    contar = 0
    mientras que Verdadero:
        derecha, marco = cap.read()
        si no se retira:
            romper
        
        # Guardar cada cuadro frame_interval
        si cuenta % frame_interval == 0:
            #Cultivo central    
            marco = crop_center_square(marco)
            # Zoom
            marco = cv2.resize(marco, (IMG_SIZE, IMG_SIZE))
            # BGR -> RGB [0,1,2] -> [2,1,0]
            cuadro = cuadro[:, :, [2, 1, 0]]
            marcos.append(marco)
        contar += 1
        
    devolver np.array (marcos)

Luego creamos un extractor de características de imagen y utilizamos el modelo previamente entrenado InceptionResNetV2 para extraer características de imagen.

def get_feature_extractor():
    feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2(
        pesos = 'imagenet',
        incluir_top = Falso,
        agrupación = 'promedio',
        forma_entrada = (IMG_SIZE, IMG_SIZE, 3)
    )
    
    preprocess_input = keras.applications.inception_resnet_v2.preprocess_input
    
    entradas = keras.Input((IMG_SIZE, IMG_SIZE, 3))
    preprocesado = preprocess_input(entradas)
    salidas = feature_extractor (preprocesado)
    
    modelo = keras.Model(entradas, salidas, nombre = 'feature_extractor')
    
    modelo de devolución

Luego extraiga el vector de características del video. Si el video tiene menos de 40 fotogramas, cree una matriz de todos 0 para rellenar:

def load_data(vídeos, etiquetas):
    
    características_video = []

    para vídeo en tqdm (vídeos):
        fotogramas = cargar_video(vídeo)
        recuentos = len(cuadros)
        # Si el número de fotogramas es menor que MAX_SEQUENCE_LENGTH
        si cuenta < MAX_SEQUENCE_LENGTH:
            # relleno
            diferencia = MAX_SEQUENCE_LENGTH - recuentos
            #Crea una matriz numerosa de todos los 0
            relleno = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))
            # Concatenación de matrices
            marcos = np.concatenate((marcos, relleno))
        # Obtener el cuadro MAX_SEQUENCE_LENGTH anterior
        cuadros = cuadros[:MAX_SEQUENCE_LENGTH, :]
        # Extraer características en lotes
        video_feature = feature_extractor.predict(fotogramas)
        video_features.append(video_feature)
        
    devolver np.array (video_features), np.array (etiquetas)

Finalmente, crea el modelo VIT con el siguiente código:

#Codificación de posición
clase PositionalEmbedding(capas.Capa):
    def __init__(self, longitud_secuencia, salida_dim):
        super().__init__()
        #Construir una lista a partir de 0~MAX_SEQUENCE_LENGTH
        self.posiciones = tf.range(0, límite=MAX_SEQUENCE_LENGTH)
        self.positional_embedding = capas.Embedding(input_dim=seq_length, output_dim=output_dim)
    
    def llamada(yo,x):
        #Codificación de posición
        posiciones_embedding = self.positional_embedding(self.posiciones)
        # Agregar entradas
        devolver x + posiciones_incrustación

# Codificador
clase TransformerEncoder (capas.Capa):
    
    def __init__(self, num_heads, embed_dim):
        super().__init__()
        self.p_embedding = Incrustación posicional (MAX_SEQUENCE_LENGTH, NUM_FEATURES)
        self.attention = capas.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, dropout=0.1)
        self.layernorm = capas.LayerNormalization()
    
    def llamada(yo,x):
        # incrustación posicional
        positional_embedding = self.p_embedding(x)
        # auto atención
        atención_fuera = self.atención(
            consulta = positional_embedding,
            valor = incrustación_posicional,
            clave = incrustación_posicional,
            máscara_atención = Ninguna
        )
        # norma de capa con conexión residual        
        salida = self.layernorm(incrustación_posicional + salida_atención)
        salida de retorno

def video_cls_model(clase_vocab):
    #Número de categorías
    núm_clases = len(clase_vocab)
    # Definir modelo
    modelo =keras.Sequential([
        capas.InputLayer(input_shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)),
        Codificador de transformador(2, NUM_FEATURES),
        capas.GlobalMaxPooling1D(),
        capas.Abandono(0.1),
        capas.Dense(classes_num, activación="softmax")
    ])
    # compilar modelo
    model.compile(optimizador = keras.optimizadores.Adam(1e-5),
                  pérdida = keras.losses.SparseCategoricalCrossentropy(from_logits=False),
                  métricas = ['precisión']
    )
    modelo de devolución

Entrenamiento modelo

Para una experiencia completa, puedes hacer clic en Ejecutar en ModelArts para ejecutar el Notebook que publiqué con un solo clic :

Captura de pantalla 2024-04-28 133611_edit_572368136181552.pngLa precisión final del modelo en todo el conjunto de datos alcanzó el 87%, lo que significa que el entrenamiento en un conjunto de datos pequeño logró resultados relativamente buenos.

razonamiento en vídeo

Primero cargue el modelo VIT y obtenga la etiqueta de índice de categoría de video:

importar aleatoriamente
#Cargar modelo
modelo = tf.keras.models.load_model('modelo_guardado')
# Etiquetas de categoría
label_to_name = {0:'Gesto no válido', 1:'Deslizar hacia arriba', 2:'Deslizar hacia abajo', 3:'Deslizar hacia la izquierda', 4:'Deslizar hacia la derecha', 5:'Abrir', 6:'Cerrar', 7: 'acercar', 8: 'alejar'}

Luego use el extractor de funciones de imagen InceptionResNetV2 para extraer funciones de video:

# Obtener funciones de video
def getVideoFeat(cuadros):
    
    recuento_cuadros = len(cuadros)
    
    # Si el número de fotogramas es menor que MAX_SEQUENCE_LENGTH
    si frame_count < MAX_SEQUENCE_LENGTH:
        # relleno
        diferencia = MAX_SEQUENCE_LENGTH - frame_count
        #Crea una matriz numerosa de todos los 0
        relleno = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))
        # Concatenación de matrices
        marcos = np.concatenate((marcos, relleno))

    # Obtener el cuadro MAX_SEQ_LENGTH anterior
    cuadros = cuadros[:MAX_SEQUENCE_LENGTH,:]
    # Calcular características de video N, 1536
    video_feat = feature_extractor.predict(fotogramas)

    devolver video_feat

Finalmente, el vector de características de la secuencia de video se ingresa en el codificador Transformer para su predicción:

#Predicción de vídeo
def pruebaVideo():
    archivo_prueba = muestra.aleatoria(vídeos, 1)[0]
    etiqueta = test_file.split('_')[-2]

    print('Nombre de archivo: {}'.format(test_file) )
    print('Categoría real:{}'.format(label_to_name.get(int(label))) )

    # Lee cada fotograma del vídeo.
    cuadros = cargar_video (archivo_prueba)
    #Seleccione el cuadro anterior MAX_SEQUENCE_LENGTH para mostrar
    cuadros = cuadros[:MAX_SEQUENCE_LENGTH].astype(np.uint8)
    # Guardar como GIF
    imageio.mimsave('animación.gif', fotogramas, duración=10)
    # Obtener funciones
    hazaña = getVideoFeat(fotogramas)
    # Inferencia del modelo
    problema = model.predict(tf.expand_dims(hazaña, eje=0))[0]
    
    print('Categoría prevista: ')
    para i en np.argsort(prob)[::-1][:5]:
        print('{}: {}%'.format(label_to_name[i], round(prob[i]*100, 2)))
    
    visualización de retorno (Imagen (open ('animation.gif', 'rb').read()))

Resultados de la predicción del modelo:

Nombre del archivo:hand_gesture/woman_014_0_7.mp4
Clase real: gesto no válido
Categoría de pronóstico:
Gestos no válidos: 99,82%
Disminución: 0,12%
Cierre: 0,04%
Deslizar hacia la izquierda: 0,01%
Abierto: 0,01%

 

Haga clic para seguir y conocer las nuevas tecnologías de Huawei Cloud lo antes posible ~

 

Decidí renunciar al software industrial de código abierto. Eventos importantes: se lanzó OGG 1.0, Huawei contribuyó con todo el código fuente y se lanzó oficialmente Ubuntu 24.04. El equipo de la Fundación Google Python fue despedido por la "montaña de código de mierda" . ". Se lanzó oficialmente Fedora Linux 40. Una conocida compañía de juegos lanzó Nuevas regulaciones: los obsequios de boda de los empleados no deben exceder los 100.000 yuanes. China Unicom lanza la primera versión china Llama3 8B del mundo del modelo de código abierto. Pinduoduo es sentenciado a compensar 5 millones de yuanes por competencia desleal. Método de entrada en la nube nacional: solo Huawei no tiene problemas de seguridad para cargar datos en la nube.
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/11062248
Recomendado
Clasificación