语音识别,语义理解一站式解决之智能照相机(人脸识别,olami)
转载请注明CSDN博文地址:
olamisdk实现了把录音或者文字转化为用户可以理解的json字符串从而实现语义理解,用户可以定义自己的语义,通过这种方式可以实现用户需要的语义理解。前面写了两篇语音识别,语义理解的博文,分别是语音在线听书和语音记帐软件,本篇是语音智能照相机。
1.智能照相机的功能
手机后摄像头像素比较高,如果用后设想头对准自己自拍,那么看不到屏幕的情况下怎么知道自己在不在镜头中呢?而本篇做的智能照相机就可以为您解决这个问题。想要做的是这样一个照相机app,可以语音切换摄像头,人脸识别并语音播报识别的人脸是否在屏幕中央,是偏向哪里,当人脸居中的时候,提示用户可以拍照了,用户说“拍照”,“茄子”就会自动抓拍并保存图片在手机中。
抓了两张应用运行时的图片:


2.eclipse中的lib目录结构如下

assets下面的事tts播报的资源文件
libs目录下,
播报所需的库文件
语音识别所需的库文件
语音识别所需的库文件
播报所需的库文件
voicesdk_语音识别所需的库文件
3.
package=""
android:versionCode="1"
android:versionName="1.0"
android:minSdkVersion="8"
android:targetSdkVersion="14"/
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:name=".MainActivity"
android:label="@string/app_name"
需要录音,网络,读写sd卡,拍照等权限。
4.layout布局
xmlns:tools=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"/
android:id="@+id/faceView"
android:layout_width="match_parent"
android:layout_height="match_parent"/
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="开始"/
在surfaceview中自定义了一个FaceView,faceview用来显示抓拍的人脸。
5.和
@Override
protectedvoidonCreate(BundlesavedInstanceState){
(savedInstanceState);
setContentView(_camera);
initHandler;//用于处理录音状态回调的消息
initView;//初始化界面
initViaVoiceRecognizerListener;//初始化olami语音回调监听
init;//初始化olami语音识别sdk
initTts;//初始化tts语音播报
DisplayMetricsdm=newDisplayMetrics;//定义DisplayMetrics对象
(dm);//取得窗口属性
mScreenCenterx=/2;//窗口的宽度
mScreenCentery=/2;//窗口的高度
}
以下是olamisdk的初始化
publicvoidinit
{
mOlamiVoiceRecognizer=newOlamiVoiceRecognizer();
TelephonyManagertelephonyManager=
(TelephonyManager)(
_SERVICE);
Stringimei=;
(imei);//设置身份标识,可以填null
//设置识别结果回调listener
(mOlamiVoiceRecognizerListener);
//设置支持的语音类型,优先选择中文简体
(
_SIMPLIFIED_CHINESE);
(
"51a4bb56ba954655a4fc834bfdc46af1",
"asr",
"68bff251789b426896e70e888f919a6d",
"nli");
//注册Appkey,在olami官网注册应用后生成的appkey
//注册api,请直接填写“asr”,标识语音识别类型
//注册secret,在olami官网注册应用后生成的secret
//注册seq,请填写“nli”
//录音时尾音结束时间,建议填//2000ms
(2000);
//设置经纬度信息,不愿上传位置信息,可以填0
(
31.4498,121.34882432933009);
}
定义OlamiVoiceRecognizerListener,此处代码就不贴了。
onError(interrCode)//出错回调,可以对比官方文档错误码看是什么错误
onOfSpeech//录音结束
onBeginningOfSpeech//录音开始
onResult(Stringresult,inttype)//result是识别结果JSON字符串
onCancel//取消识别,不会再返回识别结果
onUpdateVolume(intvolume)//录音时的音量,1-12个级别大小音量
以下是handler消息处理,包含语义解析
privatevoidinitHandler
{
mHandler=newHandler{
@Override
publicvoidhandleMessage(Messagemsg)
{
switch(){
_ACTION_START_RECORED:
("录音中");
break;
_ACTION_STOP_RECORED:
("识别中");
break;
_ACTION_CANCEL_RECORED:
("开始");
break;
_ACTION_ON_ERROR:
("开始");
break;
_ACTION_UPDATA_VOLUME:
//("音量:"+);
break;
_ACTION_RETURN_RESULT:
("开始");
try{
Stringmessage=(String);
Stringinput=null;
JSONObjectjsonObject=newJSONObject(message);
JSONArrayjArrayNli=
("data").optJSONArray("nli");
JSONObjectjObj=(0);
JSONArrayjArraySemantic=null;
if(("semantic"))
{
jArraySemantic=("semantic");
Stringmodifier=
(0).optJSONArray(
"modifier").optString(0);
if("take_photo".equals(modifier))
capture;
elseif("switch_camera".equals(modifier))
switchCamera;
}
else{
("ppp","resulterror");
}
}
catch(Exceptione)
{
;
}
break;
_ACTION_UPDATA_FACEDECTION_DATA:
if(mIsRecording)
break;
RectFrect=(RectF);
mLeft=;
mRight=;
mTop=;
mBottom=;
floatcenterx=mLeft+(mRight-mLeft)/2;
floatcentery=mTop+(mBottom-mTop)/2;
StringpromptString="";
if(centerx100)
promptString="位置偏左,";
elseif((centerxmScreenCenterx)
((centerx-mScreenCenterx)100))
promptString="位置偏右,";
if((centery
(mScreenCentery-centery)200))
{
if("".equals(promptString))
promptString="位置偏上";
else
promptString+="并且偏上";
}
elseif((centerymScreenCentery)
((centery-mScreenCenterx)200))
{
if("".equals(promptString))
promptString="位置偏下";
else
promptString+="并且偏下";
}
if("".equals(promptString))
{
promptString="位置已经居中,可以拍照了";
mIsCenter=true;
}
else
{
mIsCenter=false;
}
ITtsListenerttsListener=newITtsListener
{
@Override
publicvoidonPlay{
if(mIsCenter)
{
if(mOlamiVoiceRecognizer!=null)
;
}
}
@Override
publicvoidonPlayFlag(Stringarg0){
}
@Override
publicvoidonTTSPower(longarg0){
}
};
(,
promptString,ttsListener,_SYSTEM_PRIORITY);
break;
}
}
};
}
在_ACTION_RETURN_RESULT消息中,通过解析服务器返回的json字符串,可以找到modifier这个字段的值,如果是take_photo表示拍照,如果是switch_camera表示切换摄像头。
当用户说拍照或者茄子的时候,服务器返回如下json字符串:
[
{
"desc_obj":{
"status":0
},
"semantic":[
{
"input":"拍照",
"slots":[
],
"modifier":[
"take_photo"
],
"customer":"58df512384ae11f0bb7b487e"
}
],
"type":"camera"
}
]
这个拍照,茄子等语法都是自己定义的,详细请看:
olami开放平台语法编写简介:
olami开放平台语法官方介绍:;content=
2.人脸识别
publicclassFaceViewextsView{
;
privatePaintmPaint;
privateMatrixmatrix=newMatrix;
privateRectFmRectF=newRectF;
privateHandlermHandler;
privatelongmCurrentTime;
publicvoidsetFaces([]faces){
mFaces=faces;
invalidate;
}
publicFaceView(Contextcontext){
super(context);
init(context);
}
publicFaceView(Contextcontext,AttributeSetattrs){
super(context,attrs);
init(context);
}
publicFaceView(Contextcontext,AttributeSetattrs,intdefStyleAttr){
super(context,attrs,defStyleAttr);
init(context);
}
publicvoidinit(Contextcontext){
mPaint=newPaint;
();
(5f);
();
}
publicvoidsetHandler(Handlerhandler)
{
mHandler=handler;
}
@Override
protectedvoidonDraw(Canvascanvas){
(canvas);
if(mFaces==null||
return;
}
//准备矩形框
(matrix,false,270,getWidth,getHeight);
;
(0);
(-0);
RectFtempRectF=newRectF;
longtempTime=;
for(inti=0;i
(mFaces[i].rect);//获取face矩形框值
floattemp=;
=-;
=-temp;//上下交换
(mRectF);
(mRectF,mPaint);//绘制矩形框
(mRectF);
if((mCurrentTime==0)||((tempTime-mCurrentTime)/1000)=4)
{//超过4秒,发送一次识别face矩形框值
((
_ACTION_UPDATA_FACEDECTION_DATA,tempRectF));
mCurrentTime=tempTime;
}
("ppp","="++"="+);
}
;
}
}
自定义FaceView中,由于旋转了270度,所以需要face矩形框上下值进行交换,不然人脸识别总是左右或者上下不能追踪。每隔4秒发送一次矩形框的值,在的handler中收到这个消息并进行是否居中的判断。
_ACTION_UPDATA_FACEDECTION_DATA:
if(mIsRecording)
break;
RectFrect=(RectF);
mLeft=;
mRight=;
mTop=;
mBottom=;//保存上下左右的矩形框值
floatcenterx=mLeft+(mRight-mLeft)/2;//获取矩形框横向中心点位置
floatcentery=mTop+(mBottom-mTop)/2;//获取矩形框纵向中心点位置
StringpromptString="";
if(centerx100)
promptString="位置偏左,";
elseif((centerxmScreenCenterx)
((centerx-mScreenCenterx)100))
promptString="位置偏右,";
if((centery
(mScreenCentery-centery)200))
{
if("".equals(promptString))
promptString="位置偏上";
else
promptString+="并且偏上";
}
elseif((centerymScreenCentery)
((centery-mScreenCenterx)200))
{
if("".equals(promptString))
promptString="位置偏下";
else
promptString+="并且偏下";
}
if("".equals(promptString))
{
promptString="位置已经居中,可以拍照了";
mIsCenter=true;
}
else
{
mIsCenter=false;
}
ITtsListenerttsListener=newITtsListener
{
@Override
publicvoidonPlay{
if(mIsCenter)
{
if(mOlamiVoiceRecognizer!=null)
;
}
}
@Override
publicvoidonPlayFlag(Stringarg0){
}
@Override
publicvoidonTTSPower(longarg0){
}
};
(,
promptString,ttsListener,_SYSTEM_PRIORITY);
break;
可以获得屏幕的中心点和人脸识别的矩形框的中心点,对比横向和纵向的中心点大小和绝对值差,当横向的值差100像素以上就认为横向不居中,并且根据大小分居左和居右,纵向大小差值在200像素以上认为纵向不居中,并且根据大小分偏上和偏下,这个100,200像素值用户可以自己调节到合适的值。
6.源码下载链接
7.相关链接语音在线听书:
语音记账demo:
olami开放平台语法编写简介:
olami开放平台语法官方介绍:;content=
想看到更多这类内容?去APP商店搜IT之家,天天都有小欢喜。