版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Android中怎么實(shí)現(xiàn)動態(tài)人臉檢測
Android中怎么實(shí)現(xiàn)動態(tài)人臉檢測,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。第一步我們首先來定義一個surfaceview蓋在我們Carmen使用的surfaceview上進(jìn)行對人臉范圍的繪制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();
//
獲得兩眼之間的中間點(diǎn)
face.getMidPoint(midPoint);
//
獲得兩眼之間的距離
eyesDistance
=
face.eyesDistance();
//
換算出預(yù)覽圖片和屏幕顯示區(qū)域的比例參數(shù)
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
+
"");
//
因為拍攝的相片跟實(shí)際顯示的圖像是鏡像關(guān)系,所以在圖片上獲取的兩眼中間點(diǎn)跟手機(jī)上顯示的是相反方向
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與我們要繪制人臉范圍的畫布進(jìn)行綁定Canvascanvas=holder.lockCanvas();這樣我們就可以愉快的進(jìn)行繪制了,當(dāng)然前提是我們要拿到人臉的坐標(biāo)位置。2.還有重要的一點(diǎn),就是要讓我們用來蓋在Carema上的Surfaceview可以同名,并且設(shè)置起在視圖樹的層級為最高。
holder.setFormat(PixelFormat.TRANSPARENT);
this.setZOrderOnTop(true);第二步就是我們對人臉進(jìn)行檢測了,當(dāng)然前提是我們要獲得幀圖public
class
FaceRecognitionDemoActivity
extends
Activity
implements
OnClickListener
{
private
SurfaceView
preview;
private
Camera
camera;
private
Camera.Parameters
parameters;
private
int
orientionOfCamera;//
前置攝像頭的安裝角度
private
int
faceNumber;//
識別的人臉數(shù)
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);
//
設(shè)置緩沖類型(必不可少)
preview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//
設(shè)置surface的分辨率
preview.getHolder().setFixedSize(176,
144);
//
設(shè)置屏幕常亮(必不可少)
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);
//
設(shè)置預(yù)覽區(qū)域的大小
parameters.setPreviewSize(width,
height);
//
設(shè)置每秒鐘預(yù)覽幀數(shù)
parameters.setPreviewFrameRate(20);
//
設(shè)置預(yù)覽圖片的大小
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();
//設(shè)置相機(jī)的參數(shù)
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);
//最重要的設(shè)置
幀圖的回調(diào)
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)
{
//這里需要注意,回調(diào)出來的data不是我們直接意義上的RGB圖
而是YUV圖,因此我們需要
//將YUV轉(zhuǎn)化為bitmap再進(jìn)行相應(yīng)的人臉檢測,同時注意必須使用RGB_565,才能進(jìn)行人臉檢測,其余無效
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
預(yù)覽的圖像數(shù)據(jù)
*/
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;
//設(shè)置各個角度的相機(jī),這樣我們的檢測效果才是最好
switch
(orientionOfCamera)
{
case
0:
//初始化人臉檢測(下同)
detector
=
new
FaceDetector(width,
height,
10);
matrix.postRotate(0.0f,
width
/
2,
height
/
2);
//
以指定的寬度和高度創(chuàng)建一張可變的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;
}
//設(shè)置支持的面數(shù)(最大支持檢測多少人的臉
,可以根據(jù)需要調(diào)整,不過需要與findFaces中的參數(shù)數(shù)值相同,否則會拋出異常)
faces
=
new
FaceDetector.Face[10];
Paint
paint
=
new
Paint();
paint.setDither(true);
Canvas
canvas
=
new
Canvas();
canvas.setBitmap(bitmap2);
canvas.setMatrix(matrix);
//
將bitmap1畫到bitmap2上(這里的偏移參數(shù)根據(jù)實(shí)際情況可能要修改)
canvas.drawBitmap(bitmap1,
0,
0,
paint);
//這里通過向findFaces中傳遞幀圖轉(zhuǎn)化后的bitmap和最大檢測的人臉數(shù)face,返回檢測后的人臉數(shù)
faceNumber
=
detector.findFaces(bitmap2,
faces);
mTV.setText("facnumber"
+
faceNumber);
mTV.setTextColor(Color.RED);
//這里就是我們的人臉識別,繪制識別后的人臉區(qū)域的類
if
(faceNumber
!=
0)
{
mFindFaceView.setVisibility(View.VISIBLE);
mFindFaceView.drawRect(faces,
faceNumber);
}
else
{
mFindFaceView.setVisibility(View.GONE);
}
bitmap2.recycle();
bitmap1.recycle();
}
/**
*
設(shè)置相機(jī)的顯示方向(這里必須這么設(shè)置,不然檢測不到人臉)
*
*
@param
cameraId
相機(jī)ID(0是后置攝像頭,1是前置攝像頭)
*
@param
camera
相機(jī)對象
*/
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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 學(xué)校安全重點(diǎn)部位實(shí)驗室檢查記錄表
- 高一化學(xué)教案:專題第二單元第三課時燃料燃燒釋放的熱量
- 2024高中物理章末質(zhì)量評估一含解析粵教版選修1-1
- 2024高中語文開學(xué)第一課學(xué)生觀后感范文800字少年強(qiáng)中國強(qiáng)素材
- 2024高中語文精讀課文二第4課1貝多芬:扼住命運(yùn)的咽喉一課堂練習(xí)含解析新人教版選修中外傳記蚜
- 2024高考化學(xué)一輪復(fù)習(xí)第十二章物質(zhì)結(jié)構(gòu)與性質(zhì)第一講原子結(jié)構(gòu)與性質(zhì)規(guī)范演練含解析新人教版
- 2024高考?xì)v史一輪復(fù)習(xí)方案專題十五西方人文精神的起源和發(fā)展專題整合備考提能教學(xué)案+練習(xí)人民版
- 2025新人教版英語七年級下單詞表(小學(xué)部分)
- (2篇)2024初中英語教師工作總結(jié)初中英語教師述職報告
- 倉庫管理制度通知
- 基本藥物制度政策培訓(xùn)課件
- 2025年中國華能集團(tuán)限公司校園招聘高頻重點(diǎn)提升(共500題)附帶答案詳解
- GB/T 45002-2024水泥膠砂保水率測定方法
- 廣東省廣州海珠區(qū)2023-2024學(xué)年八年級上學(xué)期期末數(shù)學(xué)試卷(含答案)
- 飛行原理(第二版) 課件 第10章 高速空氣動力學(xué)基礎(chǔ)
- 廣西《乳腺X射線數(shù)字化體層攝影診療技術(shù)操作規(guī)范》
- 山西省2024年中考道德與法治真題試卷(含答案)
- 酒店會議室設(shè)備安裝及調(diào)試方案
- 2024年新疆(兵團(tuán))公務(wù)員考試《行測》真題及答案解析
- JGJ120-2012建筑基坑支護(hù)技術(shù)規(guī)程-20220807013156
- 英語代詞專項訓(xùn)練100(附答案)含解析
評論
0/150
提交評論