2017-09-08 20:59:01 lzc504603913 阅读数 1521
  • 数据结构与算法C/C++实现)视频教程

    C/C++实现数据结构与算法视频培训课程全面介绍计算机行业,基本的数据结构与算法,既有理论的深度也有实战的技法。课程全程讲师手敲代码,一步步代你走进数据结构与算法。 本课程涉及的数据结构与算法有,栈,队列,单向链表,双向循环链表,树,二叉树,搜索二叉树,平衡搜索二叉树,冒泡,选择,直插,希尔,,归并等,课程还涉及深度优先算法与广度优先算法等等。

    3406 人正在学习 去看看 王桂林


MFCC-DTW

Simple MFCC extractor and an speech recognition algorithm (Dynamic Time Warping)

一个MFCC参数提取模板,和语音识别算法(DTW)


main.cpp里有详细的用法,提取原理请参考其他博客。识别算法介绍请参考其他博客。抽象成一个类后,我们不必关心内部的实现方法,直接调用函数提取mfcc参数即可。


Github地址:https://github.com/Linzecong/MFCC-DTW



WaveStructure.h

#ifndef WAVESTRUCTURE_H
#define WAVESTRUCTURE_H

#include<vector>
#include<complex>
#include<cmath>
#include<string>
#include<iostream>
#include<stdlib.h>
#include<malloc.h>
#include<bitset>
using   namespace   std;
#define INF 1000000000000
const float PI=3.1415926536;
const int FS=8;
const int FiltNum=25;

struct RIFF_HEADER{
   char szRiffID[4];  // 'R','I','F','F'
   unsigned long dwRiffSize;
   char szRiffFormat[4]; // 'W','A','V','E'
};

struct FMT_HEADER{
   char  szFmtID[4]; // 'f','m','t',' '
   unsigned long  dwFmtSize; // 18 OR 16
};

struct DATA_BLOCK{
    char szDataID[4]; // 'd','a','t','a'
    unsigned long dwDataSize;
};

struct WAVE_FORMAT{
   unsigned short  wFormatTag;
   unsigned short  wChannels;
   unsigned long dwSamplesPerSec;
   unsigned long dwAvgBytesPerSec;
   unsigned short  wBlockAlign;
   unsigned short  wBitsPerSample;
   unsigned short  wAppendData;
};

struct mTWavHeader{
        int rId;    //标志符(RIFF)
        int rLen;   //数据大小,包括数据头的大小和音频文件的大小
        int wId;    //格式类型("WAVE")
        int fId;    //"fmt"
        int fLen;   //Sizeof(WAVEFORMATEX)
        short wFormatTag;       //编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等
        short nChannels;        //声道数,单声道为1,双声道为2
        int nSamplesPerSec;   //采样频率
        int nAvgBytesPerSec;  //每秒的数据量
        short nBlockAlign;      //块对齐
        short wBitsPerSample;   //WAVE文件的采样大小
        int dId;              //"data"
        int wSampleLength;    //音频数据的大小
};

#endif // WAVESTRUCTURE_H


WaveFunction.h


#ifndef WAVEFUNCTION_H
#define WAVEFUNCTION_H
#include"WaveStructure.h"

class WaveFunction{
private:
    int CharCmp(const char *first,const char *second,unsigned short len);
    void InitHamming();

    //设置滤波器参数
    //输入参数:无
    //输出参数:FiltCoe1,三角形滤波器左边的系数,FiltCoe2三角形滤波器右边的系数,Num决定每个点属于哪一个滤波器
    void InitFilt(float *FiltCoe1, float *FiltCoe2, int *Num);

    //加窗,输入为buf,输出为data
    void HammingWindow(short* buf,float* data);

    //计算傅里叶参数
    void ComputeFFT(float *buffer,vector<complex<float> >& vecList);

    //傅里叶变换
    void FFT(const unsigned long & ulN, vector<complex<float> >& vecList);

    /*
    根据滤波器参数计算频带能量
    输入参数:*spdata  ---预处理之后的一帧语音信号
              *FiltCoe1---三角形滤波器左边的系数
              *FiltCoe2---三角形滤波器右边的系数
              *Num     ---决定每个点属于哪一个滤波器
    输出参数:*En      ---输出对数频带能量
    */
    void Filt(float *spdata, float *FiltCoe1, float *FiltCoe2, int *Num, float *En,vector<complex<float> >& vecList);

    /*
    计算MFCC系数
    输入参数:*En ---对数频带能量
    */
    void MFCC(float *En);


    float ComputeDTW(float *cep1, float *cep2, int num1, int num2);
    float Distance(float * ps1,float * ps2,int k1,int k2);

    void AdjustSize();

private:
    vector<float> xishu;
    double *Hamming;
    vector<vector<float> > SourceMFCCs;
    int MFCC_P;
    int MFCC_Pf;
    int FrmLen;
    int FFTLen;

public:
    vector<vector<float> > getMFCCs(string filename);
    vector<vector<float> > addFirstOrderDifference(vector<vector<float> > mfccs);
    vector<vector<float> > addOrderDifference(vector<vector<float> > mfccs);

    //输入为两个mfcc参数,cep1,cep2,返回最短距离
    float ComputeDTW(vector<vector<float> > cep1,vector<vector<float> > cep2);
    WaveFunction(int frm_len, int mfcc_num);
    ~WaveFunction();
};

#endif // WAVEFUNCTION_H


WaveFunction.cpp

#include "WaveFunction.h"

WaveFunction::WaveFunction(int frm_len, int mfcc_num){
    MFCC_P=mfcc_num;
    MFCC_Pf=float(mfcc_num);
    FrmLen=frm_len;
    FFTLen=frm_len;
    Hamming=new double[FrmLen];
}

WaveFunction::~WaveFunction(){
    delete []Hamming;
}

vector<vector<float> > WaveFunction::getMFCCs(string filename){
    xishu.clear();
    SourceMFCCs.clear();
    //mfcc分析
    mTWavHeader waveheader;
    FILE *sourcefile;
    short buffer[FrmLen];
    float data[FrmLen];
    float FiltCoe1[FFTLen/2+1];  //左系数
    float FiltCoe2[FFTLen/2+1];  //右系数
    int Num[FFTLen/2+1];     //决定每个点属于哪一个滤波器
    float En[FiltNum+1];         //频带能量
    vector<complex<float> > vecList;

    sourcefile=fopen(filename.c_str(),"rb");
    fread(&waveheader,sizeof(mTWavHeader),1,sourcefile);
    InitHamming();//初始化汉明窗
    InitFilt(FiltCoe1,FiltCoe2,Num); //初始化MEL滤波系数

    while(fread(buffer,sizeof(short),FrmLen,sourcefile)==FrmLen){
        HammingWindow(buffer,data);
        ComputeFFT(data,vecList);
        Filt(data, FiltCoe1, FiltCoe2, Num, En,vecList);
        MFCC(En);
        vecList.clear();
        fseek(sourcefile, -FrmLen/2, SEEK_CUR);//考虑到帧移,每次移动半帧
    }

    int stdlength=xishu.size();

    for(int i=0;i<stdlength/MFCC_P;i++){
        vector<float> temp;
        for(int j=0;j<MFCC_P;j++)
            temp.push_back(xishu[i*MFCC_P+j]);
        SourceMFCCs.push_back(temp);
    }
    fclose(sourcefile);
    return SourceMFCCs;
}

vector<vector<float> > addFirstOrderDifference(vector<vector<float> > mfccs){
    vector<vector<float> > temp;
    for(int i=0;i<mfccs.size();i++){
        vector<float> line=mfccs[i];
        int size=line.size();
        for(int t=0;t<size;t++){
            if(t<2)
                line.push_back(line[t+1]-line[t]);
            else{
                if(t>size-2||t==size-2)
                    line.push_back(line[t]-line[t-1]);
                else{
                    float fenzi=line[t+1]-line[t-1]+2*(line[t+2]-line[t-2]);
                    float fenmu=sqrtf(10);
                    line.push_back(fenzi/fenmu);

                }
            }
        }
        temp.push_back(line);
    }
    return temp;
}

vector<vector<float> > addOrderDifference(vector<vector<float> > mfccs){
    vector<vector<float> > temp;
    for(int i=0;i<mfccs.size();i++){
        vector<float> line=mfccs[i];
        int size=line.size();
        //一阶差分
        for(int t=0;t<size;t++){
            if(t<2)
                line.push_back(line[t+1]-line[t]);
            else{
                if(t>size-2||t==size-2)
                    line.push_back(line[t]-line[t-1]);
                else{
                    float fenzi=line[t+1]-line[t-1]+2*(line[t+2]-line[t-2]);
                    float fenmu=sqrtf(10);
                    line.push_back(fenzi/fenmu);

                }
            }
        }
        //二阶差分
        for(int t=size;t<size*2;t++){
            if(t<2)
                line.push_back(line[t+1]-line[t]);
            else{
                if(t>size-2||t==size-2)
                    line.push_back(line[t]-line[t-1]);
                else{
                    float fenzi=line[t+1]-line[t-1]+2*(line[t+2]-line[t-2]);
                    float fenmu=sqrtf(10);
                    line.push_back(fenzi/fenmu);

                }
            }
        }
        temp.push_back(line);
    }
    return temp;
}

float WaveFunction::ComputeDTW(vector<vector<float> > cep1, vector<vector<float> > cep2)
{
    vector<float> temp;
    for(int i=0;i<cep1.size();i++)
        for(int j=0;j<cep1[i].size();j++)
            temp.push_back(cep1[i][j]);
    int stdlength=temp.size();
    float * stdmfcc = new float[stdlength];
    std::copy(temp.begin(),temp.end(),stdmfcc);

    vector<float> temp1;
    for(int i=0;i<cep2.size();i++)
        for(int j=0;j<cep2[i].size();j++)
            temp1.push_back(cep2[i][j]);
    int testlen=temp1.size();
    float * testmfcc = new float[testlen];
    std::copy(temp1.begin(),temp1.end(),testmfcc);
    return ComputeDTW(stdmfcc,testmfcc,stdlength/MFCC_P,testlen/MFCC_P);
}

int WaveFunction::CharCmp(const char *first,const char *second,unsigned short len)
{
    int i=0;
    while((first[i]==second[i])&&(i++<len));
    if(i>=len)
        return 0;
    else if(first[i-1]>second[i-1])
        return 1;
    else
        return -1;
}

void WaveFunction::InitHamming(){

    float twopi;
    int i;
    twopi=8.0F*atan(1.0F);
    for(i=0;i<FrmLen;i++)
        Hamming[i]=(float)(0.54-0.46*cos((float)i*twopi/(float)(FrmLen-1)));
}

void WaveFunction::InitFilt(float *FiltCoe1, float *FiltCoe2, int *Num){
    int i,j;
    float Freq;
    int FiltFreq[FiltNum+1] = {0,100,200,300,400,500,600,700,800,900,1000,
                               1149,1320,1516,1741,2000,2297,2639,3031,3482,4000,
                               4595,5278,6063,6964,8001};//滤波器的中心频率
    int BW[FiltNum+1]={100,100,100,100,100,100,100,100,100,100,124,
                       160,184,211,242,278,320,367,422,484,556,
                       639,734,843,969,1112};//滤波器的带宽
    for(i = 0 ; i<= FFTLen/2 ; i++ )
    {
        Num[i]=0;
    }

    for(i = 0 ; i <= FFTLen/2 ; i++)
    {
        Freq = FS * 1000.0F * (float)(i) / (float)(FFTLen);
        for(j = 0 ; j <FiltNum ; j++)
        {
            if(Freq >= (float)FiltFreq[j] && Freq <= (float)FiltFreq[j+1])
            {
                Num[i] = j;
                if(j == 0)
                {
                    FiltCoe1[i] = 0.0F;
                }
                else
                {
                    FiltCoe1[i] = ((float)(FiltFreq[j]+BW[j])-Freq) / (float)(BW[j]);
                }
                FiltCoe2[i] = (Freq-(float)(FiltFreq[j+1]-BW[j+1])) / (float)(BW[j+1]);
                FiltCoe1[i] = FiltCoe1[i] * FiltCoe1[i];
                FiltCoe2[i] = FiltCoe2[i] * FiltCoe2[i];
                break;
            }
        }
    }

}

void WaveFunction::HammingWindow(short *buf, float *data){
    int i;
    for(i=0;i<FrmLen;i++)
        data[i]=buf[i]*Hamming[i];
}

void WaveFunction::ComputeFFT(float *data, vector<complex<float> > &vecList){
    for(int i=0;i<FFTLen;++i)
    {
        if(i<FrmLen)
        {
            complex<float> temp(data[i]);
            vecList.push_back(temp);
        }
        else
        {
            complex<float> temp(0);
            vecList.push_back(temp);
        }
    }
    FFT(FFTLen,vecList);
}

void WaveFunction::FFT(const unsigned long &ulN, vector<complex<float> > &vecList){
    //得到幂数

    unsigned long ulPower = 0; //幂数
    unsigned long ulN1 = ulN - 1;
    while(ulN1 > 0)
    {
        ulPower++;
        ulN1 /= 2;
    }
    //反序

    bitset<sizeof(unsigned long) * 8> bsIndex; //二进制容器
    unsigned long ulIndex; //反转后的序号
    unsigned long ulK;
    for(unsigned long p = 0; p < ulN; p++)
    {
        ulIndex = 0;
        ulK = 1;
        bsIndex = bitset<sizeof(unsigned long) * 8>(p);
        for(unsigned long j = 0; j < ulPower; j++)
        {
            ulIndex += bsIndex.test(ulPower - j - 1) ? ulK : 0;
            ulK *= 2;
        }

        if(ulIndex > p)
        {
            complex<float> c = vecList[p];
            vecList[p] = vecList[ulIndex];
            vecList[ulIndex] = c;
        }
    }

    //计算旋转因子

    vector<complex<float> > vecW;
    for(unsigned long i = 0; i < ulN / 2; i++)
    {
        vecW.push_back(complex<float>(cos(2 * i * PI / ulN) , -1 * sin(2 * i * PI / ulN)));
    }

    /*for(unsigned long m = 0; m < ulN / 2; m++)
    {
        cout<< "\nvW[" << m << "]=" << vecW[m];
    } */

    //计算FFT

    unsigned long ulGroupLength = 1; //段的长度
    unsigned long ulHalfLength = 0; //段长度的一半
    unsigned long ulGroupCount = 0; //段的数量
    complex<float> cw; //WH(x)
    complex<float> c1; //G(x) + WH(x)
    complex<float> c2; //G(x) - WH(x)
    for(unsigned long b = 0; b < ulPower; b++)
    {
        ulHalfLength = ulGroupLength;
        ulGroupLength *= 2;
        for(unsigned long j = 0; j < ulN; j += ulGroupLength)
        {
            for(unsigned long k = 0; k < ulHalfLength; k++)
            {
                cw = vecW[k * ulN / ulGroupLength] * vecList[j + k + ulHalfLength];
                c1 = vecList[j + k] + cw;
                c2 = vecList[j + k] - cw;
                vecList[j + k] = c1;
                vecList[j + k + ulHalfLength] = c2;
            }
        }
    }
}

void WaveFunction::Filt(float *spdata, float *FiltCoe1, float *FiltCoe2, int *Num, float *En, vector<complex<float> > &vecList){
    float temp=0;
    int id, id1, id2;

    for(id = 0 ; id <= FiltNum ; id++)
    {
        En[id]=0.0F;
    }
    for(id = 0 ; id < FFTLen/2 ; id++)
    {
        temp = vecList[id].real()*vecList[id].real()+vecList[id].imag()*vecList[id].imag();
        id1 = Num[id];
        id2 = id1+1;
        En[id1] = En[id1] + FiltCoe1[id] * temp;
        En[id2] = En[id2] + FiltCoe2[id] * temp;
    }
    for(id = 1 ; id <= FiltNum ; id++)
    {
        if(En[id]!=0)
            En[id]=(float)log(En[id]);
    }
}

void WaveFunction::MFCC(float *En)
{
    int idcep, iden;
    float Cep[MFCC_P];

    for(idcep = 0 ; idcep < MFCC_P ; idcep++)
    {
        Cep[idcep] = 0.0;

        for(iden = 1 ; iden <= FiltNum ; iden++)
        {
            Cep[idcep] = Cep[idcep] + En[iden] * (float)cos((idcep+1) * (iden-0.5F) * PI/(FiltNum));
        }
        Cep[idcep] = Cep[idcep] / 10.0F;
        xishu.push_back(Cep[idcep]);
    }
}


float WaveFunction::ComputeDTW(float *cep1, float *cep2, int num1, int num2){
    struct record
    {		int x;
                int y;
    };
    struct point
    {		int x,y;
                float minvalue;
                        int stepnum;
                                bool recheck;               //记录该点是否被记录过
    };
    record * re;
    record * newre;

    newre=new record[num1*num2];    //记录下一层的所有点
    re=new record[num1*num2];       //记录当层的所有点
    int renum;
    int newrenum=0;
    int i,j;
    point * poi;
    poi=new point[num1*num2];

    for(i=0;i<num1*num2;i++)
    {
        poi[i].recheck=0;
        poi[i].minvalue=INF;
        poi[i].stepnum=0;
    }								//设置初始值

    for(i=0;i<5;i++)                //起始点
    {
        if(i==0)  {	re[i].x=1; re[i].y=1; }
        if(i==1)  {	re[i].x=1; re[i].y=2; }
        if(i==2)  {	re[i].x=1; re[i].y=3; }
        if(i==3)  {	re[i].x=2; re[i].y=1; }
        if(i==4)  {	re[i].x=3; re[i].y=1; }
        poi[(re[i].y-1)*num1+re[i].x-1].minvalue=Distance(cep1,cep2,re[i].x,re[i].y);
        poi[(re[i].y-1)*num1+re[i].x-1].stepnum=1;
    }
    renum=5;
    int newx,newy;                   //newvalue;
    for(i=0;i<renum;i++)
    {
        for(j=0;j<3;j++)
        {
            if(j==0){ newx=re[i].x+1; newy=re[i].y+2; }
            if(j==1){ newx=re[i].x+1; newy=re[i].y+1; }
            if(j==2){ newx=re[i].x+2; newy=re[i].y+1; }

            /////////////三种可能路径

            if(newx>=num1||newy>=num2)
                continue;
            if(fabs(newx-newy)<=fabs(num1-num2)+3)
            {
                if(poi[(newy-1)*num1+newx-1].recheck==0)
                {
                    newre[newrenum].x=newx;
                    newre[newrenum].y=newy;
                    newrenum++;
                }
                float tmpdis;
                int addstepnum;
                if(j==0){ tmpdis=Distance(cep1,cep2,newx-1,newy-1)*2+Distance(cep1,cep2,newx,newy); addstepnum=2;}
                if(j==1){ tmpdis=Distance(cep1,cep2,newx,newy)*2; addstepnum=1;}
                if(j==2){ tmpdis=Distance(cep1,cep2,newx-1,newy-1)*2+Distance(cep1,cep2,newx,newy); addstepnum=2;}
                if(poi[(newy-1)*num1+newx-1].minvalue>(poi[(re[i].y-1)*num1+re[i].x-1].minvalue+tmpdis))
                {
                    poi[(newy-1)*num1+newx-1].minvalue=(poi[(re[i].y-1)*num1+re[i].x-1].minvalue+tmpdis);
                    poi[(newy-1)*num1+newx-1].stepnum=poi[(re[i].y-1)*num1+re[i].x-1].stepnum+addstepnum;
                }
                if(poi[(newy-1)*num1+newx-1].recheck==0)
                    poi[(newy-1)*num1+newx-1].recheck=1;
            }
        }
        if(newrenum!=0 && i>=(renum-1))
        {
            renum=newrenum;
            newrenum=0;
            struct	record * tt;
            tt=re;
            re=newre;
            newre=tt;
            i=-1;
        }
    }
    float min=INF;
    for(j=0;j<renum;j++)
    {
        if((poi[(re[j].y-1)*num1+re[j].x-1].minvalue)/poi[(re[j].y-1)*num1+re[j].x-1].stepnum<min)
            min=(poi[(re[j].y-1)*num1+re[j].x-1].minvalue)/poi[(re[j].y-1)*num1+re[j].x-1].stepnum;
    }

    //	min;
    delete []poi;
    delete []newre;
    delete []re;
    delete []cep1;
    delete []cep2;
    return min;
}

float WaveFunction::Distance(float *ps1, float *ps2, int k1, int k2){
    int i=0;
    float sum=0;
    for(i=0;i<MFCC_P;i++)
        sum+=(1+MFCC_Pf/2*(float)sin(PI*i/MFCC_Pf))*(ps1[k1+i]-ps2[k2+i])*(ps1[k1+i]-ps2[k2+i]);

    return sum;
}

main.cpp

#include"wavefunction.h"

int main(int argc, char *argv[])
{
    WaveFunction* a=new WaveFunction(128,13);//每帧多少个采样点,MFCC参数的维数
    
    vector<vector<float> > mfccs1 = a->getMFCCs("D:\\1.wav");//提取mfcc参数
    vector<vector<float> > mfccs2 = a->getMFCCs("D:\\2.wav");

    //mfccs1=a->addFirstOrderDifference(mfccs1);//增加一阶差分系数,此时mfcc参数变为13+13维

    mfccs1=a->addOrderDifference(mfccs1);//增加一阶差分和二阶差分系数,此时mfcc参数变为13*2+13维
    mfccs2=a->addOrderDifference(mfccs2);

    
    cout<<a->ComputeDTW(mfccs1,mfccs2);//利用动态时间规整算法,计算两个语音的相似度,越小相似度越大

    return 0;
}



2018-08-08 16:59:24 weixin_38285131 阅读数 555
  • 数据结构与算法C/C++实现)视频教程

    C/C++实现数据结构与算法视频培训课程全面介绍计算机行业,基本的数据结构与算法,既有理论的深度也有实战的技法。课程全程讲师手敲代码,一步步代你走进数据结构与算法。 本课程涉及的数据结构与算法有,栈,队列,单向链表,双向循环链表,树,二叉树,搜索二叉树,平衡搜索二叉树,冒泡,选择,直插,希尔,,归并等,课程还涉及深度优先算法与广度优先算法等等。

    3406 人正在学习 去看看 王桂林

关于C++调用python函数的配置,在前两篇博客中已有介绍:
C++调用Python函数(一)——配置及测试
C++调用Python函数(二)——调用函数并输出返回值

最近做OCR字符识别方面的工作,想通过讯飞的接口进行OCR识别,前面的算法预处理,分图等工作是用C++完成的,但是用C++调用讯飞接口比较困难,于是想利用C++调用Python函数去调用讯飞接口。

一丶Python调用讯飞OCR接口函数

这里写图片描述

到讯飞开放平台进行注册,日免费次数500次
讯飞开放平台
获取自己的APIID和apiKey

import time
import urllib
import json
import hashlib
import base64
from urllib import parse,request

def main(filepath):
    f = open(filepath, 'rb')#图片存放位置
    file_content = f.read()
    base64_image = base64.b64encode(file_content)
    body = urllib.parse.urlencode({'image': base64_image})  # body数据
    body = bytes(body, 'utf-8')
    url = 'http://webapi.xfyun.cn/v1/service/v1/ocr/handwriting'
    api_key = 'xxxxxxxxxxxxxxxxxxxxxxxx'#申请的apiKey
    param = {"language":"en", "location":"false"}  # header中参数
    param_json = json.dumps(param).replace(' ', '')#字符串类型
    x_appid = 'XXXXXXXX'#讯飞的APIID,自己申请的
    param1=bytes(param_json,'utf-8')
    #pdb.set_trace()
    x_param = base64.b64encode(param1)
    x_param_decode = x_param.decode('utf-8')
    x_time = int(int(round(time.time() * 1000)) / 1000)
    text = api_key + str(x_time) + x_param_decode
    text = bytes(text, 'utf-8')
    x_checksum = hashlib.md5(text).hexdigest()
    x_header = {'X-Appid': x_appid,
                'X-CurTime': x_time,
                'X-Param': x_param,
                'X-CheckSum': x_checksum}
    req = urllib.request.Request(url, body, x_header)
    result = urllib.request.urlopen(req)
    result = result.read().decode("utf-8")
    print("讯飞返回结果,内部展示用的" + result)
    return result

 if __name__ == '__main__':
    main(r"D:\SuWenbo\Project\xunfei\testfile\cusion.png")

上面的函数已经可以完成输入图片返回识别结果的工作:

输入图片:

这里写图片描述
输出结果:是一个字典,content即为识别结果

{“code”:”0”,”data”:{“block”:[{“type”:”text”,”line”:[{“confidence”:1,”word”:[{“content”:”see“}]}]}]},”desc”:”success”,”sid”:”wcr0005befd@dx26d00ec5f60f6f1a00”}
这里写图片描述

二丶C++调用Python函数实现OCR识别

我们利用C++调用上面的Python函数实现OCR识别,利用Python的PyObject

代码如下:

#include <Python.h>
#include<iostream>
#include<string>
using namespace std;

int main()
{

    Py_Initialize();//使用python之前,要调用Py_Initialize();这个函数进行初始化
    if (!Py_IsInitialized())
    {
        printf("初始化失败!");
        return 0;
    }
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");//这一步很重要,修改Python路径


    PyObject * pModule = NULL;//声明变量
    PyObject * pFunc = NULL;// 声明变量
    pModule = PyImport_ImportModule("hello");//这里是要调用的文件名hello.py
    if (pModule == NULL)
    {
        cout << "没找到" << endl;
    }
    pFunc = PyObject_GetAttrString(pModule, "main");//这里是要调用的函数名
    if (pFunc == NULL)
    {
        cout << "函数没找到" << endl;
    }

    PyObject* args = Py_BuildValue("(s)", "D:/SuWenbo/Project/xunfei/testfile/cusion.png");//给python函数参数赋值

    PyObject* pRet = PyObject_CallObject(pFunc, args);//调用函数

    Py_Finalize();//调用Py_Finalize,这个根Py_Initialize相对应的。

    return 0;
}

返回结果:
这里写图片描述

和Python返回结果一样,可以在上面的python函数里面加上一些截取字符串的操作,然后把content:see截取下来进行保存。

参考:
1.讯飞手写字符API

2019-04-09 20:16:52 u012594175 阅读数 609
  • 数据结构与算法C/C++实现)视频教程

    C/C++实现数据结构与算法视频培训课程全面介绍计算机行业,基本的数据结构与算法,既有理论的深度也有实战的技法。课程全程讲师手敲代码,一步步代你走进数据结构与算法。 本课程涉及的数据结构与算法有,栈,队列,单向链表,双向循环链表,树,二叉树,搜索二叉树,平衡搜索二叉树,冒泡,选择,直插,希尔,,归并等,课程还涉及深度优先算法与广度优先算法等等。

    3406 人正在学习 去看看 王桂林

根据语音片段进行说话人识别的SDK,c/c++实现。

利用ivector算法,进行说话人识别,包含了一个基础的ivector模型(6M),效果一般优于gmm-ubm算法。

wav文件不要超过1M大小。

1.Windows 

Win10 and VS2013

环境配置参考《说话人识别和说话人性别识别SDK-通过语音判断说话人,及说话人的性别》。因为ivector比gmm-ubm计算量更大,debug模式可能会比较慢。

// main.cpp

#include <iostream>
#include "speaker_recognizer.h"
int main()
{
	SpeakerRecognizer spk;
	bool ret = spk.Init("iv.model");
	if (!ret)
		return -1;

	ret = spk.RegisterSpeaker("BAC009S0002W0123.wav", "s2");
	
	ret = spk.RegisterSpeaker("BAC009S0003W0121.wav", "s3");

	std::string rec = spk.RecognizeSpeaker("BAC009S0003W0122.wav"); // s3
	std::cout << rec << std::endl;

	return 0;
}

2.Android

待更新...

 

https://github.com/xulg-ai/FreeSR

完整代码下载地址:https://download.csdn.net/download/u012594175/11100773

声纹识别交流QQ群:875705987

2019-02-19 23:30:48 valada 阅读数 2692
  • 数据结构与算法C/C++实现)视频教程

    C/C++实现数据结构与算法视频培训课程全面介绍计算机行业,基本的数据结构与算法,既有理论的深度也有实战的技法。课程全程讲师手敲代码,一步步代你走进数据结构与算法。 本课程涉及的数据结构与算法有,栈,队列,单向链表,双向循环链表,树,二叉树,搜索二叉树,平衡搜索二叉树,冒泡,选择,直插,希尔,,归并等,课程还涉及深度优先算法与广度优先算法等等。

    3406 人正在学习 去看看 王桂林

Kaldi 是一款语音识别工具,可以快速训练语音识别模型。Kaldi 主要是用 C++ 编写,是用 Shell、Python 和 Perl 来作为胶水进行模型训练,并且 Kaldi 是完全免费开源的。

Kaldi 语音识别模型的快速构建,具有大量语音相关算法以及优质的论坛受到国内外企业和开发者的追捧。

本场 Chat 将以以下几个模块进行延展:

  1. Kaldi 介绍;
  2. Kaldi 环境构建;
  3. Kaldi 目录介绍;
  4. Kaldi 相关 Shell 知识介绍;
  5. Kaldi Egs 介绍;
  6. Kaldi Egs 中 AIShell 例子讲解;
  7. 如何使用独立语音进行语音模型构建。

阅读全文: http://gitbook.cn/gitchat/activity/5c6a4fbdb4e4ea7959820d68

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

FtooAtPSkEJwnW-9xkCLqSTRpBKX

2018-06-09 17:03:30 qq_23660243 阅读数 16938
  • 数据结构与算法C/C++实现)视频教程

    C/C++实现数据结构与算法视频培训课程全面介绍计算机行业,基本的数据结构与算法,既有理论的深度也有实战的技法。课程全程讲师手敲代码,一步步代你走进数据结构与算法。 本课程涉及的数据结构与算法有,栈,队列,单向链表,双向循环链表,树,二叉树,搜索二叉树,平衡搜索二叉树,冒泡,选择,直插,希尔,,归并等,课程还涉及深度优先算法与广度优先算法等等。

    3406 人正在学习 去看看 王桂林

最近准备开始进行语音识别算法的学习,所以决定拿kaldi进行解读,这样一方面更加增加自己C++的基本功,另一方面也可以让自己慢慢走入语音识别的大门,自己的路,决定了就走下去,不管有多难。

首先我决定从kaldi的官网入手,不多说进入主题。

kaldi是什么

kaldi是使用c++写的语音识别的工具,apache 授予了v2.0的证书(果真应验,apache旗下无弱将)。kaldi旨在供语音识别研究员使用。

kaldi的命名

据传说,kaldi是埃塞俄比亚人,他发现了咖啡。

kaldi相较于其他工具

kaldi在目标和范围上和HTK相似,目标是用c++写的现代灵活的代码易于修改和扩展。它包含以下重要特点:

  1. 与有限状态转换器的代码级集成(FSTs)。 【我们根据openFst工具包进行编译,将其用作库】
  2. 广泛的线性代数支持。【我们包含一个包装BLAS和LAPACK的矩阵库】
  3. 可扩展的设计。【尽可能的,我们以最通用的方式提供我们的算法。例如,我们的解码器在提供由(帧,fst-input-symbol)索引的分数的对象上进行模版化。这意味着解码器可以从任何合适的分数来源工作,例如神经网络。】
  4. 开放许可。【该代码在apache2.0下获得许可,这是限制最少的许可证之一】
  5. 完整的recipes。【我们的目标适用于构建语音识别系统的完整配方,从广泛使用的数据库(比如语言数据联合会提供的数据)开展工作。】

发布完整配方是kaldi的重要目标之一,由于代码在允许修改和重新发布的许可下公开获得,我们希望鼓励人们以kaldi自己的脚本类似的方式发布他们的代码以及脚本目录。

考虑到时间的限制,我们尽可能的使kaldi的文档尽可能的完整。但是在短时间内,我们不能希望自己生成与HTK一样全面的的文档。特别是在HTKbooks中有很多介绍性资料,为外行人解释统计语音识别,这可能永远都不会出现在kaldi的文档之中。kaldi的大部分文档是这样写的,只有专家才能访问它。在未来,我们希望能够使得它更加的容易访问,同时铭记我们的目标受众是语音识别研究人员和语音识别培训人员。总的来说,kaldi并不是一个傻瓜式的语音识别工具包。他可以让你做很多没有意义的操作(PS:最后这句说的很有意思,大家自行理解)。

The flavor of kaldi

在本节中,我们试图总结kaldi工具包一些更加通用的特性。在某种程度上,他描述了当前开发人员的目标或者说当前项目的状态。这并不意味着排除不同风格的研究人员。

  1. 我们强调通用的算法和通用的组合配方。【我们说通用算法指的是像线性变换那样的东西,而不是专属于语音的内容。但是如果更具体的算法是有用的,我们不会那么教条。我们希望可以在任意数据集上运行的配方,而不是定制的数据集的配方。】
  2. 我们更喜欢证明正确的算法。【配方的设计原则是他们绝不会以灾难性的方式失败,一直在避免可能失败的配方和算法,即使他们在正常情况下没有失败。】
  3. kaldi的代码是经过全面测试的。【目标是让所有或几乎所有的代码都具有测试例程。】
  4. 我们尽量使简单的情况简单化。【在构造一个大型的语音工具包的时候,代码可能会成为很少替换的forest,这很危险。我们试图通过以下的方式来构建工具包,来避免这种情况。每一个命令行语句通常适用于有限的一组案例。例如解码器可能只适用于GMM。因此,当你添加新模型的类型时,您将创建一个新的命令行解码器。(调用相同的底层模版代码)。】
  5. kaldi代码很容易理解。【尽管kaldi工具包整体可能会变的非常庞大,但我们的目标是让每个单独的部分都可以毫不费力的理解。如果他提高了单个件的可理解性,我们将会重复书写代码。】
  6. kaldi代码很容易重构和重用。【我们希望工具包尽可能松散耦合,这意味着给定任何的头文件都应该尽量少#include其他的头文件,矩阵库尤其依赖于另一个子目录中的代码,所以他可以独立于其他所有的kaldi代码独立使用。(PS:不错,这个库想必是算法部分使用最多的了。)】

项目的状态

目前,我们拥有大多数标准结束的代码和脚本,包括所有的标准线性变换,MMI,增强的MMI和MCE判别式训练,以及特征空间判别式训练。我们为华尔街日报和资源管理以及配电盘提供配方,由于词汇和语言模型问题,交换机配方尚未提供最新的结果。因此我们不使用任何的外部数据源。

以上是关于About the kaldi project的部分(省去了最后的引用),看到这里个人相信广大第一次接触他的人都有很多细节不懂,比如什么解码器,什么FSTs,还有那些c++矩阵包到底是如何使用的等等等等。其实我也是存在同样的很多问题,那么我们必须把问题分解,分为多个子任务从分别击破。我的想法是按照官网的理论走一遍,然后针对各个模型走一遍,然后针对模型的论文走一遍,最后代码走一遍。至于里面的第三方的包的使用方法和细节,我则利用业余时间进行测试学习,如果有可能,我会写博客进行介绍。那么今天就先到这里,与诸君共勉。

语音识别-DTW算法

阅读数 1513

没有更多推荐了,返回首页