语音识别,语义理解一站式解决之智能照相机(人脸识别,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之家,天天都有小欢喜。