Contenido principal

Esta página se ha traducido mediante traducción automática. Haga clic aquí para ver la última versión en inglés.

Reconocimiento de gestos mediante unidades de medida inerciales

Este ejemplo muestra cómo reconocer gestos basándose en una unidad de medición inercial (IMU) portátil. El reconocimiento de gestos es un subcampo del campo general de Reconocimiento de actividad humana (HAR). En este ejemplo, se utiliza la agrupación y el alineamiento temporal dinámico de cuaterniones para crear un algoritmo de coincidencia de plantillas para clasificar cinco gestos.

El alineamiento temporal dinámico es un algoritmo utilizado para medir la similitud entre dos series temporales de datos. El alineamiento temporal dinámico compara dos secuencias alineando los puntos de datos de la primera secuencia con los puntos de datos de la segunda, descuidando la sincronización temporal . El alineamiento temporal dinámico también proporciona una métrica de distancia entre dos secuencias no alineadas.

Similar al alineamiento temporal dinámico, el alineamiento temporal dinámico de cuaterniones compara dos secuencias en el espacio de cuaterniones o rotacional [1].

El alineamiento temporal dinámico de cuaterniones también devuelve una distancia escalar entre dos trayectorias de orientación. Esta métrica de distancia le permite agrupar datos y encontrar una trayectoria de plantilla para cada gesto. Puede utilizar un conjunto de trayectorias de plantilla para reconocer y clasificar nuevas trayectorias.

Este enfoque de utilizar el alineamiento temporal dinámico de cuaterniones y la agrupación para generar trayectorias de plantilla es el segundo nivel de un sistema de clasificación de dos niveles descrito en [2].

Gestos y recopilación de datos.

En este ejemplo, usted construye un algoritmo que reconoce y clasifica los siguientes cinco gestos. Cada gesto comienza en la misma posición con el antebrazo derecho al nivel, paralelo al suelo.

  • up - Levante el brazo y luego vuelva al nivel.

up.png

  • down - L baja el brazo y luego vuelve al nivel.

down.png

  • left - Desliza el brazo hacia la izquierda y luego regresa al centro. El antebrazo está paralelo al suelo durante todo el ejercicio.

left.png

  • right - Desliza el brazo hacia la derecha y luego regresa al centro. El antebrazo está paralelo al suelo durante todo el ejercicio.

right.png

  • twist - Gira la manecilla 90 grados en el sentido de las agujas del reloj y vuelve a la orientación original. El antebrazo está paralelo al suelo durante todo el ejercicio.

twist.png

Los datos de estos cinco gestos se capturan utilizando MATLAB® Support Package for Arduino® Hardware. Cuatro personas diferentes realizaron los cinco gestos y repitieron cada gesto de nueve a diez veces. Los datos registrados, guardados como table, contienen lecturas del acelerómetro y del giroscopio, la frecuencia de muestreo, el gesto que se realiza y el nombre de la persona que realiza el gesto.

Preprocesamiento de fusión de sensores

El primer paso es fusionar todas las lecturas del acelerómetro y giroscopio para producir un conjunto de series de tiempo de orientación o trayectorias. Utilizará imufilter System object ™ para fusionar las lecturas del acelerómetro y el giroscopio. El imufilter System object está disponible tanto en Navigation Toolbox ™ como en Sensor Fusion and Tracking Toolbox ™. Puede utilizar un bucle parfor para acelerar el cálculo. Si tiene Parallel Computing Toolbox ™, el bucle parfor se ejecutará en paralelo; de lo contrario, un bucle for normal se ejecutará secuencialmente.

ld = load("imuGestureDataset.mat");
dataset = ld.imuGestureDataset;

dataset = dataset(randperm(size(dataset,1)), :); % Shuffle the dataset

Ntrials = size(dataset,1);
Orientation = cell(Ntrials,1);
parfor ii=1:Ntrials
    h = imufilter("SampleRate", dataset(ii,:).SampleRate);
    Orientation{ii} = h(dataset.Accelerometer{ii}, dataset.Gyroscope{ii}); 
end
dataset = addvars(dataset, Orientation, NewVariableNames="Orientation");
gestures = string(unique(dataset.Gesture));  % Array of all gesture types
people = string(unique(dataset.Who));
Ngestures = numel(gestures);
Npeople = numel(people);

Fondo de alineamiento temporal dinámico del cuaternión

Alineamiento temporal dinámico del cuaternión [1] compara dos series temporales de orientación en el espacio del cuaternión y formula una métrica de distancia compuesta de tres partes relacionadas con la distancia del cuaternión, la derivada y la curvatura. En este ejemplo, solo comparará señales según la distancia del cuaternión.

El alineamiento temporal dinámico de cuaterniones utiliza la distorsión del tiempo para calcular una alineación óptima entre dos secuencias.

A continuación se utiliza el alineamiento temporal dinámico de cuaterniones para comparar dos secuencias de orientaciones (cuaterniones).

Crea dos orientaciones aleatorias:

rng(20);
q = randrot(2,1);

Cree dos trayectorias diferentes conectando las dos orientaciones:

h1 = 0:0.01:1;
h2 = [zeros(1,10) (h1).^2];
traj1 = slerp(q(1),q(2),h1).';
traj2 = slerp(q(1),q(2),h2).';

Tenga en cuenta que, aunque traj1 y traj2 comienzan y terminan en las mismas orientaciones, tienen longitudes diferentes y realizan la transición a lo largo de esas orientaciones a ritmos diferentes.

A continuación, compare y encuentre la mejor alineación entre estas dos trayectorias utilizando el alineamiento temporal dinámico de cuaterniones.

[qdist, idx1, idx2] = helperQDTW(traj1, traj2);

La métrica de distancia entre ellos es un escalar.

qdist
qdist = 1.1474

Grafique la mejor alineación utilizando las variables idx1 y idx2.

e1 = eulerd(traj1, "ZYX", "frame");
e2 = eulerd(traj2, "ZYX", "frame");

figure;
subplot(3,1,1);
plot(e1, "-");
legend ("Yaw (Z)", "Pitch (Y)", "Roll (X)");
ylabel("traj1")

subplot(3,1,2);
set(gca, "ColorOrderIndex", 4);
hold on;
plot(e2, "-");
legend ("Yaw (Z)", "Pitch (Y)", "Roll (X)");
ylabel("traj2")
hold off;

subplot(3,1,3);
plot(1:numel(idx1), e1(idx1,:), "-", ...
    1:numel(idx2), e2(idx2,:), "o" ); 
title("Aligned signals");
subplot(3,1,1);
title("Euler Angles for traj1 and traj2")

Figure contains 3 axes objects. Axes object 1 with title Euler Angles for traj1 and traj2 contains 3 objects of type line. These objects represent Yaw (Z), Pitch (Y), Roll (X). Axes object 2 contains 3 objects of type line. These objects represent Yaw (Z), Pitch (Y), Roll (X). Axes object 3 with title Aligned signals contains 6 objects of type line.

snapnow;

Partición de datos de entrenamiento y prueba

El conjunto de datos contiene trayectorias de cuatro sujetos de prueba. Entrenará su algoritmo con datos de tres sujetos y probará el algoritmo en el cuarto sujeto. Repite este proceso cuatro veces, alternando cada vez quién se utiliza para las pruebas y quién se utiliza para el entrenamiento. Producirá una matriz de confusión para cada ronda de pruebas para ver la precisión de la clasificación.

accuracy = zeros(1,Npeople);
for pp=1:Npeople
    testPerson = people(pp);
    trainset = dataset(dataset.Who ~= testPerson,:);
    testset = dataset(dataset.Who == testPerson,:);

Con los datos de gestos recopilados, puede utilizar la función de alineamiento temporal dinámico de cuaterniones para calcular las distancias mutuas entre todas las grabaciones de un gesto específico.

    % Preallocate a struct of distances and compute distances
    for gg=1:Ngestures
        gest = gestures(gg);
        subdata = trainset(trainset.Gesture == gest,:);
        Nsubdata = size(subdata,1);
        D = zeros(Nsubdata);
        traj = subdata.Orientation;
        parfor ii=1:Nsubdata
            for jj=1:Nsubdata
                if jj > ii  % Only calculate triangular matrix
                    D(ii,jj) = helperQDTW(traj{ii}, traj{jj}); 
                end
            end
        end
        allgestures.(gest) = traj;
        dist.(gest) = D + D.'; % Render symmetric matrix to get all mutual distances
    end

Agrupación y plantillas

El siguiente paso es generar trayectorias de plantilla para cada gesto. La estructura dist contiene las distancias mutuas entre todos los pares de grabaciones para un gesto determinado. En esta sección, agrupa todas las trayectorias de un gesto determinado según la distancia mutua. La función helperClusterWithSplitting utiliza un enfoque de división de clústeres descrito en [2]. Todas las trayectorias se colocan inicialmente en un solo grupo. El algoritmo divide el clúster si el radio del clúster (la distancia más grande entre dos trayectorias cualesquiera en el clúster) es mayor que radiusLimit.

El proceso de división continúa de forma recursiva para cada grupo. Una vez que se encuentra una mediana para cada grupo, la trayectoria asociada con ese grupo se guarda como plantilla para ese gesto en particular. Si la relación entre el número de trayectorias del grupo y el número total de trayectorias de un gesto determinado es menor que clusterMinPct, el grupo se descarta. Esto evita que las trayectorias atípicas afecten negativamente al proceso de clasificación. Dependiendo de la elección de radiusLimit y clusterMinPct, un gesto puede tener uno o varios grupos y, por lo tanto, puede tener una o varias plantillas.

    radiusLimit = 60;
    clusterMinPct = 0.2;
    parfor gg=1:Ngestures
        gest = gestures(gg);
        Dg = dist.(gest); %#ok<*PFBNS> 
        [gclusters, gtemplates] = helperClusterWithSplitting(Dg, radiusLimit);
        clusterSizes = cellfun(@numel, gclusters, "UniformOutput", true);
        totalSize = sum(clusterSizes);
        clusterPct = clusterSizes./totalSize;
        validClusters = clusterPct > clusterMinPct;
        tidx = gtemplates(validClusters);
        tmplt = allgestures.(gest)(tidx);
        templateTraj{gg} = tmplt;
        labels{gg} = repmat(gest, numel(tmplt),1);
    end
    templates = table(vertcat(templateTraj{:}), vertcat(labels{:}));
    templates.Properties.VariableNames = ["Orientation", "Gesture"];

La variable template se almacena como table. Cada fila contiene una trayectoria de plantilla almacenada en la variable Orientation y una etiqueta de gesto asociada almacenada en la variable Gesture. Utilizarás este conjunto de plantillas para reconocer nuevos gestos en testset.

Sistema de clasificación

Utilizando el alineamiento temporal dinámico de cuaterniones, se pueden comparar los nuevos datos de gestos del conjunto de prueba con cada una de las plantillas de gestos. El sistema clasifica el nuevo gesto desconocido como la clase de plantilla que tiene la distancia de alineamiento temporal dinámico del cuaternión más pequeña con respecto al gesto desconocido. Si la distancia a cada plantilla supera los radiusLimit, el gesto de prueba se marca como unrecognized.

    Ntest = size(testset,1);
    Ntemplates = size(templates,1);
    testTraj = testset.Orientation;
    expected = testset.Gesture;
    actual = strings(size(expected));

    parfor ii=1:Ntest
        testdist = zeros(1,Ntemplates);
        for tt=1:Ntemplates
            testdist(tt) = helperQDTW(testTraj{ii}, templates.Orientation{tt}); 
        end
        [mind, mindidx] = min(testdist);
        if mind > radiusLimit
            actual(ii) = "unrecognized";
        else
            actual(ii) = templates.Gesture{mindidx};
        end
    end
    results.(testPerson).actual = actual;
    results.(testPerson).expected = expected;
end
    

Calcular la precisión del sistema al identificar gestos en el conjunto de prueba y generar una matriz de confusión.

for pp=1:Npeople   
    figure;
    act = results.(people(pp)).actual;
    exp = results.(people(pp)).expected;
    numCorrect = sum(act == exp);
    Ntest = numel(act);
    accuracy = 100 * numCorrect./Ntest;
    confusionchart([exp; "unrecognized"], [act; missing]);
    title("Test subject = " + people(pp) + newline + "Accuracy = " + accuracy + "%" );
end
snapnow;

MATLAB figure

MATLAB figure

MATLAB figure

MATLAB figure

La precisión promedio en las cuatro configuraciones de los sujetos de prueba es superior al 90%.

AverageAccuracy = mean(accuracy)
AverageAccuracy = 94

Conclusión

Al fusionar datos IMU con el objeto imufilter y usar el alineamiento temporal dinámico de cuaterniones para comparar una trayectoria de gesto con un conjunto de trayectorias de plantilla, se reconocen gestos con gran precisión. Puede utilizar la fusión de sensores junto con la deformación y agrupación de alineamiento temporal dinámico de cuaterniones para construir un sistema eficaz de reconocimiento de gestos.

Referencias

[1] B. Jablonski, "Quaternion Dynamic Time Warping", en IEEE Transactions on Signal Processing, vol. 60, núm. 3 de marzo de 2012.

[2] R. Srivastava y P. Sinha, "Caracterización de movimientos y gestos de las manos mediante la técnica de alineamiento temporal dinámico de cuaterniones", en IEEE Sensors Journal, vol. 16, n.º 5, 1 de marzo de 2016.