欢迎转载,转载时请标明出处:http://blog.csdn.net/android_for_james/article/details/51016170

今天给大家带来一个通过使用Face++来实现人脸识别的功能

我们先去这个Face++官网看看:http://www.faceplusplus.com.cn

我们点开案例可以看到众多我们熟知的软件都是使用的这个公司所提供的SDK

然后我们点击开发者中心中的开发工具与sdk下载我们所需要的sdk

之后再点击我的应用中的创建应用之后他会给我们两个密钥

要保存这两个值我们在程序中要用到它们

我今天实现的是实现面部捕捉并且识别性别和年龄来看一下效果图

闲话不多说我们来看看实现

1.工具类Constant用来存放密钥

public class Constant {//设置两个之前获取的两个常量public static final String Key="你的key";public static final String Secret="你的secret";
}

2.工具类InternetDetect

import android.graphics.Bitmap;import com.facepp.error.FaceppParseException;
import com.facepp.http.HttpRequests;
import com.facepp.http.PostParameters;import org.json.JSONObject;import java.io.ByteArrayOutputStream;public class InternetDetect {public interface CallBack{void success(JSONObject jsonObject);void error(FaceppParseException exception);}public static void dectect(final Bitmap bitmap, final CallBack callBack){//因为这里要向网络发送数据是耗时操作所以要在新线程中执行new Thread(new Runnable() {@Overridepublic void run() {/*1.设置请求* 2.创建一个Bitmap* 3.创建字符数组流* 4.将bitmap转换为字符并传入流中* 5.新建字符数组接受流* 6.创建发送数据包* 7.创建接受数据包** */try {HttpRequests httpRequests=new HttpRequests(Constant.Key,Constant.Secret,true,true);//从0,0点挖取整个视图,后两个参数是目标大小Bitmap bitmapsmall = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());//这里api要求传入一个字节数组数据,因此要用字节数组输出流ByteArrayOutputStream stream=new ByteArrayOutputStream();/*Bitmap.compress()方法可以用于将Bitmap-->byte[]既将位图的压缩到指定的OutputStream。如果返回true,位图可以通过传递一个相应的InputStream BitmapFactory.decodeStream(重建)第一个参数可设置JPEG或PNG格式,第二个参数是图片质量,第三个参数是一个流信息*/bitmapsmall.compress(Bitmap.CompressFormat.JPEG, 100, stream);byte[] arrays=stream.toByteArray();//实现发送参数功能PostParameters parameters=new PostParameters();//发送数据parameters.setImg(arrays);//服务器返回一个JSONObject的数据JSONObject jsonObject=httpRequests.detectionDetect(parameters);System.out.println("jsonObject:"+jsonObject.toString());if(callBack!=null){//设置回调callBack.success(jsonObject);}} catch (FaceppParseException e) {System.out.println("error");e.printStackTrace();if(callBack!=null){callBack.error(e);}}}}).start();}}

3.MainActivity

import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;import com.facepp.error.FaceppParseException;import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;public class MainActivity extends ActionBarActivity implements View.OnClickListener {private static final int PICK_CODE =1;private ImageView myPhoto;private Button getImage;private Button detect;private TextView tip;private View mWaitting;private String ImagePath=null;private Paint mypaint;private Bitmap myBitmapImage;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mypaint=new Paint();initViews();initEvent();}private void initViews(){myPhoto=(ImageView)findViewById(R.id.id_photo);getImage=(Button)findViewById(R.id.get_image);detect=(Button)findViewById(R.id.detect);tip=(TextView)findViewById(R.id.id_Tip);mWaitting=findViewById(R.id.id_waitting);tip.setMovementMethod(ScrollingMovementMethod.getInstance());}private void initEvent(){getImage.setOnClickListener(this);detect.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.get_image://获取系统选择图片intentIntent intent=new Intent(Intent.ACTION_PICK);intent.setType("image/*");//开启选择图片功能响应码为PICK_CODEstartActivityForResult(intent,PICK_CODE);break;case R.id.detect://显示进度条圆形mWaitting.setVisibility(View.VISIBLE);//这里需要注意判断用户是否没有选择图片直接点击了detect按钮//否则会报一个空指针异常而造成程序崩溃if(ImagePath!=null&&!ImagePath.trim().equals("")){//如果不是直接点击的图片则压缩当前选中的图片resizePhoto();}else{//否则将默认的背景图作为bitmap传入myBitmapImage=BitmapFactory.decodeResource(getResources(),R.drawable.test1);}//设置回调InternetDetect.dectect(myBitmapImage, new InternetDetect.CallBack() {@Overridepublic void success(JSONObject jsonObject) {Message message=Message.obtain();message.what=MSG_SUCESS;message.obj=jsonObject;myhandler.sendMessage(message);}@Overridepublic void error(FaceppParseException exception) {Message message=Message.obtain();message.what=MSG_ERROR;message.obj=exception;myhandler.sendMessage(message);}});break;}}//设置响应intent请求@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) {super.onActivityResult(requestCode, resultCode, intent);if(requestCode==PICK_CODE){if(intent!=null){//获取图片路径//获取所有图片资源Uri uri=intent.getData();//设置指针获得一个ContentResolver的实例Cursor cursor=getContentResolver().query(uri,null,null,null,null);cursor.moveToFirst();//返回索引项位置int index=cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);//返回索引项路径ImagePath=cursor.getString(index);cursor.close();//这个jar包要求请求的图片大小不得超过3m所以要进行一个压缩图片操作resizePhoto();myPhoto.setImageBitmap(myBitmapImage);tip.setText("Click Detect==>");}}}private void resizePhoto() {//得到BitmapFactory的操作权BitmapFactory.Options options = new BitmapFactory.Options();// 如果设置为 true ,不获取图片,不分配内存,但会返回图片的高宽度信息。options.inJustDecodeBounds = true;BitmapFactory.decodeFile(ImagePath,options);//计算宽高要尽可能小于1024double ratio=Math.max(options.outWidth*1.0d/1024f,options.outHeight*1.0d/1024f);//设置图片缩放的倍数。假如设为 4 ,则宽和高都为原来的 1/4 ,则图是原来的 1/16 。options.inSampleSize=(int)Math.ceil(ratio);//我们这里并想让他显示图片所以这里要置为falseoptions.inJustDecodeBounds=false;//利用Options的这些值就可以高效的得到一幅缩略图。myBitmapImage=BitmapFactory.decodeFile(ImagePath,options);}private static final int MSG_SUCESS=11;private static final int MSG_ERROR=22;private Handler myhandler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case MSG_SUCESS://关闭缓冲条mWaitting.setVisibility(View.GONE);//拿到新线程中返回的JSONObject数据JSONObject rsobj= (JSONObject) msg.obj;//准备Bitmap,这里会解析JSONObject传回的数据prepareBitmap(rsobj);//让主线程的相框刷新myPhoto.setImageBitmap(myBitmapImage);break;case MSG_ERROR:mWaitting.setVisibility(View.GONE);String errormsg= (String) msg.obj;break;}}};private void prepareBitmap(JSONObject JS) {//新建一个Bitmap使用它作为Canvas操作的对象Bitmap bitmap=Bitmap.createBitmap(myBitmapImage.getWidth(),myBitmapImage.getHeight(),myBitmapImage.getConfig());//实例化一块画布Canvas canvas=new Canvas(bitmap);//把原图先画到画布上面canvas.drawBitmap(myBitmapImage, 0, 0, null);//解析传回的JSONObject数据try {//JSONObject中包含着众多JSONArray,但是我们这里需要关键字为face的数组中的信息JSONArray faces=JS.getJSONArray("face");//获取得到几个人脸int faceCount=faces.length();//让提示文本显示人脸数tip.setText("find"+faceCount);//下面对每一张人脸都进行单独的信息绘制for(int i=0;i<faceCount;i++){//拿到每张人脸的信息JSONObject face=faces.getJSONObject(i);//拿到人脸的详细位置信息JSONObject position=face.getJSONObject("position");float x=(float)position.getJSONObject("center").getDouble("x");float y=(float)position.getJSONObject("center").getDouble("y");float w=(float)position.getDouble("width");float h=(float)position.getDouble("height");//注意这里拿到的各个参数并不是实际的像素值,而是一个比例,都是相对于整个屏幕而言的比例信息//因此我们使用的时候要进行一下数据处理x=x/100*bitmap.getWidth();y=y/100*bitmap.getHeight();w=w/100*bitmap.getWidth();h=h/100*bitmap.getHeight();//设置画笔颜色mypaint.setColor(0xffffffff);//设置画笔宽度mypaint.setStrokeWidth(3);//绘制一个矩形框canvas.drawLine(x-w/2,y-h/2,x-w/2,y+h/2,mypaint);canvas.drawLine(x-w/2,y-h/2,x+w/2,y-h/2,mypaint);canvas.drawLine(x+w/2,y-h/2,x+w/2,y+h/2,mypaint);canvas.drawLine(x-w/2,y+h/2,x+w/2,y+h/2,mypaint);//得到年龄信息int age=face.getJSONObject("attribute").getJSONObject("age").getInt("value");//得到性别信息String gender=face.getJSONObject("attribute").getJSONObject("gender").getString("value");System.out.println("age:"+age);System.out.println("gender:"+gender);//现在要把得到的文字信息转化为一个图像信息,我们写一个专门的函数来处理Bitmap ageBitmap=buildAgeBitmap(age,("Male").equals(gender));//进行图片提示气泡的缩放,这个很有必要,当人脸很小的时候我们需要把提示气泡也变小int agewidth=ageBitmap.getWidth();int agehight=ageBitmap.getHeight();if(bitmap.getWidth()<myPhoto.getWidth()&&bitmap.getHeight()<myPhoto.getHeight()){//设置缩放比float ratio=Math.max(bitmap.getWidth()*1.0f/myPhoto.getWidth(),bitmap.getHeight()*1.0f/myPhoto.getHeight());//完成缩放ageBitmap=Bitmap.createScaledBitmap(ageBitmap,(int)(agewidth*ratio*0.8),(int)(agehight*ratio*0.5),false);}//在画布上画出提示气泡canvas.drawBitmap(ageBitmap,x-ageBitmap.getWidth()/2,y-h/2-ageBitmap.getHeight(),null);//得到新的bitmapmyBitmapImage=bitmap;}} catch (JSONException e) {e.printStackTrace();}}private Bitmap buildAgeBitmap(int age, boolean isMale) {//这里要将文字信息转化为图像信息,如果拿Canvas直接画的话操作量太大//因此这里有一些技巧,将提示气泡设置成一个TextView,他的背景就是气泡的背景//他的内容左侧是显示性别的图片右侧是年龄TextView tv= (TextView) mWaitting.findViewById(R.id.id_age_and_gender);//这里要记得显示数字的时候后面最好跟一个""不然有时候会显示不出来tv.setText(age + "");if(isMale){//判断性别tv.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.male),null,null,null);}else{tv.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.female),null,null,null);}//使用setDrawingCacheEnabled(boolean flag)提高绘图速度//View组件显示的内容可以通过cache机制保存为bitmap//这里要获取它的cache先要通过setDrawingCacheEnable方法把cache开启,// 然后再调用getDrawingCache方法就可 以获得view的cache图片了。tv.setDrawingCacheEnabled(true);Bitmap bitmap=Bitmap.createBitmap(tv.getDrawingCache());//关闭许可tv.destroyDrawingCache();return bitmap;}}

布局文件比较简单因此代码我就不上传了

这里我用红色字体标出我在实现的过程中遇到的问题希望大家可以避免:

1.在写按键响应的时候要注意判断用户是否没有选择图片而直接点击了detect按钮,这样的话避免了获取图片时存在空指针异常的问题

2.上传图片时要保证图片小于3M因此注意图片的压缩

3.气泡处理有技巧,把它当作Textview更方便

4.在绘制气泡的时候也要注意缩放不然的话当人脸很小的时候气泡会占据整个图片导致用户体验降低

希望对大家有所帮助,欢迎转载但要标明出处,谢谢!

有什么不足的地方可以留言给我我会尽快回复并改正!

欢迎关注我的博客:http://blog.csdn.net/android_for_james

源码下载网址(点开后面链接后在文章末尾有点击下载按钮):点击打开链接

Android使用Face++架构包实现人脸识别相关推荐

  1. Android基于虹软SDK实现离线人脸识别

    一.需求 Android端实现离线人脸识别功能,即对比两张人脸是否是同一个人. 二.解决方案 选用虹软人脸识别SDK来实现人脸特征数据比对. 三.步骤 1. 打开虹软开发者中心 开发者中心 2. 新建 ...

  2. 联想z5 Android 9.0,联想Z5开启Android 9.0内测,新增人脸识别!

    如今,就国内智能手机市场来说,华为.小米.OPPO.vivo等智能手机厂商不仅在硬件配置上激烈较量,比如手机运行内存就从6GB.8GB提升到了10GB乃至于12GB.当然,在软件系统上,各大智能手机厂 ...

  3. 在python中利用OpenCV包实现人脸识别

    一.实验环境 1.python3.6环境,numpy包,OpenCV包,pillow包 2.联想T470笔记本电脑,win10系统 3.在测试目录下新建两个文件夹,一个是Facedata用于存放采集的 ...

  4. nokia 7 Android8,诺基亚 7获升Android 8.1:终于支持人脸识别

    诺基亚手机的系统更新速度向来都十分快速,目前绝大部分诺基亚手机都已经升级到了Android 8.0 Oreo版本,其中也有一部分已经升级到了Android 8.1. 近日,诺基亚宣布,即将推送诺基亚 ...

  5. Android从零开始配置opencv+tensorflow进行人脸识别+口罩识别(二:opencv展示当前图像并作适当调整)

    前言 上一章已经成功导入了opencv,但并没说如何展示从摄像头获取图像并展示出来,这章将简单的说说怎么展示,以及里面出现的问题作修正 一.使用opencv正常展示图像 首先准备一个空的activit ...

  6. Android打造圆形相机并实现人脸识别(三)

    这里就主要讲下整个人脸识别模块的接入及使用. 百度AI SDK 首先我们要去百度官网申请一个帐号,接而进入这个网址: https://console.bce.baidu.com/ai/#/ai/fac ...

  7. Android之人脸识别

    前言 人工智能时代快速来临,其中人脸识别是当前比较热门的技术,在国内也越来越多的运用,例如刷脸打卡.刷脸App,身份识别,人脸门禁等等.当前的人脸识别技术分为WEBAPI和SDK调用两种法方式,WEB ...

  8. Android自带人脸识别

    前言 碰到项目需求要判断上传的图片里只能有一个人,就像到了人脸识别功能,网上查资料说需要用opencv等各种图像库,项目肯定不能接受,没想到Android很早就已经集成了人脸识别的功能,这里记录一下. ...

  9. android 人脸检测代码,在Android实现人脸识别的详细过程

    照相时,在预览画面上提示用户人脸的位置,并完成自动对焦等,是个错的应用; 下面是实现细节 我们知道在android的代码中已有人脸识别的底层算法代码,而且在framework层也封了调用的API函数 ...

最新文章

  1. vmware响应时间过长_性能调优高并发下如何缩短响应时间
  2. idea双击无反应,打不开的解决方法,两种情况。
  3. boost::mpl::less相关的测试程序
  4. git bash命令_更优雅地使用命令行
  5. python socket.error: [Errno 24] Too many open files
  6. Django:快速搭建简单的Blog
  7. 又漏了一张发票,所以报销要及时
  8. win7副本不是正版_征途正版官网版下载-征途正版手游官网版下载1.0
  9. 栈的基本操作(java)
  10. 2022年Java面试宝典【4万字带答案】
  11. MATLAB——tiff文件数据读取,modis
  12. 【Python基础】制作一个汇率换算程序
  13. 又见猛犸象:基因剪刀重新定制生命
  14. WindowsPhone8 应用开发学习笔记(一)
  15. java stringbuilder_Java stringBuilder的使用方法及实例解析
  16. Java程序占用 CPU 过高怎么排查
  17. 基于JAVAWeb前端开发技术儿童教育网站计算机毕业设计源码+数据库+lw文档+系统+部署
  18. 关于学习如何组装基于F4V3S飞控的竞速穿越机
  19. 2022华中杯、五一竞赛赛事备战
  20. 【打字母游戏_C语言实现】

热门文章

  1. js 格式化prettier配置_Prettier格式化配置
  2. vscode常用插件总结
  3. mysql 索引 优化 面试
  4. iPhoneX官网停售了,价格会暴跌吗?
  5. Mysql递归查询父/子级
  6. 微信小程序--》从零实现小程序项目案例
  7. Android流媒体处理流程分析
  8. python爬虫爬取武汉房价信息
  9. CAD怎么转成PDF清晰图
  10. 热血军团-vSyncCount