




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】Android中怎么实现动态人脸检测
Android中怎么实现动态人脸检测,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。第一步我们首先来定义一个surfaceview盖在我们Carmen使用的surfaceview上进行对人脸范围的绘制public
class
FindFaceView
extends
SurfaceView
implements
SurfaceHolder.Callback
{
private
SurfaceHolder
holder;
private
int
mWidth;
private
int
mHeight;
private
float
eyesDistance;
public
FindFaceView(Context
context,
AttributeSet
attrs)
{
super(context,
attrs);
holder
=
getHolder();
holder.addCallback(this);
holder.setFormat(PixelFormat.TRANSPARENT);
this.setZOrderOnTop(true);
}
@Override
public
void
surfaceChanged(SurfaceHolder
holder,
int
format,
int
width,
int
height)
{
mWidth
=
width;
mHeight
=
height;
}
@Override
public
void
surfaceCreated(SurfaceHolder
holder)
{
}
@Override
public
void
surfaceDestroyed(SurfaceHolder
holder)
{
}
public
void
drawRect(FaceDetector.Face[]
faces,
int
numberOfFaceDetected)
{
Canvas
canvas
=
holder.lockCanvas();
if
(canvas
!=
null)
{
Paint
clipPaint
=
new
Paint();
clipPaint.setAntiAlias(true);
clipPaint.setStyle(Paint.Style.STROKE);
clipPaint
.setXfermode(new
PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawPaint(clipPaint);
canvas.drawColor(getResources().getColor(color.transparent));
Paint
paint
=
new
Paint();
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(5.0f);
for
(int
i
=
0;
i
<
numberOfFaceDetected;
i++)
{
Face
face
=
faces[i];
PointF
midPoint
=
new
PointF();
//
获得两眼之间的中间点
face.getMidPoint(midPoint);
//
获得两眼之间的距离
eyesDistance
=
face.eyesDistance();
//
换算出预览图片和屏幕显示区域的比例参数
float
scale_x
=
mWidth
/
500;
float
scale_y
=
mHeight
/
600;
Log.e("eyesDistance=",
eyesDistance
+
"");
Log.e("midPoint.x=",
midPoint.x
+
"");
Log.e("midPoint.y=",
midPoint.y
+
"");
//
因为拍摄的相片跟实际显示的图像是镜像关系,所以在图片上获取的两眼中间点跟手机上显示的是相反方向
canvas.drawRect((int)
(240
-
midPoint.x
-
eyesDistance)
*
scale_x,
(int)
(midPoint.y
*
scale_y),
(int)
(240
-
midPoint.x
+
eyesDistance)
*
scale_x,
(int)
(midPoint.y
+
3
*
eyesDistance)
*
scale_y,
paint);
}
holder.unlockCanvasAndPost(canvas);
}
}
}重要的地方1.holder=getHolder();获取surfaceholder与我们要绘制人脸范围的画布进行绑定Canvascanvas=holder.lockCanvas();这样我们就可以愉快的进行绘制了,当然前提是我们要拿到人脸的坐标位置。2.还有重要的一点,就是要让我们用来盖在Carema上的Surfaceview可以同名,并且设置起在视图树的层级为最高。
holder.setFormat(PixelFormat.TRANSPARENT);
this.setZOrderOnTop(true);第二步就是我们对人脸进行检测了,当然前提是我们要获得帧图public
class
FaceRecognitionDemoActivity
extends
Activity
implements
OnClickListener
{
private
SurfaceView
preview;
private
Camera
camera;
private
Camera.Parameters
parameters;
private
int
orientionOfCamera;//
前置摄像头的安装角度
private
int
faceNumber;//
识别的人脸数
private
FaceDetector.Face[]
faces;
private
FindFaceView
mFindFaceView;
private
ImageView
iv_photo;
private
Button
bt_camera;
TextView
mTV;
/**
*
Called
when
the
activity
is
first
created.
*/
@Override
public
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected
void
onStart()
{
super.onStart();
iv_photo
=
(ImageView)
findViewById(R.id.iv_photo);
bt_camera
=
(Button)
findViewById(R.id.bt_camera);
mTV
=
(TextView)
findViewById(R.id.show_count);
bt_camera.setOnClickListener(this);
mFindFaceView
=
(FindFaceView)
findViewById(R.id.my_preview);
preview
=
(SurfaceView)
findViewById(R.id.preview);
//
设置缓冲类型(必不可少)
preview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//
设置surface的分辨率
preview.getHolder().setFixedSize(176,
144);
//
设置屏幕常亮(必不可少)
preview.getHolder().setKeepScreenOn(true);
preview.getHolder().addCallback(new
SurfaceCallback());
}
private
final
class
MyPictureCallback
implements
PictureCallback
{
@Override
public
void
onPictureTaken(byte[]
data,
Camera
camera)
{
try
{
Bitmap
bitmap
=
BitmapFactory.decodeByteArray(data,
0,
data.length);
Matrix
matrix
=
new
Matrix();
matrix.setRotate(-90);
Bitmap
bmp
=
Bitmap.createBitmap(bitmap,
0,
0,
bitmap
.getWidth(),
bitmap.getHeight(),
matrix,
true);
bitmap.recycle();
iv_photo.setImageBitmap(bmp);
camera.startPreview();
}
catch
(Exception
e)
{
e.printStackTrace();
}
}
}
private
final
class
SurfaceCallback
implements
Callback
{
@Override
public
void
surfaceChanged(SurfaceHolder
holder,
int
format,
int
width,
int
height)
{
if
(camera
!=
null)
{
parameters
=
camera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
//
设置预览区域的大小
parameters.setPreviewSize(width,
height);
//
设置每秒钟预览帧数
parameters.setPreviewFrameRate(20);
//
设置预览图片的大小
parameters.setPictureSize(width,
height);
parameters.setJpegQuality(80);
}
}
@Override
public
void
surfaceCreated(SurfaceHolder
holder)
{
int
cameraCount
=
0;
Camera.CameraInfo
cameraInfo
=
new
Camera.CameraInfo();
cameraCount
=
Camera.getNumberOfCameras();
//设置相机的参数
for
(int
i
=
0;
i
<
cameraCount;
i++)
{
Camera.getCameraInfo(i,
cameraInfo);
if
(cameraInfo.facing
==
Camera.CameraInfo.CAMERA_FACING_FRONT)
{
try
{
camera
=
Camera.open(i);
camera.setPreviewDisplay(holder);
setCameraDisplayOrientation(i,
camera);
//最重要的设置
帧图的回调
camera.setPreviewCallback(new
MyPreviewCallback());
camera.startPreview();
}
catch
(Exception
e)
{
e.printStackTrace();
}
}
}
}
@Override
public
void
surfaceDestroyed(SurfaceHolder
holder)
{
//记得释放,避免OOM和占用
if
(camera
!=
null)
{
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera
=
null;
}
}
}
private
class
MyPreviewCallback
implements
PreviewCallback
{
@Override
public
void
onPreviewFrame(byte[]
data,
Camera
camera)
{
//这里需要注意,回调出来的data不是我们直接意义上的RGB图
而是YUV图,因此我们需要
//将YUV转化为bitmap再进行相应的人脸检测,同时注意必须使用RGB_565,才能进行人脸检测,其余无效
Camera.Size
size
=
camera.getParameters().getPreviewSize();
YuvImage
yuvImage
=
new
YuvImage(data,
ImageFormat.NV21,
size.width,
size.height,
null);
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream();
yuvIpressToJpeg(new
Rect(0,
0,
size.width,
size.height),
80,
baos);
byte[]
byteArray
=
baos.toByteArray();
detectionFaces(byteArray);
}
}
/**
*
检测人脸
*
*
@param
data
预览的图像数据
*/
private
void
detectionFaces(byte[]
data)
{
BitmapFactory.Options
options
=
new
BitmapFactory.Options();
Bitmap
bitmap1
=
BitmapFactory.decodeByteArray(data,
0,
data.length,
options);
int
width
=
bitmap1.getWidth();
int
height
=
bitmap1.getHeight();
Matrix
matrix
=
new
Matrix();
Bitmap
bitmap2
=
null;
FaceDetector
detector
=
null;
//设置各个角度的相机,这样我们的检测效果才是最好
switch
(orientionOfCamera)
{
case
0:
//初始化人脸检测(下同)
detector
=
new
FaceDetector(width,
height,
10);
matrix.postRotate(0.0f,
width
/
2,
height
/
2);
//
以指定的宽度和高度创建一张可变的bitmap(图片格式必须是RGB_565,不然检测不到人脸)
bitmap2
=
Bitmap.createBitmap(width,
height,
Bitmap.Config.RGB_565);
break;
case
90:
detector
=
new
FaceDetector(height,
width,
1);
matrix.postRotate(-270.0f,
height
/
2,
width
/
2);
bitmap2
=
Bitmap.createBitmap(height,
width,
Bitmap.Config.RGB_565);
break;
case
180:
detector
=
new
FaceDetector(width,
height,
1);
matrix.postRotate(-180.0f,
width
/
2,
height
/
2);
bitmap2
=
Bitmap.createBitmap(width,
height,
Bitmap.Config.RGB_565);
break;
case
270:
detector
=
new
FaceDetector(height,
width,
1);
matrix.postRotate(-90.0f,
height
/
2,
width
/
2);
bitmap2
=
Bitmap.createBitmap(height,
width,
Bitmap.Config.RGB_565);
break;
}
//设置支持的面数(最大支持检测多少人的脸
,可以根据需要调整,不过需要与findFaces中的参数数值相同,否则会抛出异常)
faces
=
new
FaceDetector.Face[10];
Paint
paint
=
new
Paint();
paint.setDither(true);
Canvas
canvas
=
new
Canvas();
canvas.setBitmap(bitmap2);
canvas.setMatrix(matrix);
//
将bitmap1画到bitmap2上(这里的偏移参数根据实际情况可能要修改)
canvas.drawBitmap(bitmap1,
0,
0,
paint);
//这里通过向findFaces中传递帧图转化后的bitmap和最大检测的人脸数face,返回检测后的人脸数
faceNumber
=
detector.findFaces(bitmap2,
faces);
mTV.setText("facnumber"
+
faceNumber);
mTV.setTextColor(Color.RED);
//这里就是我们的人脸识别,绘制识别后的人脸区域的类
if
(faceNumber
!=
0)
{
mFindFaceView.setVisibility(View.VISIBLE);
mFindFaceView.drawRect(faces,
faceNumber);
}
else
{
mFindFaceView.setVisibility(View.GONE);
}
bitmap2.recycle();
bitmap1.recycle();
}
/**
*
设置相机的显示方向(这里必须这么设置,不然检测不到人脸)
*
*
@param
cameraId
相机ID(0是后置摄像头,1是前置摄像头)
*
@param
camera
相机对象
*/
private
void
setCameraDisplayOrientation(int
cameraId,
Camera
camera)
{
Camera.CameraInfo
info
=
new
Camera.CameraInfo();
Camera.getCameraInfo(cameraId,
info);
int
r
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 新能源汽车动力电池及零部件检测合同
- 商品分销代理合同
- 承揽合同是何种类型合同
- 商业空间装修设计合同2025
- 中保人寿个人养老金保险合同范本
- 兼职人员聘用合同(试聘版)
- 正式合同样本:电子产品供货合同
- 矿产销售合同
- 5 草船借箭(教学设计)2023-2024学年统编版语文五年级下册
- 房屋买卖合同新条款解析
- 公安食药环培训课件
- 《群英会蒋干中计》课件38张 2023-2024学年高教版(2023)中职语文基础模块下册
- 大单元教学和集体备课研究
- 《学术不端行为》课件
- 《麦田怪圈探密》课件
- 《智能建造导论》 课件 刘占省 第1-5章 智能建造的兴起-智能建造与全生命周期的目标规划
- 经济数学《线性代数》期末试卷一(含答案解析)
- 个人民事起诉状模板
- 劳务人员管理制度(7篇)
- 事故隐患安全培训事故排查安全隐患
- 新人教版高中数学选择性必修第一册全套精品课件
评论
0/150
提交评论