一、云狐简介
云狐语音识别软件是基于百度智能云,由进击的狐狸进行开发的一款软件。注意,因为核心类代码是2017年就已经写好的了,所以使用的C# SDK包不是最新的。云狐目前支持的平台是Windows系统平台,使用时需要安装微软最新的.net framework 。云狐的主要功能是长时间的语音识别,支持时长超过一分钟的各种类型的语音文件识别,缺点就是速度较慢一些。
云狐视频演示及代码解析的视频链接:
https://v.qq.com/x/page/j3023vgs9yz.html
云狐语音识别软件下载:
https://blog.csdn.net/ciel_arc/article/details/103172138
另外,云狐和云猫实际上是姐妹软件,因为他们都是基于百度智能云,用C#进行开发的,使用的是百度最新的人工智能技术。而且他们目前都是免费的。这里联动一下,对云猫OCR和云狐语音感兴趣的同学,可以百度搜索“云猫OCR”或“云狐语音” 进行了解。
二、云狐的简单评测
云狐软件自带有计时功能,我们可以简单做一下评测。从上文视频演示的结果可以看出,1分钟左右的语音文件,云狐可以在10秒以内识别完毕,而30分钟左右的语音文件,云狐需要120秒即2分钟左右,才能识别完毕。从中推算出识别速度大概是4秒/分钟。
三、云狐软件的代码原理
百度智能云给出的长语音识别接口只支持一分钟以内的语音文件的识别。而对于超过一分钟的语音文件识别,我们需要怎么做呢?
云狐软件的原理就是:把超过一分钟的文件进行切片,切成若干个小于或者等于一分钟时长的语音文件。对每个切片文件调用百度云语音识别接口进行识别,再把结果串联起来即可。
四、云狐的代码简明解析
(一)核心类foxSpeechDemo
namespace foxAudio2Word
{
class foxSpeechDemo
{
private readonly Asr _asrClient;
public foxSpeechDemo(string myAPIKey,string mySecretKey)
{
_asrClient = new Asr(myAPIKey,mySecretKey);
}
// 识别本地文件
public string AsrData(string pcmFilePath)
{
var data = File.ReadAllBytes(pcmFilePath);
var result = _asrClient.Recognize(data, "pcm", 16000);
return result.ToString();
}
}
}
上面的代码是根据百度SDK包文档,进行少量改动实现的。注意为了简便,这里贴出的代码段可能跟具体的云狐实现代码有一些出入。
不是任何一个语音文件都可以交给百度智能云直接识别。文件需要预处理,不然识别效果会很差。具体来说,作者用FFmpeg对语音文件进行预处理,然后再用百度接口识别。FFmpeg的命令行预处理类似下面的形式:
ffmpeg -y -i 003_16k.wav -acodec pcm_s16le -f s16le -ac 1 -ar 16000 16k.pcm
(二)预处理的辅助函数
共有大概4个关于预处理的辅助函数,代码如下:
1.此函数的主要功能是用C#程序自动执行命令行语句,它可执行任何语句的命令行,string cmdStr是形参,可以将命令行语句赋值给cmdStr进行执行。
private string myCmdFun(string cmdStr)
{
try
{
Process CmdProcess = new Process();
CmdProcess.StartInfo.FileName = "cmd.exe";
CmdProcess.StartInfo.CreateNoWindow = true; // 不创建新窗口
CmdProcess.StartInfo.UseShellExecute = false; //不启用shell启动进程
CmdProcess.StartInfo.RedirectStandardInput = true; // 重定向输入
CmdProcess.StartInfo.RedirectStandardOutput = true; // 重定向标准输出
CmdProcess.StartInfo.RedirectStandardError = true; // 重定向错误输出
//CmdProcess.StartInfo.Arguments = "/c " + "=====cmd命令======";//“/C”表示执行完命令后马上退出
//string cmdStr = "ffmpeg -y -i 003_16k.wav -acodec pcm_s16le -f s16le -ac 1 -ar 16000 16k.pcm";
CmdProcess.StartInfo.Arguments = "/c " + cmdStr;//“/C”表示执行完命令后马上退出
CmdProcess.Start();//执行
string temp = CmdProcess.StandardOutput.ReadToEnd();//输出
CmdProcess.WaitForExit();//等待程序执行完退出进程
CmdProcess.Close();//结束
return temp;
}
catch (Exception ex)
{
return ex.ToString();
}
}
2.此函数表示利用ffprobe命令行获取语音文件的时长信息,以便对语音文件进行分割,注意返回值是整形变量。比如语音时长有1.5分钟,这个函数就会返回2 ,以此类推。
///
/// 获取音频文件的持续时间信息
///
///
///
private int foxGetAudioDuration(string filename)
{
//使用命令行要非常小心对空格的处理
string tempCmdStr = "ffprobe -v quiet -print_format json -show_streams "
+ filename;
string result = myCmdFun(tempCmdStr);
//结果使用json格式解析
JObject jo = (JObject)JsonConvert.DeserializeObject(result);
string audioDuration = jo["streams"][0]["duration"].ToString();
//直接返回整形数据,单位是秒
int durationSecond = (int)Math.Ceiling(System.Convert.ToDouble(audioDuration));
//转成分钟表示
int durationMinute = (durationSecond / 60) + 1;
return durationMinute;
}
3.此函数主要功能是对语音文件进行分割,时间单位是秒。比如我有一个2分钟的语音文件,程序就把这个文件分成2块,每块60秒即1分钟,以此类推。
///分割的时间单位应该是秒
///分割音频文件
private void foxAudioCut(string filename,int timePos,int duration,int fileIndex)
{
//string tempCmdStr = "ffmpeg -i 003_16k.wav -ss 10 -t 10 003_1.wav";
string tempCmdStr = "ffmpeg -y -i "+filename+
" -ss "+timePos.ToString()
+" -t "+duration.ToString()
+" "+ "temp\\" + fileIndex.ToString()+".wav";
myCmdFun(tempCmdStr);
}
4.此函数的主要功能是把切片文件转换成百度云能够进行正常识别的文件格式。
///
/// 把目标音频文件转换为百度语音能够识别的文件
///
///
private string foxAudioConvert(string filename,int fileIndex)
{
//临时工作夹目录设置为“temp”
string resultFileName = "Convert_" + fileIndex.ToString() + ".wav";
//注意这句含有两个“temp\\”
string tempCmdStr = "ffmpeg -y -i "+ "temp\\" + filename
+" -acodec pcm_s16le -ac 1 -ar 16000 "
+ "temp\\" +resultFileName;
myCmdFun(tempCmdStr);
return resultFileName;
}
(三)主函数的代码逻辑
//注意:文件路径里面不能含有空格
string tempFilePath = Path.GetFullPath(openFileDialog1.FileName);
//获取音频文件持续时间信息
int duration = foxGetAudioDuration(tempFilePath);
//主要的长语音识别逻辑
//将音频文件分成块,每块的长度默认为1分钟
for (int i = 0; i < duration; i++)
{
//首先分割文件
foxAudioCut(tempFilePath, i * 60, 60, i);
//然后转换格式
string tempConvertFileName = foxAudioConvert(i.ToString() + ".wav", i);
//最后进行识别
//tempResult += fd.AsrData("temp\\" + tempConvertFileName);
//解析json
string tempStr = fd.AsrData("temp\\" + tempConvertFileName);
JObject jo = (JObject)JsonConvert.DeserializeObject(tempStr);
if (jo["err_no"].ToString().Equals("0"))
{
string result = jo["result"][0].ToString();
tempResult += result;
}
}
richTextBox1.Text = tempResult;
上面是主函数里面的核心代码段,里面有很多的注释,大家可以仔细看看。主要功能就是整合预处理辅助函数的作用,把文件切片并转换格式,最后提交给百度智能云进行识别,并对识别结果进行解析,把json转换成对人类友好的文本格式。
作者:kohakuarc