Android人脸检测1(静态图片)
搭建Android人脸识别环境花了很长时间(可以查看之前的文章),解决Android开发中的杂七杂八小问题也耗时不少.
今天记录一下,点击选择照片或者拍照上传照片进行人脸检测的小demo.
(android.media.FaceDetector;方法)
先看效果图:
手机在电脑拍摄的图片:

要点说明:
参考: http://blog.csdn.net/zhandoushi1982/article/details/8613916
1, 必须要把bitmap转换RGB_565才能检测
bitmap565 = bitmap.copy(Bitmap.Config.RGB_565, true);
2, 给bitmap画框
Canvas canvas = new Canvas(bitmap565);
参考: https://stackoverflow.com/questions/4918079/android-drawing-a-canvas-to-an-imageview
3, 调用系统相册相机需要配置权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
4, 调用 FaceDetector 感觉很慢,而且会识别多余人脸,最后附图.
5, 后续做动态人脸检测.
代码:
package com.***.facedetection; import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.media.FaceDetector;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File; public class MainActivity extends AppCompatActivity { private static String CAMERAIMAGENAME = "image.jpg";
private customImageButton imageButton;
private TextView textView;
private Bitmap bitmap;
private Bitmap resizeBitmap;
private int numberOfFaceDetected;
private FaceDetector.Face[] myFace;
private Bitmap bitmap565;
private Toast toast; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.tv_face);
imageButton = (customImageButton) findViewById(R.id.iv_face);
imageButton.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); } /**
* 点击添加照片事件
*
* @param v
*/
public void onClick(View v) { int bt_id = v.getId();
switch (bt_id) {
case R.id.addPic:
// 添加照片
// 打开本地相册
Intent intent1 = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent1, 101);
break; case R.id.takePhoto:
// 拍照
// 打开本地相机
Intent intent2 = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), CAMERAIMAGENAME));
intent2.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent2, 102); break; default:
break;
} } @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 加判断 不选择照片或者不拍照时不闪退
//Log.e("data", String.valueOf(data));
//if (data == null)
//return; bitmap = null;
switch (requestCode) {
// 选择图片库的图片
case 101:
if (resultCode == RESULT_OK) {
try {
Uri uri = data.getData();
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri); } catch (Exception e) {
e.printStackTrace();
}
}
break; // 表示调用本地照相机拍照
case 102:
if (resultCode == RESULT_OK) {
//Bundle bundle = data.getExtras();
//bm = (Bitmap) bundle.get("data");
bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + "/" + CAMERAIMAGENAME); }
break;
default:
break;
} Log.e("bitmap", String.valueOf(bitmap)); if (bitmap == null) {
toast = Toast.makeText(MainActivity.this, "未选择图像", Toast.LENGTH_SHORT);
toast.show();
return;
} // 转换 释放
bitmap565 = bitmap.copy(Bitmap.Config.RGB_565, true); if (!bitmap.isRecycled())
bitmap.recycle(); // 识别图片
detectFace(); // 画框
drawFace(); // 将照片剪裁 bitmap将被释放重新赋值
int ibWidth = imageButton.getWidth();
int ibHeight = imageButton.getHeight();
resizeBitmap = imageButton.cropBitmap(bitmap565, ibWidth, ibHeight); imageButton.setBitmap(resizeBitmap); } private void detectFace() {
int numberOfFace = 12;
FaceDetector myFaceDetect; int imageWidth = bitmap565.getWidth();
int imageHeight = bitmap565.getHeight();
myFace = new FaceDetector.Face[numberOfFace];
myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);
numberOfFaceDetected = myFaceDetect.findFaces(bitmap565, myFace); textView.setText(String.format("检测到%1$d个人脸", numberOfFaceDetected)); } private void drawFace() {
Canvas canvas = new Canvas(bitmap565);
// canvas.drawBitmap(bitmap565, 0, 0, null);
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
for (int i = 0; i < numberOfFaceDetected; i++) {
FaceDetector.Face face = myFace[i];
PointF myMidPoint = new PointF();
face.getMidPoint(myMidPoint);
float myEyesDistance = face.eyesDistance();
canvas.drawRect((int) (myMidPoint.x - myEyesDistance * 1.5),
(int) (myMidPoint.y - myEyesDistance * 1.5),
(int) (myMidPoint.x + myEyesDistance * 1.5),
(int) (myMidPoint.y + myEyesDistance * 1.8), myPaint);
} } }
自定义ImageButton类,可以按比例缩放bitmap适应ImageButton居中显示:
package com.***.facedetection; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; public class customImageButton extends LinearLayout {
private TextView _textView;
private ImageView _imageView; public customImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
_imageView = new ImageView(context, attrs);
_imageView.setPadding(2, 2, 2, 2); _textView = new TextView(context, attrs);
_textView.setBackgroundColor(Color.TRANSPARENT);
_textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
_textView.setPadding(0, 0, 0, 0); setClickable(true);
setFocusable(true);
setOrientation(LinearLayout.VERTICAL);
addView(_textView);
addView(_imageView);
} public void setText(String text) {
_textView.setText(text);
} public void setButtonEnable(Boolean bool) {
_imageView.setEnabled(bool);
} public void clearnImage() {
_textView.setVisibility(View.VISIBLE);
_imageView.setImageDrawable(null);
} public void setBitmap(Bitmap bm) {
_textView.setVisibility(View.GONE);
_imageView.setImageDrawable(null);
_imageView.setImageBitmap(bm); } public Bitmap cropBitmap(Bitmap bm, int ivbWidth, int ivbHeight) {
Bitmap resizeBmp = null;
try { Matrix matrix = new Matrix(); float scale;
if (ivbWidth <= ivbHeight) {
scale = (float) ivbWidth / bm.getWidth();
matrix.postScale(scale, scale); //长和宽放大缩小的比例
resizeBmp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
} else {
scale = (float) ivbHeight / bm.getHeight();
matrix.postScale(scale, scale);
resizeBmp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
} Log.e("scale", scale + ""); if (!bm.isRecycled())
bm.recycle(); } catch (Exception e) {
e.printStackTrace(); }
return resizeBmp;
} }
布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.***.facedetection.MainActivity"> <com.***.facedetection.customImageButton
android:id="@+id/iv_face"
android:layout_width="match_parent"
android:layout_height="450dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" /> <TextView
android:id="@+id/tv_face"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="未检测到人脸"
android:textColor="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@+id/takePhoto"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" /> <Button
android:id="@+id/takePhoto"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:onClick="onClick"
android:text="拍照"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/addPic"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" /> <Button
android:id="@+id/addPic"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="选择图片"
android:textSize="16sp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>
检测多余人脸:

Android人脸检测1(静态图片)的更多相关文章
- Android+openCV人脸检测2(静态图片)
前几篇文章中有提到对openCV环境配置,这里再重新梳理导入和使用openCV进行简单的人脸检测(包括使用级联分类器) 一 首先导入openCVLibrary320 二 设置gradle的sdk版本号 ...
- android 人脸检测你一定会遇到的坑
笔者今年做了一个和人脸有关的android产品,主要是获取摄像头返回的预览数据流,判断该数据流是否包含了人脸,有人脸时显示摄像头预览框,无人脸时摄像头预览框隐藏,看上去这个功能并不复杂,其实在开发过程 ...
- OpenCV人脸检测并把图片写成avi视频
读出某一个文件夹下“jpg”后缀的全部图片后,用的OpenCV自带的人脸检测检测图片中的人脸,调整图片的大小写成一个avi视频. 主要是要记录一下CvVideoWriter的用法和如何从文件夹中读取某 ...
- 虹软 Android 人脸检测与人脸识别集成分享
目前我们的应用内使用了 ArcFace 的人脸检测功能,其他的我们并不了解,所以这里就和大家分享一下我们的集成过程和一些使用心得 集成ArcFace FD 的集成过程非常简单 在 ArcFace FD ...
- ArcFace Android 人脸检测与人脸识别集成分享
目前我们的应用内使用了 ArcFace 的人脸检测功能,其他的我们并不了解,所以这里就和大家分享一下我们的集成过程和一些使用心得集成ArcFace FD 的集成过程非常简单在 ArcFace FD 的 ...
- OpenCV神技——人脸检测,猫脸检测
简介 OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效--由一系列 C 函数和少量 ...
- OpenCV + Python 人脸检测
必备知识 Haar-like opencv api 读取图片 灰度转换 画图 显示图像 获取人脸识别训练数据 探测人脸 处理人脸探测的结果 实例 图片素材 人脸检测代码 人脸检测结果 总结 下午的时候 ...
- Android中显示gif动态图片
在android中显示一个静态图片比如png jpg等等都很方便,但是如果要显示一个gif 动态图片就需要进行一些处理. 本文是采用自定义view 然后进行重新onDraw方法来实现 首先自定义Vie ...
- OpenCV + python 实现人脸检测(基于照片和视频进行检测)
OpenCV + python 实现人脸检测(基于照片和视频进行检测) Haar-like 通俗的来讲,就是作为人脸特征即可. Haar特征值反映了图像的灰度变化情况.例如:脸部的一些特征能由矩形特征 ...
随机推荐
- Codeforces1100F Ivan and Burgers 【整体二分】【线性基】
题目分析: 一道近似的题目曾经出现在SCOI中,那题可以利用RMQ或者线段树做,这题如果用那种做法时间复杂度会是$log$三次方的. 采用一种类似于整体二分的方法可以解决这道题. 将序列的线段树模型建 ...
- 【JVM】深度分析Java的ClassLoader机制(源码级别)
原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...
- [CTSC2018]暴力写挂
题目描述 www.lydsy.com/JudgeOnline/upload/201805/day1(1).pdf 题解 首先来看这个我们要最大化的东西. deep[u]+deep[v]-deep[lc ...
- 项目管理——WBS工作分解法
首先我们要了解什么是WBS工作分解法 工作分解结构(Work Breakdown Structure,简称WBS)跟因数分解是一个原理,就是把一个项目,按一定的原则分解,项目分解成任务,任务再分解成一 ...
- Springboot 5.Springboot 返回cookies信息的post接口开发
首先创建一个类,类里面首先登陆获取到cookie,然后带着cookie去发送请求 package com.course.server; import com.course.bean.User; imp ...
- springboot中关闭eureka server中已注册服务列表自我保护配置
配置集群服务可以向eureka通知应用是否可以使用a.在eureka server的application.properties中加入:# 设为false,关闭自我保护eureka.server.en ...
- js的几大重点
闭包,:作用域(函数创建),上下文环境(函数执行,会销毁) 匿名函数,:没有函数名的函数,function(){} 自执行函数,:立即调用的匿名函数,(function(){})() 原型链,:继承的 ...
- [再寄小读者之数学篇](2014-05-23 $\ln x-ax=0$ 有两个根时的估计)
已知函数 $f(x)=\ln x-ax$, 其中 $a$ 为常数. 如果 $f(x)$ 有两个零点 $x_1,x_2$. 试证: $x_1x_2>e^2$. 证明: 由 $$\bex \ln x ...
- Jquery+php 动态web表单增删改查
如这类效果: 例一:简单 <html> <head> <meta http-equiv="content-type" content="te ...
- (二)校园信息通微信小程序从后台获取首页的数据笔记
在从后台获取数据之前,需要先搭建好本地服务器的环境. 确保Apache,MySql处于开启状态.下图为Apache,MySql处于开启时状态 然后进入后台管理平台进行字段和列表的定义 然后在后台添加数 ...