孔庆威的博客

精于心,简于形


  • 首页

  • 分类

  • 归档

  • 标签

OpenCV实现图像亮区扩张

发表于 2016-08-18 | 分类于 OpenCV |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


效果图

效果图

效果图

源码

KqwOpenCVBlurDemo

亮区扩张,也叫膨胀,要实现这样的效果,我们可以选取一个合适大小的核,用被核覆盖的最大值代替锚点像素。膨胀可以用来融合可能被分割的目标。

二值图像(左)和膨胀后的图像(右)

我们首先定义一个合适大小的核

1
Mat kernelDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));

然后调用Imgproc.dilate()方法把图像的亮区放大

1
2
// 扩大亮区
Imgproc.dilate(src, src, kernelDilate);

封装

这里我用到了RxJava。主要是因为图片处理是耗时操作,会阻塞线程,为了防止界面卡顿,这里使用RxJava进行了线程切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 扩大图片亮区
*
* @param bitmap 要处理的图片
*/
public void dilate(Bitmap bitmap) {
// 使用RxJava处理图片
if (null != mSubscriber)
Observable
.just(bitmap)
.map(new Func1<Bitmap, Bitmap>() {
@Override
public Bitmap call(Bitmap bitmap) {
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
// 定义一个合适大小的核
Mat kernelDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
// 扩大亮区
Imgproc.dilate(src, src, kernelDilate);
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);
return processedImage;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mSubscriber);
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 图片处理的工具类
mBlurUtil = new BlurUtil(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
// 图片处理完成
dismissProgressDialog();
}
@Override
public void onError(Throwable e) {
// 图片处理异常
dismissProgressDialog();
}
@Override
public void onNext(Bitmap bitmap) {
// 获取到处理后的图片
mIvImageProcessed.setImageBitmap(bitmap);
}
});
// 扩大图片亮区
mBlurUtil.dilate(mSelectImage);

OpenCV实现图片锐化

发表于 2016-08-18 | 分类于 OpenCV |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


效果图

效果图

效果图

源码

KqwOpenCVBlurDemo

锐化也可以看作是一种线性滤波操作,并且锚点像素有较高的权重,而周围的像素权重较低。
因此,我们可以自定义一个这样的核。

自定义核

1
2
3
4
5
6
7
8
/*
自定义核
0 -1 0
-1 5 -1
0 -1 0
*/
Mat kernel = new Mat(3, 3, CvType.CV_16SC1);
kernel.put(0, 0, 0, -1, 0, -1, 5, -1, 0, -1, 0);

这里我们将图像的深度设为16SC1,表示包含一个通道(C1),图像中的每个像素包含一个16比特有符号整型数(16S)。

定义完核以后,我们对图像和核做卷积操作

1
2
// 对图像和自定义核做卷积
Imgproc.filter2D(src, src, src.depth(), kernel);
  • 第一个参数表示输入的图像
  • 第二个参数表示输出的图像
  • 第三个参数表示图像的深度
  • 第四个参数是我们自定义的核

封装

这里我用到了RxJava。主要是因为图片处理是耗时操作,会阻塞线程,为了防止界面卡顿,这里使用RxJava进行了线程切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 锐化图片
*
* @param bitmap 要处理的图片
*/
public void filter2D(Bitmap bitmap) {
// 使用RxJava处理图片
if (null != mSubscriber)
Observable
.just(bitmap)
.map(new Func1<Bitmap, Bitmap>() {
@Override
public Bitmap call(Bitmap bitmap) {
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
/*
自定义核
0 -1 0
-1 5 -1
0 -1 0
*/
Mat kernel = new Mat(3, 3, CvType.CV_16SC1);
kernel.put(0, 0, 0, -1, 0, -1, 5, -1, 0, -1, 0);
// 对图像和自定义核做卷积
Imgproc.filter2D(src, src, src.depth(), kernel);
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);
return processedImage;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mSubscriber);
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 图片处理的工具类
mBlurUtil = new BlurUtil(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
// 图片处理完成
dismissProgressDialog();
}
@Override
public void onError(Throwable e) {
// 图片处理异常
dismissProgressDialog();
}
@Override
public void onNext(Bitmap bitmap) {
// 获取到处理后的图片
mIvImageProcessed.setImageBitmap(bitmap);
}
});
// 锐化图片
mBlurUtil.filter2D(mSelectImage);

2OpenCV中值模糊方法

发表于 2016-08-18 | 分类于 OpenCV |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


效果图

效果图

效果图

源码

KqwOpenCVBlurDemo

步骤

  1. 将获取到的Bitmap图片转成Mat对象
1
2
3
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
  1. 调用OpenCV的中值模糊方法
1
2
// 中值模糊方法
Imgproc.medianBlur(src, src, 33);
  1. 将处理完的Mat数据转成Bitmap对象
1
2
3
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);

封装

这里我用到了RxJava。主要是因为图片处理是耗时操作,会阻塞线程,为了防止界面卡顿,这里使用RxJava进行了线程切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package kong.qingwei.kqwopencvblurdemo;
import android.graphics.Bitmap;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Created by kqw on 2016/8/17.
* 图片虚化的工具类
*/
public class BlurUtil {
private Subscriber<Bitmap> mSubscriber;
public BlurUtil(Subscriber<Bitmap> subscriber) {
mSubscriber = subscriber;
}
/**
* 中值模糊方法
*
* @param bitmap 要处理的图片
*/
public void medianBlur(Bitmap bitmap) {
// RxJava处理图片虚化
if (null != mSubscriber)
Observable
.just(bitmap)
.map(new Func1<Bitmap, Bitmap>() {
@Override
public Bitmap call(Bitmap bitmap) {
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
// 中值模糊方法
Imgproc.medianBlur(src, src, 33);
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);
return processedImage;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mSubscriber);
}
}

工具类的初始化

图片处理在子线程处理,处理完通过回调返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 图片模糊处理的工具类
mBlurUtil = new BlurUtil(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
// 图片处理完成
dismissProgressDialog();
}
@Override
public void onError(Throwable e) {
// 图片处理异常
dismissProgressDialog();
}
@Override
public void onNext(Bitmap bitmap) {
// 获取到处理后的图片
mIvImageProcessed.setImageBitmap(bitmap);
}
});

图片模糊处理

1
2
// 中值模糊算法处理图片
mBlurUtil.medianBlur(mSelectImage);

OpenCV高斯模糊方法

发表于 2016-08-17 | 分类于 OpenCV |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


效果图

高斯模糊方法

高斯模糊方法

源码

KqwOpenCVBlurDemo

步骤

  1. 将获取到的Bitmap图片转成Mat对象
1
2
3
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
  1. 调用OpenCV的高斯模糊方法
1
2
// 高斯模糊方法
Imgproc.GaussianBlur(src, src, new Size(91, 91), 0);
  1. 将处理完的Mat数据转成Bitmap对象
1
2
3
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);

封装

这里我用到了RxJava。主要是因为图片处理是耗时操作,会阻塞线程,为了防止界面卡顿,这里使用RxJava进行了线程切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package kong.qingwei.kqwopencvblurdemo;
import android.graphics.Bitmap;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Created by kqw on 2016/8/17.
* 图片虚化的工具类
*/
public class BlurUtil {
private Subscriber<Bitmap> mSubscriber;
public BlurUtil(Subscriber<Bitmap> subscriber) {
mSubscriber = subscriber;
}
/**
* 高斯模糊方法
*
* @param bitmap 要处理的图片
*/
public void gaussianBlur(Bitmap bitmap) {
// RxJava处理图片虚化
if (null != mSubscriber)
Observable
.just(bitmap)
.map(new Func1<Bitmap, Bitmap>() {
@Override
public Bitmap call(Bitmap bitmap) {
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
// 高斯模糊方法
Imgproc.GaussianBlur(src, src, new Size(91, 91), 0);
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);
return processedImage;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mSubscriber);
}
}

工具类的初始化

图片处理在子线程处理,处理完通过回调返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 图片模糊处理的工具类
mBlurUtil = new BlurUtil(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
// 图片处理完成
dismissProgressDialog();
}
@Override
public void onError(Throwable e) {
// 图片处理异常
dismissProgressDialog();
}
@Override
public void onNext(Bitmap bitmap) {
// 获取到处理后的图片
mIvImageProcessed.setImageBitmap(bitmap);
}
});

图片模糊处理

1
2
// 高斯模糊算法处理图片
mBlurUtil.gaussianBlur(mSelectImage);

OpenCV均值模糊方法

发表于 2016-08-17 | 分类于 OpenCV |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


效果图

效果图

效果图

源码

KqwOpenCVBlurDemo

步骤

  1. 将获取到的Bitmap图片转成Mat对象
1
2
3
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
  1. 调用OpenCV的均值模糊方法
1
2
// 均值模糊方法
Imgproc.blur(src, src, new Size(100, 100));
  1. 将处理完的Mat数据转成Bitmap对象
1
2
3
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);

封装

这里我用到了RxJava。主要是因为图片处理是耗时操作,会阻塞线程,为了防止界面卡顿,这里使用RxJava进行了线程切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package kong.qingwei.kqwopencvblurdemo;
import android.graphics.Bitmap;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Created by kqw on 2016/8/17.
* 图片虚化的工具类
*/
public class BlurUtil {
private Subscriber<Bitmap> mSubscriber;
public BlurUtil(Subscriber<Bitmap> subscriber) {
mSubscriber = subscriber;
}
public void blur(Bitmap bitmap) {
// RxJava处理图片虚化
if (null != mSubscriber)
Observable
.just(bitmap)
.map(new Func1<Bitmap, Bitmap>() {
@Override
public Bitmap call(Bitmap bitmap) {
// Bitmap转为Mat
Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, src);
// 均值模糊方法
Imgproc.blur(src, src, new Size(100, 100));
// Mat转Bitmap
Bitmap processedImage = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, processedImage);
return processedImage;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mSubscriber);
}
}

工具类的初始化

图片处理在子线程处理,处理完通过回调返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 图片模糊处理的工具类
mBlurUtil = new BlurUtil(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
// 图片处理完成
dismissProgressDialog();
}
@Override
public void onError(Throwable e) {
// 图片处理异常
dismissProgressDialog();
}
@Override
public void onNext(Bitmap bitmap) {
// 获取到处理后的图片
mIvImageProcessed.setImageBitmap(bitmap);
}
});

图片模糊处理

1
2
// 均值模糊算法模糊图片
mBlurUtil.blur(mSelectImage);

OpenCV的部署

发表于 2016-08-17 | 分类于 OpenCV |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


官网

官网

之前时间比较紧张,在网上找了很多文章,写了一个人脸识别的程序,也是模棱两可,今天开始抽时间系统学习一下OpenCV在Android上的使用。

OpenCV版本

后面用到的是OpenCV的2.4.11版本,据说新的3.x的版本和2.x的版本改动较大,2.x的版本学习完可以再看看与3.x版本的区别。毕竟老版本的学习资源更多一些。

SDK

我们下载完SDK以后,里面会有一个Library的库供我们使用,但是核心的功能不在这里面,它只是一个调用的工具,我们还需要安装OpenCV Manager,在下载的SDK里有一个apk的文件夹,里面是对应各个cup架构的Manager,选择对应的Manager安装就可以了。
除了安装OpenCV Manager,也可以直接在工程里添加so,但是这会使我们的APK体积大大增加,不过这不是我们要关心的,我们主要学习怎么使用OpenCV。

OpenCV的图像存储

OpenCV使用Mat对象存储图像,该对象保存了图像的行数、列数、数据等能唯一标识该图像的信息,并且可以利用该数据还原图像,不同的图像所包含的信息量也不同,例如彩色图像所包含的信息量就要比灰色图像多得多。因为灰色图是单通道的,彩色图是三通道的。

灰色图

灰色图像单通道

数字代表指定颜色的亮度
以整数表示时,取值范围是0~255,0表示纯黑色,255表示纯白色。
以浮点数表示时,取值范围是0~1,0表示纯黑色,1表示纯白色。

彩色图

彩色图像三通道

第一通道表示蓝色,第二通道表示绿色,第三通道表示红色。

OpenCV的线性滤波器

有的时候,图像信息量太大,处理的时间就会比较长(有的时候可能不需要这么信息就可以解析出来我们想要的结果了),为了解决这个问题,OpenCV提供了一个线性滤波器,可以对图片进行模糊处理。

很多线性滤波器都利用了称为核的数字向量,核可以看作是沿着像素滑动的窗口,并把计算结果输出给核像素。

下面的图中,是一个3 * 3的核作用在了一副10 * 10的图像上。

核

创建OpenCV工程

Android Studio版本:2.1

  1. 创建Android Studio工程,命名为FirstOpenCVDemo
  2. 导入OpenCV Library

    File -> New -> Import Module

    导入OpenCV Library
    导入OpenCV Library

  3. 引用OpenCV Library

    引用OpenCV Library

  4. 安装OpenCV Manager

    加载OpenCV Manager,如果诶呦安装会有提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
Log.i(TAG, "OpenCV Manager已安装,可以学习OpenCV啦。");
break;
default:
super.onManagerConnected(status);
break;
}
}
};
@Override
protected void onResume() {
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_11, this, mOpenCVCallBack);
}

到此,准备工作做完,就可以在此工程上学习OpenCV了。

如果你在运行的过程中,遇到这样的问题

问题

这是SDK版本的问题,将targetSdkVersion改为19即可。

运行结果

OpenCV部署成功

源码

FirstOpenCVDemo

科大讯飞与灵云语音对比

发表于 2016-08-16 | 分类于 语音 |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


对比

科大讯飞 灵云语音
语音能力 语音合成、语音识别、语义、命令词、唤醒 没有独立的唤醒功能,需要使用命令词实现唤醒。
初始化 我们购买完离线资源包以后,集成到工程里,就可以保持在离线环境下使用 即使使用离线语音能力,第一次使用的时候,也必须要联网,激活离线语音能力以后,才可以使用
网络请求 各种请求均异步操作,不会阻塞线程。 在线文字语义识别,是同步操作,其它是异步操作过程。(同步操作时间超过5秒会导致Android终端抛出NAR异常导致崩溃)
语义 场景定义灵活,开发者可在后台自定义,通过申请的方式,可以开通自定义场景,目前免费开放。语义解析失败,可以将语音转文字。 场景的定义需要联系客服人员开通,自定义场景需要付费(说是一般一个场景2万元)。语义解析失败不能转成文字
语音唤醒 支持(官方自称低功耗) 实际没有唤醒功能,是使用离线命令词的方式模拟出了唤醒,效果不理想。尚未发现可以发现可以设置门限值等常用参数的API。
命令词识别 离线使用BNF语法,在线使用ABNF语法,语法可以使用占位符等等的操作符 离线和在线都使用JSGF语法。

灵云唤醒机制

用命令词的方式实现唤醒,用唤醒词做命令词,做好标识,然后循环开启命令词识别,当识别到唤醒的命令词的时候,视为被唤醒了。


个人认为这种方式实现唤醒效果不好,原因如下:

  1. 录音都有前端点超时时间和后端点超时时间,这样一来,即使我们准确的说出唤醒词,也要在说完唤醒词以后,保证在后端点时间内不再有声音录入,才能提高被唤醒的几率。

  2. 唤醒不是即时的,即使我们准确的说出唤醒词,并保持不再有声音录入,也要至少等待后端点时间过去,录音结束以后,才会识别(被唤醒)。

  3. 这种方式的唤醒其实就是在进行语音识别,如果一直开启唤醒,消耗性能,耗电。


  • 前端点超时时间: 在前置端点时间内没有有效的声音录入,表示此次录音无效,结束录音.
  • 后端点超时时间: 录音结束以后,在后置端点时间内没有再录入有效声音,表示录音完成,结束录音。

总结

科大讯飞语音方面更灵活,更好用。

灵云语音,在人工智能方面提供的技术更全面(还包括图像识别,手写识别,人脸识别,指纹识别、机器翻译等),偏定制(智能家居、车载系统、机器人等智能设备的定制)。

单从语音能力角度来比较,讯飞更好。

灵云语音唤醒

发表于 2016-08-16 | 分类于 语音 |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


严格来讲,灵云没有语音唤醒功能,但是通过命令词的方式可以实现


实现方式

用命令词的方式实现唤醒,用唤醒词做命令词,做好标识,然后循环开启命令词识别,当识别到唤醒的命令词的时候,视为被唤醒了。


我个人认为这种方式实现唤醒意义不大,所以没有做demo,原因如下:

  1. 录音都有前端点超时时间和后端点超时时间,这样一来,即使我们准确的说出唤醒词,也要在说完唤醒词以后,保证在后端点时间内不再有声音录入,才能提高被唤醒的几率。

  2. 唤醒不是即时的,即使我们准确的说出唤醒词,并保持不再有声音录入,也要至少等待后端点时间过去,录音结束以后,才会识别(被唤醒)。

  3. 这种方式的唤醒其实就是在进行语音识别,如果一直开启唤醒,消耗性能,耗电。


  • 前端点超时时间: 在前置端点时间内没有有效的声音录入,表示此次录音无效,结束录音.
  • 后端点超时时间: 录音结束以后,在后置端点时间内没有再录入有效声音,表示录音完成,结束录音。

灵云语音识别

发表于 2016-08-15 | 分类于 语音 |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


源码

GitHub

在线语音识别

SDK下载

灵云SDK下载

SDK集成

下载SDK以后,将jar和so导入工程

权限

1
2
3
4
5
6
7
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

封装

灵云配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package kong.qingwei.kqwhcidemo;
/**
* Created by kqw on 2016/8/12.
* 灵云配置信息
*/
public final class ConfigUtil {
/**
* 灵云APP_KEY
*/
public static final String APP_KEY = "3d5d5466";
/**
* 开发者密钥
*/
public static final String DEVELOPER_KEY = "eca643ff7b3c758745d7cf516e808d34";
/**
* 灵云云服务的接口地址
*/
public static final String CLOUD_URL = "test.api.hcicloud.com:8888";
/**
* 需要运行的灵云能力
*/
public static final String CAP_KEY = "tts.local.synth";
// public static final String CAP_KEY = "tts.cloud.wangjing";
public static final String CAP_KEY_NUL = "nlu.cloud";
}

初始化灵云语音能力的工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package kong.qingwei.kqwhcidemo;
import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Created by kqw on 2016/8/12.
* 初始化灵云语音
*/
public class HciUtil {
private static final String TAG = "HciUtil";
private Activity mActivity;
private final String mConfigStr;
public HciUtil(Activity activity) {
mActivity = activity;
// 加载信息,返回InitParam, 获得配置参数的字符串
InitParam initParam = getInitParam();
mConfigStr = initParam.getStringConfig();
}
public boolean initHci() {
// 初始化
int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);
if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {
Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
return false;
}
// 获取授权/更新授权文件 :
errCode = checkAuthAndUpdateAuth();
if (errCode != HciErrorCode.HCI_ERR_NONE) {
// 由于系统已经初始化成功,在结束前需要调用方法hciRelease()进行系统的反初始化
Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
HciCloudSys.hciRelease();
return false;
}
return true;
}
/**
* 释放
*/
public void hciRelease(){
HciCloudSys.hciRelease();
}
/**
* 加载初始化信息
*
* @return 系统初始化参数
*/
private InitParam getInitParam() {
String authDirPath = mActivity.getFilesDir().getAbsolutePath();
// 前置条件:无
InitParam initparam = new InitParam();
// 授权文件所在路径,此项必填
initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
// 是否自动访问云授权,详见 获取授权/更新授权文件处注释
initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");
// 灵云云服务的接口地址,此项必填
initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
// 开发者Key,此项必填,由捷通华声提供
initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
// 应用Key,此项必填,由捷通华声提供
initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
// 配置日志参数
String sdcardState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
String packageName = mActivity.getPackageName();
String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;
// 日志文件地址
File fileDir = new File(logPath);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
// 日志的路径,可选,如果不传或者为空则不生成日志
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
// 日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
// 日志大小,默认一个日志文件写多大,单位为K
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
// 日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
}
return initparam;
}
/**
* 获取授权
*
* @return 授权结果
*/
private int checkAuthAndUpdateAuth() {
// 获取系统授权到期时间
int initResult;
AuthExpireTime objExpireTime = new AuthExpireTime();
initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
if (initResult == HciErrorCode.HCI_ERR_NONE) {
// 显示授权日期,如用户不需要关注该值,此处代码可忽略
Date date = new Date(objExpireTime.getExpireTime() * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
Log.i(TAG, "expire time: " + sdf.format(date));
if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
// 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
Log.i(TAG, "checkAuth success");
return initResult;
}
}
// 获取过期时间失败或者已经过期
initResult = HciCloudSys.hciCheckAuth();
if (initResult == HciErrorCode.HCI_ERR_NONE) {
Log.i(TAG, "checkAuth success");
return initResult;
} else {
Log.e(TAG, "checkAuth failed: " + initResult);
return initResult;
}
}
}

语音识别的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package kong.qingwei.kqwhcidemo;
import android.app.Activity;
import android.util.Log;
import com.sinovoice.hcicloudsdk.android.asr.recorder.ASRRecorder;
import com.sinovoice.hcicloudsdk.common.asr.AsrConfig;
import com.sinovoice.hcicloudsdk.common.asr.AsrInitParam;
import com.sinovoice.hcicloudsdk.common.asr.AsrRecogResult;
import com.sinovoice.hcicloudsdk.recorder.ASRRecorderListener;
import com.sinovoice.hcicloudsdk.recorder.RecorderEvent;
/**
* Created by kqw on 2016/8/15.
* 语音识别类
*/
public class AsrUtil {
private static final String TAG = "AsrUtil";
private Activity mActivity;
private ASRRecorder mAsrRecorder;
private AsrConfig asrConfig;
private OnAsrRecogListener mOnAsrRecogListener;
public AsrUtil(Activity activity) {
mActivity = activity;
initAsr();
}
private void initAsr() {
Log.i(TAG, "initAsr: ");
// 初始化录音机
mAsrRecorder = new ASRRecorder();
// 配置初始化参数
AsrInitParam asrInitParam = new AsrInitParam();
String dataPath = mActivity.getFilesDir().getPath().replace("files", "lib");
asrInitParam.addParam(AsrInitParam.PARAM_KEY_INIT_CAP_KEYS, ConfigUtil.CAP_KEY_ASR_CLOUD_FREETALK);
asrInitParam.addParam(AsrInitParam.PARAM_KEY_DATA_PATH, dataPath);
asrInitParam.addParam(AsrInitParam.PARAM_KEY_FILE_FLAG, AsrInitParam.VALUE_OF_PARAM_FILE_FLAG_ANDROID_SO);
Log.v(TAG, "init parameters:" + asrInitParam.getStringConfig());
// 设置初始化参数
mAsrRecorder.init(asrInitParam.getStringConfig(), new ASRResultProcess());
// 配置识别参数
asrConfig = new AsrConfig();
// PARAM_KEY_CAP_KEY 设置使用的能力
asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_CAP_KEY, ConfigUtil.CAP_KEY_ASR_CLOUD_FREETALK);
// PARAM_KEY_AUDIO_FORMAT 音频格式根据不同的能力使用不用的音频格式
asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_AUDIO_FORMAT, AsrConfig.AudioConfig.VALUE_OF_PARAM_AUDIO_FORMAT_PCM_16K16BIT);
// PARAM_KEY_ENCODE 音频编码压缩格式,使用OPUS可以有效减小数据流量
asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_ENCODE, AsrConfig.AudioConfig.VALUE_OF_PARAM_ENCODE_SPEEX);
// 其他配置,此处可以全部选取缺省值
asrConfig.addParam("intention", "weather");
}
/**
* 开始语音识别
*/
public void start(OnAsrRecogListener listener) {
mOnAsrRecogListener = listener;
if (mAsrRecorder.getRecorderState() == ASRRecorder.RECORDER_STATE_IDLE) {
asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_REALTIME, "no");
mAsrRecorder.start(asrConfig.getStringConfig(), null);
} else {
Log.i(TAG, "start: 录音机未处于空闲状态,请稍等");
}
}
private class ASRResultProcess implements ASRRecorderListener {
@Override
public void onRecorderEventError(RecorderEvent event, int errorCode) {
Log.i(TAG, "onRecorderEventError: errorCode = " + errorCode);
if (null != mOnAsrRecogListener) {
mOnAsrRecogListener.onError(errorCode);
}
}
@Override
public void onRecorderEventRecogFinsh(RecorderEvent recorderEvent, final AsrRecogResult arg1) {
if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_COMPLETE) {
Log.i(TAG, "onRecorderEventRecogFinsh: 识别结束");
}
if (null != mOnAsrRecogListener) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mOnAsrRecogListener.onAsrRecogResult(arg1);
}
});
}
}
@Override
public void onRecorderEventStateChange(RecorderEvent recorderEvent) {
if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECORD) {
Log.i(TAG, "onRecorderEventStateChange: 开始录音");
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECOGNIZE) {
Log.i(TAG, "onRecorderEventStateChange: 开始识别");
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_NO_VOICE_INPUT) {
Log.i(TAG, "onRecorderEventStateChange: 无音频输入");
} else {
Log.i(TAG, "onRecorderEventStateChange: recorderEvent = " + recorderEvent);
}
}
@Override
public void onRecorderRecording(byte[] volumedata, int volume) {
if (null != mOnAsrRecogListener) {
mOnAsrRecogListener.onVolume(volume);
}
}
@Override
public void onRecorderEventRecogProcess(RecorderEvent recorderEvent, AsrRecogResult arg1) {
if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_PROCESS) {
Log.i(TAG, "onRecorderEventRecogProcess: 识别中间反馈");
}
if (arg1 != null) {
if (arg1.getRecogItemList().size() > 0) {
Log.i(TAG, "onRecorderEventRecogProcess: 识别中间结果结果为:" + arg1.getRecogItemList().get(0).getRecogResult());
} else {
Log.i(TAG, "onRecorderEventRecogProcess: 未能正确识别,请重新输入");
}
}
}
}
/**
* 语音识别的回调接口
*/
public interface OnAsrRecogListener {
// 识别结果
void onAsrRecogResult(AsrRecogResult asrRecogResult);
// 识别错误码
void onError(int errorCode);
// 录音音量
void onVolume(int volume);
}
}

使用

初始化灵云的语音能力和语音识别

1
2
3
4
5
6
7
8
9
// 灵云语音工具类
mInitTts = new HciUtil(this);
// 初始化灵云语音
boolean isInitHci = mInitTts.initHci();
if (isInitHci) { // 初始化成功
……
// 语音识别
mAsrUtil = new AsrUtil(this);
}

语音识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 语音识别(语音转文字)
*
* @param view view
*/
public void asr(View view) {
mAsrUtil.start(new AsrUtil.OnAsrRecogListener() {
@Override
public void onAsrRecogResult(AsrRecogResult asrRecogResult) {
StringBuilder stringBuffer = new StringBuilder();
ArrayList<AsrRecogItem> asrRecogItemArrayList = asrRecogResult.getRecogItemList();
for (AsrRecogItem asrRecogItem : asrRecogItemArrayList) {
String result = asrRecogItem.getRecogResult();
Log.i(TAG, "onAsrRecogResult: " + result);
stringBuffer.append(result).append("\n");
}
showDialog("识别结果", stringBuffer.toString());
}
@Override
public void onError(int errorCode) {
Log.i(TAG, "onError: " + errorCode);
}
@Override
public void onVolume(int volume) {
Log.i(TAG, "onVolume: " + volume);
}
});
}

离线语音识别

离线命令词和在线很类似,只需要更改CapKey,导入离线资源包即可,我们先下载离线资源

下载完解压

解压后的源文件

将里面所有的文件重命名,前面加lib,后面加.so,然后导入工程

重命名

修改CapKey为asr.local.freetalk

注意,灵云的离线语音功能第一次使用需要联网激活,激活以后才可以使用离线功能。

在线语音识别 + 语义理解

直接在在线语音识别的基础上实现语义理解更加简单,只要将CapKey换成asr.cloud.dialog即可

但是需要注意一点的是,想要使用哪个场景,必须开通以后,在参数里加上对应的场景,才是识别出来。

类似这样

1
asrConfig.addParam("intention", "weather");

这里的天气,对应的参数是weather,了解更多场景和对应场景参数可以查看捷通华声灵云公有云能力平台NLU结果开发手册.pdf

灵云语义理解

发表于 2016-08-15 | 分类于 语音 |

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


效果图

效果图

源码

GitHub

SDK下载

灵云SDK下载

SDK集成

下载SDK以后,将jar和so导入工程

导入SDK

权限

1
2
3
4
5
6
7
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

封装

灵云配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package kong.qingwei.kqwhcidemo;
/**
* Created by kqw on 2016/8/12.
* 灵云配置信息
*/
public final class ConfigUtil {
/**
* 灵云APP_KEY
*/
public static final String APP_KEY = "3d5d5466";
/**
* 开发者密钥
*/
public static final String DEVELOPER_KEY = "eca643ff7b3c758745d7cf516e808d34";
/**
* 灵云云服务的接口地址
*/
public static final String CLOUD_URL = "test.api.hcicloud.com:8888";
/**
* 需要运行的灵云能力
*/
public static final String CAP_KEY = "tts.local.synth";
// public static final String CAP_KEY = "tts.cloud.wangjing";
public static final String CAP_KEY_NUL = "nlu.cloud";
}

初始化灵云语音能力的工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package kong.qingwei.kqwhcidemo;
import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Created by kqw on 2016/8/12.
* 初始化灵云语音
*/
public class HciUtil {
private static final String TAG = "HciUtil";
private Activity mActivity;
private final String mConfigStr;
public HciUtil(Activity activity) {
mActivity = activity;
// 加载信息,返回InitParam, 获得配置参数的字符串
InitParam initParam = getInitParam();
mConfigStr = initParam.getStringConfig();
}
public boolean initHci() {
// 初始化
int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);
if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {
Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
return false;
}
// 获取授权/更新授权文件 :
errCode = checkAuthAndUpdateAuth();
if (errCode != HciErrorCode.HCI_ERR_NONE) {
// 由于系统已经初始化成功,在结束前需要调用方法hciRelease()进行系统的反初始化
Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
HciCloudSys.hciRelease();
return false;
}
return true;
}
/**
* 释放
*/
public void hciRelease(){
HciCloudSys.hciRelease();
}
/**
* 加载初始化信息
*
* @return 系统初始化参数
*/
private InitParam getInitParam() {
String authDirPath = mActivity.getFilesDir().getAbsolutePath();
// 前置条件:无
InitParam initparam = new InitParam();
// 授权文件所在路径,此项必填
initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
// 是否自动访问云授权,详见 获取授权/更新授权文件处注释
initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");
// 灵云云服务的接口地址,此项必填
initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
// 开发者Key,此项必填,由捷通华声提供
initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
// 应用Key,此项必填,由捷通华声提供
initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
// 配置日志参数
String sdcardState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
String packageName = mActivity.getPackageName();
String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;
// 日志文件地址
File fileDir = new File(logPath);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
// 日志的路径,可选,如果不传或者为空则不生成日志
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
// 日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
// 日志大小,默认一个日志文件写多大,单位为K
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
// 日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
}
return initparam;
}
/**
* 获取授权
*
* @return 授权结果
*/
private int checkAuthAndUpdateAuth() {
// 获取系统授权到期时间
int initResult;
AuthExpireTime objExpireTime = new AuthExpireTime();
initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
if (initResult == HciErrorCode.HCI_ERR_NONE) {
// 显示授权日期,如用户不需要关注该值,此处代码可忽略
Date date = new Date(objExpireTime.getExpireTime() * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
Log.i(TAG, "expire time: " + sdf.format(date));
if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
// 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
Log.i(TAG, "checkAuth success");
return initResult;
}
}
// 获取过期时间失败或者已经过期
initResult = HciCloudSys.hciCheckAuth();
if (initResult == HciErrorCode.HCI_ERR_NONE) {
Log.i(TAG, "checkAuth success");
return initResult;
} else {
Log.e(TAG, "checkAuth failed: " + initResult);
return initResult;
}
}
}

语义理解的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package kong.qingwei.kqwhcidemo;
import android.app.Activity;
import android.util.Log;
import com.sinovoice.hcicloudsdk.api.nlu.HciCloudNlu;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.Session;
import com.sinovoice.hcicloudsdk.common.nlu.NluConfig;
import com.sinovoice.hcicloudsdk.common.nlu.NluInitParam;
import com.sinovoice.hcicloudsdk.common.nlu.NluRecogResult;
/**
* Created by kqw on 2016/8/12.
* 语义理解类
*/
public class NluUtil {
private static final String TAG = "NluUtil";
private Activity mActivity;
public NluUtil(Activity activity) {
mActivity = activity;
}
public boolean initNul() {
//构造Asr初始化的帮助类的实例
NluInitParam initParam = new NluInitParam();
// 获取App应用中的lib的路径,放置能力所需资源文件。如果使用/data/data/packagename/lib目录,需要添加android_so的标记
String dataPath = mActivity.getFilesDir().getAbsolutePath().replace("files", "lib");
initParam.addParam(NluInitParam.PARAM_KEY_DATA_PATH, dataPath);
initParam.addParam(NluInitParam.PARAM_KEY_FILE_FLAG, NluInitParam.VALUE_OF_PARAM_FILE_FLAG_ANDROID_SO);
initParam.addParam(NluInitParam.PARAM_KEY_INIT_CAP_KEYS, ConfigUtil.CAP_KEY_NUL);
int errCode = HciCloudNlu.hciNluInit(initParam.getStringConfig());
Log.i(TAG, "initNul: errCode = " + errCode);
return errCode == HciErrorCode.HCI_ERR_NONE || errCode == HciErrorCode.HCI_ERR_NLU_ALREADY_INIT;
}
public void recog(String text, OnNluRecogListener onNluRecogListener) {
// 初始化配置参数
NluConfig nluConfig = initConfig();
// 创建会话
Session session = new Session();
// 开始会话
int errCode = HciCloudNlu.hciNluSessionStart(nluConfig.getStringConfig(), session);
if (errCode == HciErrorCode.HCI_ERR_NONE) {
// 开始翻译
// 调用HciCloudMt.hciMtTrans() 方法进行合成
NluRecogResult nluResult = new NluRecogResult();
errCode = HciCloudNlu.hciNluRecog(session, text, nluConfig.getStringConfig(), nluResult);
if (errCode == HciErrorCode.HCI_ERR_NONE) {
onNluRecogListener.onNluResult(nluResult);
} else {
onNluRecogListener.onError(errCode);
}
// 结束会话
errCode = HciCloudNlu.hciNluSessionStop(session);
if (errCode != HciErrorCode.HCI_ERR_NONE) {
onNluRecogListener.onError(errCode);
}
} else {
onNluRecogListener.onError(errCode);
}
}
private NluConfig initConfig() {
NluConfig nluConfig = new NluConfig();
nluConfig.addParam(NluConfig.SessionConfig.PARAM_KEY_CAP_KEY, ConfigUtil.CAP_KEY_NUL);
nluConfig.addParam("intention", "weather");
return nluConfig;
}
public interface OnNluRecogListener {
void onNluResult(NluRecogResult nluRecogResult);
void onError(int errorCode);
}
}

使用

初始化灵云的语音能力和语义理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 灵云语音工具类
mInitTts = new HciUtil(this);
// 初始化灵云语音
boolean isInitHci = mInitTts.initHci();
if (isInitHci) { // 初始化成功
……
// 语义理解
mNluUtil = new NluUtil(this);
boolean isInitNul = mNluUtil.initNul();
if (isInitNul) {
Toast.makeText(this, "语义理解 初始化成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "语义理解 初始化失败", Toast.LENGTH_SHORT).show();
}
}

语义理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 语义理解
*
* @param view
*/
public void recog(View view) {
final String text = mEditText2.getText().toString();
if (TextUtils.isEmpty(text)) {
Toast.makeText(this, "理解句子内容为空", Toast.LENGTH_SHORT).show();
return;
}
mNluUtil.recog(text, new NluUtil.OnNluRecogListener() {
@Override
public void onNluResult(NluRecogResult nluRecogResult) {
StringBuilder stringBuffer = new StringBuilder();
ArrayList<NluRecogResultItem> nluRecogResultItems = nluRecogResult.getRecogResultItemList();
for (NluRecogResultItem nluRecogResultItem : nluRecogResultItems) {
String result = nluRecogResultItem.getResult();
stringBuffer.append(result).append("\n");
Log.i(TAG, "onNluResult: " + result);
}
showDialog(text, stringBuffer.toString());
}
@Override
public void onError(int errorCode) {
Log.i(TAG, "onError: errorCode = " + errorCode);
}
});
}

Dialog

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 显示Dialog
*
* @param title title
* @param message message
*/
private void showDialog(String title, String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton("确认", null);
builder.create().show();
}

注意

灵云的语义,想要识别哪个场景,必须要先开通对应场景,然后做配置以后才可以使用,类似这样

1
nluConfig.addParam("intention", "weather");

这里的天气,对应的参数是weather,了解更多场景和对应场景参数可以查看捷通华声灵云公有云能力平台NLU结果开发手册.pdf

1…3456
kongqw

kongqw

Android Developer

54 日志
4 分类
25 标签
GitHub CSDN
Links
  • 干货集中营
  • 讯飞开放平台
  • 环信
  • 百度统计
  • DISQUS评论
  • BTC Wallet
  • OKCoin中国站
  • OKCoin国际站
  • BTC.com
© 2015 - 2018 kongqw
由 Hexo 强力驱动
主题 - NexT.Pisces