通过聚类中心进行0-9数字语音识别(matlab)——基于K-means聚类

项目已免费开源:https://gitee.com/zhengzsj/automatic-speech-recognition–ars/tree/master

1、技术路线

通过聚类中心进行0-9数字语音识别(matlab)——基于K-means聚类_第1张图片

2、实现过程

  层次聚类和K-means聚类的样本是0-9语音每个数字各5个,分类时加入一个新录入的语音与之前的50个样本进行分类,并与10个K-means聚类求出的质心求距离,在通过实验确定的阈值约束下,选取最小值进行分类,如果最小值大于阈值则显示无法识别。
    语音预处理和提取MFCC参数矩阵在这里不再赘述,求出MFCC矩阵之后对行取平均值,即对所有帧的MFCC参数求取平均,为简化运算和消除高频与低频噪音的影响,取第2-20个MFCC参数作为聚类样本,因此高维数据变成1*18维数据,可直接进行层次聚类和K-means聚类,层次聚类和K-means聚类都直接调用MATLAB提供的函数,求距离用欧氏距离。

3、聚类、分类效果

  从图中可以看出层次聚类效果很不错,数字相近的5个样本属于同一个数,即相同颜色的数据聚类成同一类,聚类正确率可达87.96%,同时录音‘5’(第51号文件)进行分类,确实与聚类成5的一组分类在一起,分类正确,但多次实验验证分类正确率并不高,最高只能达到30%左右。
通过聚类中心进行0-9数字语音识别(matlab)——基于K-means聚类_第2张图片

4、GUI界面

  聚类、分类GUI界面如下,左边‘开始’、‘停止’可输入语音,中间坐标轴可视化层次聚类结果和输入语音分类结果,下边显示与K-means聚类质心进行分类的结果。同时作为服务机,可以接受客户机发送到数据并显示到下方聚类结果显示栏,同时电子音一一播放接收的数据,可清除聚类结果显示栏和坐标。
通过聚类中心进行0-9数字语音识别(matlab)——基于K-means聚类_第3张图片

5、结果与结论

( 1)当说0时,层次聚类后分类效果不错,其与K-means聚类质心距离和质心间的距离如表1、表2。

通过聚类中心进行0-9数字语音识别(matlab)——基于K-means聚类_第4张图片
  实验确定样本与质心间距离阈值为500,确实样本‘0’与数字‘0’质心间距离很小,只有88.85,但样本与所有质点间的距离都比较小,而质心间的类间距特别大,聚类数据间的类间距也特别大,样本与质心间的类内距很小,但样本与其他质心间的类间距也很小,这可能也是分类准确率不高的一个原因。除此之外,求平均的数据降维方式过于简单、粗暴,可能损失了大量有效信息,也是影响分类效果的很大原因。
表1  样本‘0’与10个质心DTW距离

表1 样本‘0’与10个质心DTW距离

注:第i列代表样本‘0’与数字‘i’的质心间的距离。红色为最大值,绿色为最小值。

通过聚类中心进行0-9数字语音识别(matlab)——基于K-means聚类_第5张图片

表2 K-means聚类10个质心间DTW距离(类间差)

注:i行j列代表数字‘i’质心与数字‘j’质心的距离。红色为最大值,绿色为最小值。
( 2)0-9数字模板匹配识别和聚类、分类识别对比
  时间上来说模板匹配和聚类差不多,但由于模板匹配的正确率高很多,最后选用模板匹配的方式进行数字识别。但模板匹配准确率特别依赖模板的数量、方式以及录音人性别,本小组100个模板全为同一个女生,最后由6个女生测试得到平均准确率为83%,但如果男生来测试可能准确率就很低了,而且并不一定模板越多准确率越高,可能出现当采用多个人的语音作为模板时,不同人的1和7极为相似而使得类间距缩小,而降低准确率,因此在实际中不会采用模板匹配的方式进行语音识别。
在这里插入图片描述
使用模板匹配的方式进行0-9语音识别参考:https://blog.csdn.net/weixin_43808138/article/details/123184195?spm=1001.2014.3001.5501
部分代码:

%% kmeans聚类中心判别
type=11;
min_=100000;
% load C4
C4=xlsread('C4.xlsx');
for i=1:10
    D(i,1)=dtw(C4(i,:),me0);
    if(D(i,1)<500)
        type=i-1;
        set(handles.edit1,'string',type);
    end
%       if(D(i,1)<min_)
%           min_=D(i,1);
%           type=i;
%       end
end
if type==11
    set(handles.edit1,'string','无法识别');
end
%% 层次聚类
fileFolder='层次聚类\';
dirOutput=dir(strcat(fileFolder,'*'));
fileNames={dirOutput.name};
len = length(fileNames); 
%% 循环读取
for j=3:len
    % 连接路径和文件名得到完整的文件路径
    K_Trace = strcat(fileFolder, fileNames(j));
   eval(['[x,fs]','=','audioread(K_Trace{1,1})',';']);
%% 端点检测
%幅度归一化到[-1,1]
x = double(x);
x = x / max(abs(x));
% figure,plot(x);
%常数设置
FrameLen = 256;%帧长为256点
FrameInc = 80;%帧移为80点
amp1 = 20;%初始短时能量高门限
amp2 = 2;%初始短时能量低门限
zcr1 = 10;%初始短时过零率高门限
zcr2 = 5;%初始短时过零率低门限
maxsilence = 8;  % 8*10ms  = 80ms
%语音段中允许的最大静音长度,如果语音段中的静音帧数未超过此值,则认为语音还没结束;如果超过了
%该值,则对语音段长度count进行判断,若count<minlen,则认为前面的语音段为噪音,舍弃,跳到静音
%状态0;若count>minlen,则认为语音段结束;
minlen  = 15;    % 15*10ms = 150ms
%语音段的最短长度,若语音段长度小于此值,则认为其为一段噪音
status  = 0;     %初始状态为静音状态
count   = 0;     %初始语音段长度为0
silence = 0;     %初始静音段长度为0
%计算过零率
x1=x(1:end-1);
x2=x(2:end);
%分帧
tmp1=enframe(x1,FrameLen,FrameInc);
tmp2=enframe(x2,FrameLen,FrameInc);
signs = (tmp1.*tmp2)<0;
diffs = (tmp1 -tmp2)>0.02;
zcr   = sum(signs.*diffs, 2);%一帧一个值,2表示按行求和
%计算短时能量
%一帧一个值
%amp = sum(abs(enframe(filter([1 -0.9375], 1, x), FrameLen, FrameInc)), 2);
amp = sum(abs(enframe(x, FrameLen, FrameInc)), 2);
%调整能量门限
amp1 = min(amp1, max(amp)/4);
amp2 = min(amp2, max(amp)/8);
%开始端点检测
%For循环,整个信号各帧比较
%根据各帧能量判断帧所处的阶段
x1 = 0;
x2 = 0;
v_num=0;%记录语音段数
v_Begin=[];%记录所有语音段的起点
v_End=[];%记录所有语音段的终点
%length(zcr)即为帧数
for n=1:length(zcr)
   goto = 0;
   switch status
   case {0,1}                   % 0 = 静音, 1 = 可能开始
      if amp(n) > amp1          % 确信进入语音段
         x1 = max(n-count-1,1);
%          '打印每个x1*FrameInc'
%          x1*FrameInc
         status  = 2;
         silence = 0;
         count   = count + 1;
      elseif amp(n) > amp2 | ... % 可能处于语音段
             zcr(n) > zcr2
         status = 1;
         count  = count + 1;
      else                       % 静音状态
         status  = 0;
         count   = 0;
      end
   case 2                     % 2 = 语音段
      if amp(n) > amp2 | ...     % 保持在语音段
         zcr(n) > zcr2
         count = count + 1;
      else                       % 语音将结束
         silence = silence+1;
         if silence < maxsilence % 静音还不够长,尚未结束
            count  = count + 1;
         elseif count < minlen   % 语音长度太短,认为是噪声
            status  = 0;
            silence = 0;
            count   = 0;
         else                    % 语音结束
            status  = 3;
         end
      end
   case 3
      %break;
      %记录当前语音段数据
      v_num=v_num+1;   %语音段个数加一
      count = count-silence/2;
      x2 = x1 + count -1;
      v_Begin(1,v_num)=x1*FrameInc; 
      v_End(1,v_num)=x2*FrameInc;
      %不跳出 数据归零继续往下查找下一段语音
      status  = 0;     %初始状态为静音状态
      count   = 0;     %初始语音段长度为0
      silence = 0;     %初始静音段长度为0
   end
end  
if length(v_End)==0
    x2 = x1 + count -1;
    v_Begin(1,1)=x1*FrameInc; 
    v_End(1,1)=x2*FrameInc;
end
lenafter=0;
for len=1:length(v_End)
    tmp=v_End(1,len)-v_Begin(1,len);
    lenafter=lenafter+tmp;
end
lenafter;
afterEndDet=zeros(lenafter,1);%返回去除静音段的语音信号
beginnum=0;
endnum=0; 
    for k=1:length(v_End)
        tmp=x(v_Begin(1,k):v_End(1,k));
        beginnum=endnum+1;
        endnum=beginnum+v_End(1,k)-v_Begin(1,k);
        afterEndDet(beginnum:endnum)=tmp; 
    end
%     figure,plot(tmp);
% end
x=tmp;
%% Mel三角滤波器组参数
fh=fs/2; % fs=8000Hz,fh=4000Hz    语音信号的频率一般在300-3400Hz,所以一般情况下采样频率设为8000Hz即可。
max_melf=2595*log10(1+fh/700);%耳朵响应频率
M=24;%三角滤波器的个数
N=floor(0.03*fs);%设置帧长
i=0:25;
 f=700*(10.^(max_melf/2595*i/(M+1))-1);%将mei频域中的 各滤波器的中心频率 转到实际频率
F=zeros(24,N);
 for m=1:24
     for k=1:N
         i=fh*k/N;
         if (f(m)<=i)&&(i<=f(m+1))
             F(m,k)=(i-f(m))/(f(m+1)-f(m));
         else if (f(m+1)<=i)&&(i<=f(m+2))
                 F(m,k)=(f(m+2)-i)/(f(m+2)-f(m+1));
         else
                 F(m,k)=0;
             end
         end
     end
 end
%  figure,plot((1:N)*fh/N,F);
 %% DCT系数的计算方法
dctcoef=zeros(12,24);
 for k=1:12
   n=1:24;
   dctcoef(k,:)=cos((2*n-1)*k*pi/(2*24));
 end
 %% 预加重
len=length(x);
 alpha=0.98;
 y=zeros(len,1);
 for i=2:len
     y(i)=x(i)-alpha*x(i-1);
 end
 %% MFCC特征参数的求取
 h=hamming(N);%256*1
 num=floor(0.235*N); %帧移
 count=floor((len-N)/num+1);%帧数
 c1=zeros(count,12);
 for i=1:count
     x_frame=y(num*(i-1)+1:num*(i-1)+N);%分帧
     w = x_frame.* h;%
     Fx=abs(fft(w));%     Fx=abs(fft(x_frame));
     s=log(F*Fx.^2);%取对数
     c1(i,:)=(dctcoef*s)'; %离散余弦变换 
 end
%% 求取一阶差分mfcc系数
dtm = zeros(size(c1));
for i=3:size(c1,1)-2
  dtm(i,:) = -2*c1(i-2,:) - c1(i-1,:) + c1(i+1,:) + 2*c1(i+2,:);
end
dtm = dtm/3;
%% 合并
ccc=[c1 dtm];
ccc = ccc(3:size(c1,1)-2,:);
%% 一段语音的所有帧的mfcc参数求均值
me1(j,:)=mean(ccc);
end
me1=me1(3:end,2:20);
me=[me1;me0];
%%
Y=pdist(me);              % 计算样本点之间的欧氏距离
Y=squareform(Y);  
Z=linkage(Y);             % 用最短距离法创建系统聚类树?
% C2=cophenet(Z,Y)        % //0.94698
T=cluster(Z,10);           % 聚类结果
dendrogram(Z,0,'ColorThreshold',20);

后期会上传整个项目代码~
项目已免费开源:https://gitee.com/zhengzsj/automatic-speech-recognition–ars/tree/master
点个赞和收藏吧~谢谢啦!

你可能感兴趣的:(matlab,matlab,k-means,语音识别,聚类)