安卓OpenCV開發(fā)(二)人臉檢測

重點是人臉檢測,檢測吼野,檢測校哎。

就是把人臉檢測出來,不是識別瞳步,不是識別闷哆,不是識別。識別的意思单起,就是檢測到人臉抱怔,并且通過數(shù)據(jù)比對,算法分析后得出人臉相識度的過程嘀倒。而檢測屈留,僅僅是檢測出來。

針對全網(wǎng)關(guān)于安卓OpenCV識別XXX之類的標(biāo)題括儒,而實際只做了檢測的相關(guān)文章绕沈,在此表示呵呵

回到正題

如何預(yù)覽視頻并進行人臉檢測锐想?

(一)預(yù)覽視頻

可直接使用OpenCV庫中的JavaCameraView控件帮寻,進行視頻的預(yù)覽。

1赠摇、布局中聲明該對象:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <org.opencv.android.JavaCameraView
        android:id="@+id/activity_main_camera_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

2固逗、在布局中,直接調(diào)用該對象的enableView()方法藕帜,即可預(yù)覽烫罩。

備注:權(quán)限申請之類的老生常談,這里不再啰嗦洽故。

(二)構(gòu)建檢測分類器

OpenCV中贝攒,CascadeClassifier是用于分類器進行數(shù)據(jù)處理的。首先时甚,構(gòu)建一個分類器隘弊,需要數(shù)據(jù)源,而人臉檢測的分類器數(shù)據(jù)源荒适,OpenCV官方已經(jīng)有一個可以直接用了梨熙,這里可以直接拿過來用。而文件的路徑刀诬,就在下載的資源文件中的OpenCV-android-sdk\sdk\etc\lbpcascades目錄下咽扇,關(guān)于構(gòu)建項目的流程,不懂可看我上一篇文章
OpenCV導(dǎo)入

把分類器數(shù)據(jù)復(fù)制到主項目的res-raw目錄下,沒有該目錄就新建质欲,復(fù)制后如下圖:


raw文件目錄

然后树埠,在應(yīng)用檢測前,進行分類器數(shù)據(jù)復(fù)制到本地把敞,并初始化分類器弥奸,代碼如下:

try {
            InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
            File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
            File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
            FileOutputStream os = new FileOutputStream(mCascadeFile);

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            is.close();
            os.close();
            cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
        } catch (Exception e) {
            Log.e("OpenCVActivity", "Error loading cascade", e);
        }

這樣就完成了分類器的構(gòu)建了。

(三)監(jiān)聽視頻數(shù)據(jù)

對JavaCameraView設(shè)置CameraBridgeViewBase.CvCameraViewListener即可對視頻數(shù)據(jù)進行監(jiān)聽

(四)人臉檢測奋早,基于第三部盛霎,在監(jiān)聽回調(diào)方法onCameraFragment()中,對回調(diào)的視頻數(shù)據(jù)進行監(jiān)聽耽装,實現(xiàn)代碼如下:

   @Override
    public Mat onCameraFrame(Mat aInputFrame) {
        Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
        MatOfRect faces = new MatOfRect();
        if (cascadeClassifier != null) {
            cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 3, 2,
                    new Size(absoluteFaceSize, absoluteFaceSize), new Size());
        }
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i <facesArray.length; i++){
            Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
        }
        return aInputFrame;
    }

首先愤炸,這里對傳入的圖片幀,進行了一個色值轉(zhuǎn)換的才做掉奄,然后再通過分類器的detectMultiScale方法规个,進行人臉檢測,最后通過Imgproc.rectangle()方法姓建,進行繪制人臉诞仓。

對于detectMultiScale方法的傳入?yún)?shù),析意如下:

1.image表示的是要檢測的輸入圖像
2.objects表示檢測到的人臉目標(biāo)序列
3.scaleFactor表示每次圖像尺寸減小的比例
4.minNeighbors表示每一個目標(biāo)至少要被檢測到3次才算是真的目標(biāo)(因為周圍的像素和不同的窗口大小都可以檢測到人臉)
5.minSize為目標(biāo)的最小尺寸
6.minSize為目標(biāo)的最大尺寸

最后附上完整代碼:

package com.north.light.libopencv;

import android.Manifest;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;

import androidx.appcompat.app.AppCompatActivity;


import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener{

    private CameraBridgeViewBase openCvCameraView;
    private CascadeClassifier cascadeClassifier;
    private Mat grayscaleImage;
    private int absoluteFaceSize;
    private void initializeOpenCVDependencies() {
        try {
            InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
            File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
            File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
            FileOutputStream os = new FileOutputStream(mCascadeFile);

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            is.close();
            os.close();
            cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
        } catch (Exception e) {
            Log.e("OpenCVActivity", "Error loading cascade", e);
        }
        openCvCameraView.enableView();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_main);   // 為該活動設(shè)置布局
        openCvCameraView = findViewById(R.id.activity_main_camera_view);
        openCvCameraView.setCvCameraViewListener(this);

    }
    @Override
    public void onCameraViewStarted(int width, int height) {
        grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
        absoluteFaceSize = (int) (height * 0.2);
    }

    @Override
    public void onCameraViewStopped() {
    }

    @Override
    public Mat onCameraFrame(Mat aInputFrame) {
        Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
        MatOfRect faces = new MatOfRect();
        if (cascadeClassifier != null) {
            cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 3, 2,
                    new Size(absoluteFaceSize, absoluteFaceSize), new Size());
        }
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i <facesArray.length; i++){
            Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
        }
        return aInputFrame;
    }
    @Override
    public void onResume() {
        super.onResume();

        if (!OpenCVLoader.initDebug()) {
        }
        initializeOpenCVDependencies();
        final String[] permissions = {
                Manifest.permission.CAMERA
        };
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(permissions,0);
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        Log.d("返回鍵","back back back");
    }
}

至此速兔,人臉檢測已經(jīng)完成墅拭,不過目前檢測人臉的預(yù)覽顯示,還是橫屏了涣狗,官方的demo也是橫屏顯示的谍婉,而對于豎屏顯示,請看我下一篇文章镀钓。
that's all---------------------------------------------------------------------------------

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末穗熬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丁溅,更是在濱河造成了極大的恐慌唤蔗,老刑警劉巖狱意,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宴霸,死亡現(xiàn)場離奇詭異,居然都是意外死亡偎行,警方通過查閱死者的電腦和手機饰序,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門领虹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人求豫,你說我怎么就攤上這事塌衰∷呱裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵最疆,是天一觀的道長杯巨。 經(jīng)常有香客問我,道長努酸,這世上最難降的妖魔是什么服爷? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮获诈,結(jié)果婚禮上仍源,老公的妹妹穿的比我還像新娘。我一直安慰自己舔涎,他們只是感情好笼踩,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著亡嫌,像睡著了一般嚎于。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挟冠,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天于购,我揣著相機與錄音,去河邊找鬼知染。 笑死肋僧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的持舆。 我是一名探鬼主播色瘩,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼伪窖,長吁一口氣:“原來是場噩夢啊……” “哼逸寓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起覆山,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤竹伸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后簇宽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勋篓,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年魏割,在試婚紗的時候發(fā)現(xiàn)自己被綠了譬嚣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡钞它,死狀恐怖拜银,靈堂內(nèi)的尸體忽然破棺而出殊鞭,到底是詐尸還是另有隱情,我是刑警寧澤尼桶,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布操灿,位于F島的核電站,受9級特大地震影響泵督,放射性物質(zhì)發(fā)生泄漏趾盐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一小腊、第九天 我趴在偏房一處隱蔽的房頂上張望救鲤。 院中可真熱鬧,春花似錦秩冈、人聲如沸蜒简。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搓茬。三九已至,卻和暖如春队他,著一層夾襖步出監(jiān)牢的瞬間卷仑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工麸折, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锡凝,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓垢啼,卻偏偏與公主長得像窜锯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子芭析,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 原文地址: https://blog.csdn.net/qq_34902522/article/details/8...
    宇寶守護神y閱讀 2,243評論 0 3
  • 人臉檢測函數(shù) 在OpenCV中锚扎,人臉檢測使用的函數(shù)是cv2.CascadeClassifier.detectMul...
    極客學(xué)編程閱讀 1,777評論 0 3
  • 之前一直覺得人臉檢測是非常麻煩的,即使是用OpenCV麻煩到我都不敢去碰馁启。這兩天仔細(xì)看了下驾孔,如果只是調(diào)用openc...
    冰不語閱讀 10,094評論 3 17
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來的情緒惯疙。表情可以傳達(dá)很多信息翠勉。高興了當(dāng)然就笑了,難過就哭了霉颠。兩者是相互影響密不可...
    Persistenc_6aea閱讀 125,099評論 2 7
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險厭惡者对碌,不喜歡去冒險,但是人生放棄了冒險蒿偎,也就放棄了無數(shù)的可能朽们。 ...
    yichen大刀閱讀 6,054評論 0 4