android 人臉檢測你一定會遇到的坑

来源:http://www.cnblogs.com/cq-jiang/archive/2017/11/13/7823462.html
-Advertisement-
Play Games

筆者今年做了一個和人臉有關的android產品,主要是獲取攝像頭返回的預覽數據流,判斷該數據流是否包含了人臉,有人臉時顯示攝像頭預覽框,無人臉時攝像頭預覽框隱藏,看上去這個功能並不複雜,其實在開發過程中,遇到的問題也不多,全部都處理了,在正式推出前,這個產品在公司內部也測試了幾個月,也沒發現bug, ...


      筆者今年做了一個和人臉有關的android產品,主要是獲取攝像頭返回的預覽數據流,判斷該數據流是否包含了人臉,有人臉時顯示攝像頭預覽框,無人臉時攝像頭預覽框隱藏,看上去這個功能並不複雜,其實在開發過程中,遇到的問題也不多,全部都處理了,在正式推出前,這個產品在公司內部也測試了幾個月,也沒發現bug,但最近實施人員,在客戶公司做實施時,反饋回來各種問題,這些問題有部分是程式bug,也有一部分是和硬體有關,因為測試環境有限,筆者無法對各種型號,各個廠家的硬體進行測試,這篇文章主要是記錄,攝像頭給我們帶來的一些坑,分享給涉及到人臉開發的朋友,讓大家少走彎路。

  一:概述

  android有原生的api做人臉檢測,通過android.media.FaceDetector來檢測bitmap是否包含人臉,android.media.FaceDetector.Face來檢測人臉位置信息,我們需要在activity中實現Carema.PreviewCallBack介面,該介面有一個onPreviewFrame方法,這個方法返回攝像頭實時圖像的數據流,由於這個方法返回的數據流時nv21格式,我們需要轉換bitmap才能進行人臉檢測,轉換過程如下:byte[] --> YuvImage --> ByteArrayOutputStream --> byte[] -->  bitmap ,具體轉換的代碼如下:

 

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);

通過上面的轉換,我們已經得到了人臉檢測的bitmap,此時只需要進行人臉檢測就ok了,代碼如下:

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

代碼基本上就哪麽多,由於受到硬體的影響,上面的代碼有很多地雷。

  二:人臉檢測常見問題

  產品上線後,主要問題有,人站在攝像頭面前,app無法識別人臉,軟體運行性能也會下降,出現嚴重卡頓等問題,當前我比較鬱悶,明明在測試環境都運行幾個月了,都沒有出現這些問題,正式實施的時候,問題不斷,通過近兩個月的整理,主要問題有以下幾個。

  2.1   無法識別人臉

  1):相機角度問題

  由於我在測試的時候,攝像頭圖像是垂直的,沒有任何問題,但正式使用時,攝像頭來自不同商家,導致攝像頭圖像是水平的了,如下圖:

                                 

  圖像角度都不對了,當然無法識別人臉了,此時我們需要得到攝像頭的預設旋轉的角度,再作處理,特別聲明:setDisplayOrientation() 這個方法是逆時針旋轉,代碼如下:

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):相機設置旋轉後,預覽圖片和相機返回實時流角度問題

  這個坑太噁心了,當我把相機角度旋轉後,把app打包發一個給同事,結果同事告訴我,還是不行,還好在公司借到一個銳士達1080p的攝像頭,然後我把onPreviewFrame返回的流畫到imageView發現返回的圖像,和預覽的圖像,根本不一樣,我勒個去,雖然預覽圖像旋轉了,我們還需要對onPreviewFrame返回的流進行處理,這個坑也讓我比較無語,害我找了好久。雖然說解決的代碼只有簡短的幾句,但找出原因過程只有自己能體會,然後我使用Matrix來旋轉onPreviewFrame返回的流,關於Matrix,完全是參考android Matrix詳細,這篇文章寫得非常好,然而matrix的postRotate是順時針旋轉,和camera.setDisplayOrientation()剛好相反我勒個去,這兩個難兄難弟太不讓人省心,一個順時針,一個逆時針,超級無語,修改後的代碼如下。

//mOrienta來源於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攝像頭涉及到的問題

  1):獲取攝像頭支持預覽尺寸遇到的問題

     初始化相機時,我們需要設置攝像頭支持的預覽尺寸,如果不是相機支持的尺寸,會出現異常,根據項目需要,本地環境我直接指定一個下標,然後硬體變化後,這個值也跟著變了,如下圖:

      

此處根據實際情況獲取,可以計算每一個尺寸的面積,通過一個基礎面積獲取適應的預覽尺寸。具體代碼就不帖了,只需要清楚有這一個坑就ok了。

  2):獲取預覽偵寬高大小帶來的問題

  如果程式的lock,和線程問題沒處理好,性能問題顯而易見。

    

  如果只是簡單的識別人臉,我們可以通過壓縮圖片的方法來解決這個問題。

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):攝像頭返回的流頻率過快,導致人臉識別處理速度根不上的解決辦法

  最初軟體運行的時候,運行一段時間,app直接崩潰了,最後發現是,onPreviewFrame返回的流太快,網上說可以在啟動相機時,設置流的頻率,常見設置的代碼

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

然而這樣設置後,完全沒有用,如圖:

處理這個問題並不是很複雜,只是判斷一個兩次處理流的時候,大於300毫秒(具體時間,根據需求變動)

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

 

  2.3 刷臉的人員走開後,屏幕仍然顯示和人臉相關信息 

   通過以上描述我們知道,相機預覽圖尺寸過大,導致刷臉人員走開幾秒鐘內,android設備屏,仍然顯示和人臉有關的信息,因為onPreviewFrame頻率較快,而處理人臉的時間過長,導致人臉對列越來越大,所以人走開後,屏才會顯示相關信息,這裡需要控制,onPreviewFrame處理人臉的頻率大於,以及提升人臉識別的時間.

 

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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 表格 內添加斑馬線形式的條紋 ( IE8 不支持) ----.table-bordered 為所有表格的單元格添加邊框 ----.table-hover 指針懸停在行上時會出現淺灰色背景 ----.table-condensed 讓表格更加緊湊 --> 用來標識表格的主題,即首行各列的標題 ----... ...
  • React介紹: React是一個庫而不是一個MVC框架,因為React只負責解決MVC框架中V(View)層面的問題,React致力於創建可重用的UI組件。(React is a library for building composable user interfaces. It encoura ...
  • 用angular寫手機頁面,有時候會發現input輸入框點擊了卻不能輸入,或者長按才能輸入,可能是因為input綁定了ng-click導致,可去掉ng-click,將ng-click綁定的方法改用ng-focus就好了 ...
  • 文章導航 前期準備 安裝hexo 修改hexo主題 自定義主題 部署本地文件到github查看 我的第一篇博客 前期準備 下載安裝git命令行工具、node及npm環境 註冊自己的GitHub賬號 安裝hexo 在任意位置右鍵–>git bash(以下命令都在gitBash中執行) 輸入如下命令 自 ...
  • 原文地址: "canvas圖表(1) 柱狀圖" 前幾天用到了圖表庫,其中百度的ECharts,感覺做得最好,看它預設用的是canvas,canvas圖表在處理大數據方面比svg要好。那我也用canvas來實現一個圖表庫吧,感覺不會太難,先實現個簡單的柱狀圖。 效果請看: "柱狀圖https://ed ...
  • Web開發如今是如日中天,熱的發燙。那我們應該怎麼學習呢?這不光是初學者,很多學了幾年的人也會有些迷茫或者彷徨,大家也都知道不斷學習是不可避免的,不學習肯定要掉隊;那怎麼學效率更高,那些是坑,那些是路,每個人可能都有自己的簡介。作為一個程式猿,從兩個方面說說我的想法: 學習方面 1.基礎部分,主要就 ...
  • 本人整理的筆記,來自有道雲筆記: http://note.youdao.com/noteshare?id=12186e338fe5b73cba3cc5876ff167e8&sub=9049D3EE84474F4592905E5B91B13118 ...
  • 對於移動端這塊,筆者之前一直都是進行iOS開發的,也從來沒用過Java。但是因為進入了Google Android全國大學生移動互聯網創新挑戰賽(進入官網)的總決賽(筆者“西部電腦教育提升計劃”的項目被直接推薦進入決賽),這個比賽要求一定要提交apk程式,所以我不得不趕緊學習一下Android開發 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...