照相时,在预览画面上提示用户人脸的位置,并完成自动对焦等,是个错的应用; 下面是实现细节

我们知道在android的代码中已有人脸识别的底层算法代码,而且在framework层也封了调用的API函数

extern/neven 目录下是实现人脸识别的算法代码。

添加获取照相时预览图片数据,可以在onPreviewFrame回调函数中得。在开始预览的地方,用mCameraDevice.setPreviewCallback(mPreviewCallback);设置预览回调函数。

import android.media.FaceDetector;

import android.media.FaceDetector.Face;

//Harrison add

private void DrawRectOnFace() {

if (numberOfFaceDetected != 0) {

Face mFace1 = mFace[0];

PointF midPoint = new PointF();

mFace1.getMidPoint(midPoint);

if ((Math.abs(mPreMidPoint.x-midPoint.x) < 50) && (Math.abs(mPreMidPoint.y-midPoint.y) < 50)) {

Log.i("Harrison", "not draw Rect .");

return ;

}

mPreMidPoint.x = midPoint.x;

mPreMidPoint.y = midPoint.y;

mFindFaceView.setVisibility(View.VISIBLE);

} else {

mPreMidPoint.x = 0;

mPreMidPoint.y = 0;

mFindFaceView.clearDraw();

mFindFaceView.setVisibility(View.GONE);

return;

}

mFindFaceView.drawRects(mFace, numberOfFaceDetected);

}

//调用API找人脸,需要import进软件包哦!

private void FindFacesInBitmap(Bitmap myBitmap) {

imageWidth = myBitmap.getWidth();

imageHeight = myBitmap.getHeight();

Log.i("Harrison", "imageWidth="+imageWidth+",  imageHeight="+imageHeight);

mFace = new FaceDetector.Face[numberOfFace];

mFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);

numberOfFaceDetected = mFaceDetect.findFaces(myBitmap, mFace);

Log.i("Harrison", "numberOfFaceDetected="+numberOfFaceDetected);

}

private Bitmap rotateMyBitmap(Bitmap bitmap) {

int width = bitmap.getWidth();

int height = bitmap.getHeight();

Matrix matrix = new Matrix();

matrix.postRotate(90); //椤烘椂閽熸棆杞?0搴︺€?

Bitmap rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

return rotateBitmap;

}

private Bitmap scaleMyBitmap(Bitmap bitmap) {

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int nWidth = mFindFaceView.getFaceViewWidth();;

int nHeight = mFindFaceView.getFaceViewHeight();

// Log.i("Harrison", "nWidth="+nWidth+",  nHeight"+nHeight);

float scaleWidth = ((float) nWidth)/width;

float scaleHeight = ((float)nHeight)/height;

Matrix matrix = new Matrix();

matrix.postScale(scaleWidth, scaleHeight);

Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

return resizedBitmap;

}

//处理图片格式,一般摄像头抓到的数据为ImageFormat.NV21,不同的格式,需要调整的。

private void decodeToBitMap(byte[] data, android.hardware.Camera _camera) {

mCameraDevice.setPreviewCallback(null);

Size size = mCameraDevice.getParameters().getPreviewSize();

//FileOutputStream outStream = null;

try {

YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);

if (image != null) {

ByteArrayOutputStream stream = new ByteArrayOutputStream();

image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);

//  outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));

//  outStream.write(stream.toByteArray());

//  outStream.close();

//  Log.i("Harrison", "write file to sdcard.");

//在我的手机上有两种预览模式,发现全屏模式时需要调整图片的大小才能正确定位。

Bitmap myBitmap=BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

stream.close();

if (mPreviewLayoutProxy.getFullScreenMode()) { // fullscreen mode

Bitmap tmpScaleBmp=null;

Bitmap tmpRotateBmp=null;

//手机是竖屏横排是与其别的哦

if (((mOrientation/90) == 0) || ((mOrientation/90) == 2)) {

tmpRotateBmp = rotateMyBitmap(myBitmap);

tmpScaleBmp = scaleMyBitmap(tmpRotateBmp);

FindFacesInBitmap(tmpScaleBmp);

if (tmpRotateBmp != null) {

tmpRotateBmp.recycle();

tmpRotateBmp = null;

}

} else {

FindFacesInBitmap(scaleMyBitmap(myBitmap));

}

if (tmpScaleBmp != null) {

tmpScaleBmp.recycle();

tmpScaleBmp = null;

}

} else { //normal mode

FindFacesInBitmap(myBitmap);

}

DrawRectOnFace();

if (myBitmap != null) {

myBitmap.recycle();

myBitmap = null;

}

}

} catch (Exception ex) {

Log.e("Sys", "Error:" + ex.getMessage());

}

mCameraDevice.setPreviewCallback(mPreviewCallback);

}

private  final class PostPreviewCallback implements PreviewCallback {

@Override

public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {

decodeToBitMap(data, camera);

}

}

我们知道,相机预览是用 SurfaceView来显示图片的;在我们画提示框时,不能直接用那个view的,会出现黑屏的状态,预览的画面也不流畅的。

添加一个一样大小的SurfaceView来提示。

在xml布局中添加

android:layout_width="match_parent"

android:layout_height="match_parent"/>

android:id="@+id/faces_rectangle"

android:layout_width="fill_parent"

android:layout_height="fill_parent" />

我的画提示框代码:

package com.android.camera;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Bitmap;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Rect;

import android.graphics.Paint.Style;

import android.graphics.PixelFormat;

import android.graphics.PorterDuffXfermode;

import android.graphics.PorterDuff;

import android.util.AttributeSet;

import android.util.Log;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

import android.view.View;

import android.graphics.PointF;

import android.media.FaceDetector;

import android.media.FaceDetector.Face;

public class FindFaceView extends SurfaceView implements SurfaceHolder.Callback{

protected SurfaceHolder sh;

private  SurfaceHolder mCameraSh;

private int mWidth;

private int mHeight;

private float mEyesDistance;

public FindFaceView(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

sh = getHolder();

sh.addCallback(this);

sh.setFormat(PixelFormat.TRANSPARENT);

setZOrderOnTop(true);

}

public void surfaceChanged(SurfaceHolder arg0, int arg1, int w, int h) {

// TODO Auto-generated method stub

mWidth = w;

mHeight = h;

}

public void surfaceCreated(SurfaceHolder arg0) {

// TODO Auto-generated method stub

}

public void surfaceDestroyed(SurfaceHolder arg0) {

// TODO Auto-generated method stub

}

void setCameraPreviewSurfaceHolder(SurfaceHolder  sh) {

mCameraSh = sh;

}

public int getFaceViewWidth() {

return mWidth;

}

public int getFaceViewHeight() {

return mHeight;

}

void clearDraw() {

Canvas canvas = sh.lockCanvas();

Paint clipPaint = new Paint();

clipPaint.setAntiAlias(true);

clipPaint.setStyle(Paint.Style.STROKE);

clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

canvas.drawPaint(clipPaint);

sh.unlockCanvasAndPost(canvas);

}

public void drawRects(FaceDetector.Face[] mFace, int numberOfFaceDetected) {

Canvas canvas = sh.lockCanvas();

Paint clipPaint = new Paint();

clipPaint.setAntiAlias(true);

clipPaint.setStyle(Paint.Style.STROKE);

clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

canvas.drawPaint(clipPaint);

canvas.drawColor(Color.TRANSPARENT);

Paint p = new Paint();

p.setAntiAlias(true);

p.setColor(Color.RED);

p.setStyle(Style.STROKE);

for (int i = 0; i < numberOfFaceDetected; i++) {

//  if (0 == i) {

//   p.setColor(Color.WHITE);

//  } else {

//   p.setColor(Color.GRAY);

//  }

Face face = mFace[i];

PointF myMidPoint = new PointF();

face.getMidPoint(myMidPoint);

mEyesDistance = face.eyesDistance();

Log.i("Harrison", "i="+i+"("+myMidPoint.x+", "+myMidPoint.y+")");

canvas.drawRect((int)(myMidPoint.x-mEyesDistance),

(int)(myMidPoint.y-mEyesDistance),

(int)(myMidPoint.x+mEyesDistance),

(int)(myMidPoint.y+mEyesDistance),

p);

}

sh.unlockCanvasAndPost(canvas);

}

//测试两个View是否错移

public void drawBitmap(Bitmap myBitmap) {

Canvas canvas = sh.lockCanvas();

canvas.drawBitmap(myBitmap, 0, 0, null);

sh.unlockCanvasAndPost(canvas);

// mImage.setImageBitmap(myBitmap);

// mImage.invalidate();

}

public void doDraw() {

Canvas canvas = sh.lockCanvas();

canvas.drawColor(Color.TRANSPARENT);// 这里是绘制背景

Paint p = new Paint(); // 笔触

p.setAntiAlias(true); // 反锯齿

p.setColor(Color.RED);

p.setStyle(Style.STROKE);

canvas.drawLine(mWidth/2 – 100, 0, mWidth/2 – 100, mHeight, p);

canvas.drawLine(mWidth/2 + 100, 0, mWidth/2 + 100, mHeight, p);

// ————————

// 画边框———————

Rect rec = canvas.getClipBounds();

rec.bottom–;

rec.right–;

p.setColor(Color.GRAY);

// 颜色

p.setStrokeWidth(5);

canvas.drawRect(rec, p);

// 提交绘制

sh.unlockCanvasAndPost(canvas);

}

}

遇到一个问题,在预览时频繁的全屏普通切换,容易粗出现识别库无效。请高手指点指点。

本文转载自:CSDN博客

欢迎加入我爱机器学习QQ14群:336582044

微信扫一扫,关注我爱机器学习公众号

android 人脸识别边框_在Android实现人脸识别的详细过程相关推荐

  1. android 人脸识别边框_【技术分享】虹软人脸识别 - Android Camera实时人脸追踪画框适配...

    在使用虹软人脸识别Android SDK的过程中 ,预览时一般都需要绘制人脸框,但是和PC平台相机应用不同,在Android平台相机进行应用开发还需要考虑前后置相机切换.设备横竖屏切换等情况,因此在人 ...

  2. android 人脸识别边框_人脸框抠图如何实现

    最近在尝试做一个人脸识别项目,在对比几款主流人脸识别SDK后,采用了虹软的Arcface SDK,因为它提供了免费版本,并且可以离线使用,接入难度也比较低.项目中有一个需求就是显示检测到的人脸,但是如 ...

  3. android opencv 识别文字_基于SpringBoot的车牌识别系统(附项目地址)

    gitee开源地址 https://gitee.com/admin_yu/yx-image-recognition 介绍 spring boot + maven 实现的车牌识别及训练系统 基于java ...

  4. android 按钮修改边框颜色代码,Android CheckBox修改大小、边框颜色,以及自定义CheckBox;...

    CheckBox修改大小: android:scaleX="0.8" android:scaleY="0.8" CheckBox修改边框颜色,注意不是背景色: ...

  5. android mvp模式例子_关于Android市场这件事,没有饱和的市场只有饱和的思维

    前言 早在几年之前,我们就一直在讨论Android程序员已经饱和的这个问题,直到2020年,Android程序员也没有饱和,相反对高级程序员的需求越来越大. 为什么会有Android程序员已经饱和的错 ...

  6. android 动画 最顶层_【Android编程实战】StrandHogg漏洞复现及原理分析_Android系统上的维京海盗...

    0x00 StrandHogg漏洞详情 StrandHogg漏洞 CVE编号:暂无 [漏洞危害] 近日,Android平台上发现了一个高危漏洞 该漏洞允许攻击者冒充任意合法应用,诱导受害者授予恶意应用 ...

  7. android开发java环境_搭建Android开发环境 - Android - mobile - JavaEye论坛

    Android的开发现在是如火如荼,逞现在不是很忙了,学习了下,这里记录下了在windows在如何搭建Android开发环境,对自己是个记录,对新入门的兄弟姐妹们可以参考一下! (1)安装JDK,省略 ...

  8. android实现评论列表_【Android视图效果】分组列表实现吸顶效果

    效果图 效果图 分析 先来分析一下,可以看到这是一个按月份分组的2行图片列表,列表顶部一个悬浮栏,会随着列表滑动而刷新,点击顶部栏,弹出了一个筛选框. 思路 1.列表部分 可以用RecyclerVie ...

  9. android淡入淡出动画_在Android中淡入动画示例

    android淡入淡出动画 1) XML File: activity_main 1)XML文件:activity_main <?xml version="1.0" enco ...

最新文章

  1. qt获取当前系统音量值_Qt编写自定义控件50-迷你仪表盘
  2. python如何编程-怎么用手机编写Python程序?
  3. CSDN:2020博客之星年度总评选大赛,趣味总结!
  4. 如何设置WIN7自动登录(去除登录密码)
  5. MFC开发IM-第十九篇、获取编辑框内容,并且追加内容
  6. mac mysql 的lb_简单Mysql的lb集群
  7. python永久保存数据_Python学习笔记(四)——文件永久存储
  8. (life)新的一年新的一页
  9. eclipse里source的快捷方法_Eclipse快捷键大全
  10. Coap协议学习(二)
  11. ubuntu 910 下安装万能五笔
  12. C++ 两点之间的距离
  13. firewalld防火墙IP伪装和端口转发
  14. 企业微信开发之获取media_id的值
  15. 关于指针所占的字节数
  16. 太赞了!2021最新Android开发者学习路线,offer拿到手软
  17. 1029: 三角形判定 C语言
  18. git ssh远程登录
  19. 手游立项(一):理解手游开发
  20. ES6—字符串模板引擎

热门文章

  1. C#.net编写摄像头驱动程序,用avicap32.dll
  2. easy-x常用函数
  3. 差价500,Find X3和小米11哪个好?对比后答案明显
  4. 看电影《爱情呼叫转移》
  5. 在上海工作中的一些小技术总结--孔雀开屏列表
  6. EXCEL跨sheet 或者跨 workbook 工作簿 查询是否有重复的!(说明了,跨表只要其他表打开,都可以正常操作,查找,甚至修改,读取等)
  7. 4G网络数据传输流程 二
  8. 【程序员思维进阶】(8)
  9. 编写算法求无向图的连通分量的个数,求无向图的连通分量
  10. Linux(gcc编译原理、过程以及常用调试命令)