版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(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
+
"");
//
因?yàn)榕臄z的相片跟實(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年河南工業(yè)職業(yè)技術(shù)學(xué)院高職單招職業(yè)適應(yīng)性測試近5年??及鎱⒖碱}庫含答案解析
- 2025年江西水利職業(yè)學(xué)院高職單招職業(yè)技能測試近5年??及鎱⒖碱}庫含答案解析
- 專題03 句子(第3期)
- 專題04 世界古代史(易混易錯點(diǎn))
- 簽訂二手房買賣合同注意事項(xiàng)
- 民法租賃合同
- 安裝燈具合同范本
- 裝修工人員工勞動合同
- 渣土運(yùn)輸工程合同
- 直播銷售策劃合同
- 2025年人教五四新版八年級物理上冊階段測試試卷含答案
- 2025新人教版英語七年級下單詞表(小學(xué)部分)
- 2025年春季1530安全教育記錄主題
- 礦山2025年安全工作計(jì)劃
- 2025年包裝印刷項(xiàng)目可行性研究報(bào)告
- 給客戶的福利合同(2篇)
- T-WAPIA 052.3-2023 無線局域網(wǎng)設(shè)備技術(shù)規(guī)范 第3部分:接入點(diǎn)和控制器
- 運(yùn)動技能學(xué)習(xí)與控制完整
- Unit4MyfamilyStorytime(課件)人教新起點(diǎn)英語三年級下冊
- 財(cái)務(wù)管理專業(yè)《生產(chǎn)實(shí)習(xí)》教學(xué)大綱
- 一年級口算天天練(可直接打印)
評論
0/150
提交評論