成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

詳解android人臉檢測(cè)你一定會(huì)遇到的坑

筆者今年做了一個(gè)和人臉有關(guān)的android產(chǎn)品,主要是獲取攝像頭返回的預(yù)覽數(shù)據(jù)流,判斷該數(shù)據(jù)流是否包含了人臉,有人臉時(shí)顯示攝像頭預(yù)覽框,無(wú)人臉時(shí)攝像頭預(yù)覽框隱藏,看上去這個(gè)功能并不復(fù)雜,其實(shí)在開(kāi)發(fā)過(guò)程中,遇到的問(wèn)題也不多,全部都處理了,在正式推出前,這個(gè)產(chǎn)品在公司內(nèi)部也測(cè)試了幾個(gè)月,也沒(méi)發(fā)現(xiàn)bug,但最近實(shí)施人員,在客戶(hù)公司做實(shí)施時(shí),反饋回來(lái)各種問(wèn)題,這些問(wèn)題有部分是程序bug,也有一部分是和硬件有關(guān),因?yàn)闇y(cè)試環(huán)境有限,筆者無(wú)法對(duì)各種型號(hào),各個(gè)廠家的硬件進(jìn)行測(cè)試,這篇文章主要是記錄,攝像頭給我們帶來(lái)的一些坑,分享給涉及到人臉開(kāi)發(fā)的朋友,讓大家少走彎路。

創(chuàng)新互聯(lián)長(zhǎng)期為近千家客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為吳起企業(yè)提供專(zhuān)業(yè)的成都做網(wǎng)站、成都網(wǎng)站制作,吳起網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

一:概述

Android SDK 中支持人臉檢測(cè),它提供了一個(gè)直接在位圖上進(jìn)行人臉檢測(cè)的方法,這個(gè) API 是android.media.FaceDetector,源文件路徑是:

frameworks/base/media/java/android/media/FaceDetector.java

調(diào)用 findFaces 方法就可進(jìn)行人臉檢測(cè),該方法返回檢測(cè)到的人臉總數(shù),并且會(huì)將每個(gè)”人臉”的信息保存在FaceDetector.Face 的數(shù)組中。每個(gè) Face 都包含下面幾點(diǎn)信息:

  1. 該 Face 為人臉的可信度.取值范圍是 0~1,大于 0.3 則表明可信度較高。
  2. 雙眼之間的距離
  3. 雙眼中點(diǎn)的 x,y 坐標(biāo)
  4. 臉部的歐拉角度,可用于判斷抬頭,側(cè)臉的角度等。

識(shí)別流程是這樣的:

1. 讀取一張圖片至 Bitmap,且該 Bitmap 必須是 565 格式。

2. 調(diào)用 findFaces 方法分析 Bitmap(注意待分析的 Bitmap 寬度必須是偶數(shù)),將探測(cè)到的人臉數(shù)據(jù)存儲(chǔ)在一個(gè)FaceDetector.Face 數(shù)組中,并返回檢測(cè)到的人臉總數(shù)。Android SDK 中的 FaceDetector 介紹

android有原生的api做人臉檢測(cè),通過(guò)android.media.FaceDetector來(lái)檢測(cè)bitmap是否包含人臉,android.media.FaceDetector.Face來(lái)檢測(cè)人臉位置信息,我們需要在activity中實(shí)現(xiàn)Carema.PreviewCallBack接口,該接口有一個(gè)onPreviewFrame方法,這個(gè)方法返回?cái)z像頭實(shí)時(shí)圖像的數(shù)據(jù)流,由于這個(gè)方法返回的數(shù)據(jù)流時(shí)nv21格式,我們需要轉(zhuǎn)換bitmap才能進(jìn)行人臉檢測(cè),轉(zhuǎn)換過(guò)程如下:byte[] --> YuvImage --> ByteArrayOutputStream --> byte[] -->  bitmap ,具體轉(zhuǎn)換的代碼如下:

Camera.Size size = mtCamera.getParameters().getPreviewSize();
YuvImage yuvImage = new YuvImage(mData, ImageFormat.NV21, size.width, size.height, null);
yuvImage.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, mBitmapOutput);
options.inPreferredConfig = Bitmap.Config.RGB_565;
bitmap = BitmapFactory.decodeByteArray(mBitmapOutput.toByteArray(), 0, mBitmapOutput.toByteArray().length, options);
mBitmapOutput.reset();
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mMatrix, false);

通過(guò)上面的轉(zhuǎn)換,我們已經(jīng)得到了人臉檢測(cè)的bitmap,此時(shí)只需要進(jìn)行人臉檢測(cè)就ok了,代碼如下:

detector = new FaceDetector(source.getWidth(),source.getHeight(), maxFaceNum);
Face[] faces = new Face[maxFaceNum];
detector.findFaces(source, faces);

代碼基本上就哪么多,由于受到硬件的影響,上面的代碼有很多地雷。

二:人臉檢測(cè)常見(jiàn)問(wèn)題

產(chǎn)品上線后,主要問(wèn)題有,人站在攝像頭面前,app無(wú)法識(shí)別人臉,軟件運(yùn)行性能也會(huì)下降,出現(xiàn)嚴(yán)重卡頓等問(wèn)題,當(dāng)前我比較郁悶,明明在測(cè)試環(huán)境都運(yùn)行幾個(gè)月了,都沒(méi)有出現(xiàn)這些問(wèn)題,正式實(shí)施的時(shí)候,問(wèn)題不斷,通過(guò)近兩個(gè)月的整理,主要問(wèn)題有以下幾個(gè)。

2.1   無(wú)法識(shí)別人臉

1):相機(jī)角度問(wèn)題

由于我在測(cè)試的時(shí)候,攝像頭圖像是垂直的,沒(méi)有任何問(wèn)題,但正式使用時(shí),攝像頭來(lái)自不同商家,導(dǎo)致攝像頭圖像是水平的了,如下圖:

詳解android 人臉檢測(cè)你一定會(huì)遇到的坑 

詳解android 人臉檢測(cè)你一定會(huì)遇到的坑                                

圖像角度都不對(duì)了,當(dāng)然無(wú)法識(shí)別人臉了,此時(shí)我們需要得到攝像頭的默認(rèn)旋轉(zhuǎn)的角度,再作處理,特別聲明:setDisplayOrientation() 這個(gè)方法是逆時(shí)針旋轉(zhuǎn),代碼如下:

public void setCameraDisplayOrientation (Activity activity, int cameraId, android.hardware.Camera camera) {
  android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
  android.hardware.Camera.getCameraInfo (cameraId , info);
  int rotation = activity.getWindowManager ().getDefaultDisplay ().getRotation ();
  int degrees = 0;
  switch (rotation) {
   case Surface.ROTATION_0:
    degrees = 0;
    break;
   case Surface.ROTATION_90:
    degrees = 90;
    break;
   case Surface.ROTATION_180:
    degrees = 180;
    break;
   case Surface.ROTATION_270:
    degrees = 270;
    break;
  }
  int result;
  if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
   result = (info.orientation + degrees) % 360;
   result = (360 - result) % 360; // compensate the mirror
  } else {
   // back-facing
   result = ( info.orientation - degrees + 360) % 360;
  }
  mOrienta = result;//該值有其它用途
  camera.setDisplayOrientation (result);
 }

2):相機(jī)設(shè)置旋轉(zhuǎn)后,預(yù)覽圖片和相機(jī)返回實(shí)時(shí)流角度問(wèn)題

這個(gè)坑太惡心了,當(dāng)我把相機(jī)角度旋轉(zhuǎn)后,把a(bǔ)pp打包發(fā)一個(gè)給同事,結(jié)果同事告訴我,還是不行,還好在公司借到一個(gè)銳士達(dá)1080p的攝像頭,然后我把onPreviewFrame返回的流畫(huà)到imageView,發(fā)現(xiàn)返回的圖像,和預(yù)覽的圖像,根本不一樣,我勒個(gè)去,雖然預(yù)覽圖像旋轉(zhuǎn)了,我們還需要對(duì)onPreviewFrame返回的流進(jìn)行處理,這個(gè)坑也讓我比較無(wú)語(yǔ),害我找了好久。雖然說(shuō)解決的代碼只有簡(jiǎn)短的幾句,但找出原因過(guò)程只有自己能體會(huì),然后我使用Matrix來(lái)旋轉(zhuǎn)onPreviewFrame返回的流,關(guān)于Matrix,完全是參考android Matrix詳細(xì),這篇文章寫(xiě)得非常好,然而matrix的postRotate是順時(shí)針旋轉(zhuǎn),和camera.setDisplayOrientation()剛好相反,我勒個(gè)去,這兩個(gè)難兄難弟太不讓人省心,一個(gè)順時(shí)針,一個(gè)逆時(shí)針,超級(jí)無(wú)語(yǔ),修改后的代碼如下。

詳解android 人臉檢測(cè)你一定會(huì)遇到的坑 

//mOrienta來(lái)源于setCameraDisplayOrientation
mMatrix = new Matrix();
    switch (mOrienta){
     case 90:
      mMatrix.postRotate(270);
      break;
     case 270:
      mMatrix.postRotate(90);
      break;
     default:
      mMatrix.postRotate(mOrienta);
      break;
    }

 

2.2   720p攝像頭和1080p攝像頭涉及到的問(wèn)題

1):獲取攝像頭支持預(yù)覽尺寸遇到的問(wèn)題

初始化相機(jī)時(shí),我們需要設(shè)置攝像頭支持的預(yù)覽尺寸,如果不是相機(jī)支持的尺寸,會(huì)出現(xiàn)異常,根據(jù)項(xiàng)目需要,本地環(huán)境我直接指定一個(gè)下標(biāo),然后硬件變化后,這個(gè)值也跟著變了,如下圖:

詳解android 人臉檢測(cè)你一定會(huì)遇到的坑    

此處根據(jù)實(shí)際情況獲取,可以計(jì)算每一個(gè)尺寸的面積,通過(guò)一個(gè)基礎(chǔ)面積獲取適應(yīng)的預(yù)覽尺寸。具體代碼就不帖了,只需要清楚有這一個(gè)坑就ok了。

2):獲取預(yù)覽偵寬高大小帶來(lái)的問(wèn)題

如果程序的lock,和線程問(wèn)題沒(méi)處理好,性能問(wèn)題顯而易見(jiàn)。

詳解android 人臉檢測(cè)你一定會(huì)遇到的坑    

如果只是簡(jiǎn)單的識(shí)別人臉,我們可以通過(guò)壓縮圖片的方法來(lái)解決這個(gè)問(wèn)題。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize =2;
options.inPreferredConfig = Bitmap.Config.RGB_565;
bitmap = BitmapFactory.decodeByteArray(mBitmapOutput.toByteArray(), 0, mBitmapOutput.toByteArray().length, options);

3):攝像頭返回的流頻率過(guò)快,導(dǎo)致人臉識(shí)別處理速度根不上的解決辦法

最初軟件運(yùn)行的時(shí)候,運(yùn)行一段時(shí)間,app直接崩潰了,最后發(fā)現(xiàn)是,onPreviewFrame返回的流太快,網(wǎng)上說(shuō)可以在啟動(dòng)相機(jī)時(shí),設(shè)置流的頻率,常見(jiàn)設(shè)置的代碼

Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewFrameRate(3);//設(shè)置每秒3幀,沒(méi)有效果

然而這樣設(shè)置后,完全沒(méi)有用,如圖:

詳解android 人臉檢測(cè)你一定會(huì)遇到的坑 

處理這個(gè)問(wèn)題并不是很復(fù)雜,只是判斷一個(gè)兩次處理流的時(shí)候,大于300毫秒(具體時(shí)間,根據(jù)需求變動(dòng))

 public void onPreviewFrame(byte[] data, Camera camera) {
  Logger.i(TAG+"收到相機(jī)回調(diào):onpreviewframe()"+index);
  if(data!=null&&data.length>0&&System.currentTimeMillis()-time>200){
   time=System.currentTimeMillis();
   mFaceHandle.post(new FaceThread(data,camera,(++index)));
  }
 }

2.3 刷臉的人員走開(kāi)后,屏幕仍然顯示和人臉相關(guān)信息

通過(guò)以上描述我們知道,相機(jī)預(yù)覽圖尺寸過(guò)大,導(dǎo)致刷臉人員走開(kāi)幾秒鐘內(nèi),android設(shè)備屏,仍然顯示和人臉有關(guān)的信息,因?yàn)閛nPreviewFrame頻率較快,而處理人臉的時(shí)間過(guò)長(zhǎng),導(dǎo)致人臉對(duì)列越來(lái)越大,所以人走開(kāi)后,屏才會(huì)顯示相關(guān)信息,這里需要控制,onPreviewFrame處理人臉的頻率大于,以及提升人臉識(shí)別的時(shí)間.

完整demo 下載地址:https://github.com/jlq023/democamera

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

分享標(biāo)題:詳解android人臉檢測(cè)你一定會(huì)遇到的坑
文章源于:http://jinyejixie.com/article20/jjjjjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、小程序開(kāi)發(fā)軟件開(kāi)發(fā)、品牌網(wǎng)站設(shè)計(jì)網(wǎng)站改版、電子商務(wù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)