在过去的几年里,科研界对使用基于表面肌电信号 (sEMG) 的深度学习方法进行手势分类产生了浓厚的兴趣。根据该领域的最新工作,我的工作目标是设计一种新颖的卷积神经网络架构,用于手势分类。我的模型虽然避免了过度拟合,但与更浅的网络相比,性能并没有显着提高。结果表明,某些手势之间的 sEMG 记录缺乏多样性,从而限制了 ML 模型的性能。
然而,我使用商业设备 (Myo Armband) 开发的数据集的分类准确度明显高于使用相同设备记录的类似基准数据集(约 24%)。
MyoUP 数据集
为了有助于获取 sEMG 数据,特别是从不需要专业校准的设备中获取,我开发了一个相当大的 sEMG 数据集。我们的数据集 MyoUP 受到 Ninapro 数据集的启发,所有记录的手势都与 Ninapro 中的一些 ( http://ninaweb.hevs.ch ) 相同。我们使用的录音设备是 Thalmic 实验室的 Myo Armband。Myo Armband 是一种相对便宜且易于佩戴的设备,其采样频率为 200Hz,8 个干式 sEMG 通道已在科学研究中广泛采用。
MyoUP 数据集包含来自 8 名完整受试者的记录(3 名女性,5 名男性;1 名左撇子,7 名右手;年龄 22.38 ± 1.06 岁)。采集过程分为三个部分:5 个基本手指动作、12 个等张和等长手部配置以及 5 个抓握手势。在进行每组练习之前,志愿者已经习惯了该程序。指示受试者重复每个手势 5 次,持续 5 秒,中间有 5 秒的中断,以避免肌肉疲劳。一名主管协助受试者将 Myo Armband 戴在他们的惯用手上,以便将设备放置在受试者舒适的位置,并且设备将准确检测 sEMG 信号。受试者可以在屏幕上看到 sEMG 以及必须执行的手势图片。
实时手势识别
通过使用来自 MyoUP 数据集的 sEMG 记录训练我们的 CNN,我设法开发了一个实时手势识别软件。
数据处理的matlab文件
%% Training signals - creation - Myo - step #1
clc;
clear all;
START = 's';
END = 'e1.mat';
filename = "s";
for subject = 1 : 8
%_________________________________________
code = strcat(START,int2str(subject),END);
disp(code);
struct = load(code);
rep = struct.pulse;
emg = struct.emg;
%_________________________________________
counter = 1;
points = zeros(1, 50);
for i = 2 : length(rep)
if(rep(i - 1) == 0 && rep(i) > 0)
points(counter) = i;
counter = counter + 1;
end
if(rep(i - 1) > 0 && rep(i) == 0)
points(counter) = i - 1;
counter = counter + 1;
end
end
counter = 1;
repeat = 0;
exercise = 0;
exe_number = 1;
for i = 1 : length(points) / 2
starting_point = points(counter);
counter = counter + 1;
finishing_point = points(counter);
counter = counter + 1;
disp(starting_point)
disp(finishing_point)
disp('______________')
repeat = repeat + 1;
exercise = exercise + 1;
columns = finishing_point - starting_point + 1;
matrix = zeros(8, columns);
column = 1;
for pointer = starting_point : finishing_point
for channel = 1 : 8
matrix(channel, column) = emg(pointer, channel);
end
column = column + 1;
end
file = filename + subject + "e" + exe_number + "rep" + repeat + ".mat";
save(file, 'matrix')
if(repeat == 5)
repeat = 0;
end
if(exercise == 5)
exercise = 0;
exe_number = exe_number + 1;
end
end
end
%% Maximum Size Matrix - step #2
clc;
maximum_size = 0;
emg_sizes = zeros(1, 3400);
counter = 0;
for subject = 1 : 8
for exercise = 1 : 5
for repetition = 1 : 5
counter = counter + 1;
filename = strcat('s', int2str(subject), 'e', int2str(exercise), 'rep', int2str(repetition));
path = 'Myo_training\E1\';
load_path = strcat(path, filename);
load_path = strcat(load_path, '.mat');
signal = load(load_path);
matrix = signal.matrix;
matrix_size = size(matrix); matrix_size = matrix_size(2);
emg_sizes(1, counter) = matrix_size;
if(matrix_size > maximum_size)
maximum_size = matrix_size;
end
end
end
end
%% Training Images - creation II - step #3
clear all;
clc;
for subject = 1 : 8
disp('Subject: ');
disp(subject)
for exercise = 1 : 12
for repetition = 1 : 5
filename = strcat('s', int2str(subject), 'e', int2str(exercise), 'rep', int2str(repetition));
path = 'Myo_training\E2\';
load_path = strcat(path, filename);
load_path = strcat(load_path, '.mat');
signal = load(load_path);
original_matrix = signal.matrix;
noisy_matrix = awgn(original_matrix,25);
matrix_size = size(original_matrix); matrix_size = matrix_size(2);
window_type_one = matrix_size / 6;
window_type_one = int16(fix(window_type_one));
window_type_two = 226 - window_type_one;
if(window_type_one > 226)
window_type_one = 225;
end
start_index = 1;
end_index = 15;
%________%: Normal Windows.
for div = 1 : window_type_one
if(exercise ~= 10 && exercise ~= 11 && exercise ~= 12)
filename = strcat('X2_e0', int2str(exercise), '_s', int2str(subject), '_E2_rep', int2str(repetition));
fn = strcat('X2_e0', int2str(exercise), '_s', int2str(subject), '_E2_rep', int2str(repetition));
else
filename = strcat( 'X2_e', int2str(exercise), '_s', int2str(subject), '_E2_rep', int2str(repetition));
fn = strcat( 'X2_e', int2str(exercise), '_s', int2str(subject), '_E2_rep', int2str(repetition));
end
counter = 1;
if(end_index <= matrix_size)
filename = strcat(filename, '_image', int2str(div));
if(repetition == 1 || repetition == 3 || repetition == 5)
save_matrix_path = strcat('EMG_data\train_set\' , filename, '.mat');
save_matrix_path_gaussian = strcat('EMG_data\train_set\' , filename, '_GAUSSIAN.mat');
end
if(repetition == 2)
save_matrix_path = strcat('EMG_data\test_set\' , filename, '.mat');
save_matrix_path_gaussian = strcat('EMG_data\test_set\' , filename, '_GAUSSIAN.mat');
end
if(repetition == 4)
save_matrix_path = strcat('EMG_data\val_set\' , filename, '.mat');
save_matrix_path_gaussian = strcat('EMG_data\val_set\' , filename, '_GAUSSIAN.mat');
end
image = zeros(8, 15);
image = original_matrix(1:8, start_index : end_index);
save(save_matrix_path, 'image')
image = zeros(8, 15);
image = noisy_matrix(1:8, start_index : end_index);
save(save_matrix_path_gaussian, 'image')
start_index = start_index + 6;
end_index = end_index + 6;
else
div = div - 1;
end
end
%________%: Random Windows.
for index = div : 226
limit = matrix_size - 20;
random_number = randi([1,limit]);
index_start_random = random_number;
index_end_random = index_start_random + 14;
if(repetition == 1 || repetition == 3 || repetition == 5)
save_path = strcat('EMG_data\train_set\' , fn, '_image', int2str(index), '.mat');
save_path_gaussian = strcat('EMG_data\train_set\' , fn, '_image', int2str(index), '_GAUSSIAN.mat');
end
if(repetition == 2)
save_path = strcat('EMG_data\test_set\' , fn, '_image', int2str(index), '.mat');
save_path_gaussian = strcat('EMG_data\test_set\' , fn, '_image', int2str(index), '_GAUSSIAN.mat');
end
if(repetition == 4)
save_path = strcat('EMG_data\val_set\' , fn, '_image', int2str(index), '.mat');
save_path_gaussian = strcat('EMG_data\val_set\' , fn, '_image', int2str(index), '_GAUSSIAN.mat');
end
image = zeros(8, 15);
image = original_matrix(1:8, index_start_random : index_end_random);
save(save_path, 'image');
image = zeros(8, 15);
image = noisy_matrix(1:8, index_start_random : index_end_random);
save(save_path_gaussian, 'image')
end
end
end
end