语音识别 | Java 实现 AI 人工智能技术 - 语音识别功能

说到语音识别、语音翻译、图像识别、人脸识别等等,现在已经非常非常非常普及了,看过‘最强大脑’的朋友,也应该对‘小度’这个机器人有所了解,战胜国际顶尖的‘大脑’- 水哥,(PS:内幕不知),那么今天,我们来看下关于语音识别,是如何做到的,Java又是如何识别语音的?如何转换语音?

语音识别技术,也被称为自动语音识别Automatic Speech Recognition,(ASR),其目标是将人类的语音中的词汇内容转换为计算机可读的输入,例如按键、二进制编码或者字符序列。与说话人识别及说话人确认不同,后者尝试识别或确认发出语音的说话人而非其中所包含的词汇内容。

语音识别场景

1:语音翻译

2:语音辨别、语音记事本

3:智能终端

语音识别原理

技术应用:

语音识别技术所涉及的领域包括:信号处理、模式识别、概率论和信息论、发声机理和听觉机理、人工智能等等。

原理:

语音识别系统提示客户在新的场合使用新的口令密码,这样使用者不需要记住固定的口令,系统也不会被录音欺骗。文本相关的声音识别方法可以分为动态时间伸缩隐马尔可夫模型方法。文本无关声音识别已经被研究很长时间了,不一致环境造成的性能下降是应用中的一个很大的障碍。

动态时间伸缩方法使用瞬间的、变动倒频。1963年Bogert et al出版了《回声的时序倒频分析》。通过交换字母顺序,他们用一个含义广泛的词汇定义了一个新的信号处理技术,倒频谱的计算通常使用快速傅立叶变换。

从1975年起,隐马尔可夫模型变得很流行。运用隐马尔可夫模型的方法,频谱特征的统计变差得以测量。文本无关语音识别方法的例子有平均频谱法、矢量量化法和多变量自回归法

平均频谱法使用有利的倒频距离,语音频谱中的音位影响被平均频谱去除。使用矢量量化法,语者的一套短期训练的特征向量可以直接用来描绘语者的本质特征。但是,当训练向量的数量很大时,这种直接的描绘是不切实际的,因为存储和计算的量变得离奇的大。所以尝试用矢量量化法去寻找有效的方法来压缩训练数据。Montacie et al在倒频向量的时序中应用多变量自回归模式来确定语者特征,取得了很好的效果。

想骗过语音识别系统要有高质量的录音机,那不是很容易买到的。一般的录音机不能记录声音的完整频谱,录音系统的质量损失也必须是非常低的。对于大多数的语音识别系统,模仿的声音都不会成功。用语音识别来辨认身份是非常复杂的,所以语音识别系统会结合个人身份号码识别或芯片卡

语音识别系统得益于廉价的硬件设备,大多数的计算机都有声卡和麦克风,也很容易使用。但语音识别还是有一些缺点的。语音随时间而变化,所以必须使用生物识别模板。语音也会由于伤风、嗓音沙哑、情绪压力或是青春期而变化。语音识别系统比指纹识别系统有着较高的误识率,因为人们的声音不像指纹那样独特和唯一。对快速傅立叶变换计算来说,系统需要协同处理器和比指纹系统更多的效能。目前语音识别系统不适合移动应用或以电池为电源的系统。

倒频谱的计算-->识别方法-->压缩训练-->语音质量-->硬件设备

JAVA语音识别示例

需求:java实现语音识别--语音音频文件的识别

技术:Java、jdk1.8、maven、百度云、mp3、开通百度云开发者平台,并创建语音应用,获取AK和SK

1:新建maven project工程,如图

2:导入语音识别百度云包和音频文件转换包,代码如下:

<dependencies>
    <dependency>
        <groupId>com.baidu.aip</groupId>
        <artifactId>java-sdk</artifactId>
        <version>4.4.1</version>
    </dependency>
    <dependency>
        <groupId>com.googlecode.soundlibs</groupId>
        <artifactId>mp3spi</artifactId>
        <version>1.9.5.4</version>
     </dependency>
</dependencies>

3:新建将mp3文件转换为pcm文件的工具类

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;

public class ConvertMP32PCM {

    /**
     * MP3转换PCM文件方法
     *
     * @param mp3filepath
     *            原始文件路径
     * @param pcmfilepath
     *            转换文件的保存路径
     * @throws Exception
     */
    public static void convertMP32PCM(String mp3filepath, String pcmfilepath) throws Exception {
        AudioInputStream audioInputStream = getPcmAudioInputStream(mp3filepath);
        AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, new File(pcmfilepath));
    }

    /**
     * 播放MP3方法
     *
     * @param mp3filepath
     * @throws Exception
     */
    public static void playMP3(String mp3filepath) throws Exception {
        File mp3 = new File(mp3filepath);

        // 播放
        int k = 0, length = 8192;
        AudioInputStream audioInputStream = getPcmAudioInputStream(mp3filepath);
        if (audioInputStream == null)
            System.out.println("null audiostream");
        AudioFormat targetFormat;
        targetFormat = audioInputStream.getFormat();
        byte[] data = new byte[length];
        DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, targetFormat);
        SourceDataLine line = null;
        try {

            line = (SourceDataLine) AudioSystem.getLine(dinfo);
            line.open(targetFormat);
            line.start();

            int bytesRead = 0;
            byte[] buffer = new byte[length];
            while ((bytesRead = audioInputStream.read(buffer, 0, length)) != -1) {
                line.write(buffer, 0, bytesRead);
            }
            audioInputStream.close();

            line.stop();
            line.close();

        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("audio problem " + ex);

        }
    }

    private static AudioInputStream getPcmAudioInputStream(String mp3filepath) {
        File mp3 = new File(mp3filepath);
        AudioInputStream audioInputStream = null;
        AudioFormat targetFormat = null;
        try {
            AudioInputStream in = null;
            MpegAudioFileReader mp = new MpegAudioFileReader();
            in = mp.getAudioInputStream(mp3);
            AudioFormat baseFormat = in.getFormat();
            targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
                    baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
            audioInputStream = AudioSystem.getAudioInputStream(targetFormat, in);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return audioInputStream;
    }

    public static void mp3Convertpcm(String mp3filepath,String pcmfilepath) throws Exception{
        File mp3 = new File(mp3filepath);
        File pcm = new File(pcmfilepath);
        //原MP3文件转AudioInputStream
        AudioInputStream mp3audioStream = AudioSystem.getAudioInputStream(mp3);
        //将AudioInputStream MP3文件 转换为PCM AudioInputStream
        AudioInputStream pcmaudioStream = AudioSystem.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED, mp3audioStream);
        //准备转换的流输出到OutputStream
        OutputStream os = new FileOutputStream(pcm);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead=pcmaudioStream.read(buffer, 0, 8192))!=-1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        pcmaudioStream.close();
    }


    public static void main(String[] args) {
        String mp3filepath = "D:\\mp3\\你牛什么牛.mp3";
        String pcmfilepath = "D:\\mp3\\你牛什么牛.pcm";

        try {
//            ConvertMP32PCM.convertMP32PCM(mp3filepath, pcmfilepath);
//            ConvertMP32PCM.playMP3(mp3filepath);
            mp3Convertpcm(mp3filepath,pcmfilepath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4:调用百度云的语音识别接口,返回识别结果

package com.ms;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.xml.bind.DatatypeConverter;

import org.json.JSONObject;

public class Sample {

    private static final String serverURL = "http://vop.baidu.com/server_api";
    private static String token = "";
    private static final String testFileName = "E:\\test.pcm"; // 百度语音提供技术支持
    //put your own params here
    // 下面3个值要填写自己申请的app对应的值
    private static final String apiKey = "";
    private static final String secretKey = "";
    private static final String cuid = "";

    public static void main(String[] args) throws Exception {
        getToken();
        method1();
        method2();
    }

    private static void getToken() throws Exception {
        String getTokenURL = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials" +
                "&client_id=" + apiKey + "&client_secret=" + secretKey;
        HttpURLConnection conn = (HttpURLConnection) new URL(getTokenURL).openConnection();
        token = new JSONObject(printResponse(conn)).getString("access_token");
        System.out.println(token);
    }

    private static void method1() throws Exception {
        File pcmFile = new File(testFileName);
        System.out.println(pcmFile.exists());
        HttpURLConnection conn = (HttpURLConnection) new URL(serverURL).openConnection();

        // construct params
        JSONObject params = new JSONObject();
        params.put("format", "pcm");
        params.put("rate", 16000);
        params.put("channel", "1");
        params.put("token", token);
        params.put("lan", "zh");
        params.put("cuid", cuid);
        params.put("len", pcmFile.length());
        params.put("speech", DatatypeConverter.printBase64Binary(loadFile(pcmFile)));

        // add request header
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");

        conn.setDoInput(true);
        conn.setDoOutput(true);

        // send request
        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.writeBytes(params.toString());
        wr.flush();
        wr.close();

        printResponse(conn);
    }

    private static void method2() throws Exception {
        File pcmFile = new File(testFileName);
        HttpURLConnection conn = (HttpURLConnection) new URL(serverURL
                + "?cuid=" + cuid + "&token=" + token).openConnection();

        // add request header
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "audio/pcm; rate=16000");

        conn.setDoInput(true);
        conn.setDoOutput(true);

        // send request
        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.write(loadFile(pcmFile));
        wr.flush();
        wr.close();

        System.out.println(printResponse(conn));
    }

    private static String printResponse(HttpURLConnection conn) throws Exception {
        if (conn.getResponseCode() != 200) {
            // request error
            System.out.println("conn.getResponseCode() = " + conn.getResponseCode());
            return "";
        }
        InputStream is = conn.getInputStream();
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
        String line;
        StringBuffer response = new StringBuffer();
        while ((line = rd.readLine()) != null) {
            response.append(line);
            response.append('\r');
        }
        rd.close();
        System.out.println(new JSONObject(response.toString()).toString(4));
        return response.toString();
    }

    private static byte[] loadFile(File file) throws IOException {
        InputStream is = new FileInputStream(file);

        long length = file.length();
        byte[] bytes = new byte[(int) length];

        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
                && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
            offset += numRead;
        }

        if (offset < bytes.length) {
            is.close();
            throw new IOException("Could not completely read file " + file.getName());
        }

        is.close();
        return bytes;
    }
}

识别结果:

原文发布于微信公众号 - 码神联盟(lkchatspace)

原文发表时间:2018-07-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏恰同学骚年

自己动手写游戏:坦克撕逼大战

START:最近在公交车上无聊,于是用平板看了看下载的坦克大战的开发教程,于是在晚上回家后花了两天模仿了一个,现在来总结一下。

1886
来自专栏数据结构与算法

9.22模拟赛解题报告

T2读题就花了半个小时,而且一开始没认真理解题目的意思,前后各dp了一遍,后来仔细揣摩了一下题意,细心品味了一下出题人的语言,正着的dp好像是没用的。。。

853
来自专栏racaljk

当我们谈论计算机科学

下午偶有所悟,特作此文防止青年痴呆。 这学期的学习算是走了一半计算机科学概论。广度的学习通常会被指责为广而不精,但对我而言这是毫无意义的,因为 ...

1034
来自专栏牛客网

个人的前端面经,回馈社会

酷家乐(10-20k) 电话一面 三十五分钟 如何学习前端,看了什么书 谈实习经历 谈项目,问为什么用那么多插件,有没有想过自己写 position有几个属性 ...

3725
来自专栏小樱的经验随笔

2017广东工业大学程序设计竞赛初赛 题解&源码(A,水 B,数学 C,二分 D,枚举 E,dp F,思维题 G,字符串处理 H,枚举)

Problem A: An easy problem Description     Peter Manson owned a small house in a...

3796
来自专栏一个会写诗的程序员的博客

《Spring Boot极简教程》附录3 编程简史附录3 编程简史名词纪要参考资料

1801,Joseph Marie Jacquard用打孔卡为一台织布机编写指令,在提花织布机(或称甲卡提花织布机,Jacquard loom)上,运用打孔卡上...

782
来自专栏数据派THU

一文读懂PyTorch张量基础(附代码)

本文介绍了PyTorch Tensor最基础的知识以及如何跟Numpy的ndarray互相转换。

1043
来自专栏数据小魔方

空间数据可视化与simple future模型应用

这是一篇关于关于空间地理信息数据可视化与simple feature 模型应用的笔记小结。

1453
来自专栏编程一生

一条项目中常用的linux命令引发的经典算法题

1223
来自专栏人工智能头条

知识图谱系列 | 知识图谱的前世今生与RDF的实践

【人工智能头条导读】本文是我们知识图谱系列的第二篇文章,希望人工智能头条为大家准备的文章对大家的学习有更多的帮助。

5542

扫码关注云+社区

领取腾讯云代金券