资讯专栏INFORMATION COLUMN

人脸识别和语音识别智能照相机

jonh_felix / 3071人阅读

摘要:语音识别,语义理解一站式解决之智能照相机人脸识别如果有代码排版和图片显示问题,请访问博客。前面写了两篇语音识别,语义理解的博文,分别是语音在线听书和语音记帐软件,本篇是语音智能照相机。

语音识别,语义理解一站式解决之智能照相机(人脸识别,olami)

如果有代码排版和图片显示问题,请访问CSDN博客。
转载请注明CSDN博文地址:http://blog.csdn.net/ls0609/a...

olami sdk实现了把录音或者文字转化为用户可以理解的json字符串从而实现语义理解,用户可以定义自己的
语义,通过这种方式可以实现用户需要的语义理解。前面写了两篇语音识别,语义理解的博文,分别是语音
在线听书和语音记帐软件,本篇是语音智能照相机。

1.智能照相机的功能

手机后摄像头像素比较高,如果用后设想头对准自己自拍,那么看不到屏幕的情况下怎么知道
自己在不在镜头中呢?而本篇做的智能照相机就可以为您解决这个问题。
想要做的是这样一个照相机app,可以语音切换摄像头,人脸识别并语音播报识别的人脸是否在屏幕中央,
是偏向哪里,当人脸居中的时候,提示用户可以拍照了,用户说“拍照”,“茄子”就会自动抓拍并保存图
片在手机中。

抓了两张应用运行时的图片:

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

assets下面的事tts播报的资源文件
libs目录下,
libtts.so tts播报所需的库文件
libspeex.so 语音识别所需的库文件
libolamsc.so 语音识别所需的库文件
tts.jar tts播报所需的库文件
voicesdk_android.jar 语音识别所需的库文件

3.AndroidManifest.xml


package="com.olami"
android:versionCode="1"
android:versionName="1.0" >



 
 
 
 







    
        
            

            
        
    

需要录音,网络,读写sd卡,拍照等权限。

4.layout布局

xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">


 

    
                    

在surfaceview中自定义了一个FaceView,faceview用来显示抓拍的人脸。
屏幕最下方有个button,因为这个版本暂时不支持语音唤醒功能(后续添加后再更新),添加一个button用于用户想随时说拍照的时候点击触发用。

5.MainActivity.java 和FaceView.java

1.MainActivity.Java
@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.layout_camera);

initHandler();//用于处理录音状态回调的消息

initView(); //初始化界面

initViaVoiceRecognizerListener(); //初始化olami语音回调监听

init();  //初始化olami语音识别sdk

initTts(); //初始化tts语音播报

DisplayMetrics dm = new DisplayMetrics();//定义DisplayMetrics对象
getWindowManager().getDefaultDisplay().getMetrics(dm);//取得窗口属性
mScreenCenterx = dm.widthPixels/2;//窗口的宽度
mScreenCentery = dm.heightPixels/2; //窗口的高度

}

以下是olamisdk的初始化

public void init()
{

    mOlamiVoiceRecognizer = new OlamiVoiceRecognizer(MainActivity.this);
    TelephonyManager telephonyManager=
                               (TelephonyManager) this.getSystemService(
                                this.getBaseContext().TELEPHONY_SERVICE);
    String imei=telephonyManager.getDeviceId();
    mOlamiVoiceRecognizer.init(imei);//设置身份标识,可以填null

    //设置识别结果回调listener
    mOlamiVoiceRecognizer.setListener(mOlamiVoiceRecognizerListener);

    //设置支持的语音类型,优先选择中文简体        
    mOlamiVoiceRecognizer.setLocalization(
                       OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE);
     mOlamiVoiceRecognizer.setAuthorization(
           "51a4bb56ba954655a4fc834bfdc46af1",
           "asr",
           "68bff251789b426896e70e888f919a6d",
           "nli");
    //注册Appkey,在olami官网注册应用后生成的appkey
    //注册api,请直接填写“asr”,标识语音识别类型
    //注册secret,在olami官网注册应用后生成的secret
    //注册seq ,请填写“nli”   

//录音时尾音结束时间,建议填//2000ms         
mOlamiVoiceRecognizer.setVADTailTimeout(2000);
//设置经纬度信息,不愿上传位置信息,可以填0 
mOlamiVoiceRecognizer.setLatitudeAndLongitude(
                                     31.155364678184498,121.34882432933009); 

}

定义OlamiVoiceRecognizerListener,此处代码就不贴了。
onError(int errCode)//出错回调,可以对比官方文档错误码看是什么错误
onEndOfSpeech()//录音结束
onBeginningOfSpeech()//录音开始
onResult(String result, int type)//result是识别结果JSON字符串
onCancel()//取消识别,不会再返回识别结果
onUpdateVolume(int volume)//录音时的音量,1-12个级别大小音量

以下是handler消息处理,包含语义解析

private void initHandler()

{
    mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what){
            case MessageConst.CLIENT_ACTION_START_RECORED:
                mBtnStart.setText("录音中");
                break;
            case MessageConst.CLIENT_ACTION_STOP_RECORED:
                mBtnStart.setText("识别中");
                break;
            case MessageConst.CLIENT_ACTION_CANCEL_RECORED:
                mBtnStart.setText("开始");
                break;
            case MessageConst.CLIENT_ACTION_ON_ERROR:
                mBtnStart.setText("开始");
                break;
            case MessageConst.CLIENT_ACTION_UPDATA_VOLUME:
                //mTextViewVolume.setText("音量: "+msg.arg1);
                break;
            case MessageConst.SERVER_ACTION_RETURN_RESULT:
                mBtnStart.setText("开始");
                try{
                    String message = (String) msg.obj;
                    String input = null;
                    JSONObject jsonObject = new JSONObject(message);
                    JSONArray jArrayNli = 
                    jsonObject.optJSONObject("data").optJSONArray("nli");
                    JSONObject jObj = jArrayNli.optJSONObject(0);
                    JSONArray jArraySemantic = null;
                    if(message.contains("semantic"))
                    {
                      jArraySemantic = jObj.getJSONArray("semantic");
                      String modifier = 
                          jArraySemantic.optJSONObject(0).optJSONArray(
                                               "modifier").optString(0);
                      if("take_photo".equals(modifier))
                          capture();    
                      else if("switch_camera".equals(modifier))
                          switchCamera();
                    }
                    else{
                      Log.i("ppp","result error");
                    }
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }                   
                break;  
            case MessageConst.CLIENT_ACTION_UPDATA_FACEDECTION_DATA:
                if(mIsRecording)
                    break;
                RectF rect = (RectF) msg.obj;
                mLeft = rect.left;
                mRight = rect.right;
                mTop = rect.top;
                mBottom = rect.bottom;
                float centerx = mLeft +(mRight - mLeft)/2;
                float centery = mTop + (mBottom-mTop)/2;
                String promptString = "";
                if(centerx100)
                    promptString = "位置偏左,";
                else if((centerx > mScreenCenterx)&&
                                        (Math.abs(centerx -mScreenCenterx)>100))                
                    promptString = "位置偏右,";
                if((centery < mScreenCentery)&&(
                                          Math.abs(mScreenCentery-centery) >200))
                {
                    if("".equals(promptString))
                        promptString = "位置偏上";
                    else
                        promptString += "并且偏上";
                }
                else if((centery > mScreenCentery)&&
                (Math.abs(centery -mScreenCenterx)>200))
                {
                    if("".equals(promptString))
                        promptString = "位置偏下";
                    else
                        promptString += "并且偏下";
                }
                if("".equals(promptString))
                {
                    promptString = "位置已经居中,可以拍照了";
                    mIsCenter = true;
                }
                else
                {
                    mIsCenter = false;
                }

                ITtsListener ttsListener = new ITtsListener()
                {

                    @Override
                    public void onPlayEnd() {
                        if(mIsCenter)
                        {
                            if(mOlamiVoiceRecognizer != null)
                                mOlamiVoiceRecognizer.start();  
                        }
                    }

                    @Override
                    public void onPlayFlagEnd(String arg0) {

                    }

                    @Override
                    public void onTTSPower(long arg0) {

                    }

                };
                TtsPlayer.playText(MainActivity.this, 
                      promptString, ttsListener,Tts.TTS_SYSTEM_PRIORITY);   
                break;
            }
        }
    };
}

在MessageConst.SERVER_ACTION_RETURN_RESULT消息中,通过解析服务器返回的json字符串,可以找到modifier这个字段的值,如果是take_photo表示拍照,如果是switch_camera表示切换摄像头。
当用户说拍照或者茄子的时候,服务器返回如下json字符串:
[
{

"desc_obj": {
  "status": 0
},
"semantic": [
  {
    "app": "camera",
    "input": "拍照",
    "slots": [

    ],
    "modifier": [
      "take_photo"
    ],
    "customer": "58df512384ae11f0bb7b487e"
  }
],
"type": "camera"

}
]

这个拍照,茄子等语法都是自己定义的,详细请看:
olami开放平台语法编写简介:http://blog.csdn.net/ls0609/a...
olami开放平台语法官方介绍:https://cn.olami.ai/wiki/?mp=...
• 2.人脸识别FaceView.java

public class FaceView extends View {

private Camera.Face[] mFaces;
private Paint mPaint;
private Matrix matrix = new Matrix();
private RectF mRectF = new RectF();
private Handler mHandler;
private long mCurrentTime;
public void setFaces(Camera.Face[] faces) {
    mFaces = faces;
    invalidate();
}

public FaceView(Context context) {
    super(context);
    init(context);
}

public FaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public FaceView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

public void init(Context context) {
    mPaint = new Paint();
    mPaint.setColor(Color.RED);
    mPaint.setStrokeWidth(5f);
    mPaint.setStyle(Paint.Style.STROKE);

}

public void setHandler(Handler handler)
{
    mHandler = handler;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mFaces == null || mFaces.length < 0) {
        return;
    }
    //准备矩形框
    MainActivity.prepareMatrix(matrix, false, 270, getWidth(), getHeight());
    canvas.save();
    matrix.postRotate(0);
    canvas.rotate(-0);
    RectF tempRectF = new RectF();
    long tempTime = System.currentTimeMillis();
    for (int i = 0; i < mFaces.length; i++) {
        mRectF.set(mFaces[i].rect);//获取face矩形框值
        float temp = mRectF.top;
        mRectF.top = -mRectF.bottom;
        mRectF.bottom = - temp;  //上下交换         
        matrix.mapRect(mRectF);
        canvas.drawRect(mRectF, mPaint);//绘制矩形框
        tempRectF.set(mRectF);
        if((mCurrentTime == 0) ||((tempTime-mCurrentTime)/1000) >= 4)
        {//超过4秒,发送一次识别face矩形框值
            mHandler.sendMessage(mHandler.obtainMessage(
            MessageConst.CLIENT_ACTION_UPDATA_FACEDECTION_DATA, tempRectF));
            mCurrentTime = tempTime;
        }
        Log.i("ppp","mRectF.left = "+mRectF.left+"   mRectF.right = "+mRectF.right);
    }
    canvas.restore();
}

}

自定义FaceView中,由于旋转了270度,所以需要face矩形框上下值进行交换,不然人脸识别总是左右或者上下不能追踪。每隔4秒发送一次矩形框的值,在MainActivity.java的handler中收到这个消息并进行是否居中的判断。

case MessageConst.CLIENT_ACTION_UPDATA_FACEDECTION_DATA:

if(mIsRecording)
    break;
RectF rect = (RectF) msg.obj;
mLeft = rect.left;
mRight = rect.right;
mTop = rect.top;
mBottom = rect.bottom;//保存上下左右的矩形框值
float centerx = mLeft +(mRight - mLeft)/2;//获取矩形框横向中心点位置
float centery = mTop + (mBottom-mTop)/2;//获取矩形框纵向中心点位置
String promptString = "";
if(centerx100)
    promptString = "位置偏左,";
else if((centerx > mScreenCenterx)&&
                        (Math.abs(centerx -mScreenCenterx)>100))                
    promptString = "位置偏右,";
if((centery < mScreenCentery)&&(
                          Math.abs(mScreenCentery-centery) >200))
{
    if("".equals(promptString))
        promptString = "位置偏上";
    else
        promptString += "并且偏上";
}
else if((centery > mScreenCentery)&&
(Math.abs(centery -mScreenCenterx)>200))
{
    if("".equals(promptString))
        promptString = "位置偏下";
    else
        promptString += "并且偏下";
}
if("".equals(promptString))
{
    promptString = "位置已经居中,可以拍照了";
    mIsCenter = true;
}
else
{
    mIsCenter = false;
}

ITtsListener ttsListener = new ITtsListener()
{

    @Override
    public void onPlayEnd() {
        if(mIsCenter)
        {
            if(mOlamiVoiceRecognizer != null)
                mOlamiVoiceRecognizer.start();  
        }
    }

    @Override
    public void onPlayFlagEnd(String arg0) {

    }

    @Override
    public void onTTSPower(long arg0) {

    }

};
TtsPlayer.playText(MainActivity.this, 
      promptString, ttsListener,Tts.TTS_SYSTEM_PRIORITY);   

break;

可以获得屏幕的中心点和人脸识别的矩形框的中心点,对比横向和纵向的中心点大小和绝对值差,当横向的值差100像素以上就认为横向不居中,并且根据大小分居左和居右,纵向大小差值在200像素以上认为纵向不居中,并且根据大小分偏上和偏下,这个100,200像素值用户可以自己调节到合适的值。
调用TtsPlayer.playText提示,当播报结束后回调到onPlayEnd() ,如果居中那么已经提示用户可以拍照了,此时启动录音程序,用户不用点击button也不用唤醒,只许说拍照或者茄子就可以拍照了。

6.源码下载链接
https://pan.baidu.com/s/1qXITWs8

7.相关链接

语音在线听书:http://blog.csdn.net/ls0609/a...

语音记账demo:http://blog.csdn.net/ls0609/a...

olami开放平台语法编写简介:http://blog.csdn.net/ls0609/a...

olami开放平台语法官方介绍:https://cn.olami.ai/wiki/?mp=...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67610.html

相关文章

  • 首次披露!阿里线下智能方案进化史

    摘要:前言阿里巴巴机器智能实验室线下智能团队从年底开始涉及线下智能领域,从算法工程产品化业务落地多个方面入手,与合作伙伴们一起取得了一些小小的成绩。目前,该套工具作为推荐的量化工具广泛应用在阿里集团内多个线下业务场景中。 showImg(https://segmentfault.com/img/remote/1460000019246850); 阿里妹导读:AI 技术已经从互联网走向零售、...

    keelii 评论0 收藏0
  • 前端也可以调教人工智能

    摘要:这群小伙伴们坚信的强大能力,坚信可以模拟人类很多的感官功能,包括视觉听觉,甚至包括思考能力给安装上一个机械手臂,甚至可以模拟人类的肢体功能,这就是阿里云人工智能的能力。 阿里云人工智能 ET, 代表的是阿里云语音识别、语音合成、自然语言理解、实时图像识别、机器学习的综合技术,背后是阿里云飞天系统强大的计算能力。 可是这么高大上的 ET,最近居然开始不务正业了,来看看它都干了啥!!! 视...

    yvonne 评论0 收藏0
  • AWS的人工智能版图

    摘要:的人工智能版图人工智能版图由应用平台框架三大部分组成应用层是提供各种应用服务,比如平台层是平台。应用层主推三大成熟应用基于深度学习的图像和视频分析它能实现对象与场景检测人脸分析面部比较人脸识别名人识别图片调节等功能。AWS的人工智能版图 AWS人工智能版图由:应用、平台、框架三大部分组成 AI应用层:是提供各种应用服务,比如Amazon Rekognition、Polly...

    William_Sang 评论0 收藏0
  • AWS的人工智能版图

    摘要:的人工智能版图人工智能版图由应用平台框架三大部分组成应用层是提供各种应用服务,比如平台层是平台。应用层主推三大成熟应用基于深度学习的图像和视频分析它能实现对象与场景检测人脸分析面部比较人脸识别名人识别图片调节等功能。 AWS的人工智能版图AWS人工智能版图由:应用、平台、框架三大部分组成AI应用层:是提供各种...

    Pluser 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<